diff --git a/AUTHORS b/AUTHORS index 4bb6b20..aad65f3c 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -1114,6 +1114,7 @@ Vernon Tang <vt@foilhead.net> Viatcheslav Ostapenko <sl.ostapenko@samsung.com> Victor Costan <costan@gmail.com> +Victor Solonsky <victor.solonsky@gmail.com> Viet-Trung Luu <viettrungluu@gmail.com> Vinay Anantharaman <vinaya@adobe.com> Vinoth Chandar <vinoth@uber.com>
diff --git a/BUILD.gn b/BUILD.gn index 299555e1..9309623 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -90,6 +90,7 @@ "//third_party/angle/src/tests:angle_end2end_tests", "//third_party/angle/src/tests:angle_unittests", "//third_party/angle/src/tests:angle_white_box_tests", + "//third_party/distributed_point_functions", "//third_party/flatbuffers:flatbuffers_unittests", "//third_party/liburlpattern:liburlpattern_unittests", "//tools/binary_size:binary_size_trybot_py",
diff --git a/DEPS b/DEPS index 0c2879bb..e62a90f 100644 --- a/DEPS +++ b/DEPS
@@ -209,11 +209,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': 'a733cb07c66464f13bd41581dca3d54d16886842', + 'skia_revision': 'f4741026ea7343b00e131fa0f2a2272af06c04db', # 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': '583828a7ea1c6af3d5849ed37226e31eb9b51ccc', + 'v8_revision': 'c42bdb75168de2fe93086a587d890bad7f08f212', # 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. @@ -221,7 +221,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': 'a5b302d38fc7f5bb49b65da2b9272b9f52aa347c', + 'angle_revision': 'bb6e12a389871059e8bbfcb7a0cec952f87dcd7c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -268,7 +268,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling HarfBuzz # and whatever else without interference from each other. - 'harfbuzz_revision': '7ab0f4eda9a8a1d7ccd334fa7f9fef4b038a1c24', + 'harfbuzz_revision': '4811e8f5d76ef528b4cec00f241cc4ab8110db30', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Emoji Segmenter # and whatever else without interference from each other. @@ -280,7 +280,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': '8bf7a0b3c8bddeccd9c5b3ca4a58dccfa8797702', + 'catapult_revision': 'c8ae7ec5346bb7878d7e24250e776191b825d9d1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -288,7 +288,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': '7554e1a13d8427c6f5292103845c03ca12d84278', + 'devtools_frontend_revision': 'c8872627959e942715fe444e463f6439858905f9', # 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. @@ -324,11 +324,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'shaderc_revision': '772eac6bcaa2742a5c8da44f5480cf6a71d562d9', + 'shaderc_revision': '7eea4ddee04743e4438c81826e0ec58bc0c6b374', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '6dc5562fbbc72724c517f4a5711875d9ec665225', + 'dawn_revision': '08a18771c16813b7014fbd56ec67980fc2f047c4', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -730,7 +730,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '8d-gGcc4KVhOnn2B-Od7eR421Q-sNZQ0U7dMrNz_VX4C', + 'version': 'SZh6kDBh5bVJm_ADaQfC6SaHIHPyAeMCYgYd3xRQsegC', }, ], 'condition': 'checkout_android', @@ -946,7 +946,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '982a27aa6b95c0e515730c1ac2b89efb3c338e9c', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0337586cec30409038f1f2afd012ba4ceda76a31', 'condition': 'checkout_chromeos', }, @@ -966,11 +966,14 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'a5b6b2f8b75c5c0a14a074be91c7c32ddd278388', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '730b974ee71ab08e1a9781439724bbe8e5e7ec12', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), + 'src/third_party/distributed_point_functions/src': + Var('chromium_git') + '/external/github.com/google/distributed_point_functions.git' + '@' + 'ea175a91e6eda5b22392fdae82080eb9709cd0eb', + 'src/third_party/dom_distiller_js/dist': Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + 'f339eb9463714c3d31657c8ee1bd53d1c7e5c555', @@ -1349,7 +1352,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '468c71c71f9b2f51f88a71eddfcf1068e9c026a7', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '0856d6eecd570d889e563399e658803ebc5c0a95', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1547,7 +1550,7 @@ 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '22ba62ffe79c3881581ab430368bf3764d9533eb', - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@121f7d60f035f7dfb3fadb3633b292140d79b454', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@9f96b6d32ac6a749dec013f15e80e8fe9b404060', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '732a76d9d3c70d6aa487216495eeb28518349c3a', @@ -1574,7 +1577,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '6e5cab434bacd6fcbb833b8e5cb8ff47495d4a64', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '1a778a24bae53d98f372a93429344953be9f5491', + Var('webrtc_git') + '/src.git' + '@' + '637a9eebd70442f7a239d0c0e84e23a567231930', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1635,7 +1638,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@aa017d9e3db52282ae37381214f1cc2a71a8fd27', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c8ddcfd412f40182fa9e45bee123e5fac31fee0e', 'condition': 'checkout_src_internal', }, @@ -1654,7 +1657,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'O7R570kj6BjdLWsxJYo37RmLSHDyNnahPCuvX4kseEsC', + 'version': 'rpUlHZm7I5acL2GpcJwCQJAj1UTBCa1hvqqjdnVZqfgC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/WATCHLISTS b/WATCHLISTS index 942ef27..9586929a4 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -956,6 +956,11 @@ 'media/cdm/|' \ 'third_party/widevine/cdm/' }, + 'enterprise_reporting_private': { + 'filepath': 'chrome/common/extensions/api/enterprise_reporting_private.idl|' \ + 'chrome/browser/extensions/api/enterprise_reporting_private/|' \ + 'chrome/browser/enterprise/signals/' + }, 'exo': { 'filepath': 'components/exo', }, @@ -2446,6 +2451,8 @@ 'downloads_ui': ['dtrainor+watch@chromium.org'], 'drive_resource_metadata': ['hashimoto+watch@chromium.org'], 'eme': ['eme-reviews@chromium.org'], + 'enterprise_reporting_private': ['domfc+watch@chromium.org', + 'anthonyvd+watch@chormium.org'], 'exo': ['crostini-ui+exo@chromium.org'], 'explore_sites': ['chili+watch@chromium.org', 'dewittj+watch@chromium.org',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 27b22b4..0f3d9b7 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -475,6 +475,7 @@ "java/src/org/chromium/android_webview/AwWebContentsObserver.java", "java/src/org/chromium/android_webview/AwWebResourceInterceptResponse.java", "java/src/org/chromium/android_webview/AwZoomControls.java", + "java/src/org/chromium/android_webview/BrowserSafeModeActionList.java", "java/src/org/chromium/android_webview/CleanupReference.java", "java/src/org/chromium/android_webview/ClientCertLookupTable.java", "java/src/org/chromium/android_webview/DefaultVideoPosterRequestHandler.java", @@ -514,6 +515,7 @@ "java/src/org/chromium/android_webview/safe_browsing/AwSafeBrowsingConversionHelper.java", "java/src/org/chromium/android_webview/safe_browsing/AwSafeBrowsingResponse.java", "java/src/org/chromium/android_webview/variations/VariationsSeedLoader.java", + "java/src/org/chromium/android_webview/variations/VariationsSeedSafeModeAction.java", ] deps = [ ":common_aidl_java", @@ -526,7 +528,7 @@ "//android_webview/nonembedded:system_webview_manifest", "//android_webview/proto:metrics_bridge_records_proto_java", "//base:base_java", - "//components/android_autofill/android:java", + "//components/android_autofill/browser:java", "//components/autofill/android:autofill_java", "//components/background_task_scheduler:background_task_scheduler_task_ids_java", "//components/component_updater/android:embedded_component_loader_java",
diff --git a/android_webview/browser/BUILD.gn b/android_webview/browser/BUILD.gn index c72525b..a5a3e688 100644 --- a/android_webview/browser/BUILD.gn +++ b/android_webview/browser/BUILD.gn
@@ -199,7 +199,7 @@ "//android_webview/common:mojom", "//android_webview/proto:aw_variations_seed_proto", "//base", - "//components/android_autofill/android", + "//components/android_autofill/browser:android", "//components/autofill/content/browser", "//components/cdm/browser", "//components/component_updater/android:embedded_component_loader", @@ -237,6 +237,7 @@ "//components/safe_browsing/android:remote_database_manager", "//components/safe_browsing/content/browser", "//components/safe_browsing/content/common:interfaces", + "//components/safe_browsing/content/triggers", "//components/safe_browsing/content/web_ui", "//components/safe_browsing/core:features", "//components/safe_browsing/core:ping_manager", @@ -245,7 +246,6 @@ "//components/safe_browsing/core/common", "//components/safe_browsing/core/db:database_manager", "//components/safe_browsing/core/db:safebrowsing_proto", - "//components/safe_browsing/core/triggers", "//components/safe_browsing/core/web_ui:constants", "//components/security_interstitials/content:security_interstitial_page", "//components/security_interstitials/core",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS index 57bd101b..822e592b 100644 --- a/android_webview/browser/DEPS +++ b/android_webview/browser/DEPS
@@ -7,7 +7,6 @@ "+android_webview/proto", "+android_webview/test/android_webview_unittests_jni", "+cc", - "+components/android_autofill/android", "+components/android_autofill/browser", "+components/autofill/content/browser", "+components/autofill/content/common",
diff --git a/android_webview/browser/aw_browser_process.h b/android_webview/browser/aw_browser_process.h index 48b0dd5..a4a3487 100644 --- a/android_webview/browser/aw_browser_process.h +++ b/android_webview/browser/aw_browser_process.h
@@ -17,7 +17,7 @@ #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/android/remote_database_manager.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" #include "content/public/browser/network_service_instance.h" #include "net/log/net_log.h" #include "services/network/network_service.h"
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc index 1c6d1dd..11c99bcc 100644 --- a/android_webview/browser/aw_contents.cc +++ b/android_webview/browser/aw_contents.cc
@@ -61,8 +61,8 @@ #include "base/supports_user_data.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" -#include "components/android_autofill/android/autofill_provider_android.h" #include "components/android_autofill/browser/android_autofill_manager.h" +#include "components/android_autofill/browser/autofill_provider_android.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_features.h"
diff --git a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc index ff93cc4..0bac4feb 100644 --- a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc +++ b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc
@@ -16,11 +16,11 @@ #include "base/metrics/histogram_macros.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/content/browser/threat_details.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/safe_browsing/core/common/safebrowsing_constants.h" #include "components/safe_browsing/core/common/utils.h" #include "components/safe_browsing/core/features.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" #include "components/security_interstitials/content/security_interstitial_controller_client.h" #include "components/security_interstitials/content/settings_page_helper.h" #include "components/security_interstitials/content/unsafe_resource_util.h"
diff --git a/android_webview/java/src/org/chromium/android_webview/BrowserSafeModeActionList.java b/android_webview/java/src/org/chromium/android_webview/BrowserSafeModeActionList.java new file mode 100644 index 0000000..61d6de8 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/BrowserSafeModeActionList.java
@@ -0,0 +1,25 @@ +// Copyright 2021 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. + +package org.chromium.android_webview; + +import org.chromium.android_webview.common.SafeModeAction; +import org.chromium.android_webview.variations.VariationsSeedSafeModeAction; + +/** + * Exposes the SafeModeActions supported by the browser process. + */ +public final class BrowserSafeModeActionList { + // Do not instantiate this class. + private BrowserSafeModeActionList() {} + + /** + * A list of SafeModeActions supported in the browser process. The set of actions to be + * executed will be specified by the nonembedded SafeModeService, however each action (if + * specified by the service) will be executed in the order listed below. + */ + public static final SafeModeAction[] sList = { + new VariationsSeedSafeModeAction(), + }; +}
diff --git a/android_webview/java/src/org/chromium/android_webview/variations/VariationsSeedLoader.java b/android_webview/java/src/org/chromium/android_webview/variations/VariationsSeedLoader.java index f6c7109..5eccafa 100644 --- a/android_webview/java/src/org/chromium/android_webview/variations/VariationsSeedLoader.java +++ b/android_webview/java/src/org/chromium/android_webview/variations/VariationsSeedLoader.java
@@ -364,8 +364,8 @@ } // Block on loading the seed with a timeout. Then if a seed was successfully loaded, initialize - // variations. - public void finishVariationsInit() { + // variations. Returns whether or not variations was initialized. + public boolean finishVariationsInit() { long start = SystemClock.elapsedRealtime(); try { try { @@ -376,7 +376,7 @@ long seedAge = TimeUnit.MILLISECONDS.toSeconds(new Date().getTime() - seedDate); VariationsUtils.debugLog("Loaded seed with age " + seedAge + "s"); } - return; + return gotSeed; } finally { long end = SystemClock.elapsedRealtime(); recordSeedLoadBlockingTime(end - start); @@ -389,6 +389,7 @@ recordLoadSeedResult(LoadSeedResult.LOAD_OTHER_FAILURE); } Log.e(TAG, "Failed loading variations seed. Variations disabled."); + return false; } @NativeMethods
diff --git a/android_webview/java/src/org/chromium/android_webview/variations/VariationsSeedSafeModeAction.java b/android_webview/java/src/org/chromium/android_webview/variations/VariationsSeedSafeModeAction.java new file mode 100644 index 0000000..eafb664 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/variations/VariationsSeedSafeModeAction.java
@@ -0,0 +1,42 @@ +// Copyright 2021 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. + +package org.chromium.android_webview.variations; + +import androidx.annotation.NonNull; + +import org.chromium.android_webview.common.SafeModeAction; +import org.chromium.android_webview.common.variations.VariationsUtils; +import org.chromium.base.Log; + +import java.io.File; + +/** + * A {@link SafeModeAction} to delete the variations seed. + */ +public class VariationsSeedSafeModeAction implements SafeModeAction { + private static final String TAG = "WebViewSafeMode"; + + // This ID should not be changed or reused. + private static final String ID = "delete_variations_seed"; + + @Override + @NonNull + public String getId() { + return ID; + } + + @Override + public void execute() { + deleteIfExists(VariationsUtils.getSeedFile()); + deleteIfExists(VariationsUtils.getNewSeedFile()); + deleteIfExists(VariationsUtils.getStampFile()); + } + + private static void deleteIfExists(File file) { + if (file.exists() && !file.delete()) { + Log.e(TAG, "Failed to delete " + file); + } + } +}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeModeTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeModeTest.java index 0ca2216..6fae808 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/SafeModeTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeModeTest.java
@@ -21,15 +21,22 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.android_webview.BrowserSafeModeActionList; import org.chromium.android_webview.common.SafeModeAction; import org.chromium.android_webview.common.SafeModeController; import org.chromium.android_webview.common.services.ISafeModeService; +import org.chromium.android_webview.common.variations.VariationsUtils; import org.chromium.android_webview.services.SafeModeService; +import org.chromium.android_webview.test.VariationsSeedLoaderTest.TestLoader; +import org.chromium.android_webview.test.VariationsSeedLoaderTest.TestLoaderResult; import org.chromium.android_webview.test.services.ServiceConnectionHelper; +import org.chromium.android_webview.test.util.VariationsTestUtils; +import org.chromium.android_webview.variations.VariationsSeedSafeModeAction; import org.chromium.base.ContextUtils; import org.chromium.base.test.util.Feature; import org.chromium.build.BuildConfig; +import java.io.File; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -313,4 +320,73 @@ Assert.assertEquals("testAction1 should be executed third the next time", 6, testAction1.getExecutionOrder()); } + + @Test + @MediumTest + public void testSafeModeAction_canRegisterBrowserActions() throws Exception { + // Validity check: verify we can register the production SafeModeAction list. As long as + // this finishes without throwing, assume the list is in good shape (e.g., no duplicate + // SafeModeAction IDs). + SafeModeController.getInstance().registerActions(BrowserSafeModeActionList.sList); + } + + @Test + @MediumTest + public void testVariations_deletesSeedFiles() throws Exception { + try { + File oldFile = VariationsUtils.getSeedFile(); + File newFile = VariationsUtils.getNewSeedFile(); + Assert.assertTrue("Seed file already exists", oldFile.createNewFile()); + Assert.assertTrue("New seed file already exists", newFile.createNewFile()); + VariationsTestUtils.writeMockSeed(oldFile); + VariationsTestUtils.writeMockSeed(newFile); + VariationsSeedSafeModeAction action = new VariationsSeedSafeModeAction(); + action.execute(); + Assert.assertFalse( + "Old seed should have been deleted but it still exists", oldFile.exists()); + Assert.assertFalse( + "New seed should have been deleted but it still exists", newFile.exists()); + } finally { + VariationsTestUtils.deleteSeeds(); + } + } + + @Test + @MediumTest + public void testVariations_doesNotLoadExperiments() throws Exception { + try { + File oldFile = VariationsUtils.getSeedFile(); + File newFile = VariationsUtils.getNewSeedFile(); + Assert.assertTrue("Seed file already exists", oldFile.createNewFile()); + Assert.assertTrue("New seed file already exists", newFile.createNewFile()); + VariationsTestUtils.writeMockSeed(oldFile); + VariationsTestUtils.writeMockSeed(newFile); + VariationsSeedSafeModeAction action = new VariationsSeedSafeModeAction(); + action.execute(); + + TestLoader loader = new TestLoader(new TestLoaderResult()); + loader.startVariationsInit(); + boolean loadedSeed = loader.finishVariationsInit(); + Assert.assertFalse( + "Loaded a variations seed even though it should have been deleted by SafeMode", + loadedSeed); + } finally { + VariationsTestUtils.deleteSeeds(); + } + } + + @Test + @MediumTest + public void testVariations_doesNothingIfSeedDoesNotExist() throws Exception { + try { + File oldFile = VariationsUtils.getSeedFile(); + File newFile = VariationsUtils.getNewSeedFile(); + VariationsSeedSafeModeAction action = new VariationsSeedSafeModeAction(); + action.execute(); + Assert.assertFalse("Old seed should never have existed", oldFile.exists()); + Assert.assertFalse("New seed should never have existed", newFile.exists()); + } finally { + VariationsTestUtils.deleteSeeds(); + } + } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/VariationsSeedLoaderTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/VariationsSeedLoaderTest.java index 4888870..d15f46e 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/VariationsSeedLoaderTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/VariationsSeedLoaderTest.java
@@ -50,7 +50,11 @@ @Rule public AwActivityTestRule mActivityTestRule = new AwActivityTestRule(); - private static class TestLoaderResult extends CallbackHelper { + /** + * Helper class to interact with {@link TestLoader}. This can be used to retrieve whether + * TestLoader requested a seed. + */ + public static class TestLoaderResult extends CallbackHelper { private volatile boolean mBackgroundWorkFinished; private volatile boolean mForegroundWorkFinished; private volatile boolean mSeedRequested; @@ -81,7 +85,13 @@ } } - private static class TestLoader extends VariationsSeedLoader { + /** + * A {@link VariationsSeedLoader} which is suitable for integration tests. This overrides the + * default timeout to be suitable for integration tests, allowing the test to call + * startVariationsInit() immediately before finishVariationsInit(). This also overrides the + * service Intent to match the test environment. + */ + public static class TestLoader extends VariationsSeedLoader { private TestLoaderResult mResult; public TestLoader(TestLoaderResult result) {
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index c35188e4..bd17208f 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -59,7 +59,7 @@ "//android_webview:platform_service_bridge_upstream_implementation_java", "//base:base_java", "//base:base_java_test_support", - "//components/android_autofill/android/test_support:component_autofill_provider_java_test_support", + "//components/android_autofill/browser/test_support:component_autofill_provider_java_test_support", "//components/embedder_support/android:util_java", "//components/heap_profiling/multi_process:heap_profiling_java_test_support", "//components/policy/android:policy_java_test_support", @@ -161,7 +161,7 @@ "//android_webview/nonembedded", "//android_webview/public", "//base", - "//components/android_autofill/android/test_support:component_autofill_provider_native_test_support", + "//components/android_autofill/browser/test_support:component_autofill_provider_native_test_support", "//components/heap_profiling/multi_process:test_support", "//content/public/test/android:content_native_test_support", "//gpu/vulkan", @@ -194,8 +194,8 @@ "//android_webview/test/embedded_test_server:aw_net_java_test_support", "//base:base_java", "//base:base_java_test_support", - "//components/android_autofill/android:java", - "//components/android_autofill/android/test_support:component_autofill_provider_java_test_support", + "//components/android_autofill/browser:java", + "//components/android_autofill/browser/test_support:component_autofill_provider_java_test_support", "//components/autofill/android:autofill_java", "//components/autofill/core/common/mojom:mojo_types_java", "//components/background_task_scheduler:background_task_scheduler_task_ids_java",
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc index be1a972..83c2c9c 100644 --- a/ash/ambient/ambient_controller.cc +++ b/ash/ambient/ambient_controller.cc
@@ -13,6 +13,7 @@ #include "ash/ambient/ui/ambient_container_view.h" #include "ash/ambient/ui/ambient_view_delegate.h" #include "ash/ambient/util/ambient_util.h" +#include "ash/assistant/model/assistant_interaction_model.h" #include "ash/constants/ash_features.h" #include "ash/login/ui/lock_screen.h" #include "ash/public/cpp/ambient/ambient_backend_controller.h" @@ -22,7 +23,7 @@ #include "ash/public/cpp/ambient/ambient_ui_model.h" #include "ash/public/cpp/ambient/common/ambient_settings.h" #include "ash/public/cpp/ambient/fake_ambient_backend_controller_impl.h" -#include "ash/public/cpp/assistant/controller/assistant_ui_controller.h" +#include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller_impl.h" @@ -63,12 +64,6 @@ // Used by wake lock APIs. constexpr char kWakeLockReason[] = "AmbientMode"; -void CloseAssistantUi() { - DCHECK(AssistantUiController::Get()); - AssistantUiController::Get()->CloseUi( - chromeos::assistant::AssistantExitPoint::kUnspecified); -} - std::unique_ptr<AmbientBackendController> CreateAmbientBackendController() { #if BUILDFLAG(ENABLE_CROS_AMBIENT_MODE_BACKEND) return std::make_unique<AmbientBackendControllerImpl>(); @@ -208,6 +203,9 @@ if (!user_activity_observer_.IsObserving()) user_activity_observer_.Observe(ui::UserActivityDetector::Get()); + // Add observer for assistant interaction model + AssistantInteractionController::Get()->GetModel()->AddObserver(this); + Shell::Get()->AddPreTargetHandler(this); StartRefreshingImages(); @@ -221,17 +219,15 @@ // again. StopRefreshingImages(); - // We close the Assistant UI after ambient screen not being shown to sync - // states to |AssistantUiController|. This will be a no-op if the - // |kAmbientAssistant| feature is disabled, or the Assistant UI has - // already been closed. - CloseAssistantUi(); - // Should do nothing if the wake lock has already been released. ReleaseWakeLock(); Shell::Get()->RemovePreTargetHandler(this); + // Should stop observing AssistantInteractionModel when ambient screen is + // not shown. + AssistantInteractionController::Get()->GetModel()->RemoveObserver(this); + // |start_time_| may be empty in case of |AmbientUiVisibility::kHidden| if // ambient mode has just started. if (start_time_) { @@ -433,6 +429,14 @@ DismissUI(); } +void AmbientController::OnInteractionStateChanged( + InteractionState interaction_state) { + if (interaction_state == InteractionState::kActive) { + // Assistant is active. + DismissUI(); + } +} + void AmbientController::ShowUi() { DVLOG(1) << __func__;
diff --git a/ash/ambient/ambient_controller.h b/ash/ambient/ambient_controller.h index 616456f..2c9c86c 100644 --- a/ash/ambient/ambient_controller.h +++ b/ash/ambient/ambient_controller.h
@@ -14,6 +14,7 @@ #include "ash/ambient/model/ambient_backend_model.h" #include "ash/ambient/ui/ambient_view_delegate.h" #include "ash/ash_export.h" +#include "ash/assistant/model/assistant_interaction_model_observer.h" #include "ash/public/cpp/ambient/ambient_ui_model.h" #include "ash/public/cpp/session/session_observer.h" #include "ash/session/session_controller_impl.h" @@ -54,7 +55,8 @@ public chromeos::PowerManagerClient::Observer, public device::mojom::FingerprintObserver, public ui::UserActivityObserver, - public ui::EventHandler { + public ui::EventHandler, + public AssistantInteractionModelObserver { public: static void RegisterProfilePrefs(PrefRegistrySimple* registry); @@ -95,6 +97,9 @@ // ui::EventHandler: void OnKeyEvent(ui::KeyEvent* event) override; + // AssistantInteractionModelObserver: + void OnInteractionStateChanged(InteractionState interaction_state) override; + void ShowUi(); // Ui will be enabled but not shown immediately. If there is no user activity // Ui will be shown after a short delay.
diff --git a/ash/ambient/ambient_controller_unittest.cc b/ash/ambient/ambient_controller_unittest.cc index cc3a07aa..df21b99 100644 --- a/ash/ambient/ambient_controller_unittest.cc +++ b/ash/ambient/ambient_controller_unittest.cc
@@ -10,8 +10,11 @@ #include "ash/ambient/test/ambient_ash_test_base.h" #include "ash/ambient/ui/ambient_container_view.h" +#include "ash/assistant/assistant_interaction_controller_impl.h" +#include "ash/assistant/model/assistant_interaction_model.h" #include "ash/public/cpp/ambient/ambient_prefs.h" #include "ash/public/cpp/ambient/ambient_ui_model.h" +#include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/system/power/power_status.h" @@ -22,6 +25,7 @@ #include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/dbus/power_manager/power_supply_properties.pb.h" #include "chromeos/dbus/power_manager/suspend.pb.h" +#include "chromeos/services/libassistant/public/cpp/assistant_interaction_metadata.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes_posix.h" #include "ui/events/platform/platform_event_source.h" @@ -30,6 +34,8 @@ namespace ash { +using chromeos::assistant::AssistantInteractionMetadata; + constexpr char kUser1[] = "user1@gmail.com"; constexpr char kUser2[] = "user2@gmail.com"; @@ -1051,4 +1057,20 @@ EXPECT_FALSE(ctrl->power_status_observer_.IsObserving()); } +TEST_F(AmbientControllerTest, ShowDismissAmbientScreenUponAssistantQuery) { + // Without user interaction, should show ambient mode. + ShowAmbientScreen(); + EXPECT_TRUE(ambient_controller()->IsShown()); + + // Trigger Assistant interaction. + static_cast<AssistantInteractionControllerImpl*>( + AssistantInteractionController::Get()) + ->OnInteractionStarted(AssistantInteractionMetadata()); + base::RunLoop().RunUntilIdle(); + + // Ambient screen should dismiss. + EXPECT_TRUE(GetContainerViews().empty()); + EXPECT_FALSE(ambient_controller()->IsShown()); +} + } // namespace ash
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc index 25e7073..08cb273 100644 --- a/ash/app_list/views/apps_grid_view.cc +++ b/ash/app_list/views/apps_grid_view.cc
@@ -94,15 +94,6 @@ // Maximum vertical and horizontal spacing between tiles. constexpr int kMaximumTileSpacing = 96; -// Animation curve used for fading in the target page when opening or closing -// a folder. -constexpr gfx::Tween::Type kFolderFadeInTweenType = gfx::Tween::EASE_IN_2; - -// Animation curve used for fading out the target page when opening or closing -// a folder. -constexpr gfx::Tween::Type kFolderFadeOutTweenType = - gfx::Tween::FAST_OUT_LINEAR_IN; - // RowMoveAnimationDelegate is used when moving an item into a different row. // Before running the animation, the item's layer is re-created and kept in // the original position, then the item is moved to just before its target @@ -759,25 +750,6 @@ return view_model_.view_at(index); } -void AppsGridView::ScheduleShowHideAnimation(bool show) { - // Stop any previous animation. - layer()->GetAnimator()->StopAnimating(); - - // Set initial state. - SetVisible(true); - layer()->SetOpacity(show ? 0.0f : 1.0f); - - ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); - animation.AddObserver(this); - animation.SetTweenType(show ? kFolderFadeInTweenType - : kFolderFadeOutTweenType); - animation.SetTransitionDuration( - show ? GetAppListConfig().folder_transition_in_duration() - : GetAppListConfig().folder_transition_out_duration()); - - layer()->SetOpacity(show ? 1.0f : 0.0f); -} - void AppsGridView::InitiateDragFromReparentItemInRootLevelGridView( AppListItemView* original_drag_view, const gfx::Rect& drag_view_rect,
diff --git a/ash/app_list/views/apps_grid_view.h b/ash/app_list/views/apps_grid_view.h index d607063..4768972 100644 --- a/ash/app_list/views/apps_grid_view.h +++ b/ash/app_list/views/apps_grid_view.h
@@ -201,9 +201,6 @@ // view at |index|. AppListItemView* GetItemViewAt(int index) const; - // Schedules an animation to show or hide the view. - void ScheduleShowHideAnimation(bool show); - // Called to initiate drag for reparenting a folder item in root level grid // view. // Both |drag_view_rect| and |drag_pint| is in the coordinates of root level
diff --git a/ash/app_list/views/contents_view.cc b/ash/app_list/views/contents_view.cc index 01c7836..a1a6e53 100644 --- a/ash/app_list/views/contents_view.cc +++ b/ash/app_list/views/contents_view.cc
@@ -37,6 +37,7 @@ #include "ui/events/event.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/view_constants_aura.h" #include "ui/views/view_model.h" #include "ui/views/widget/widget.h" @@ -428,9 +429,9 @@ // state. expand_arrow_view_->SetFocusBehavior( expand_arrow_enabled ? FocusBehavior::ALWAYS : FocusBehavior::NEVER); - expand_arrow_view_->ink_drop()->SetMode( - expand_arrow_enabled ? views::InkDropHost::InkDropMode::ON - : views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(expand_arrow_view_) + ->SetMode(expand_arrow_enabled ? views::InkDropHost::InkDropMode::ON + : views::InkDropHost::InkDropMode::OFF); // Allow ChromeVox to focus the expand arrow only when peeking launcher. expand_arrow_view_->GetViewAccessibility().OverrideIsIgnored(
diff --git a/ash/app_list/views/contents_view.h b/ash/app_list/views/contents_view.h index 42288a2..19a1ec1 100644 --- a/ash/app_list/views/contents_view.h +++ b/ash/app_list/views/contents_view.h
@@ -17,7 +17,6 @@ #include "ash/public/cpp/pagination/pagination_model_observer.h" #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "ui/views/view.h" #include "ui/views/view_model.h"
diff --git a/ash/app_list/views/expand_arrow_view.cc b/ash/app_list/views/expand_arrow_view.cc index 9d96f33..6e8c2ce1 100644 --- a/ash/app_list/views/expand_arrow_view.cc +++ b/ash/app_list/views/expand_arrow_view.cc
@@ -24,6 +24,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/controls/highlight_path_generator.h" @@ -141,18 +142,18 @@ // TODO(pbos): Replace ::OnPaint focus painting with FocusRing + // HighlightPathGenerator usage. SetInstallFocusRingOnFocus(false); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); views::HighlightPathGenerator::Install( this, std::make_unique<ExpandArrowHighlightPathGenerator>()); - views::InkDrop::UseInkDropWithoutAutoHighlight(ink_drop(), + views::InkDrop::UseInkDropWithoutAutoHighlight(views::InkDrop::Get(this), /*highlight_on_hover=*/false); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](Button* host) -> std::unique_ptr<views::InkDropRipple> { const AppListColorProvider* color_provider = AppListColorProvider::Get(); return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetLocalBounds().InsetsFrom(GetCircleBounds()), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), color_provider->GetRippleAttributesBaseColor(), color_provider->GetRippleAttributesInkDropOpacity()); }, @@ -367,7 +368,7 @@ button_pressed_ = true; ResetHintingAnimation(); TransitToFullscreenAllAppsState(); - ink_drop()->GetInkDrop()->AnimateToState( + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( views::InkDropState::ACTION_TRIGGERED); }
diff --git a/ash/app_list/views/page_switcher.cc b/ash/app_list/views/page_switcher.cc index 7921e31d..10181fd 100644 --- a/ash/app_list/views/page_switcher.cc +++ b/ash/app_list/views/page_switcher.cc
@@ -24,6 +24,7 @@ #include "ui/gfx/skia_util.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/controls/button/button.h" @@ -55,9 +56,9 @@ : is_root_app_grid_page_switcher_(is_root_app_grid_page_switcher), background_color_(background_color) { SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - views::InkDrop::UseInkDropForFloodFillRipple(ink_drop()); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(this)); + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](PageSwitcherButton* host) { const AppListColorProvider* const color_provider = AppListColorProvider::Get(); @@ -71,7 +72,7 @@ return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](PageSwitcherButton* host) -> std::unique_ptr<views::InkDropRipple> { const gfx::Point center = host->GetLocalBounds().CenterPoint(); const int max_radius = @@ -84,7 +85,7 @@ AppListColorProvider::Get(); return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetLocalBounds().InsetsFrom(bounds), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), color_provider->GetRippleAttributesBaseColor( host->background_color_), color_provider->GetRippleAttributesInkDropOpacity( @@ -128,7 +129,7 @@ // views::Button: void NotifyClick(const ui::Event& event) override { Button::NotifyClick(event); - ink_drop()->GetInkDrop()->AnimateToState( + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( views::InkDropState::ACTION_TRIGGERED); }
diff --git a/ash/app_list/views/privacy_info_view.cc b/ash/app_list/views/privacy_info_view.cc index fe07c68..767abba 100644 --- a/ash/app_list/views/privacy_info_view.cc +++ b/ash/app_list/views/privacy_info_view.cc
@@ -18,6 +18,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/border.h" #include "ui/views/controls/button/button.h" @@ -297,13 +298,16 @@ close_button->SizeToPreferredSize(); // Ink ripple. - close_button->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(close_button.get()) + ->SetMode(views::InkDropHost::InkDropMode::ON); constexpr SkColor kInkDropBaseColor = gfx::kGoogleGrey900; constexpr float kInkDropVisibleOpacity = 0.06f; constexpr float kInkDropHighlightOpacity = 0.08f; - close_button->ink_drop()->SetVisibleOpacity(kInkDropVisibleOpacity); - close_button->ink_drop()->SetHighlightOpacity(kInkDropHighlightOpacity); - close_button->ink_drop()->SetBaseColor(kInkDropBaseColor); + views::InkDrop::Get(close_button.get()) + ->SetVisibleOpacity(kInkDropVisibleOpacity); + views::InkDrop::Get(close_button.get()) + ->SetHighlightOpacity(kInkDropHighlightOpacity); + views::InkDrop::Get(close_button.get())->SetBaseColor(kInkDropBaseColor); close_button->SetHasInkDropActionOnClick(true); views::InstallCircleHighlightPathGenerator(close_button.get()); close_button_ = AddChildView(std::move(close_button));
diff --git a/ash/app_list/views/search_result_actions_view.cc b/ash/app_list/views/search_result_actions_view.cc index 030576d..cc5839c 100644 --- a/ash/app_list/views/search_result_actions_view.cc +++ b/ash/app_list/views/search_result_actions_view.cc
@@ -20,6 +20,7 @@ #include "ui/gfx/geometry/insets.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/border.h" #include "ui/views/controls/button/image_button.h" @@ -77,8 +78,8 @@ // Avoid drawing default dashed focus and draw customized focus in // OnPaintBackground(); SetFocusPainter(nullptr); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](SearchResultImageButton* host) { const AppListColorProvider* const color_provider = AppListColorProvider::Get(); @@ -91,7 +92,7 @@ return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](SearchResultImageButton* host) -> std::unique_ptr<views::InkDropRipple> { const gfx::Point center = host->GetLocalBounds().CenterPoint(); @@ -103,7 +104,7 @@ const SkColor bg_color = color_provider->GetSearchBoxBackgroundColor(); return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetLocalBounds().InsetsFrom(bounds), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), color_provider->GetRippleAttributesBaseColor(bg_color), color_provider->GetRippleAttributesInkDropOpacity(bg_color)); },
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 912ab56a..5315ad8 100644 --- a/ash/app_list/views/search_result_suggestion_chip_view.cc +++ b/ash/app_list/views/search_result_suggestion_chip_view.cc
@@ -25,6 +25,7 @@ #include "ui/gfx/color_palette.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/controls/image_view.h" @@ -63,11 +64,11 @@ SetInstallFocusRingOnFocus(true); focus_ring()->SetColor(AppListColorProvider::Get()->GetFocusRingColor()); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); views::InstallPillHighlightPathGenerator(this); - views::InkDrop::UseInkDropWithoutAutoHighlight(ink_drop(), + views::InkDrop::UseInkDropWithoutAutoHighlight(views::InkDrop::Get(this), /*highlight_on_hover=*/false); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](Button* host) -> std::unique_ptr<views::InkDropRipple> { const gfx::Point center = host->GetLocalBounds().CenterPoint(); const int ripple_radius = host->width() / 2; @@ -79,7 +80,7 @@ const SkColor bg_color = color_provider->GetSearchBoxBackgroundColor(); return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetLocalBounds().InsetsFrom(bounds), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), color_provider->GetRippleAttributesBaseColor(bg_color), color_provider->GetRippleAttributesInkDropOpacity(bg_color)); },
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index c0b6ad2f..74a3a3c 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1277,12 +1277,6 @@ <message name="IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_NO_RECEPTION_STATE_TOOLTIP" desc="Tooltip message that indicates to the user that the Enable Hotspot feature is disabled because their phone does not have mobile data."> Your phone must have mobile data to provide a hotspot </message> - <message name="IDS_ASH_STATUS_TRAY_PROJECTOR_BUTTON_LABEL" desc="The label text for the button in the status tray to Projector."> - Presentation tools - </message> - <message name="IDS_ASH_PROJECTOR_KEY_IDEA_MARKED" desc="Message content on the toast that appears when a key idea is marked"> - Marked as a key idea - </message> <message name="IDS_ASH_STYLUS_BATTERY_LOW_LABEL" desc="The label next to the stylus battery indicator when the battery level is below 24%"> Low </message> @@ -3631,6 +3625,13 @@ <!-- Strings for Projector--> + <message name="IDS_ASH_STATUS_TRAY_PROJECTOR_BUTTON_LABEL" desc="The label text for the button in the status tray to Projector."> + Presentation tools + </message> + <message name="IDS_ASH_PROJECTOR_KEY_IDEA_MARKED" desc="Message content on the toast that appears when a key idea is marked"> + Marked as a key idea + </message> + <message name="IDS_KEY_IDEA_BUTTON" desc="The name for the key idea button."> Add key idea </message> @@ -3639,8 +3640,8 @@ Laser pointer </message> - <message name="IDS_MARKER_BUTTON" desc="The name for the marker button."> - Marker + <message name="IDS_MARKER_TOOLS_BUTTON" desc="The name for the button that enables or disables marker tools."> + Marker drawing tools </message> <message name="IDS_INK_PEN_BUTTON" desc="The name for the ink pen button."> @@ -3695,8 +3696,8 @@ Stop closed captions </message> - <message name="IDS_BAR_LOCATION_BUTTON" desc="The name for the bar location button."> - Toggle bar location + <message name="IDS_TOOLBAR_LOCATION_BUTTON" desc="The name for the button that toggles the toolbar location."> + Toggle toolbar location </message> <message name="IDS_BLACK_COLOR_BUTTON" desc="The name for the black marker button.">
diff --git a/ash/ash_strings_grd/IDS_BAR_LOCATION_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_BAR_LOCATION_BUTTON.png.sha1 deleted file mode 100644 index dba4d64a0..0000000 --- a/ash/ash_strings_grd/IDS_BAR_LOCATION_BUTTON.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -a5bd6a8c1710652534a9ec6baa5d2821e3e3e8bf \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_CLEAR_ALL_MARKERS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_CLEAR_ALL_MARKERS_BUTTON.png.sha1 index 13e3b254..42b1faf 100644 --- a/ash/ash_strings_grd/IDS_CLEAR_ALL_MARKERS_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_CLEAR_ALL_MARKERS_BUTTON.png.sha1
@@ -1 +1 @@ -876fcbe8ce6916f81d7f49ed105e24e424ffb729 \ No newline at end of file +bf52571e6538536d954bc5f7ab5bff08b7f114c4 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_COLLAPSE_MARKER_TOOLS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_COLLAPSE_MARKER_TOOLS_BUTTON.png.sha1 index 7bc6983a..608302c 100644 --- a/ash/ash_strings_grd/IDS_COLLAPSE_MARKER_TOOLS_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_COLLAPSE_MARKER_TOOLS_BUTTON.png.sha1
@@ -1 +1 @@ -44f37b74dffb0d2387e16f998afe731ffbbccadd \ No newline at end of file +5030b7afebcbab68432f771159d1088c19c67e39 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_EXPAND_MARKER_TOOLS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_EXPAND_MARKER_TOOLS_BUTTON.png.sha1 index b846563..ac4041c 100644 --- a/ash/ash_strings_grd/IDS_EXPAND_MARKER_TOOLS_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_EXPAND_MARKER_TOOLS_BUTTON.png.sha1
@@ -1 +1 @@ -79d4d0863a36aa153cc92176eb0ce9e6764404e5 \ No newline at end of file +9584cb036084ab0a67c49fd168d01e55508ad670 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_INK_PEN_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_INK_PEN_BUTTON.png.sha1 index be90797..02135a3 100644 --- a/ash/ash_strings_grd/IDS_INK_PEN_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_INK_PEN_BUTTON.png.sha1
@@ -1 +1 @@ -9621a79948d5f9804d5d24213a3698b8f2a0b5e9 \ No newline at end of file +4d08978ee307c6ae5120fc812dea49115a6c97f0 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_KEY_IDEA_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_KEY_IDEA_BUTTON.png.sha1 index 624e8bd..5887a2a 100644 --- a/ash/ash_strings_grd/IDS_KEY_IDEA_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_KEY_IDEA_BUTTON.png.sha1
@@ -1 +1 @@ -4640217c15a4b968f27094c0a70fa499b749ae43 \ No newline at end of file +409eb934589eafcf411453ccd60b3dff8b03c955 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_LASER_POINTER_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_LASER_POINTER_BUTTON.png.sha1 index 9190f58..946547ab 100644 --- a/ash/ash_strings_grd/IDS_LASER_POINTER_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_LASER_POINTER_BUTTON.png.sha1
@@ -1 +1 @@ -7ff2ddde7110785a542df75117bf740e8ec9cde4 \ No newline at end of file +d5f899c13a7d95e5d1604a03b3620d0790a4b832 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_MARKER_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_MARKER_BUTTON.png.sha1 deleted file mode 100644 index 3dfccb7bc..0000000 --- a/ash/ash_strings_grd/IDS_MARKER_BUTTON.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -3007dfdbbbb2ac01f7dcb91ff4b035ea6efdb118 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_MARKER_COLOR_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_MARKER_COLOR_BUTTON.png.sha1 index c889abf7..473238e 100644 --- a/ash/ash_strings_grd/IDS_MARKER_COLOR_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_MARKER_COLOR_BUTTON.png.sha1
@@ -1 +1 @@ -a22f2f1da5d6764d0d0752aacfb1a4905f6bb7f7 \ No newline at end of file +0df7242fd3bee5c3ce90f805c3465810ac22e8ea \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_MARKER_PEN_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_MARKER_PEN_BUTTON.png.sha1 index c2e3a67..58703e47 100644 --- a/ash/ash_strings_grd/IDS_MARKER_PEN_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_MARKER_PEN_BUTTON.png.sha1
@@ -1 +1 @@ -6e0aad7230b25193689822690661cbb1eaebab70 \ No newline at end of file +17ef3b3da262c45adaf21002c7aa60566c952122 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_MARKER_TOOLS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_MARKER_TOOLS_BUTTON.png.sha1 new file mode 100644 index 0000000..fce1b8a --- /dev/null +++ b/ash/ash_strings_grd/IDS_MARKER_TOOLS_BUTTON.png.sha1
@@ -0,0 +1 @@ +a515597abdad465bdde9d8e80a269a5e145e34b0 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_START_CLOSED_CAPTIONS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_START_CLOSED_CAPTIONS_BUTTON.png.sha1 index 2f496cb9..cdad85b2 100644 --- a/ash/ash_strings_grd/IDS_START_CLOSED_CAPTIONS_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_START_CLOSED_CAPTIONS_BUTTON.png.sha1
@@ -1 +1 @@ -b33e78eefa35815bc615bff941bfe44ef7824df1 \ No newline at end of file +0e8549b12f28e03a537fce502ab397470b6836f8 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_START_MAGNIFIER_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_START_MAGNIFIER_BUTTON.png.sha1 index 25e3b07..9dceabfa 100644 --- a/ash/ash_strings_grd/IDS_START_MAGNIFIER_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_START_MAGNIFIER_BUTTON.png.sha1
@@ -1 +1 @@ -e7a83d97040706131735a3559eb9a0e1c437557d \ No newline at end of file +3c960e6a2a6239782cb8540ee58bb38e1afcc21a \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_START_SELFIE_CAMERA_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_START_SELFIE_CAMERA_BUTTON.png.sha1 index 5e4f75b..40f0960 100644 --- a/ash/ash_strings_grd/IDS_START_SELFIE_CAMERA_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_START_SELFIE_CAMERA_BUTTON.png.sha1
@@ -1 +1 @@ -a6cc5126c2040f2bf221b54721c48dd8d2a421fd \ No newline at end of file +2665483398cbb197b1612b1d0411e006562365e7 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_STOP_CLOSED_CAPTIONS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_STOP_CLOSED_CAPTIONS_BUTTON.png.sha1 index 82882b9..05f44c8 100644 --- a/ash/ash_strings_grd/IDS_STOP_CLOSED_CAPTIONS_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_STOP_CLOSED_CAPTIONS_BUTTON.png.sha1
@@ -1 +1 @@ -9d06341f57fee98c4366bc3f85cf950525c985cb \ No newline at end of file +eadae376e83f38eb48238f6d6d9b2a2808dc30ce \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_STOP_MAGNIFIER_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_STOP_MAGNIFIER_BUTTON.png.sha1 index 4031133b..4f1f7b5 100644 --- a/ash/ash_strings_grd/IDS_STOP_MAGNIFIER_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_STOP_MAGNIFIER_BUTTON.png.sha1
@@ -1 +1 @@ -44eda6d367523f4fc69e9ebd19cba56f4ea70bb2 \ No newline at end of file +fe8e68b751c38fd02e603b8943ce9a07e98ef176 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_STOP_SELFIE_CAMERA_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_STOP_SELFIE_CAMERA_BUTTON.png.sha1 index 64141e4..2bd6407b 100644 --- a/ash/ash_strings_grd/IDS_STOP_SELFIE_CAMERA_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_STOP_SELFIE_CAMERA_BUTTON.png.sha1
@@ -1 +1 @@ -26e40ae7b76394489afbc0b6ef1b5ac5e6555b9d \ No newline at end of file +bd36b1fcdb84eda4eb6894d0829b8ed8922b9c24 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_TOOLBAR_LOCATION_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_TOOLBAR_LOCATION_BUTTON.png.sha1 new file mode 100644 index 0000000..c977274 --- /dev/null +++ b/ash/ash_strings_grd/IDS_TOOLBAR_LOCATION_BUTTON.png.sha1
@@ -0,0 +1 @@ +6984eb5970957772d653a458806e4083a49d634f \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_UNDO_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_UNDO_BUTTON.png.sha1 index 5157fb6..360a338 100644 --- a/ash/ash_strings_grd/IDS_UNDO_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_UNDO_BUTTON.png.sha1
@@ -1 +1 @@ -29432a50d1c76fc76d230c165636a7947533c194 \ No newline at end of file +1efc549e48b75b812a968d8064083a2f0516a71c \ No newline at end of file
diff --git a/ash/assistant/ui/base/assistant_button.cc b/ash/assistant/ui/base/assistant_button.cc index e3dd44c8..e318cb88 100644 --- a/ash/assistant/ui/base/assistant_button.cc +++ b/ash/assistant/ui/base/assistant_button.cc
@@ -13,6 +13,7 @@ #include "ui/gfx/color_utils.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/controls/highlight_path_generator.h" @@ -53,27 +54,28 @@ SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); // Ink drop. - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - ink_drop()->SetBaseColor(kInkDropBaseColor); - ink_drop()->SetVisibleOpacity(kInkDropVisibleOpacity); + views::InkDrop::Get(this)->SetBaseColor(kInkDropBaseColor); + views::InkDrop::Get(this)->SetVisibleOpacity(kInkDropVisibleOpacity); views::InstallCircleHighlightPathGenerator(this, gfx::Insets(kInkDropInset)); - views::InkDrop::UseInkDropForFloodFillRipple(ink_drop()); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(this)); + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](Button* host) { auto highlight = std::make_unique<views::InkDropHighlight>( - gfx::SizeF(host->size()), host->ink_drop()->GetBaseColor()); + gfx::SizeF(host->size()), + views::InkDrop::Get(host)->GetBaseColor()); highlight->set_visible_opacity(kInkDropHighlightOpacity); return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](Button* host) -> std::unique_ptr<views::InkDropRipple> { return std::make_unique<views::FloodFillInkDropRipple>( host->size(), gfx::Insets(kInkDropInset), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), - host->ink_drop()->GetBaseColor(), - host->ink_drop()->GetVisibleOpacity()); + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetBaseColor(), + views::InkDrop::Get(host)->GetVisibleOpacity()); }, this)); } @@ -110,7 +112,8 @@ // Note that the current assumption is that button bounds are square. DCHECK_EQ(width(), height()); SetFocusPainter(views::Painter::CreateSolidRoundRectPainter( - SkColorSetA(ink_drop()->GetBaseColor(), 0xff * kInkDropHighlightOpacity), + SkColorSetA(views::InkDrop::Get(this)->GetBaseColor(), + 0xff * kInkDropHighlightOpacity), width() / 2 - kInkDropInset, gfx::Insets(kInkDropInset))); }
diff --git a/ash/assistant/ui/main_stage/assistant_onboarding_suggestion_view.cc b/ash/assistant/ui/main_stage/assistant_onboarding_suggestion_view.cc index 7616edb..ae406b9 100644 --- a/ash/assistant/ui/main_stage/assistant_onboarding_suggestion_view.cc +++ b/ash/assistant/ui/main_stage/assistant_onboarding_suggestion_view.cc
@@ -81,8 +81,12 @@ InitLayout(suggestion); } -AssistantOnboardingSuggestionView::~AssistantOnboardingSuggestionView() = - default; +AssistantOnboardingSuggestionView::~AssistantOnboardingSuggestionView() { + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); +} int AssistantOnboardingSuggestionView::GetHeightForWidth(int width) const { return kPreferredHeightDip; @@ -128,11 +132,11 @@ focus_ring()->SetColor(gfx::kGoogleBlue300); // Ink Drop. - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - ink_drop()->SetBaseColor(GetForegroundColor(index_)); - ink_drop()->SetVisibleOpacity(kInkDropVisibleOpacity); - ink_drop()->SetHighlightOpacity(kInkDropHighlightOpacity); + views::InkDrop::Get(this)->SetBaseColor(GetForegroundColor(index_)); + views::InkDrop::Get(this)->SetVisibleOpacity(kInkDropVisibleOpacity); + views::InkDrop::Get(this)->SetHighlightOpacity(kInkDropHighlightOpacity); // Installing this highlight path generator will set the desired shape for // both ink drop effects as well as our focus ring.
diff --git a/ash/capture_mode/capture_label_view.cc b/ash/capture_mode/capture_label_view.cc index fc3eb06..7650900e 100644 --- a/ash/capture_mode/capture_label_view.cc +++ b/ash/capture_mode/capture_label_view.cc
@@ -25,6 +25,7 @@ #include "ui/gfx/text_constants.h" #include "ui/gfx/transform.h" #include "ui/gfx/transform_util.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/background.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/highlight_path_generator.h" @@ -162,12 +163,14 @@ label_button_->SetHorizontalAlignment(gfx::ALIGN_CENTER); label_button_->SetNotifyEnterExitOnChild(true); - label_button_->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(label_button_) + ->SetMode(views::InkDropHost::InkDropMode::ON); const auto ripple_attributes = color_provider->GetRippleAttributes(background_color); - label_button_->ink_drop()->SetVisibleOpacity( - ripple_attributes.inkdrop_opacity); - label_button_->ink_drop()->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(label_button_) + ->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(label_button_) + ->SetBaseColor(ripple_attributes.base_color); label_button_->SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY); label_ = AddChildView(std::make_unique<views::Label>(std::u16string()));
diff --git a/ash/capture_mode/capture_mode_button.cc b/ash/capture_mode/capture_mode_button.cc index ab72d582..b250011 100644 --- a/ash/capture_mode/capture_mode_button.cc +++ b/ash/capture_mode/capture_mode_button.cc
@@ -34,22 +34,24 @@ // static void CaptureModeButton::ConfigureButton(views::ImageButton* button, views::FocusRing* focus_ring) { - button->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(button)->SetMode(views::InkDropHost::InkDropMode::ON); button->SetHasInkDropActionOnClick(true); - button->ink_drop()->SetVisibleOpacity(capture_mode::kInkDropVisibleOpacity); - views::InkDrop::UseInkDropForFloodFillRipple(button->ink_drop(), + views::InkDrop::Get(button)->SetVisibleOpacity( + capture_mode::kInkDropVisibleOpacity); + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(button), /*highlight_on_hover=*/false, /*highlight_on_focus=*/false); - button->ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(button)->SetCreateHighlightCallback(base::BindRepeating( [](views::Button* host) { auto highlight = std::make_unique<views::InkDropHighlight>( - gfx::SizeF(host->size()), host->ink_drop()->GetBaseColor()); + gfx::SizeF(host->size()), + views::InkDrop::Get(host)->GetBaseColor()); highlight->set_visible_opacity( capture_mode::kInkDropHighlightVisibleOpacity); return highlight; }, button)); - button->ink_drop()->SetBaseColor(capture_mode::kInkDropBaseColor); + views::InkDrop::Get(button)->SetBaseColor(capture_mode::kInkDropBaseColor); button->SetImageHorizontalAlignment(ALIGN_CENTER); button->SetImageVerticalAlignment(ALIGN_MIDDLE);
diff --git a/ash/clipboard/views/clipboard_history_delete_button.cc b/ash/clipboard/views/clipboard_history_delete_button.cc index 1f50e79..cf7c4cc 100644 --- a/ash/clipboard/views/clipboard_history_delete_button.cc +++ b/ash/clipboard/views/clipboard_history_delete_button.cc
@@ -34,7 +34,7 @@ SetPreferredSize(gfx::Size(ClipboardHistoryViews::kDeleteButtonSizeDip, ClipboardHistoryViews::kDeleteButtonSizeDip)); SetVisible(false); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); ink_drop_container_ = AddChildView(std::make_unique<views::InkDropContainerView>()); @@ -49,11 +49,17 @@ // The ink drop ripple should be circular. views::InstallFixedSizeCircleHighlightPathGenerator( this, ClipboardHistoryViews::kDeleteButtonSizeDip / 2); - views::InkDrop::UseInkDropForFloodFillRipple( - ink_drop(), /*highlight_on_hover=*/false, /*highlight_on_focus=*/true); + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(this), + /*highlight_on_hover=*/false, + /*highlight_on_focus=*/true); } -ClipboardHistoryDeleteButton::~ClipboardHistoryDeleteButton() = default; +ClipboardHistoryDeleteButton::~ClipboardHistoryDeleteButton() { + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); +} const char* ClipboardHistoryDeleteButton::GetClassName() const { return "DeleteButton"; @@ -82,9 +88,11 @@ const AshColorProvider::RippleAttributes ripple_attributes = AshColorProvider::Get()->GetRippleAttributes(); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); - ink_drop()->SetHighlightOpacity(ripple_attributes.highlight_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetHighlightOpacity( + ripple_attributes.highlight_opacity); } void ClipboardHistoryDeleteButton::RemoveLayerBeneathView(ui::Layer* layer) {
diff --git a/ash/clipboard/views/clipboard_history_item_view.cc b/ash/clipboard/views/clipboard_history_item_view.cc index 7a4a6f8..618ca98e 100644 --- a/ash/clipboard/views/clipboard_history_item_view.cc +++ b/ash/clipboard/views/clipboard_history_item_view.cc
@@ -46,7 +46,7 @@ const bool focused = (container_->pseudo_focus_ == PseudoFocus::kDeleteButton); - delete_button_->ink_drop()->GetInkDrop()->SetFocused(focused); + views::InkDrop::Get(delete_button_)->GetInkDrop()->SetFocused(focused); if (focused) { delete_button_->NotifyAccessibilityEvent(ax::mojom::Event::kHover, /*send_native_event*/ true);
diff --git a/ash/clipboard/views/clipboard_history_main_button.cc b/ash/clipboard/views/clipboard_history_main_button.cc index f4bfc7f..8621a40 100644 --- a/ash/clipboard/views/clipboard_history_main_button.cc +++ b/ash/clipboard/views/clipboard_history_main_button.cc
@@ -30,7 +30,7 @@ base::Unretained(container))), container_(container) { SetFocusBehavior(views::View::FocusBehavior::ALWAYS); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetID(ClipboardHistoryUtil::kMainButtonViewID); // Let the parent handle accessibility features. @@ -50,7 +50,7 @@ // Hence, highlighted background is implemented by customizing in // `PaintButtonContents()`. views::InkDrop::UseInkDropForFloodFillRipple( - ink_drop(), /*highlight_on_hover=*/false, + views::InkDrop::Get(this), /*highlight_on_hover=*/false, /*highlight_on_focus=*/!focus_ring()); } @@ -90,8 +90,9 @@ const AshColorProvider::RippleAttributes ripple_attributes = AshColorProvider::Get()->GetRippleAttributes(); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); } void ClipboardHistoryMainButton::OnGestureEvent(ui::GestureEvent* event) {
diff --git a/ash/components/BUILD.gn b/ash/components/BUILD.gn index f779dc1..9fd04ba 100644 --- a/ash/components/BUILD.gn +++ b/ash/components/BUILD.gn
@@ -21,3 +21,9 @@ "//ui/resources:ui_test_pak_data", ] } + +group("closure_compile") { + testonly = true + + deps = [ "//ash/components/os_feedback_ui:closure_compile" ] +}
diff --git a/ash/components/account_manager/access_token_fetcher.cc b/ash/components/account_manager/access_token_fetcher.cc index c15ad925..16500a6 100644 --- a/ash/components/account_manager/access_token_fetcher.cc +++ b/ash/components/account_manager/access_token_fetcher.cc
@@ -21,9 +21,11 @@ AccessTokenFetcher::AccessTokenFetcher( ash::AccountManager* account_manager, mojom::AccountKeyPtr mojo_account_key, + const std::string& consumer_name, base::OnceCallback<void(AccessTokenFetcher*)> done_callback, mojo::PendingReceiver<mojom::AccessTokenFetcher> receiver) - : done_callback_(std::move(done_callback)), + : consumer_name_(consumer_name), + done_callback_(std::move(done_callback)), receiver_(this, std::move(receiver)) { receiver_.set_disconnect_handler(base::BindOnce( &AccessTokenFetcher::OnMojoPipeError, base::Unretained(this))); @@ -77,6 +79,10 @@ Finish(); } +std::string AccessTokenFetcher::GetConsumerName() const { + return consumer_name_; +} + void AccessTokenFetcher::OnMojoPipeError() { if (access_token_fetcher_) access_token_fetcher_->CancelRequest();
diff --git a/ash/components/account_manager/access_token_fetcher.h b/ash/components/account_manager/access_token_fetcher.h index 50b3acb4..219d2f8 100644 --- a/ash/components/account_manager/access_token_fetcher.h +++ b/ash/components/account_manager/access_token_fetcher.h
@@ -34,6 +34,7 @@ AccessTokenFetcher( ash::AccountManager* account_manager, mojom::AccountKeyPtr mojo_account_key, + const std::string& consumer_name, base::OnceCallback<void(AccessTokenFetcher*)> done_callback, mojo::PendingReceiver<mojom::AccessTokenFetcher> receiver); AccessTokenFetcher(const AccessTokenFetcher&) = delete; @@ -47,6 +48,7 @@ // OAuth2AccessTokenConsumer overrides. void OnGetTokenSuccess(const TokenResponse& token_response) override; void OnGetTokenFailure(const GoogleServiceAuthError& error) override; + std::string GetConsumerName() const override; private: // Mojo pipe disconnection handler. @@ -56,6 +58,7 @@ std::unique_ptr<OAuth2AccessTokenFetcher> access_token_fetcher_; base::OnceCallback<void(mojom::AccessTokenResultPtr)> callback_; + const std::string consumer_name_; // Called after `this` object's work is done and it can be safely deleted. base::OnceCallback<void(AccessTokenFetcher*)> done_callback_; mojo::Receiver<mojom::AccessTokenFetcher> receiver_;
diff --git a/ash/components/account_manager/account_manager_ash.cc b/ash/components/account_manager/account_manager_ash.cc index df8766e..a17cdfe 100644 --- a/ash/components/account_manager/account_manager_ash.cc +++ b/ash/components/account_manager/account_manager_ash.cc
@@ -143,7 +143,8 @@ mojo::PendingRemote<mojom::AccessTokenFetcher> pending_remote; auto access_token_fetcher = std::make_unique<AccessTokenFetcher>( - account_manager_, std::move(mojo_account_key), /*done_closure=*/ + account_manager_, std::move(mojo_account_key), oauth_consumer_name, + /*done_closure=*/ base::BindOnce(&AccountManagerAsh::DeletePendingAccessTokenFetchRequest, weak_ptr_factory_.GetWeakPtr()), /*receiver=*/pending_remote.InitWithNewPipeAndPassReceiver());
diff --git a/ash/components/account_manager/account_manager_unittest.cc b/ash/components/account_manager/account_manager_unittest.cc index 27c93664..c3e94c53 100644 --- a/ash/components/account_manager/account_manager_unittest.cc +++ b/ash/components/account_manager/account_manager_unittest.cc
@@ -326,6 +326,10 @@ OnGetTokenFailure, (const GoogleServiceAuthError& error), (override)); + + std::string GetConsumerName() const override { + return "account_manager_unittest"; + } }; TEST(AccountManagerKeyTest, TestValidity) {
diff --git a/ash/components/os_feedback_ui/BUILD.gn b/ash/components/os_feedback_ui/BUILD.gn index c48b3e19..84a265a9 100644 --- a/ash/components/os_feedback_ui/BUILD.gn +++ b/ash/components/os_feedback_ui/BUILD.gn
@@ -18,6 +18,11 @@ deps = [ "//ash/components/resources:os_feedback_resources", "//content/public/browser", + "//ui/resources", "//ui/webui", ] } + +group("closure_compile") { + deps = [ "resources:closure_compile_module" ] +}
diff --git a/ash/components/os_feedback_ui/DEPS b/ash/components/os_feedback_ui/DEPS index 7db1554..ddfe6f2 100644 --- a/ash/components/os_feedback_ui/DEPS +++ b/ash/components/os_feedback_ui/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+content/public/browser", + "+ui/resources", "+ui/webui", ]
diff --git a/ash/components/os_feedback_ui/os_feedback_ui.cc b/ash/components/os_feedback_ui/os_feedback_ui.cc index 270ac018..bc89f2c3 100644 --- a/ash/components/os_feedback_ui/os_feedback_ui.cc +++ b/ash/components/os_feedback_ui/os_feedback_ui.cc
@@ -11,6 +11,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" +#include "ui/resources/grit/webui_generated_resources.h" #include "ui/webui/mojo_web_ui_controller.h" namespace ash { @@ -22,6 +23,10 @@ int default_resource) { source->AddResourcePaths(resources); source->SetDefaultResource(default_resource); + source->AddResourcePath("test_loader.html", IDR_WEBUI_HTML_TEST_LOADER_HTML); + source->AddResourcePath("test_loader.js", IDR_WEBUI_JS_TEST_LOADER_JS); + source->AddResourcePath("test_loader_util.js", + IDR_WEBUI_JS_TEST_LOADER_UTIL_JS); } } // namespace @@ -30,6 +35,10 @@ : MojoWebUIController(web_ui) { auto source = base::WrapUnique( content::WebUIDataSource::Create(kChromeUIOSFeedbackHost)); + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::ScriptSrc, + "script-src chrome://resources chrome://test 'self';"); + source->DisableTrustedTypesCSP(); const auto resources = base::make_span(kAshOsFeedbackResources, kAshOsFeedbackResourcesSize);
diff --git a/ash/components/os_feedback_ui/resources/BUILD.gn b/ash/components/os_feedback_ui/resources/BUILD.gn index 2cf8dfe..1faa95ee 100644 --- a/ash/components/os_feedback_ui/resources/BUILD.gn +++ b/ash/components/os_feedback_ui/resources/BUILD.gn
@@ -3,19 +3,53 @@ # found in the LICENSE file. import("//build/config/chromeos/ui_mode.gni") +import("//third_party/closure_compiler/compile_js.gni") +import("//tools/grit/grit_rule.gni") +import("//tools/grit/preprocess_if_expr.gni") +import("//tools/polymer/html_to_js.gni") import("//ui/webui/resources/tools/generate_grd.gni") assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //ash") +preprocessed_dir = "preprocessed" +preprocessed_gen_manifest = "preprocessed_gen_manifest.json" + +polymer_element_files = [ "confirmation_page.js" ] + generate_grd("build_grd") { - input_files_base_dir = rebase_path(".", "//") input_files = [ "app_icon_48.png", "app_icon_192.png", "app_icon_256.png", "index.html", ] - manifest_files = [] + input_files_base_dir = rebase_path(".", "//") + deps = [ ":preprocess_generated" ] + manifest_files = [ "$target_gen_dir/$preprocessed_gen_manifest" ] grd_prefix = "ash_os_feedback" out_grd = "$target_gen_dir/${grd_prefix}_resources.grd" } + +js_type_check("closure_compile_module") { + is_polymer3 = true + closure_flags = default_closure_args + deps = [ ":confirmation_page" ] +} + +js_library("confirmation_page") { + deps = [ + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + ] +} + +preprocess_if_expr("preprocess_generated") { + deps = [ ":web_components" ] + in_folder = target_gen_dir + out_folder = "$target_gen_dir/$preprocessed_dir" + out_manifest = "$target_gen_dir/$preprocessed_gen_manifest" + in_files = polymer_element_files +} + +html_to_js("web_components") { + js_files = polymer_element_files +}
diff --git a/ash/components/os_feedback_ui/resources/confirmation_page.html b/ash/components/os_feedback_ui/resources/confirmation_page.html new file mode 100644 index 0000000..03ed6009 --- /dev/null +++ b/ash/components/os_feedback_ui/resources/confirmation_page.html
@@ -0,0 +1,2 @@ +<!-- TODO(xiangdongkong): replace with real content--> +<div id="header"></div>
diff --git a/ash/components/os_feedback_ui/resources/confirmation_page.js b/ash/components/os_feedback_ui/resources/confirmation_page.js new file mode 100644 index 0000000..4d7c261 --- /dev/null +++ b/ash/components/os_feedback_ui/resources/confirmation_page.js
@@ -0,0 +1,32 @@ +// Copyright 2021 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 {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +/** + * @fileoverview + * 'confirmation-page' is the last step of the feedback tool. + */ +export class ConfirmationPageElement extends PolymerElement { + static get is() { + return 'confirmation-page'; + } + + static get template() { + return html`{__html_template__}`; + } + + /** @override */ + ready() { + super.ready(); + /**TODO(xiangdongkong): remove */ + this.$.header.textContent = 'Thank you for your feedback'; + } + + close_() { + window.close(); + } +}; + +customElements.define(ConfirmationPageElement.is, ConfirmationPageElement);
diff --git a/ash/components/os_feedback_ui/resources/index.html b/ash/components/os_feedback_ui/resources/index.html index 4bc311c..e4cae19a 100644 --- a/ash/components/os_feedback_ui/resources/index.html +++ b/ash/components/os_feedback_ui/resources/index.html
@@ -9,7 +9,11 @@ </head> <body> + <!-- TODO(xiangdongkong): replace with real content--> <div>Hello, World!</div> + <confirmation-page></confirmation-page> + + <script type="module" src="confirmation_page.js"></script> </body> </html>
diff --git a/ash/components/resources/BUILD.gn b/ash/components/resources/BUILD.gn index 2766f5a..bf73866 100644 --- a/ash/components/resources/BUILD.gn +++ b/ash/components/resources/BUILD.gn
@@ -12,7 +12,10 @@ enable_input_discovery_for_gn_analyze = false os_feedback_gen_dir = "$root_gen_dir/ash/components/os_feedback_ui/resources" source = "$os_feedback_gen_dir/ash_os_feedback_resources.grd" - deps = [ "//ash/components/os_feedback_ui/resources:build_grd" ] + deps = [ + "//ash/components/os_feedback_ui/resources:build_grd", + "//ash/components/os_feedback_ui/resources:web_components", + ] outputs = [ "grit/ash_os_feedback_resources.h",
diff --git a/ash/display/extended_mouse_warp_controller_unittest.cc b/ash/display/extended_mouse_warp_controller_unittest.cc index 8a0de72..93368781 100644 --- a/ash/display/extended_mouse_warp_controller_unittest.cc +++ b/ash/display/extended_mouse_warp_controller_unittest.cc
@@ -389,8 +389,9 @@ // Check that the point in the rotated secondary display's warp region is // converted correctly from native host coordinates to screen DIP coordinates. // (see https://crbug.com/905035) +// Flaky. https://crbug.com/1217187. TEST_F(ExtendedMouseWarpControllerTest, - CheckHostPointToScreenInMouseWarpRegion) { + DISABLED_CheckHostPointToScreenInMouseWarpRegion) { // Zoom factor is needed to trigger rounding error which occured in previous // code. UpdateDisplay("50+50-200x200@0.8,50+300-300x100/r");
diff --git a/ash/events/accessibility_event_rewriter.cc b/ash/events/accessibility_event_rewriter.cc index 062e4aec..c49c100 100644 --- a/ash/events/accessibility_event_rewriter.cc +++ b/ash/events/accessibility_event_rewriter.cc
@@ -10,6 +10,7 @@ #include "ash/keyboard/keyboard_util.h" #include "ash/public/cpp/accessibility_event_rewriter_delegate.h" #include "ash/shell.h" +#include "base/system/sys_info.h" #include "ui/chromeos/events/event_rewriter_chromeos.h" #include "ui/events/devices/device_data_manager.h" #include "ui/events/event.h" @@ -29,8 +30,9 @@ return ui::INPUT_DEVICE_USB; if (switch_access_device_type == kSwitchAccessBluetoothDevice) return ui::INPUT_DEVICE_BLUETOOTH; - - NOTREACHED(); + // On Chrome OS emulated on Linux, the keyboard is always "UNKNOWN". + if (base::SysInfo::IsRunningOnChromeOS()) + NOTREACHED(); return ui::INPUT_DEVICE_UNKNOWN; } } // namespace
diff --git a/ash/fast_ink/fast_ink_points.cc b/ash/fast_ink/fast_ink_points.cc index a5ea5495..4f51239 100644 --- a/ash/fast_ink/fast_ink_points.cc +++ b/ash/fast_ink/fast_ink_points.cc
@@ -69,6 +69,26 @@ } } +gfx::Rect FastInkPoints::UndoLastStroke() { + if (points_.empty()) + return gfx::Rect(); + + gfx::PointF min_point = GetNewest().location; + gfx::PointF max_point = min_point; + // Skip the last gap to delete until the penultimate gap. + if (points_.back().gap_after) + points_.pop_back(); + + while (!points_.empty() && !points_.back().gap_after) { + const gfx::PointF& location = points_.back().location; + min_point.SetToMin(location); + max_point.SetToMax(location); + points_.pop_back(); + } + + return gfx::ToEnclosingRect(gfx::BoundingRect(min_point, max_point)); +} + void FastInkPoints::Clear() { points_.clear(); } @@ -82,7 +102,7 @@ return gfx::RectF(); gfx::PointF min_point = GetOldest().location; - gfx::PointF max_point = GetOldest().location; + gfx::PointF max_point = min_point; for (const FastInkPoint& point : points_) { min_point.SetToMin(point.location); max_point.SetToMax(point.location);
diff --git a/ash/fast_ink/fast_ink_points.h b/ash/fast_ink/fast_ink_points.h index 26b45add..3d3f467 100644 --- a/ash/fast_ink/fast_ink_points.h +++ b/ash/fast_ink/fast_ink_points.h
@@ -46,6 +46,10 @@ // Updates the collection latest time. Automatically clears points that are // too old. void MoveForwardToTime(const base::TimeTicks& latest_time); + // Removes the last stroke by removing the points since the last gap. If there + // are no gaps, deletes all points. Returns the bounding rectangle of the + // deleted points. + gfx::Rect UndoLastStroke(); // Removes all points. void Clear(); // Gets the bounding box of the points, int coordinates.
diff --git a/ash/fast_ink/fast_ink_points_unittest.cc b/ash/fast_ink/fast_ink_points_unittest.cc index 1625c70..6aa9d6424fd 100644 --- a/ash/fast_ink/fast_ink_points_unittest.cc +++ b/ash/fast_ink/fast_ink_points_unittest.cc
@@ -253,4 +253,51 @@ EXPECT_FALSE(points[5].gap_after); } +// Tests deleting points from the last stroke. +TEST_F(FastInkPointsTest, UndoLastStroke) { + // Calling undo with no points should not crash. + gfx::Rect bounding_box = points_.UndoLastStroke(); + EXPECT_EQ(bounding_box, gfx::Rect()); + + points_.AddPoint(gfx::PointF(0, 0), base::TimeTicks()); + points_.AddPoint(gfx::PointF(1, 1), base::TimeTicks()); + points_.AddGap(); + + // Calling undo should clear all points. + bounding_box = points_.UndoLastStroke(); + EXPECT_TRUE(points_.IsEmpty()); + EXPECT_EQ(bounding_box, gfx::Rect(0, 0, 1, 1)); + + points_.AddPoint(gfx::PointF(0, 0), base::TimeTicks()); + points_.AddPoint(gfx::PointF(1, 1), base::TimeTicks()); + points_.AddGap(); + points_.AddPoint(gfx::PointF(2, 2), base::TimeTicks()); + points_.AddPoint(gfx::PointF(3, 3), base::TimeTicks()); + points_.AddPoint(gfx::PointF(4, 4), base::TimeTicks()); + points_.AddGap(); + + // Calling undo should clear the second stroke only. + bounding_box = points_.UndoLastStroke(); + EXPECT_EQ(points_.GetNumberOfPoints(), 2); + EXPECT_TRUE(points_.GetNewest().gap_after); + EXPECT_EQ(bounding_box, gfx::Rect(2, 2, 2, 2)); + + points_.AddPoint(gfx::PointF(0, 0), base::TimeTicks()); + points_.AddPoint(gfx::PointF(1, 1), base::TimeTicks()); + points_.AddGap(); + points_.AddPoint(gfx::PointF(2, 2), base::TimeTicks()); + points_.AddPoint(gfx::PointF(3, 3), base::TimeTicks()); + points_.AddPoint(gfx::PointF(4, 4), base::TimeTicks()); + points_.AddGap(); + points_.AddPoint(gfx::PointF(5, 5), base::TimeTicks()); + + // Calling undo twice should clear the third and second strokes. + bounding_box = points_.UndoLastStroke(); + EXPECT_EQ(bounding_box, gfx::Rect(5, 5, 0, 0)); + bounding_box = points_.UndoLastStroke(); + EXPECT_EQ(bounding_box, gfx::Rect(2, 2, 2, 2)); + EXPECT_EQ(points_.GetNumberOfPoints(), 4); + EXPECT_TRUE(points_.GetNewest().gap_after); +} + } // namespace fast_ink
diff --git a/ash/highlighter/highlighter_view.cc b/ash/highlighter/highlighter_view.cc index c832da4..0fc67d85 100644 --- a/ash/highlighter/highlighter_view.cc +++ b/ash/highlighter/highlighter_view.cc
@@ -149,6 +149,24 @@ gesture_type, std::move(done))); } +void HighlighterView::UndoLastStroke() { + if (points_.IsEmpty()) + return; + + // Previous prediction needs to be erased. + if (!predicted_points_.IsEmpty()) { + highlighter_damage_rect_.Union( + InflateDamageRect(predicted_points_.GetBoundingBox())); + predicted_points_.Clear(); + } + + const gfx::Rect bounding_box = points_.UndoLastStroke(); + // Ensure deleting the points also erases them by expanding the damage + // rectangle. + highlighter_damage_rect_.Union(InflateDamageRect(bounding_box)); + ScheduleUpdateBuffer(); +} + void HighlighterView::FadeOut(const gfx::PointF& pivot, HighlighterGestureType gesture_type, base::OnceClosure done) {
diff --git a/ash/highlighter/highlighter_view.h b/ash/highlighter/highlighter_view.h index 37dad5c..e6325d9b 100644 --- a/ash/highlighter/highlighter_view.h +++ b/ash/highlighter/highlighter_view.h
@@ -51,12 +51,14 @@ void Animate(const gfx::PointF& pivot, HighlighterGestureType gesture_type, base::OnceClosure done); + // Deletes the last stroke. + void UndoLastStroke(); private: friend class HighlighterControllerTestApi; friend class MarkerControllerTestApi; - HighlighterView(const base::TimeDelta presentation_delay); + explicit HighlighterView(const base::TimeDelta presentation_delay); void FadeOut(const gfx::PointF& pivot, HighlighterGestureType gesture_type,
diff --git a/ash/lock_screen_action/lock_screen_action_background_view.cc b/ash/lock_screen_action/lock_screen_action_background_view.cc index 2ce4ce2e..f1a5f3b5 100644 --- a/ash/lock_screen_action/lock_screen_action_background_view.cc +++ b/ash/lock_screen_action/lock_screen_action_background_view.cc
@@ -14,6 +14,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_host_view.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" @@ -28,17 +29,19 @@ explicit NoteBackground(views::InkDropObserver* observer) : observer_(observer) { DCHECK(observer); - ink_drop_.SetMode(views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); - ink_drop_.SetCreateInkDropCallback(base::BindRepeating( + views::InkDrop::Install(this, std::make_unique<views::InkDropHost>(this)); + views::InkDrop::Get(this)->SetMode( + views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); + views::InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](NoteBackground* host) { std::unique_ptr<views::InkDrop> ink_drop = views::InkDrop::CreateInkDropWithoutAutoHighlight( - &host->ink_drop_, /*highlight_on_hover=*/false); + views::InkDrop::Get(host), /*highlight_on_hover=*/false); ink_drop->AddObserver(host->observer_); return ink_drop; }, this)); - ink_drop_.SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](NoteBackground* host) -> std::unique_ptr<views::InkDropRipple> { const gfx::Point center = base::i18n::IsRTL() ? host->GetLocalBounds().origin() @@ -46,25 +49,21 @@ auto ink_drop_ripple = std::make_unique<views::FloodFillInkDropRipple>( host->size(), gfx::Insets(), center, - host->ink_drop_.GetBaseColor(), 1); + views::InkDrop::Get(host)->GetBaseColor(), 1); ink_drop_ripple->set_use_hide_transform_duration_for_hide_fade_out( true); ink_drop_ripple->set_duration_factor(1.5); return ink_drop_ripple; }, this)); - ink_drop_.SetBaseColor(SK_ColorBLACK); + views::InkDrop::Get(this)->SetBaseColor(SK_ColorBLACK); } ~NoteBackground() override = default; - views::InkDropHost* ink_drop() { return &ink_drop_; } - private: views::InkDropObserver* observer_; - views::InkDropHost ink_drop_{this}; - DISALLOW_COPY_AND_ASSIGN(NoteBackground); }; @@ -90,15 +89,16 @@ animation_end_callback_ = std::move(done); animating_to_state_ = views::InkDropState::ACTIVATED; - background_->ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, - nullptr); + views::InkDrop::Get(background_) + ->AnimateToState(views::InkDropState::ACTIVATED, nullptr); } void LockScreenActionBackgroundView::AnimateHide(base::OnceClosure done) { animation_end_callback_ = std::move(done); animating_to_state_ = views::InkDropState::HIDDEN; - background_->ink_drop()->AnimateToState(views::InkDropState::HIDDEN, nullptr); + views::InkDrop::Get(background_) + ->AnimateToState(views::InkDropState::HIDDEN, nullptr); } void LockScreenActionBackgroundView::InkDropAnimationStarted() {}
diff --git a/ash/login/ui/lock_screen_media_controls_view.cc b/ash/login/ui/lock_screen_media_controls_view.cc index b7adc8eb..84dc460 100644 --- a/ash/login/ui/lock_screen_media_controls_view.cc +++ b/ash/login/ui/lock_screen_media_controls_view.cc
@@ -35,6 +35,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/message_center/message_center.h" #include "ui/message_center/vector_icons.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/background.h" #include "ui/views/controls/button/image_button_factory.h" @@ -156,12 +157,13 @@ view, this)), icon_size_(icon_size) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](Button* host) { return std::make_unique<views::InkDropHighlight>( - gfx::SizeF(host->size()), host->ink_drop()->GetBaseColor()); + gfx::SizeF(host->size()), + views::InkDrop::Get(host)->GetBaseColor()); }, this));
diff --git a/ash/login/ui/login_base_bubble_view.cc b/ash/login/ui/login_base_bubble_view.cc index d2776a7..f3bf99e 100644 --- a/ash/login/ui/login_base_bubble_view.cc +++ b/ash/login/ui/login_base_bubble_view.cc
@@ -18,6 +18,7 @@ #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/events/event_handler.h" #include "ui/gfx/geometry/point.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/background.h" #include "ui/views/layout/box_layout.h" #include "ui/wm/core/coordinate_conversion.h" @@ -310,10 +311,10 @@ void LoginBaseBubbleView::ScheduleAnimation(bool visible) { if (GetBubbleOpener()) { - GetBubbleOpener()->ink_drop()->AnimateToState( - visible ? views::InkDropState::ACTIVATED - : views::InkDropState::DEACTIVATED, - nullptr /*event*/); + views::InkDrop::Get(GetBubbleOpener()) + ->AnimateToState(visible ? views::InkDropState::ACTIVATED + : views::InkDropState::DEACTIVATED, + nullptr /*event*/); } if (layer())
diff --git a/ash/login/ui/login_button.cc b/ash/login/ui/login_button.cc index 20c4733..07e104c 100644 --- a/ash/login/ui/login_button.cc +++ b/ash/login/ui/login_button.cc
@@ -9,6 +9,7 @@ #include "ash/login/ui/views_utils.h" #include "base/bind.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" namespace ash { @@ -28,15 +29,15 @@ : views::ImageButton(std::move(callback)) { SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER); SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](Button* host) { return std::make_unique<views::InkDropHighlight>( gfx::SizeF(host->size()), kInkDropHighlightColor); }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](LoginButton* host) -> std::unique_ptr<views::InkDropRipple> { const gfx::Point center = host->GetLocalBounds().CenterPoint(); const int radius = host->GetInkDropRadius(); @@ -45,7 +46,7 @@ return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetLocalBounds().InsetsFrom(bounds), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), kInkDropRippleColor, 1.f /*visible_opacity*/); }, this));
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc index b281fdfc..deb3f0b 100644 --- a/ash/login/ui/login_expanded_public_account_view.cc +++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -31,6 +31,7 @@ #include "ui/compositor/layer.h" #include "ui/gfx/canvas.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/border.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" @@ -128,7 +129,7 @@ layer()->SetFillsBoundsOpaquely(false); SetFocusBehavior(FocusBehavior::ALWAYS); SetLayoutManager(std::make_unique<views::FillLayout>()); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); auto add_horizontal_margin = [&](int width, views::View* parent) -> views::View* {
diff --git a/ash/login/ui/login_pin_view.cc b/ash/login/ui/login_pin_view.cc index 9ea1ad32..343d191 100644 --- a/ash/login/ui/login_pin_view.cc +++ b/ash/login/ui/login_pin_view.cc
@@ -25,6 +25,7 @@ #include "ui/gfx/geometry/size.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_state.h" @@ -105,8 +106,11 @@ // focus painter to paint. SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + + views::InkDrop::Install(this, std::make_unique<views::InkDropHost>(this)); + views::InkDrop::Get(this)->SetMode( + views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](BasePinButton* host) { auto highlight = std::make_unique<views::InkDropHighlight>( gfx::SizeF(host->size()), @@ -115,7 +119,7 @@ return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](BasePinButton* host) -> std::unique_ptr<views::InkDropRipple> { const gfx::Point center = host->GetLocalBounds().CenterPoint(); const gfx::Rect bounds(center.x() - kInkDropCornerRadiusDp, @@ -125,7 +129,7 @@ return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetLocalBounds().InsetsFrom(bounds), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), host->palette_.pin_ink_drop_ripple_color, /*visible_opacity=*/1.f); }, @@ -142,8 +146,6 @@ palette_ = palette; } - views::InkDropHost* ink_drop() { return &ink_drop_; } - // views::View: void OnFocus() override { View::OnFocus(); @@ -178,8 +180,9 @@ if (event) event->SetHandled(); - ink_drop()->AnimateToState(views::InkDropState::ACTION_TRIGGERED, - ui::LocatedEvent::FromIfValid(event)); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::ACTION_TRIGGERED, + ui::LocatedEvent::FromIfValid(event)); SchedulePaint(); // |on_press_| may delete us. @@ -193,8 +196,6 @@ LoginPalette palette_; private: - views::InkDropHost ink_drop_{this}; - const std::u16string accessible_name_; DISALLOW_COPY_AND_ASSIGN(BasePinButton); @@ -281,7 +282,8 @@ void OnEnabledChanged() { if (!GetEnabled()) { - ink_drop()->AnimateToState(views::InkDropState::DEACTIVATED, nullptr); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::DEACTIVATED, nullptr); CancelRepeat(); } UpdateImage(); @@ -328,8 +330,8 @@ if (event) event->SetHandled(); - ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, - ui::LocatedEvent::FromIfValid(event)); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::ACTIVATED, ui::LocatedEvent::FromIfValid(event)); SchedulePaint(); return; @@ -365,7 +367,8 @@ if (!did_submit && on_press_) on_press_.Run(); - ink_drop()->AnimateToState(views::InkDropState::DEACTIVATED, nullptr); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::DEACTIVATED, + nullptr); SchedulePaint(); }
diff --git a/ash/login/ui/login_remove_account_dialog_unittest.cc b/ash/login/ui/login_remove_account_dialog_unittest.cc index 0083a9c..3b1df8c 100644 --- a/ash/login/ui/login_remove_account_dialog_unittest.cc +++ b/ash/login/ui/login_remove_account_dialog_unittest.cc
@@ -12,6 +12,7 @@ #include "base/strings/utf_string_conversions.h" #include "components/user_manager/user_type.h" #include "ui/events/test/event_generator.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/layout/box_layout.h" @@ -123,7 +124,8 @@ container->AddChildView(bubble_opener); SetWidget(CreateWidgetWithContent(container)); - views::test::InkDropHostTestApi ink_drop_api(bubble_opener->ink_drop()); + views::test::InkDropHostTestApi ink_drop_api( + views::InkDrop::Get(bubble_opener)); EXPECT_EQ(ink_drop_api.ink_drop_mode(), views::InkDropHost::InkDropMode::ON); EXPECT_TRUE(ink_drop_api.HasInkDrop());
diff --git a/ash/login/ui/media_controls_header_view.cc b/ash/login/ui/media_controls_header_view.cc index 91c96ca..c128d438 100644 --- a/ash/login/ui/media_controls_header_view.cc +++ b/ash/login/ui/media_controls_header_view.cc
@@ -13,6 +13,7 @@ #include "ui/gfx/color_utils.h" #include "ui/gfx/font_list.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/button/image_button.h" @@ -91,8 +92,8 @@ std::u16string close_button_label( l10n_util::GetStringUTF16(IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_CLOSE)); close_button->SetAccessibleName(close_button_label); - close_button->ink_drop()->SetBaseColor( - color_utils::DeriveDefaultIconColor(gfx::kGoogleGrey700)); + views::InkDrop::Get(close_button.get()) + ->SetBaseColor(color_utils::DeriveDefaultIconColor(gfx::kGoogleGrey700)); close_button_ = AddChildView(std::move(close_button)); }
diff --git a/ash/login/ui/system_label_button.cc b/ash/login/ui/system_label_button.cc index a3ca5b4..a3d2979d 100644 --- a/ash/login/ui/system_label_button.cc +++ b/ash/login/ui/system_label_button.cc
@@ -12,6 +12,7 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/highlight_path_generator.h" namespace ash { @@ -58,7 +59,7 @@ SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false); SetTextSubpixelRenderingEnabled(false); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetFocusBehavior(FocusBehavior::ALWAYS); SetInstallFocusRingOnFocus(true); @@ -128,9 +129,11 @@ AshColorProvider::Get()->GetBaseLayerColor(kBubbleLayerType)); const AshColorProvider::RippleAttributes ripple_attributes = AshColorProvider::Get()->GetRippleAttributes(effective_background_color); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); - ink_drop()->SetHighlightOpacity(ripple_attributes.highlight_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetHighlightOpacity( + ripple_attributes.highlight_opacity); } } // namespace ash
diff --git a/ash/marker/marker_controller.cc b/ash/marker/marker_controller.cc index 8ccf315..a573ac3 100644 --- a/ash/marker/marker_controller.cc +++ b/ash/marker/marker_controller.cc
@@ -47,6 +47,11 @@ DestroyMarkerView(); } +void MarkerController::UndoLastStroke() { + if (GetMarkerView()) + GetMarkerView()->UndoLastStroke(); +} + void MarkerController::ChangeColor(SkColor new_color) { marker_color_ = new_color;
diff --git a/ash/marker/marker_controller.h b/ash/marker/marker_controller.h index 7145966..7a2ccc2 100644 --- a/ash/marker/marker_controller.h +++ b/ash/marker/marker_controller.h
@@ -42,6 +42,8 @@ // Clears marker pointer. void Clear(); + // Clears the last stroke. + void UndoLastStroke(); void ChangeColor(SkColor new_color);
diff --git a/ash/projector/projector_controller_impl.cc b/ash/projector/projector_controller_impl.cc index db514ff..c716be8 100644 --- a/ash/projector/projector_controller_impl.cc +++ b/ash/projector/projector_controller_impl.cc
@@ -115,6 +115,10 @@ ui_controller_->OnClearAllMarkersPressed(); } +void ProjectorControllerImpl::OnUndoPressed() { + ui_controller_->OnUndoPressed(); +} + void ProjectorControllerImpl::OnSelfieCamPressed(bool enabled) { ui_controller_->OnSelfieCamPressed(enabled);
diff --git a/ash/projector/projector_controller_impl.h b/ash/projector/projector_controller_impl.h index 857701cc8..b2740e0 100644 --- a/ash/projector/projector_controller_impl.h +++ b/ash/projector/projector_controller_impl.h
@@ -36,8 +36,9 @@ void OnSpeechRecognitionAvailable(bool available) override; void OnTranscription(const media::SpeechRecognitionResult& result) override; void OnTranscriptionError() override; - void SetProjectorToolsVisible(bool is_visible) override; - bool IsEligible() const override; + + void SetProjectorToolsVisible(bool is_visible); + bool IsEligible() const; // Sets Caption bubble state to become opened/closed. void SetCaptionBubbleState(bool is_on); @@ -63,6 +64,8 @@ void OnMarkerPressed(); // Invoked when clear all markers button is pressed. void OnClearAllMarkersPressed(); + // Invoked when the undo button is pressed. + void OnUndoPressed(); // Invoked when selfie cam button is pressed. void OnSelfieCamPressed(bool enabled); // Invoked when magnifier button is pressed.
diff --git a/ash/projector/projector_controller_unittest.cc b/ash/projector/projector_controller_unittest.cc index a99ff6d0..1df380f 100644 --- a/ash/projector/projector_controller_unittest.cc +++ b/ash/projector/projector_controller_unittest.cc
@@ -221,6 +221,11 @@ controller_->OnChangeMarkerColorPressed(SK_ColorBLACK); } +TEST_F(ProjectorControllerTest, OnUndoPressed) { + EXPECT_CALL(*mock_ui_controller_, OnUndoPressed()); + controller_->OnUndoPressed(); +} + TEST_F(ProjectorControllerTest, RecordingStarted) { EXPECT_CALL(mock_client_, StartSpeechRecognition()); EXPECT_CALL(*mock_ui_controller_, OnRecordingStateChanged(/*started=*/true));
diff --git a/ash/projector/projector_metrics.h b/ash/projector/projector_metrics.h index 215e416..067a6cc 100644 --- a/ash/projector/projector_metrics.h +++ b/ash/projector/projector_metrics.h
@@ -30,10 +30,11 @@ kToolbarLocationTopLeft = 15, kToolbarLocationTopRight = 16, kToolbarLocationBottomRight = 17, + kUndo = 18, // Add future entries above this comment, in sync with // "ProjectorToolbar" in src/tools/metrics/histograms/enums.xml. // Update kMaxValue to the last value. - kMaxValue = kToolbarLocationBottomRight + kMaxValue = kUndo }; // These enum values represent marker colors on the Projector toolbar and log to
diff --git a/ash/projector/projector_ui_controller.cc b/ash/projector/projector_ui_controller.cc index c295283..01bd45c 100644 --- a/ash/projector/projector_ui_controller.cc +++ b/ash/projector/projector_ui_controller.cc
@@ -246,6 +246,13 @@ RecordToolbarMetrics(ProjectorToolbar::kClearAllMarkers); } +void ProjectorUiController::OnUndoPressed() { + auto* marker_controller = MarkerController::Get(); + DCHECK(marker_controller); + marker_controller->UndoLastStroke(); + RecordToolbarMetrics(ProjectorToolbar::kUndo); +} + void ProjectorUiController::OnCaptionBubbleModelStateChanged(bool opened) { projector_bar_view_->OnCaptionBubbleModelStateChanged(opened); projector_controller_->OnCaptionBubbleModelStateChanged(opened);
diff --git a/ash/projector/projector_ui_controller.h b/ash/projector/projector_ui_controller.h index bd48931..1f7aec7b 100644 --- a/ash/projector/projector_ui_controller.h +++ b/ash/projector/projector_ui_controller.h
@@ -50,6 +50,8 @@ virtual void OnMarkerPressed(); // Invoked when the clear all markers button is pressed. Virtual for testing. virtual void OnClearAllMarkersPressed(); + // Invoked when the undo marker button is pressed. Virtual for testing. + virtual void OnUndoPressed(); // Invoked when transcription is available for rendering. Virtual for testing. virtual void OnTranscription(const std::string& transcription, bool is_final); // Invoked when the selfie cam button is pressed. Virtual for testing.
diff --git a/ash/projector/projector_ui_controller_unittest.cc b/ash/projector/projector_ui_controller_unittest.cc index 0706620..f948510 100644 --- a/ash/projector/projector_ui_controller_unittest.cc +++ b/ash/projector/projector_ui_controller_unittest.cc
@@ -47,9 +47,7 @@ void SetUp() override { AshTestBase::SetUp(); - controller_ = - static_cast<ProjectorControllerImpl*>(ProjectorController::Get()) - ->ui_controller(); + controller_ = Shell::Get()->projector_controller()->ui_controller(); } protected: @@ -234,9 +232,11 @@ base::HistogramTester histogram_tester; MockProjectorClient mock_client; - ProjectorController::Get()->SetClient(&mock_client); - ProjectorController::Get()->OnSpeechRecognitionAvailable(/*available=*/true); - ProjectorController::Get()->SetProjectorToolsVisible(/*is_visible=*/true); + Shell::Get()->projector_controller()->SetClient(&mock_client); + Shell::Get()->projector_controller()->OnSpeechRecognitionAvailable( + /*available=*/true); + Shell::Get()->projector_controller()->SetProjectorToolsVisible( + /*is_visible=*/true); histogram_tester.ExpectUniqueSample( kProjectorToolbarHistogramName, /*sample=*/ProjectorToolbar::kToolbarOpened, /*count=*/1); @@ -266,6 +266,10 @@ kProjectorToolbarHistogramName, /*sample=*/ProjectorToolbar::kClearAllMarkers, /*count=*/1); + bar_view_->OnUndoButtonPressed(); + histogram_tester.ExpectBucketCount(kProjectorToolbarHistogramName, + /*sample=*/ProjectorToolbar::kUndo, + /*count=*/1); bar_view_->OnMagnifierButtonPressed(/*enabled=*/true); histogram_tester.ExpectBucketCount( @@ -338,13 +342,14 @@ /*sample=*/ProjectorToolbar::kToolbarLocationBottomLeft, /*count=*/1); - ProjectorController::Get()->SetProjectorToolsVisible(/*is_visible=*/false); + Shell::Get()->projector_controller()->SetProjectorToolsVisible( + /*is_visible=*/false); histogram_tester.ExpectBucketCount( kProjectorToolbarHistogramName, /*sample=*/ProjectorToolbar::kToolbarClosed, /*count=*/1); histogram_tester.ExpectTotalCount(kProjectorToolbarHistogramName, - /*count=*/19); + /*count=*/20); } } // namespace ash
diff --git a/ash/projector/test/mock_projector_ui_controller.h b/ash/projector/test/mock_projector_ui_controller.h index 5992c76..3755ddc18 100644 --- a/ash/projector/test/mock_projector_ui_controller.h +++ b/ash/projector/test/mock_projector_ui_controller.h
@@ -32,6 +32,7 @@ MOCK_METHOD0(OnLaserPointerPressed, void()); MOCK_METHOD0(OnMarkerPressed, void()); MOCK_METHOD0(OnClearAllMarkersPressed, void()); + MOCK_METHOD0(OnUndoPressed, void()); MOCK_METHOD2(OnTranscription, void(const std::string& transcription, bool is_final)); MOCK_METHOD1(OnSelfieCamPressed, void(bool enabled));
diff --git a/ash/projector/ui/projector_bar_view.cc b/ash/projector/ui/projector_bar_view.cc index d2b95b67..2d0e5df 100644 --- a/ash/projector/ui/projector_bar_view.cc +++ b/ash/projector/ui/projector_bar_view.cc
@@ -138,6 +138,7 @@ void ProjectorBarView::OnMarkerStateChanged(bool enabled) { marker_button_->SetToggled(enabled); + undo_button_->SetEnabled(enabled); clear_all_markers_button_->SetEnabled(enabled); marker_bar_state_ = @@ -206,7 +207,8 @@ marker_button_ = AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnMarkerPressed, base::Unretained(this)), - kProjectorMarkerIcon, l10n_util::GetStringUTF16(IDS_MARKER_BUTTON))); + kProjectorMarkerIcon, + l10n_util::GetStringUTF16(IDS_MARKER_TOOLS_BUTTON))); CreateMarkerOptionsBar(); @@ -260,6 +262,9 @@ base::Unretained(this)), kUndoIcon, l10n_util::GetStringUTF16(IDS_UNDO_BUTTON))); + // This button is disabled by default until marker mode activated. + undo_button_->SetEnabled(marker_button_->GetToggled()); + // Add clear all markers button. clear_all_markers_button_ = box_layout->AddChildView(std::make_unique<ProjectorImageButton>( @@ -356,7 +361,7 @@ &ProjectorBarView::OnChangeBarLocationButtonPressed, base::Unretained(this)), kAutoclickPositionBottomLeftIcon, - l10n_util::GetStringUTF16(IDS_BAR_LOCATION_BUTTON))); + l10n_util::GetStringUTF16(IDS_TOOLBAR_LOCATION_BUTTON))); bar_location_button_->SetVisible(true); tools_bar_ = AddChildView(std::move(box_layout)); } @@ -421,7 +426,7 @@ } void ProjectorBarView::OnUndoButtonPressed() { - // TODO(crbug/1203444) Implement undo for marker. + projector_controller_->OnUndoPressed(); } void ProjectorBarView::OnChangeMarkerColorPressed(SkColor new_color) { @@ -451,7 +456,8 @@ marker_bar_->SetVisible(true); ink_pen_button_->SetVisible(false); marker_pen_button_->SetVisible(false); - undo_button_->SetVisible(false); + undo_button_->SetVisible(true); + clear_all_markers_button_->SetVisible(false); caret_left_->SetVisible(false); caret_right_->SetVisible(true); for (auto* color_button : marker_color_buttons_) @@ -463,6 +469,7 @@ ink_pen_button_->SetVisible(true); marker_pen_button_->SetVisible(true); undo_button_->SetVisible(true); + clear_all_markers_button_->SetVisible(true); caret_left_->SetVisible(true); caret_right_->SetVisible(false); for (auto* color_button : marker_color_buttons_)
diff --git a/ash/projector/ui/projector_button.cc b/ash/projector/ui/projector_button.cc index c0d123b..a6e14fd 100644 --- a/ash/projector/ui/projector_button.cc +++ b/ash/projector/ui/projector_button.cc
@@ -31,9 +31,11 @@ views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(), kProjectorButtonSize / 2.f); - views::InkDrop::UseInkDropForFloodFillRipple(ink_drop(), + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(this), /*highlight_on_hover=*/true, /*highlight_on_focus=*/true); + + SetTooltipText(name); } void ProjectorButton::OnPaintBackground(gfx::Canvas* canvas) { @@ -56,10 +58,11 @@ // Ink Drop. const AshColorProvider::RippleAttributes ripple_attributes = AshColorProvider::Get()->GetRippleAttributes(); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetHighlightOpacity(ripple_attributes.highlight_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetHighlightOpacity( + ripple_attributes.highlight_opacity); } void ProjectorButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
diff --git a/ash/public/cpp/external_arc/keyboard/arc_input_method_surface_manager.h b/ash/public/cpp/external_arc/keyboard/arc_input_method_surface_manager.h index 0a3035f..114cba2 100644 --- a/ash/public/cpp/external_arc/keyboard/arc_input_method_surface_manager.h +++ b/ash/public/cpp/external_arc/keyboard/arc_input_method_surface_manager.h
@@ -8,7 +8,6 @@ #include "ash/public/cpp/ash_public_export.h" #include "ash/public/cpp/keyboard/arc/arc_input_method_bounds_tracker.h" #include "base/macros.h" -#include "base/observer_list.h" #include "components/exo/input_method_surface_manager.h" #include "ui/gfx/geometry/rect.h"
diff --git a/ash/public/cpp/holding_space/holding_space_constants.h b/ash/public/cpp/holding_space/holding_space_constants.h index b5295b2..6fb47d7 100644 --- a/ash/public/cpp/holding_space/holding_space_constants.h +++ b/ash/public/cpp/holding_space/holding_space_constants.h
@@ -48,15 +48,17 @@ // View IDs. constexpr int kHoldingSpaceDownloadsSectionHeaderId = 1; constexpr int kHoldingSpaceFilesAppChipId = 2; -constexpr int kHoldingSpaceItemCheckmarkId = 3; -constexpr int kHoldingSpaceItemImageId = 4; -constexpr int kHoldingSpaceItemPinButtonId = 5; -constexpr int kHoldingSpacePinnedFilesBubbleId = 6; -constexpr int kHoldingSpaceRecentFilesBubbleId = 7; -constexpr int kHoldingSpaceScreenCapturePlayIconId = 8; -constexpr int kHoldingSpaceTrayDefaultIconId = 9; -constexpr int kHoldingSpaceTrayDropTargetOverlayId = 10; -constexpr int kHoldingSpaceTrayPreviewsIconId = 11; +constexpr int kHoldingSpaceItemCancelButtonId = 3; +constexpr int kHoldingSpaceItemCheckmarkId = 4; +constexpr int kHoldingSpaceItemImageId = 5; +constexpr int kHoldingSpaceItemPinButtonId = 6; +constexpr int kHoldingSpaceItemPrimaryActionContainerId = 7; +constexpr int kHoldingSpacePinnedFilesBubbleId = 8; +constexpr int kHoldingSpaceRecentFilesBubbleId = 9; +constexpr int kHoldingSpaceScreenCapturePlayIconId = 10; +constexpr int kHoldingSpaceTrayDefaultIconId = 11; +constexpr int kHoldingSpaceTrayDropTargetOverlayId = 12; +constexpr int kHoldingSpaceTrayPreviewsIconId = 13; // The maximum allowed age for files restored into the holding space model. // Note that this is not enforced for pinned items.
diff --git a/ash/public/cpp/projector/projector_controller.cc b/ash/public/cpp/projector/projector_controller.cc index 2b0608167..e8eead1 100644 --- a/ash/public/cpp/projector/projector_controller.cc +++ b/ash/public/cpp/projector/projector_controller.cc
@@ -27,4 +27,15 @@ return g_instance; } +ProjectorController::ScopedInstanceResetterForTest:: + ScopedInstanceResetterForTest() + : controller_(g_instance) { + g_instance = nullptr; +} + +ProjectorController::ScopedInstanceResetterForTest:: + ~ScopedInstanceResetterForTest() { + g_instance = controller_; +} + } // namespace ash
diff --git a/ash/public/cpp/projector/projector_controller.h b/ash/public/cpp/projector/projector_controller.h index 0902f79..05277b4b 100644 --- a/ash/public/cpp/projector/projector_controller.h +++ b/ash/public/cpp/projector/projector_controller.h
@@ -17,6 +17,19 @@ // Interface to control projector in ash. class ASH_PUBLIC_EXPORT ProjectorController { public: + class ScopedInstanceResetterForTest { + public: + ScopedInstanceResetterForTest(); + ScopedInstanceResetterForTest(const ScopedInstanceResetterForTest&) = + delete; + ScopedInstanceResetterForTest& operator=( + const ScopedInstanceResetterForTest&) = delete; + ~ScopedInstanceResetterForTest(); + + private: + ProjectorController* const controller_; + }; + ProjectorController(); ProjectorController(const ProjectorController&) = delete; ProjectorController& operator=(const ProjectorController&) = delete; @@ -37,12 +50,6 @@ // Called when there is an error in transcription. virtual void OnTranscriptionError() = 0; - - // Sets projector toolbar visibility. - virtual void SetProjectorToolsVisible(bool is_visible) = 0; - - // Returns true if Projector is eligible to start a new session. - virtual bool IsEligible() const = 0; }; } // namespace ash
diff --git a/ash/public/cpp/projector/projector_session.h b/ash/public/cpp/projector/projector_session.h index ac482b07..c43acb77 100644 --- a/ash/public/cpp/projector/projector_session.h +++ b/ash/public/cpp/projector/projector_session.h
@@ -6,7 +6,6 @@ #define ASH_PUBLIC_CPP_PROJECTOR_PROJECTOR_SESSION_H_ #include "ash/public/cpp/ash_public_export.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" namespace ash { @@ -50,4 +49,4 @@ } // namespace ash -#endif // ASH_PUBLIC_CPP_PROJECTOR_PROJECTOR_SESSION_H_ \ No newline at end of file +#endif // ASH_PUBLIC_CPP_PROJECTOR_PROJECTOR_SESSION_H_
diff --git a/ash/search_box/search_box_view_base.cc b/ash/search_box/search_box_view_base.cc index d751283b..2b6f97ba 100644 --- a/ash/search_box/search_box_view_base.cc +++ b/ash/search_box/search_box_view_base.cc
@@ -22,6 +22,7 @@ #include "ui/gfx/image/image_skia.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/border.h" @@ -93,10 +94,10 @@ SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); // InkDropState will reset after clicking. SetHasInkDropActionOnClick(true); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](Button* host) { constexpr SkColor ripple_color = SkColorSetA(gfx::kGoogleGrey900, 0x12); @@ -106,7 +107,7 @@ return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](SearchBoxImageButton* host) -> std::unique_ptr<views::InkDropRipple> { const gfx::Point center = host->GetLocalBounds().CenterPoint(); @@ -119,7 +120,7 @@ return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetLocalBounds().InsetsFrom(bounds), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), ripple_color, 1.0f); }, this));
diff --git a/ash/shelf/home_button_controller.cc b/ash/shelf/home_button_controller.cc index fefae132..3facbda 100644 --- a/ash/shelf/home_button_controller.cc +++ b/ash/shelf/home_button_controller.cc
@@ -77,7 +77,7 @@ } if (CanActivate(button_->GetDisplayId())) { - button_->ink_drop()->AnimateToState( + views::InkDrop::Get(button_)->AnimateToState( views::InkDropState::ACTION_TRIGGERED, event); } @@ -92,8 +92,8 @@ } if (CanActivate(button_->GetDisplayId())) { - button_->ink_drop()->AnimateToState(views::InkDropState::ACTION_PENDING, - event); + views::InkDrop::Get(button_)->AnimateToState( + views::InkDropState::ACTION_PENDING, event); } return false; @@ -117,7 +117,8 @@ return false; // This event happens after the user long presses and lifts the finger. - button_->ink_drop()->AnimateToState(views::InkDropState::HIDDEN, event); + views::InkDrop::Get(button_)->AnimateToState(views::InkDropState::HIDDEN, + event); // We already handled the long press; consume the long tap to avoid // bringing up the context menu again. @@ -151,8 +152,8 @@ } void HomeButtonController::OnTabletModeStarted() { - button_->ink_drop()->AnimateToState(views::InkDropState::DEACTIVATED, - nullptr); + views::InkDrop::Get(button_)->AnimateToState(views::InkDropState::DEACTIVATED, + nullptr); } void HomeButtonController::OnAssistantFeatureAllowedChanged( @@ -180,8 +181,8 @@ // Do not show a highlight in tablet mode, since the home screen view is // always open in the background. if (!Shell::Get()->IsInTabletMode()) { - button_->ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, - nullptr); + views::InkDrop::Get(button_)->AnimateToState(views::InkDropState::ACTIVATED, + nullptr); } is_showing_app_list_ = true; } @@ -190,11 +191,11 @@ // If ink drop is not hidden already, snap it to active state, so animation to // DEACTIVATED state starts immediately (the animation would otherwise wait // for the current animation to finish). - views::InkDrop* const ink_drop = button_->ink_drop()->GetInkDrop(); + views::InkDrop* const ink_drop = views::InkDrop::Get(button_)->GetInkDrop(); if (ink_drop->GetTargetInkDropState() != views::InkDropState::HIDDEN) ink_drop->SnapToActivated(); - button_->ink_drop()->AnimateToState(views::InkDropState::DEACTIVATED, - nullptr); + views::InkDrop::Get(button_)->AnimateToState(views::InkDropState::DEACTIVATED, + nullptr); is_showing_app_list_ = false; }
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc index 7af4fdc..bd8b0414 100644 --- a/ash/shelf/login_shelf_view.cc +++ b/ash/shelf/login_shelf_view.cc
@@ -57,6 +57,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/vector_icon_types.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" #include "ui/views/controls/button/button.h" @@ -217,14 +218,15 @@ this, GetButtonInsets(), ShelfConfig::Get()->control_border_radius()); focus_ring()->SetColor(ShelfConfig::Get()->shelf_focus_border_color()); SetFocusPainter(nullptr); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); AshColorProvider::RippleAttributes ripple_attributes = color_provider->GetRippleAttributes(); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); views::InkDrop::UseInkDropWithoutAutoHighlight( - ink_drop(), /*highlight_on_hover=*/false); + views::InkDrop::Get(this), /*highlight_on_hover=*/false); // Layer rendering is required when the shelf background is visible, which // happens when the wallpaper is not blurred. @@ -314,15 +316,16 @@ this, GetButtonInsets(), ShelfConfig::Get()->control_border_radius()); focus_ring()->SetColor(ShelfConfig::Get()->shelf_focus_border_color()); SetFocusPainter(nullptr); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); views::InkDrop::UseInkDropWithoutAutoHighlight( - ink_drop(), /*highlight_on_hover=*/false); + views::InkDrop::Get(this), /*highlight_on_hover=*/false); const AshColorProvider::RippleAttributes ripple_attributes = AshColorProvider::Get()->GetRippleAttributes(); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); // Layer rendering is required when the shelf background is visible, which // happens when the wallpaper is not blurred.
diff --git a/ash/shelf/scroll_arrow_view.cc b/ash/shelf/scroll_arrow_view.cc index 2150a8c..1d09432b 100644 --- a/ash/shelf/scroll_arrow_view.cc +++ b/ash/shelf/scroll_arrow_view.cc
@@ -13,6 +13,7 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" namespace ash { @@ -24,15 +25,16 @@ arrow_type_(arrow_type), is_horizontal_alignment_(is_horizontal_alignment) { SetHasInkDropActionOnClick(true); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); + views::InkDrop::Get(this)->SetMode( + views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); } ScrollArrowView::~ScrollArrowView() = default; void ScrollArrowView::NotifyClick(const ui::Event& event) { Button::NotifyClick(event); - shelf_button_delegate()->ButtonPressed(/*sender=*/this, event, - ink_drop()->GetInkDrop()); + shelf_button_delegate()->ButtonPressed( + /*sender=*/this, event, views::InkDrop::Get(this)->GetInkDrop()); } void ScrollArrowView::PaintButtonContents(gfx::Canvas* canvas) {
diff --git a/ash/shelf/scrollable_shelf_view.cc b/ash/shelf/scrollable_shelf_view.cc index 7677860..a747e70 100644 --- a/ash/shelf/scrollable_shelf_view.cc +++ b/ash/shelf/scrollable_shelf_view.cc
@@ -30,6 +30,7 @@ #include "ui/gfx/geometry/vector2d_conversions.h" #include "ui/gfx/transform_util.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/focus/focus_search.h" #include "ui/views/view_targeter_delegate.h" @@ -155,7 +156,7 @@ shelf, shelf_button_delegate), shelf_(shelf) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); SetEventTargeter(std::make_unique<views::ViewTargeter>(this)); SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false);
diff --git a/ash/shelf/scrollable_shelf_view_unittest.cc b/ash/shelf/scrollable_shelf_view_unittest.cc index ad5f2ca..769b35d 100644 --- a/ash/shelf/scrollable_shelf_view_unittest.cc +++ b/ash/shelf/scrollable_shelf_view_unittest.cc
@@ -60,10 +60,10 @@ class InkDropAnimationWaiter : public views::InkDropObserver { public: explicit InkDropAnimationWaiter(views::Button* button) : button_(button) { - button->ink_drop()->GetInkDrop()->AddObserver(this); + views::InkDrop::Get(button)->GetInkDrop()->AddObserver(this); } ~InkDropAnimationWaiter() override { - button_->ink_drop()->GetInkDrop()->RemoveObserver(this); + views::InkDrop::Get(button_)->GetInkDrop()->RemoveObserver(this); } void Wait() { @@ -645,7 +645,7 @@ scrollable_shelf_view_->left_arrow()->GetBoundsInScreen(); // Activate a shelf icon's ink drop. Verify that no crash happens. - auto* ink_drop = test_api_->GetButton(0)->ink_drop()->GetInkDrop(); + auto* ink_drop = views::InkDrop::Get(test_api_->GetButton(0))->GetInkDrop(); ink_drop->SnapToActivated(); EXPECT_EQ(views::InkDropState::ACTIVATED, ink_drop->GetTargetInkDropState()); @@ -710,7 +710,7 @@ UpdateDisplay("60x601"); // Activate a shelf icon's ink drop. Verify that no crash happens. - auto* ink_drop = test_api_->GetButton(0)->ink_drop()->GetInkDrop(); + auto* ink_drop = views::InkDrop::Get(test_api_->GetButton(0))->GetInkDrop(); ink_drop->SnapToActivated(); EXPECT_EQ(views::InkDropState::ACTIVATED, ink_drop->GetTargetInkDropState()); } @@ -782,7 +782,7 @@ waiter.Wait(); } ASSERT_EQ(views::InkDropState::ACTIVATED, - icon->ink_drop()->GetInkDrop()->GetTargetInkDropState()); + views::InkDrop::Get(icon)->GetInkDrop()->GetTargetInkDropState()); // Verify that in clamshell when the ripple ring is activated, the rounded // corners should not be applied. @@ -800,7 +800,7 @@ waiter.Wait(); } EXPECT_EQ(views::InkDropState::HIDDEN, - icon->ink_drop()->GetInkDrop()->GetTargetInkDropState()); + views::InkDrop::Get(icon)->GetInkDrop()->GetTargetInkDropState()); // Verify that the rounded corners should not be applied when the ripple ring // is hidden. @@ -837,7 +837,7 @@ waiter.Wait(); } EXPECT_EQ(views::InkDropState::ACTIVATED, - icon->ink_drop()->GetInkDrop()->GetTargetInkDropState()); + views::InkDrop::Get(icon)->GetInkDrop()->GetTargetInkDropState()); // Emulate to remove a shelf icon from context menu. shelf_model->RemoveItemAt(index);
diff --git a/ash/shelf/shelf_app_button.cc b/ash/shelf/shelf_app_button.cc index 97e68e8..4f04cdea 100644 --- a/ash/shelf/shelf_app_button.cc +++ b/ash/shelf/shelf_app_button.cc
@@ -38,6 +38,7 @@ #include "ui/gfx/scoped_canvas.h" #include "ui/gfx/skbitmap_operations.h" #include "ui/gfx/transform_util.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/square_ink_drop_ripple.h" #include "ui/views/controls/dot_indicator.h" @@ -287,17 +288,19 @@ }; icon_shadows_.assign(kShadows, kShadows + base::size(kShadows)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](ShelfAppButton* host) -> std::unique_ptr<views::InkDropRipple> { const gfx::Rect small_ripple_area = host->CalculateSmallRippleArea(); const int ripple_size = host->shelf_view_->GetShelfItemRippleSize(); return std::make_unique<views::SquareInkDropRipple>( gfx::Size(ripple_size, ripple_size), - host->ink_drop()->GetLargeCornerRadius(), small_ripple_area.size(), - host->ink_drop()->GetSmallCornerRadius(), - small_ripple_area.CenterPoint(), host->ink_drop()->GetBaseColor(), - host->ink_drop()->GetVisibleOpacity()); + views::InkDrop::Get(host)->GetLargeCornerRadius(), + small_ripple_area.size(), + views::InkDrop::Get(host)->GetSmallCornerRadius(), + small_ripple_area.CenterPoint(), + views::InkDrop::Get(host)->GetBaseColor(), + views::InkDrop::Get(host)->GetVisibleOpacity()); }, this)); @@ -320,7 +323,7 @@ notification_indicator_ = views::DotIndicator::Install(this); SetNotificationBadgeColor(kDefaultIndicatorColor); } - ink_drop()->GetInkDrop()->AddObserver(this); + views::InkDrop::Get(this)->GetInkDrop()->AddObserver(this); // Do not set a clip, allow the ink drop to burst out. views::InstallEmptyHighlightPathGenerator(this); @@ -335,7 +338,7 @@ } ShelfAppButton::~ShelfAppButton() { - ink_drop()->GetInkDrop()->RemoveObserver(this); + views::InkDrop::Get(this)->GetInkDrop()->RemoveObserver(this); } void ShelfAppButton::SetShadowedImage(const gfx::ImageSkia& image) { @@ -429,17 +432,18 @@ } views::InkDrop* ShelfAppButton::GetInkDropForTesting() { - return ink_drop()->GetInkDrop(); + return views::InkDrop::Get(this)->GetInkDrop(); } void ShelfAppButton::OnDragStarted(const ui::LocatedEvent* event) { - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, event); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, event); } void ShelfAppButton::OnMenuClosed() { DCHECK_EQ(views::InkDropState::ACTIVATED, - ink_drop()->GetInkDrop()->GetTargetInkDropState()); - ink_drop()->GetInkDrop()->AnimateToState(views::InkDropState::DEACTIVATED); + views::InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState()); + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( + views::InkDropState::DEACTIVATED); } void ShelfAppButton::ShowContextMenu(const gfx::Point& p, @@ -743,7 +747,7 @@ base::TimeDelta::FromMilliseconds(kInkDropRippleActivationTimeMs), base::BindOnce(&ShelfAppButton::OnRippleTimer, base::Unretained(this))); - ink_drop()->GetInkDrop()->AnimateToState( + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( views::InkDropState::ACTION_PENDING); event->SetHandled(); } @@ -755,9 +759,9 @@ // for this ShelfAppButton, don't deactivate the ink drop. if (!(state_ & STATE_DRAGGING) && !shelf_view_->IsShowingMenuForView(this) && - (ink_drop()->GetInkDrop()->GetTargetInkDropState() == + (views::InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == views::InkDropState::ACTIVATED)) { - ink_drop()->GetInkDrop()->AnimateToState( + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( views::InkDropState::DEACTIVATED); } ClearDragStateOnGestureEnd(); @@ -770,7 +774,8 @@ // The drag went to the bezel and is about to be passed to // ShelfLayoutManager. drag_timer_.Stop(); - ink_drop()->GetInkDrop()->AnimateToState(views::InkDropState::HIDDEN); + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( + views::InkDropState::HIDDEN); } break; case ui::ET_GESTURE_SCROLL_UPDATE: @@ -788,12 +793,14 @@ } break; case ui::ET_GESTURE_LONG_TAP: - ink_drop()->GetInkDrop()->AnimateToState(views::InkDropState::ACTIVATED); + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( + views::InkDropState::ACTIVATED); // Handle LONG_TAP to avoid opening the context menu twice. event->SetHandled(); break; case ui::ET_GESTURE_TWO_FINGER_TAP: - ink_drop()->GetInkDrop()->AnimateToState(views::InkDropState::ACTIVATED); + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( + views::InkDropState::ACTIVATED); break; default: break; @@ -848,11 +855,12 @@ } void ShelfAppButton::OnRippleTimer() { - if (ink_drop()->GetInkDrop()->GetTargetInkDropState() != + if (views::InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() != views::InkDropState::ACTION_PENDING) { return; } - ink_drop()->GetInkDrop()->AnimateToState(views::InkDropState::ACTIVATED); + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( + views::InkDropState::ACTIVATED); } gfx::Transform ShelfAppButton::GetScaleTransform(float icon_scale) {
diff --git a/ash/shelf/shelf_button.cc b/ash/shelf/shelf_button.cc index 52b33f3..d1d9eb7 100644 --- a/ash/shelf/shelf_button.cc +++ b/ash/shelf/shelf_button.cc
@@ -11,6 +11,7 @@ #include "ash/style/default_color_constants.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" namespace ash { @@ -24,14 +25,16 @@ SetHideInkDropWhenShowingContextMenu(false); const AshColorProvider::RippleAttributes ripple_attributes = AshColorProvider::Get()->GetRippleAttributes(); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); SetFocusBehavior(FocusBehavior::ALWAYS); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); + views::InkDrop::Get(this)->SetMode( + views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); SetFocusPainter(views::Painter::CreateSolidFocusPainter( ShelfConfig::Get()->shelf_focus_border_color(), kFocusBorderThickness, gfx::InsetsF())); - views::InkDrop::UseInkDropForSquareRipple(ink_drop(), + views::InkDrop::UseInkDropForSquareRipple(views::InkDrop::Get(this), /*highlight_on_hover=*/false); } @@ -76,8 +79,8 @@ Button::NotifyClick(event); if (shelf_button_delegate_) - shelf_button_delegate_->ButtonPressed(/*sender=*/this, event, - ink_drop()->GetInkDrop()); + shelf_button_delegate_->ButtonPressed( + /*sender=*/this, event, views::InkDrop::Get(this)->GetInkDrop()); } } // namespace ash
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index 65c50c46..7fd7d97 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -799,7 +799,7 @@ const ShelfItem* item = ShelfItemForView(source); if (!item_awaiting_response_.IsNull()) { if (item && item->id != item_awaiting_response_) { - static_cast<views::Button*>(source)->ink_drop()->AnimateToState( + views::InkDrop::Get(source)->AnimateToState( views::InkDropState::DEACTIVATED, nullptr); } return; @@ -2317,10 +2317,8 @@ if ((source_type == ui::MenuSourceType::MENU_SOURCE_MOUSE || source_type == ui::MenuSourceType::MENU_SOURCE_KEYBOARD) && item) { - static_cast<ShelfAppButton*>(source) - ->ink_drop() - ->GetInkDrop() - ->AnimateToState(views::InkDropState::ACTIVATED); + views::InkDrop::Get(source)->GetInkDrop()->AnimateToState( + views::InkDropState::ACTIVATED); } // Only selected shelf items with context menu opened can be dragged.
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index 7044283..0866dd5 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -82,6 +82,7 @@ #include "ui/events/types/event_type.h" #include "ui/gfx/geometry/point.h" #include "ui/views/animation/bounds_animator.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/animation/test/ink_drop_impl_test_api.h" @@ -2390,9 +2391,9 @@ auto home_button_ink_drop = std::make_unique<InkDropSpy>( views::InkDrop::CreateInkDropWithoutAutoHighlight( - home_button_->ink_drop())); + views::InkDrop::Get(home_button_))); home_button_ink_drop_ = home_button_ink_drop.get(); - views::test::InkDropHostTestApi(home_button_->ink_drop()) + views::test::InkDropHostTestApi(views::InkDrop::Get(home_button_)) .SetInkDrop(std::move(home_button_ink_drop), false); } @@ -2400,14 +2401,14 @@ browser_button_ = test_api_->GetButton(0); auto ink_drop_impl = std::make_unique<views::InkDropImpl>( - browser_button_->ink_drop(), browser_button_->size(), + views::InkDrop::Get(browser_button_), browser_button_->size(), views::InkDropImpl::AutoHighlightMode::NONE); browser_button_ink_drop_impl_ = ink_drop_impl.get(); auto browser_button_ink_drop = std::make_unique<InkDropSpy>(std::move(ink_drop_impl)); browser_button_ink_drop_ = browser_button_ink_drop.get(); - views::test::InkDropHostTestApi(browser_button_->ink_drop()) + views::test::InkDropHostTestApi(views::InkDrop::Get(browser_button_)) .SetInkDrop(std::move(browser_button_ink_drop)); }
diff --git a/ash/system/holding_space/holding_space_item_chip_view.cc b/ash/system/holding_space/holding_space_item_chip_view.cc index 40f4e7a9..ea0fecd 100644 --- a/ash/system/holding_space/holding_space_item_chip_view.cc +++ b/ash/system/holding_space/holding_space_item_chip_view.cc
@@ -104,15 +104,15 @@ // Checkmark. AddCheckmark(/*parent=*/image_and_checkmark_container); - auto* label_and_pin_button_container = + auto* label_and_primary_action_container = AddChildView(std::make_unique<views::View>()); - label_and_pin_button_container->SetLayoutManager( + label_and_primary_action_container->SetLayoutManager( std::make_unique<views::FillLayout>()); - layout->SetFlexForView(label_and_pin_button_container, 1); + layout->SetFlexForView(label_and_primary_action_container, 1); // Label. // NOTE: A11y events for `label_` are handled by its parent. - label_ = label_and_pin_button_container->AddChildView( + label_ = label_and_primary_action_container->AddChildView( std::make_unique<PaintCallbackLabel>( base::BindRepeating(&HoldingSpaceItemChipView::OnPaintLabelMask, base::Unretained(this)))); @@ -126,20 +126,20 @@ bubble_utils::ApplyStyle(label_, bubble_utils::LabelStyle::kChip); - // Pin. - views::View* pin_button_container = - label_and_pin_button_container->AddChildView( + // Primary action. + views::View* primary_action_container = + label_and_primary_action_container->AddChildView( std::make_unique<views::View>()); - auto* pin_layout = - pin_button_container->SetLayoutManager(std::make_unique<views::BoxLayout>( + layout = primary_action_container->SetLayoutManager( + std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal)); - pin_layout->set_main_axis_alignment( - views::BoxLayout::MainAxisAlignment::kEnd); - pin_layout->set_cross_axis_alignment( + layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kEnd); + layout->set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::kCenter); - AddPin(/*parent=*/pin_button_container); + AddPrimaryAction(/*parent=*/primary_action_container, + /*min_size=*/gfx::Size()); } HoldingSpaceItemChipView::~HoldingSpaceItemChipView() = default; @@ -158,8 +158,9 @@ label_->SetText(item->text()); } -void HoldingSpaceItemChipView::OnPinVisibilityChanged(bool pin_visible) { - // The `label_` must be repainted to update its mask for `pin()` visibility. +void HoldingSpaceItemChipView::OnPrimaryActionVisibilityChanged(bool visible) { + // The `label_` must be repainted to update its mask for + // `primary_action_container()` visibility. label_->SchedulePaint(); } @@ -180,17 +181,18 @@ } void HoldingSpaceItemChipView::OnPaintLabelMask(gfx::Canvas* canvas) { - // When the `pin()` is not visible no masking is necessary. - if (!pin()->GetVisible()) + // If the `primary_action_container()` isn't visible, masking is unnecessary. + if (!primary_action_container()->GetVisible()) return; - // When the `pin()` is visible, `label_` fades out its tail to avoid overlap. + // If the `primary_action_container()` is visible, `label_` fades out its tail + // to avoid overlap. gfx::Point gradient_start, gradient_end; if (base::i18n::IsRTL()) { - gradient_end.set_x(pin()->width()); + gradient_end.set_x(primary_action_container()->width()); gradient_start.set_x(gradient_end.x() + kLabelMaskGradientWidth); } else { - gradient_end.set_x(label_->width() - pin()->width()); + gradient_end.set_x(label_->width() - primary_action_container()->width()); gradient_start.set_x(gradient_end.x() - kLabelMaskGradientWidth); }
diff --git a/ash/system/holding_space/holding_space_item_chip_view.h b/ash/system/holding_space/holding_space_item_chip_view.h index 38cda04..cb756ba 100644 --- a/ash/system/holding_space/holding_space_item_chip_view.h +++ b/ash/system/holding_space/holding_space_item_chip_view.h
@@ -36,12 +36,13 @@ // HoldingSpaceItemView: views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override; void OnHoldingSpaceItemUpdated(const HoldingSpaceItem* item) override; - void OnPinVisibilityChanged(bool pin_visible) override; + void OnPrimaryActionVisibilityChanged(bool visible) override; void OnSelectionUiChanged() override; void OnThemeChanged() override; // Invoked during `label_`'s paint sequence to paint its optional mask. Note - // that `label_` is only masked when `pin_` is visible to avoid overlapping. + // that `label_` is only masked when the `primary_action()` is visible to + // avoid overlapping. void OnPaintLabelMask(gfx::Canvas* canvas); void UpdateImage();
diff --git a/ash/system/holding_space/holding_space_item_screen_capture_view.cc b/ash/system/holding_space/holding_space_item_screen_capture_view.cc index 39947f34..3358503 100644 --- a/ash/system/holding_space/holding_space_item_screen_capture_view.cc +++ b/ash/system/holding_space/holding_space_item_screen_capture_view.cc
@@ -25,9 +25,9 @@ namespace ash { // Appearance. -constexpr gfx::Insets kCheckmarkAndPinButtonContainerPadding(4); -constexpr gfx::Size kPinButtonSize(24, 24); +constexpr gfx::Insets kCheckmarkAndPrimaryActionContainerPadding(4); constexpr gfx::Size kPlayIconSize(32, 32); +constexpr gfx::Size kPrimaryActionSize(24, 24); HoldingSpaceItemScreenCaptureView::HoldingSpaceItemScreenCaptureView( HoldingSpaceViewDelegate* delegate, @@ -50,26 +50,26 @@ if (item->type() == HoldingSpaceItem::Type::kScreenRecording) AddPlayIcon(); - views::View* checkmark_and_pin_button_container = + views::View* checkmark_and_primary_action_container = AddChildView(std::make_unique<views::View>()); - auto* layout = checkmark_and_pin_button_container->SetLayoutManager( + auto* layout = checkmark_and_primary_action_container->SetLayoutManager( std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal, - kCheckmarkAndPinButtonContainerPadding)); + kCheckmarkAndPrimaryActionContainerPadding)); layout->set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::kStart); // Checkmark. - AddCheckmark(/*parent=*/checkmark_and_pin_button_container); + AddCheckmark(/*parent=*/checkmark_and_primary_action_container); // Spacer. - views::View* spacer = checkmark_and_pin_button_container->AddChildView( + views::View* spacer = checkmark_and_primary_action_container->AddChildView( std::make_unique<views::View>()); layout->SetFlexForView(spacer, 1); - // Pin. - auto* pin = AddPin(/*parent=*/checkmark_and_pin_button_container); - pin->SetPreferredSize(kPinButtonSize); + // Primary action. + AddPrimaryAction(/*parent=*/checkmark_and_primary_action_container, + /*min_size=*/kPrimaryActionSize); } HoldingSpaceItemScreenCaptureView::~HoldingSpaceItemScreenCaptureView() = @@ -99,10 +99,11 @@ // Image. UpdateImage(); - // Pin. - pin()->SetBackground(holding_space_util::CreateCircleBackground( - AshColorProvider::Get()->GetBaseLayerColor( - AshColorProvider::BaseLayerType::kTransparent80))); + // Primary action. + primary_action_container()->SetBackground( + holding_space_util::CreateCircleBackground( + AshColorProvider::Get()->GetBaseLayerColor( + AshColorProvider::BaseLayerType::kTransparent80))); if (!play_icon_) return;
diff --git a/ash/system/holding_space/holding_space_item_view.cc b/ash/system/holding_space/holding_space_item_view.cc index fb873fd..abcd125 100644 --- a/ash/system/holding_space/holding_space_item_view.cc +++ b/ash/system/holding_space/holding_space_item_view.cc
@@ -25,6 +25,7 @@ #include "ui/views/background.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/image_view.h" +#include "ui/views/layout/fill_layout.h" #include "ui/views/painter.h" #include "ui/views/style/platform_style.h" #include "ui/views/vector_icons.h" @@ -80,6 +81,33 @@ Callback callback_; }; +// MinimumSizableView --------------------------------------------------------- + +// A view which respects a minimum size restriction. +class MinimumSizableView : public views::View { + public: + explicit MinimumSizableView(const gfx::Size& min_size) + : min_size_(min_size) {} + + MinimumSizableView(const MinimumSizableView&) = delete; + MinimumSizableView& operator=(const MinimumSizableView&) = delete; + ~MinimumSizableView() override = default; + + private: + // views::View: + gfx::Size CalculatePreferredSize() const override { + gfx::Size preferred_size(views::View::CalculatePreferredSize()); + preferred_size.SetToMax(min_size_); + return preferred_size; + } + + int GetHeightForWidth(int width) const override { + return std::max(views::View::GetHeightForWidth(width), min_size_.height()); + } + + const gfx::Size min_size_; +}; + } // namespace // HoldingSpaceItemView -------------------------------------------------------- @@ -195,7 +223,7 @@ switch (event->type()) { case ui::ET_MOUSE_ENTERED: case ui::ET_MOUSE_EXITED: - UpdatePin(); + UpdatePrimaryAction(); break; default: break; @@ -237,24 +265,32 @@ InvalidateLayer(focused_layer_owner_->layer()); InvalidateLayer(selected_layer_owner_->layer()); - if (!pin_) + if (!primary_action_container_) return; - // Pin. + // Cancel. const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor( AshColorProvider::ContentLayerType::kButtonIconColor); + primary_action_cancel_->SetImage( + views::Button::STATE_NORMAL, + gfx::CreateVectorIcon(kCancelIcon, kHoldingSpaceIconSize, icon_color)); + + // Pin. const gfx::ImageSkia unpinned_icon = gfx::CreateVectorIcon( views::kUnpinIcon, kHoldingSpaceIconSize, icon_color); const gfx::ImageSkia pinned_icon = gfx::CreateVectorIcon(views::kPinIcon, kHoldingSpaceIconSize, icon_color); - pin_->SetImage(views::Button::STATE_NORMAL, unpinned_icon); - pin_->SetToggledImage(views::Button::STATE_NORMAL, &pinned_icon); + primary_action_pin_->SetImage(views::Button::STATE_NORMAL, unpinned_icon); + primary_action_pin_->SetToggledImage(views::Button::STATE_NORMAL, + &pinned_icon); } void HoldingSpaceItemView::OnHoldingSpaceItemUpdated( const HoldingSpaceItem* item) { - if (item_ == item) + if (item_ == item) { GetViewAccessibility().OverrideName(item->text()); + UpdatePrimaryAction(); + } } void HoldingSpaceItemView::StartDrag(const ui::LocatedEvent& event, @@ -299,22 +335,48 @@ return checkmark_; } -views::ToggleImageButton* HoldingSpaceItemView::AddPin(views::View* parent) { - DCHECK(!pin_); +views::View* HoldingSpaceItemView::AddPrimaryAction(views::View* parent, + const gfx::Size& min_size) { + DCHECK(!primary_action_container_); + DCHECK(!primary_action_cancel_); + DCHECK(!primary_action_pin_); - pin_ = parent->AddChildView(std::make_unique<views::ToggleImageButton>()); - pin_->SetID(kHoldingSpaceItemPinButtonId); - pin_->SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY); - pin_->SetImageHorizontalAlignment( + primary_action_container_ = + parent->AddChildView(std::make_unique<MinimumSizableView>(min_size)); + primary_action_container_->SetID(kHoldingSpaceItemPrimaryActionContainerId); + primary_action_container_->SetLayoutManager( + std::make_unique<views::FillLayout>()); + primary_action_container_->SetVisible(false); + + // Cancel. + primary_action_cancel_ = primary_action_container_->AddChildView( + std::make_unique<views::ImageButton>( + base::BindRepeating(&HoldingSpaceItemView::OnPrimaryActionPressed, + base::Unretained(this)))); + primary_action_cancel_->SetID(kHoldingSpaceItemCancelButtonId); + primary_action_cancel_->SetFocusBehavior( + views::View::FocusBehavior::ACCESSIBLE_ONLY); + primary_action_cancel_->SetImageHorizontalAlignment( + views::ImageButton::HorizontalAlignment::ALIGN_CENTER); + primary_action_cancel_->SetImageVerticalAlignment( + views::ImageButton::VerticalAlignment::ALIGN_MIDDLE); + primary_action_cancel_->SetVisible(false); + + // Pin. + primary_action_pin_ = primary_action_container_->AddChildView( + std::make_unique<views::ToggleImageButton>( + base::BindRepeating(&HoldingSpaceItemView::OnPrimaryActionPressed, + base::Unretained(this)))); + primary_action_pin_->SetID(kHoldingSpaceItemPinButtonId); + primary_action_pin_->SetFocusBehavior( + views::View::FocusBehavior::ACCESSIBLE_ONLY); + primary_action_pin_->SetImageHorizontalAlignment( views::ToggleImageButton::HorizontalAlignment::ALIGN_CENTER); - pin_->SetImageVerticalAlignment( + primary_action_pin_->SetImageVerticalAlignment( views::ToggleImageButton::VerticalAlignment::ALIGN_MIDDLE); - pin_->SetVisible(false); + primary_action_pin_->SetVisible(false); - pin_->SetCallback(base::BindRepeating(&HoldingSpaceItemView::OnPinPressed, - base::Unretained(this))); - - return pin_; + return primary_action_container_; } void HoldingSpaceItemView::OnSelectionUiChanged() { @@ -357,7 +419,17 @@ canvas->DrawRoundRect(gfx::Rect(size), kHoldingSpaceCornerRadius, flags); } -void HoldingSpaceItemView::OnPinPressed() { +void HoldingSpaceItemView::OnPrimaryActionPressed() { + DCHECK_NE(primary_action_cancel_->GetVisible(), + primary_action_pin_->GetVisible()); + + // Cancel. + if (primary_action_cancel_->GetVisible()) { + HoldingSpaceController::Get()->client()->CancelItems({item()}); + return; + } + + // Pin. const bool is_item_pinned = HoldingSpaceController::Get()->model()->ContainsItem( HoldingSpaceItem::Type::kPinnedFile, item()->file_path()); @@ -370,23 +442,29 @@ HoldingSpaceController::Get()->client()->PinItems({item()}); if (weak_ptr) - UpdatePin(); + UpdatePrimaryAction(); } -void HoldingSpaceItemView::UpdatePin() { +void HoldingSpaceItemView::UpdatePrimaryAction() { if (!IsMouseHovered()) { - pin_->SetVisible(false); - OnPinVisibilityChanged(false); + primary_action_container_->SetVisible(false); + OnPrimaryActionVisibilityChanged(false); return; } + // Cancel. + const bool is_item_in_progress = item()->IsInProgress(); + primary_action_cancel_->SetVisible(is_item_in_progress); + + // Pin. const bool is_item_pinned = HoldingSpaceController::Get()->model()->ContainsItem( HoldingSpaceItem::Type::kPinnedFile, item()->file_path()); + primary_action_pin_->SetToggled(!is_item_pinned); + primary_action_pin_->SetVisible(!is_item_in_progress); - pin_->SetToggled(!is_item_pinned); - pin_->SetVisible(true); - OnPinVisibilityChanged(true); + primary_action_container_->SetVisible(true); + OnPrimaryActionVisibilityChanged(true); } BEGIN_METADATA(HoldingSpaceItemView, views::View)
diff --git a/ash/system/holding_space/holding_space_item_view.h b/ash/system/holding_space/holding_space_item_view.h index e90dec00..356fb307 100644 --- a/ash/system/holding_space/holding_space_item_view.h +++ b/ash/system/holding_space/holding_space_item_view.h
@@ -16,6 +16,7 @@ #include "ui/views/view.h" namespace views { +class ImageButton; class ImageView; class ToggleImageButton; } // namespace views @@ -80,19 +81,19 @@ protected: views::ImageView* AddCheckmark(views::View* parent); - views::ToggleImageButton* AddPin(views::View* parent); - virtual void OnPinVisibilityChanged(bool pin_visible) {} + views::View* AddPrimaryAction(views::View* parent, const gfx::Size& min_size); + virtual void OnPrimaryActionVisibilityChanged(bool visible) {} virtual void OnSelectionUiChanged(); HoldingSpaceViewDelegate* delegate() { return delegate_; } views::ImageView* checkmark() { return checkmark_; } - views::ToggleImageButton* pin() { return pin_; } + views::View* primary_action_container() { return primary_action_container_; } private: void OnPaintFocus(gfx::Canvas* canvas, gfx::Size size); void OnPaintSelect(gfx::Canvas* canvas, gfx::Size size); - void OnPinPressed(); - void UpdatePin(); + void OnPrimaryActionPressed(); + void UpdatePrimaryAction(); // NOTE: This view may outlive `delegate_` and/or `item_` during destruction // since the widget is closed asynchronously and the model is updated prior @@ -107,7 +108,9 @@ // Owned by view hierarchy. views::ImageView* checkmark_ = nullptr; - views::ToggleImageButton* pin_ = nullptr; + views::View* primary_action_container_ = nullptr; + views::ImageButton* primary_action_cancel_ = nullptr; + views::ToggleImageButton* primary_action_pin_ = nullptr; // Owners for the layers used to paint focused and selected states. std::unique_ptr<ui::LayerOwner> selected_layer_owner_;
diff --git a/ash/system/holding_space/holding_space_tray.cc b/ash/system/holding_space/holding_space_tray.cc index ae97abf..71db445 100644 --- a/ash/system/holding_space/holding_space_tray.cc +++ b/ash/system/holding_space/holding_space_tray.cc
@@ -785,14 +785,15 @@ const views::InkDropState target_ink_drop_state = is_drop_target ? views::InkDropState::ACTION_PENDING : views::InkDropState::HIDDEN; - if (ink_drop()->GetInkDrop()->GetTargetInkDropState() == + if (views::InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == target_ink_drop_state) return; // Do *not* pass in an event as the origin for the ink drop. Since the user is // not directly over this view, it would look strange to give the ink drop an // out-of-bounds origin. - ink_drop()->AnimateToState(target_ink_drop_state, /*event=*/nullptr); + views::InkDrop::Get(this)->AnimateToState(target_ink_drop_state, + /*event=*/nullptr); } void HoldingSpaceTray::SetShouldAnimate(bool should_animate) {
diff --git a/ash/system/holding_space/pinned_files_section.cc b/ash/system/holding_space/pinned_files_section.cc index 3d61728a..96d0fb47 100644 --- a/ash/system/holding_space/pinned_files_section.cc +++ b/ash/system/holding_space/pinned_files_section.cc
@@ -25,6 +25,7 @@ #include "ui/compositor/layer.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/background.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/highlight_path_generator.h" @@ -87,8 +88,9 @@ // Ink drop. const AshColorProvider::RippleAttributes ripple_attributes = ash_color_provider->GetRippleAttributes(); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); } void Init() { @@ -97,7 +99,7 @@ SetID(kHoldingSpaceFilesAppChipId); // Ink drop. - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(), kFilesAppChipHeight / 2);
diff --git a/ash/system/ime_menu/ime_list_view.cc b/ash/system/ime_menu/ime_list_view.cc index 3de06978..b1f6809a 100644 --- a/ash/system/ime_menu/ime_list_view.cc +++ b/ash/system/ime_menu/ime_list_view.cc
@@ -30,6 +30,7 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/background.h" #include "ui/views/controls/button/toggle_button.h" #include "ui/views/controls/image_view.h" @@ -59,7 +60,7 @@ : ActionableView(TrayPopupInkDropStyle::FILL_BOUNDS), ime_list_view_(list_view), selected_(selected) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); AddChildView(tri_view);
diff --git a/ash/system/locale/locale_detailed_view.cc b/ash/system/locale/locale_detailed_view.cc index b69d792..ae5370b 100644 --- a/ash/system/locale/locale_detailed_view.cc +++ b/ash/system/locale/locale_detailed_view.cc
@@ -22,6 +22,7 @@ #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/scroll_view.h" @@ -46,7 +47,7 @@ : ActionableView(TrayPopupInkDropStyle::FILL_BOUNDS), locale_detailed_view_(locale_detailed_view), checked_(checked) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); AddChildView(tri_view);
diff --git a/ash/system/message_center/message_center_ui_controller.h b/ash/system/message_center/message_center_ui_controller.h index 99f799580..50ef5712 100644 --- a/ash/system/message_center/message_center_ui_controller.h +++ b/ash/system/message_center/message_center_ui_controller.h
@@ -10,7 +10,6 @@ #include "ash/ash_export.h" #include "ash/system/message_center/message_center_ui_delegate.h" #include "base/macros.h" -#include "base/observer_list.h" #include "ui/message_center/message_center_export.h" #include "ui/message_center/message_center_observer.h" #include "ui/message_center/public/cpp/notifier_id.h"
diff --git a/ash/system/message_center/notification_swipe_control_view.h b/ash/system/message_center/notification_swipe_control_view.h index 95a0bd7c..1ab5850 100644 --- a/ash/system/message_center/notification_swipe_control_view.h +++ b/ash/system/message_center/notification_swipe_control_view.h
@@ -7,7 +7,6 @@ #include "ash/ash_export.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/animation/animation_delegate.h"
diff --git a/ash/system/message_center/stacked_notification_bar.cc b/ash/system/message_center/stacked_notification_bar.cc index 81a4ce7..fe739ee9 100644 --- a/ash/system/message_center/stacked_notification_bar.cc +++ b/ash/system/message_center/stacked_notification_bar.cc
@@ -23,6 +23,7 @@ #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/vector_icons.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" @@ -54,7 +55,7 @@ // explicitly called after ConfigureTrayPopupButton as // ConfigureTrayPopupButton configures the InkDrop and these callbacks // override that behavior. - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](Button* host) { auto highlight = std::make_unique<views::InkDropHighlight>( gfx::SizeF(host->size()), message_center_style::kInkRippleColor); @@ -63,11 +64,11 @@ return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](Button* host) -> std::unique_ptr<views::InkDropRipple> { return std::make_unique<views::FloodFillInkDropRipple>( host->size(), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), message_center_style::kInkRippleColor, message_center_style::kInkRippleOpacity); },
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc index e3c0477..8408f5f 100644 --- a/ash/system/overview/overview_button_tray.cc +++ b/ash/system/overview/overview_button_tray.cc
@@ -72,7 +72,7 @@ } void OverviewButtonTray::SnapRippleToActivated() { - ink_drop()->GetInkDrop()->SnapToActivated(); + views::InkDrop::Get(this)->GetInkDrop()->SnapToActivated(); } void OverviewButtonTray::OnGestureEvent(ui::GestureEvent* event) { @@ -130,7 +130,8 @@ } } - ink_drop()->AnimateToState(views::InkDropState::DEACTIVATED, nullptr); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::DEACTIVATED, nullptr); wm::ActivateWindow(new_active_window); last_press_event_time_ = absl::nullopt; return true;
diff --git a/ash/system/toast/toast_overlay.cc b/ash/system/toast/toast_overlay.cc index 82726064..e08b499d1 100644 --- a/ash/system/toast/toast_overlay.cc +++ b/ash/system/toast/toast_overlay.cc
@@ -27,6 +27,7 @@ #include "ui/gfx/font_list.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -131,13 +132,13 @@ public: ToastOverlayButton(PressedCallback callback, const std::u16string& text) : views::LabelButton(std::move(callback), text, CONTEXT_TOAST_OVERLAY) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](Button* host) { return std::make_unique<views::InkDropHighlight>( gfx::SizeF(host->GetLocalBounds().size()), - host->ink_drop()->GetBaseColor()); + views::InkDrop::Get(host)->GetBaseColor()); }, this)); @@ -163,7 +164,8 @@ void OnThemeChanged() override { views::LabelButton::OnThemeChanged(); const auto* color_provider = AshColorProvider::Get(); - ink_drop()->SetBaseColor(color_provider->GetRippleAttributes().base_color); + views::InkDrop::Get(this)->SetBaseColor( + color_provider->GetRippleAttributes().base_color); SetEnabledTextColors(color_provider->GetContentLayerColor( AshColorProvider::ContentLayerType::kButtonLabelColorBlue)); }
diff --git a/ash/system/tray/actionable_view.cc b/ash/system/tray/actionable_view.cc index 6a733fc..99ae53b 100644 --- a/ash/system/tray/actionable_view.cc +++ b/ash/system/tray/actionable_view.cc
@@ -12,6 +12,7 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" @@ -34,11 +35,11 @@ SetInstallFocusRingOnFocus(false); SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); TrayPopupUtils::InstallHighlightPathGenerator(this, ink_drop_style_); - ink_drop()->SetCreateInkDropCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](Button* host) { return TrayPopupUtils::CreateInkDrop(host); }, this)); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( &TrayPopupUtils::CreateInkDropHighlight, base::Unretained(this))); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](ActionableView* host) { return TrayPopupUtils::CreateInkDropRipple(host->ink_drop_style_, host); }, @@ -52,10 +53,10 @@ void ActionableView::HandlePerformActionResult(bool action_performed, const ui::Event& event) { - ink_drop()->AnimateToState(action_performed - ? views::InkDropState::ACTION_TRIGGERED - : views::InkDropState::HIDDEN, - ui::LocatedEvent::FromIfValid(&event)); + views::InkDrop::Get(this)->AnimateToState( + action_performed ? views::InkDropState::ACTION_TRIGGERED + : views::InkDropState::HIDDEN, + ui::LocatedEvent::FromIfValid(&event)); } const char* ActionableView::GetClassName() const {
diff --git a/ash/system/tray/hover_highlight_view.cc b/ash/system/tray/hover_highlight_view.cc index 13cd0a35..e7489746 100644 --- a/ash/system/tray/hover_highlight_view.cc +++ b/ash/system/tray/hover_highlight_view.cc
@@ -5,6 +5,7 @@ #include "ash/system/tray/hover_highlight_view.h" #include <string> + #include "ash/resources/vector_icons/vector_icons.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" @@ -18,6 +19,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/canvas.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/border.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" @@ -28,7 +30,7 @@ HoverHighlightView::HoverHighlightView(ViewClickListener* listener) : ActionableView(TrayPopupInkDropStyle::FILL_BOUNDS), listener_(listener) { SetNotifyEnterExitOnChild(true); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); } HoverHighlightView::~HoverHighlightView() = default;
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc index 4e606c2..3dde626 100644 --- a/ash/system/tray/tray_background_view.cc +++ b/ash/system/tray/tray_background_view.cc
@@ -48,6 +48,7 @@ #include "ui/gfx/transform.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/background.h" #include "ui/views/controls/highlight_path_generator.h" @@ -216,11 +217,13 @@ SetNotifyEnterExitOnChild(true); auto ripple_attributes = AshColorProvider::Get()->GetRippleAttributes(); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetMode( + views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](TrayBackgroundView* host) { gfx::Rect bounds = host->GetBackgroundBounds(); // Currently, we don't handle view resize. To compensate for that, @@ -241,13 +244,13 @@ return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](TrayBackgroundView* host) -> std::unique_ptr<views::InkDropRipple> { const AshColorProvider::RippleAttributes ripple_attributes = AshColorProvider::Get()->GetRippleAttributes(); return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetBackgroundInsets(), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), ripple_attributes.base_color, ripple_attributes.inkdrop_opacity); }, this)); @@ -636,9 +639,10 @@ if (is_active_ == is_active) return; is_active_ = is_active; - ink_drop()->AnimateToState(is_active_ ? views::InkDropState::ACTIVATED - : views::InkDropState::DEACTIVATED, - nullptr); + views::InkDrop::Get(this)->AnimateToState( + is_active_ ? views::InkDropState::ACTIVATED + : views::InkDropState::DEACTIVATED, + nullptr); } views::View* TrayBackgroundView::GetBubbleAnchor() const {
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc index f3624a18..f9f6dde9 100644 --- a/ash/system/tray/tray_popup_utils.cc +++ b/ash/system/tray/tray_popup_utils.cc
@@ -26,6 +26,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/vector_icon_utils.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/square_ink_drop_ripple.h" @@ -230,13 +231,14 @@ bool highlight_on_hover, bool highlight_on_focus) { button->SetInstallFocusRingOnFocus(true); - button->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDropHost* const ink_drop = views::InkDrop::Get(button); + ink_drop->SetMode(views::InkDropHost::InkDropMode::ON); button->SetHasInkDropActionOnClick(true); - button->ink_drop()->SetCreateInkDropCallback(base::BindRepeating( + ink_drop->SetCreateInkDropCallback(base::BindRepeating( &CreateInkDrop, button, highlight_on_hover, highlight_on_focus)); - button->ink_drop()->SetCreateRippleCallback( + ink_drop->SetCreateRippleCallback( base::BindRepeating(&CreateInkDropRipple, ink_drop_style, button)); - button->ink_drop()->SetCreateHighlightCallback( + ink_drop->SetCreateHighlightCallback( base::BindRepeating(&CreateInkDropHighlight, button)); } @@ -275,7 +277,7 @@ bool highlight_on_hover, bool highlight_on_focus) { return views::InkDrop::CreateInkDropForFloodFillRipple( - host->ink_drop(), highlight_on_hover, highlight_on_focus); + views::InkDrop::Get(host), highlight_on_hover, highlight_on_focus); } std::unique_ptr<views::InkDropRipple> TrayPopupUtils::CreateInkDropRipple( @@ -285,7 +287,7 @@ AshColorProvider::Get()->GetRippleAttributes(); return std::make_unique<views::FloodFillInkDropRipple>( host->size(), GetInkDropInsets(ink_drop_style), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), ripple_attributes.base_color, ripple_attributes.inkdrop_opacity); }
diff --git a/ash/system/unified/page_indicator_view.cc b/ash/system/unified/page_indicator_view.cc index 7be169c..0099e7a3 100644 --- a/ash/system/unified/page_indicator_view.cc +++ b/ash/system/unified/page_indicator_view.cc
@@ -26,6 +26,7 @@ #include "ui/gfx/skia_util.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/background.h" @@ -52,15 +53,15 @@ base::Unretained(controller), page)) { SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); views::InstallFixedSizeCircleHighlightPathGenerator(this, kInkDropRadius); - ink_drop()->SetCreateInkDropCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](Button* host) { return TrayPopupUtils::CreateInkDrop(host, /*highlight_on_hover=*/true); }, this)); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](PageIndicatorButton* host) { auto highlight = std::make_unique<views::InkDropHighlight>( gfx::SizeF(host->size()), host->ripple_base_color_); @@ -68,7 +69,7 @@ return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](PageIndicatorButton* host) -> std::unique_ptr<views::InkDropRipple> { gfx::Point center = host->GetLocalBounds().CenterPoint(); gfx::Rect bounds(center.x() - kInkDropRadius, @@ -76,7 +77,7 @@ 2 * kInkDropRadius); return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetLocalBounds().InsetsFrom(bounds), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), host->ripple_base_color_, host->inkdrop_opacity_); }, this)); @@ -135,7 +136,7 @@ // views::Button: void NotifyClick(const ui::Event& event) override { Button::NotifyClick(event); - ink_drop()->GetInkDrop()->AnimateToState( + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( views::InkDropState::ACTION_TRIGGERED); }
diff --git a/ash/system/unified/unified_system_info_view.cc b/ash/system/unified/unified_system_info_view.cc index ed3d0cb..cff5f78a 100644 --- a/ash/system/unified/unified_system_info_view.cc +++ b/ash/system/unified/unified_system_info_view.cc
@@ -31,6 +31,7 @@ #include "ui/chromeos/devicetype_utils.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" @@ -99,7 +100,7 @@ Shell::Get()->system_tray_model()->clock()->AddObserver(this); SetEnabled(Shell::Get()->system_tray_model()->clock()->IsSettingsAvailable()); SetInstallFocusRingOnFocus(true); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); } DateView::~DateView() { @@ -287,7 +288,7 @@ gfx::Size(kUnifiedSystemInfoHeight, kUnifiedSystemInfoHeight)); SetInstallFocusRingOnFocus(true); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); } // A view that shows whether the device is enterprise managed or not. It updates
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc index 79242be..03d8ae0 100644 --- a/ash/wallpaper/wallpaper_controller_impl.cc +++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -779,6 +779,8 @@ return; if (preview_mode) { + DVLOG(1) << __func__ << " preview_mode=true"; + base::UmaHistogramBoolean("Ash.Wallpaper.Preview.Show", true); for (auto& observer : observers_) observer.OnWallpaperPreviewStarted(); }
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc index 8bcfbddd..adcc0ad 100644 --- a/ash/wallpaper/wallpaper_controller_unittest.cc +++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -2416,6 +2416,7 @@ EXPECT_TRUE( controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); + histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show", 1); // Now confirm the preview wallpaper, verify that there's no wallpaper change // because the wallpaper is already shown.
diff --git a/ash/wm/desks/close_desk_button.cc b/ash/wm/desks/close_desk_button.cc index 289f81c..6130b1d0 100644 --- a/ash/wm/desks/close_desk_button.cc +++ b/ash/wm/desks/close_desk_button.cc
@@ -12,6 +12,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/background.h" #include "ui/views/controls/highlight_path_generator.h" @@ -28,18 +29,19 @@ SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - views::InkDrop::UseInkDropForFloodFillRipple(ink_drop()); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(this)); + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](CloseDeskButton* host) { auto highlight = std::make_unique<views::InkDropHighlight>( - gfx::SizeF(host->size()), host->ink_drop()->GetBaseColor()); + gfx::SizeF(host->size()), + views::InkDrop::Get(host)->GetBaseColor()); highlight->set_visible_opacity(host->highlight_opacity_); return highlight; }, this)); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](CloseDeskButton* host) { return host->inkdrop_base_color_; }, this)); SetFocusPainter(nullptr); @@ -65,7 +67,8 @@ color_provider->GetRippleAttributes(background()->get_color()); highlight_opacity_ = ripple_attributes.highlight_opacity; inkdrop_base_color_ = ripple_attributes.base_color; - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); } bool CloseDeskButton::DoesIntersectRect(const views::View* target,
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc index f6764f5..f0d561d7 100644 --- a/ash/wm/desks/desk_preview_view.cc +++ b/ash/wm/desks/desk_preview_view.cc
@@ -34,6 +34,7 @@ #include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/vector2d_f.h" #include "ui/gfx/skia_paint_util.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/border.h" namespace ash { @@ -304,7 +305,7 @@ DCHECK(mini_view_); SetFocusPainter(nullptr); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY); SetPaintToLayer(ui::LAYER_TEXTURED);
diff --git a/ash/wm/desks/expanded_state_new_desk_button.cc b/ash/wm/desks/expanded_state_new_desk_button.cc index 9235dcf..1a476383 100644 --- a/ash/wm/desks/expanded_state_new_desk_button.cc +++ b/ash/wm/desks/expanded_state_new_desk_button.cc
@@ -17,6 +17,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/compositor/layer.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/label.h" namespace ash { @@ -82,7 +83,7 @@ if (!enabled) background_color_ = AshColorProvider::GetDisabledColor(background_color_); - ink_drop()->SetVisibleOpacity( + views::InkDrop::Get(this)->SetVisibleOpacity( color_provider->GetRippleAttributes(background_color_).inkdrop_opacity); SchedulePaint(); }
diff --git a/ash/wm/desks/zero_state_button.cc b/ash/wm/desks/zero_state_button.cc index 78d539f..9d44fdef 100644 --- a/ash/wm/desks/zero_state_button.cc +++ b/ash/wm/desks/zero_state_button.cc
@@ -21,6 +21,7 @@ #include "ui/gfx/text_constants.h" #include "ui/gfx/text_elider.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/controls/highlight_path_generator.h" @@ -56,13 +57,14 @@ // Do not show highlight on hover and focus. Since the button will be painted // with a background, see |highlight_on_hover_| for more details. - views::InkDrop::UseInkDropForFloodFillRipple(ink_drop(), + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(this), /*highlight_on_hover=*/false, /*highlight_on_focus=*/false); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](DeskButtonBase* host) { auto highlight = std::make_unique<views::InkDropHighlight>( - gfx::SizeF(host->size()), host->ink_drop()->GetBaseColor()); + gfx::SizeF(host->size()), + views::InkDrop::Get(host)->GetBaseColor()); highlight->set_visible_opacity( AshColorProvider::Get() ->GetRippleAttributes(host->background_color_) @@ -70,7 +72,7 @@ return highlight; }, this)); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](DeskButtonBase* host) { return AshColorProvider::Get() ->GetRippleAttributes(host->background_color_) @@ -78,7 +80,7 @@ }, this)); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); SetFocusPainter(nullptr); SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY);
diff --git a/ash/wm/overview/overview_item_view.cc b/ash/wm/overview/overview_item_view.cc index 8202f7c3..79a3b36 100644 --- a/ash/wm/overview/overview_item_view.cc +++ b/ash/wm/overview/overview_item_view.cc
@@ -27,6 +27,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" #include "ui/views/controls/button/image_button.h" @@ -89,8 +90,9 @@ public: explicit OverviewCloseButton(PressedCallback callback) : views::ImageButton(std::move(callback)) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); - views::InkDrop::UseInkDropForFloodFillRipple(ink_drop()); + views::InkDrop::Get(this)->SetMode( + views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(this)); SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER); SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); SetMinimumImageSize(gfx::Size(kHeaderHeightDp, kHeaderHeightDp)); @@ -119,8 +121,9 @@ gfx::CreateVectorIcon(kOverviewWindowCloseIcon, color)); const auto ripple_attributes = color_provider->GetRippleAttributes(color); - ink_drop()->SetBaseColor(ripple_attributes.base_color); - ink_drop()->SetVisibleOpacity(ripple_attributes.inkdrop_opacity); + views::InkDrop::Get(this)->SetBaseColor(ripple_attributes.base_color); + views::InkDrop::Get(this)->SetVisibleOpacity( + ripple_attributes.inkdrop_opacity); } };
diff --git a/base/containers/linked_list.h b/base/containers/linked_list.h index 054807c..037d7f2 100644 --- a/base/containers/linked_list.h +++ b/base/containers/linked_list.h
@@ -5,7 +5,7 @@ #ifndef BASE_CONTAINERS_LINKED_LIST_H_ #define BASE_CONTAINERS_LINKED_LIST_H_ -#include "base/check_op.h" +#include "base/base_export.h" // Simple LinkedList type. (See the Q&A section to understand how this // differs from std::list).
diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc index 71b7fa38..81c9ecc 100644 --- a/base/message_loop/message_pump_glib.cc +++ b/base/message_loop/message_pump_glib.cc
@@ -9,6 +9,7 @@ #include <math.h> #include "base/logging.h" +#include "base/notreached.h" #include "base/numerics/safe_conversions.h" #include "base/posix/eintr_wrapper.h" #include "base/synchronization/lock.h"
diff --git a/base/message_loop/message_pump_glib.h b/base/message_loop/message_pump_glib.h index e5c2a29c..ae174fc5 100644 --- a/base/message_loop/message_pump_glib.h +++ b/base/message_loop/message_pump_glib.h
@@ -11,7 +11,6 @@ #include "base/macros.h" #include "base/message_loop/message_pump.h" #include "base/message_loop/watchable_io_message_pump_posix.h" -#include "base/observer_list.h" #include "base/threading/thread_checker.h" #include "base/time/time.h"
diff --git a/base/task/post_job.h b/base/task/post_job.h index 3f36b52..d8ea9eb 100644 --- a/base/task/post_job.h +++ b/base/task/post_job.h
@@ -13,7 +13,6 @@ #include "base/location.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/task/task_traits.h" namespace base { namespace internal { @@ -21,6 +20,9 @@ class PooledTaskRunnerDelegate; } +class TaskTraits; +enum class TaskPriority : uint8_t; + // Delegate that's passed to Job's worker task, providing an entry point to // communicate with the scheduler. To prevent deadlocks, JobDelegate methods // should never be called while holding a user lock.
diff --git a/base/test/task_environment.h b/base/test/task_environment.h index 7e82f1a0..a222d69 100644 --- a/base/test/task_environment.h +++ b/base/test/task_environment.h
@@ -10,7 +10,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "base/single_thread_task_runner.h" #include "base/task/lazy_thread_pool_task_runner.h" #include "base/task/sequence_manager/sequence_manager.h"
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h index d0a0c8c..20e65c8 100644 --- a/base/trace_event/trace_event_impl.h +++ b/base/trace_event/trace_event_impl.h
@@ -14,7 +14,6 @@ #include "base/base_export.h" #include "base/callback.h" -#include "base/observer_list.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_util.h" #include "base/synchronization/condition_variable.h"
diff --git a/base/values.cc b/base/values.cc index 2ac181a8..9593f6dd 100644 --- a/base/values.cc +++ b/base/values.cc
@@ -1333,15 +1333,6 @@ const_cast<const ListValue**>(out_value)); } -bool DictionaryValue::GetBooleanWithoutPathExpansion(StringPiece key, - bool* out_value) const { - const Value* value = FindKey(key); - if (!value) - return false; - - return value->GetAsBoolean(out_value); -} - bool DictionaryValue::GetDoubleWithoutPathExpansion(StringPiece key, double* out_value) const { const Value* value = FindKey(key);
diff --git a/base/values.h b/base/values.h index 4c87676b1..da0339d 100644 --- a/base/values.h +++ b/base/values.h
@@ -737,8 +737,6 @@ // Like `Get()`, but without special treatment of '.'. This allows e.g. URLs // to be used as paths. - // DEPRECATED, use `Value::FindBoolKey(key)` instead. - bool GetBooleanWithoutPathExpansion(StringPiece key, bool* out_value) const; // DEPRECATED, use `Value::FindDoubleKey(key)` instead. bool GetDoubleWithoutPathExpansion(StringPiece key, double* out_value) const; // DEPRECATED, use `Value::FindStringKey(key)` instead.
diff --git a/build/android/gyp/compile_java.py b/build/android/gyp/compile_java.py index 521631a4..3bfbc52 100755 --- a/build/android/gyp/compile_java.py +++ b/build/android/gyp/compile_java.py
@@ -4,6 +4,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import functools import logging import multiprocessing import optparse @@ -14,16 +15,12 @@ import time import zipfile +import javac_output_processor from util import build_utils from util import md5_check from util import jar_info_utils from util import server_utils -sys.path.insert( - 0, - os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party', 'colorama', 'src')) -import colorama - _JAVAC_EXTRACTOR = os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party', 'android_prebuilts', 'build_tools', 'common', 'framework', 'javac_extractor.jar') @@ -190,14 +187,7 @@ ] -def ProcessJavacOutput(output): - fileline_prefix = r'(?P<fileline>(?P<file>[-.\w/\\]+.java):(?P<line>[0-9]+):)' - warning_re = re.compile(fileline_prefix + - r'(?P<full_message> warning: (?P<message>.*))$') - error_re = re.compile(fileline_prefix + - r'(?P<full_message> (?P<message>.*))$') - marker_re = re.compile(r'\s*(?P<marker>\^)\s*$') - +def ProcessJavacOutput(output, target_name): # These warnings cannot be suppressed even for third party code. Deprecation # warnings especially do not help since we must support older android version. deprecated_re = re.compile( @@ -208,17 +198,6 @@ activity_re = re.compile(r'^(?P<prefix>\s*location: )class Activity$') - warning_color = ['full_message', colorama.Fore.YELLOW + colorama.Style.DIM] - error_color = ['full_message', colorama.Fore.MAGENTA + colorama.Style.BRIGHT] - marker_color = ['marker', colorama.Fore.BLUE + colorama.Style.BRIGHT] - - def Colorize(line, regex, color): - match = regex.match(line) - start = match.start(color[0]) - end = match.end(color[0]) - return (line[:start] + color[1] + line[start:end] + colorama.Fore.RESET + - colorama.Style.RESET_ALL + line[end:]) - def ApplyFilters(line): return not (deprecated_re.match(line) or unchecked_re.match(line) or recompile_re.match(line)) @@ -230,17 +209,12 @@ line, prefix, 'docs/ui/android/bytecode_rewriting.md') return line - def ApplyColors(line): - if warning_re.match(line): - line = Colorize(line, warning_re, warning_color) - elif error_re.match(line): - line = Colorize(line, error_re, error_color) - elif marker_re.match(line): - line = Colorize(line, marker_re, marker_color) - return line - lines = (l for l in output.split('\n') if ApplyFilters(l)) - lines = (ApplyColors(Elaborate(l)) for l in lines) + lines = (Elaborate(l) for l in lines) + + output_processor = javac_output_processor.JavacOutputProcessor(target_name) + lines = output_processor.Process(lines) + return '\n'.join(lines) @@ -492,12 +466,15 @@ f.write(' '.join(java_files)) cmd += ['@' + java_files_rsp_path] + process_javac_output_partial = functools.partial( + ProcessJavacOutput, target_name=options.target_name) + logging.debug('Build command %s', cmd) start = time.time() build_utils.CheckOutput(cmd, print_stdout=options.chromium_code, - stdout_filter=ProcessJavacOutput, - stderr_filter=ProcessJavacOutput, + stdout_filter=process_javac_output_partial, + stderr_filter=process_javac_output_partial, fail_on_output=options.warnings_as_errors) end = time.time() - start logging.info('Java compilation took %ss', end) @@ -645,7 +622,6 @@ stamp_file=options.jar_path)): return - colorama.init() javac_cmd = [] if options.gomacc_path: javac_cmd.append(options.gomacc_path)
diff --git a/build/android/gyp/compile_java.pydeps b/build/android/gyp/compile_java.pydeps index f14fd0b..c1c7d5fd 100644 --- a/build/android/gyp/compile_java.pydeps +++ b/build/android/gyp/compile_java.pydeps
@@ -1,14 +1,28 @@ # Generated by running: # build/print_python_deps.py --root build/android/gyp --output build/android/gyp/compile_java.pydeps build/android/gyp/compile_java.py +../../../third_party/catapult/devil/devil/__init__.py +../../../third_party/catapult/devil/devil/android/__init__.py +../../../third_party/catapult/devil/devil/android/constants/__init__.py +../../../third_party/catapult/devil/devil/android/constants/chrome.py +../../../third_party/catapult/devil/devil/android/sdk/__init__.py +../../../third_party/catapult/devil/devil/android/sdk/keyevent.py +../../../third_party/catapult/devil/devil/android/sdk/version_codes.py +../../../third_party/catapult/devil/devil/constants/__init__.py +../../../third_party/catapult/devil/devil/constants/exit_codes.py ../../../third_party/colorama/src/colorama/__init__.py ../../../third_party/colorama/src/colorama/ansi.py ../../../third_party/colorama/src/colorama/ansitowin32.py ../../../third_party/colorama/src/colorama/initialise.py ../../../third_party/colorama/src/colorama/win32.py ../../../third_party/colorama/src/colorama/winterm.py +../../../tools/android/modularization/convenience/lookup_dep.py ../../gn_helpers.py ../../print_python_deps.py +../list_java_targets.py +../pylib/__init__.py +../pylib/constants/__init__.py compile_java.py +javac_output_processor.py util/__init__.py util/build_utils.py util/jar_info_utils.py
diff --git a/build/android/gyp/javac_output_processor.py b/build/android/gyp/javac_output_processor.py new file mode 100755 index 0000000..9390d316 --- /dev/null +++ b/build/android/gyp/javac_output_processor.py
@@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# +# Copyright 2021 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. +"""Contains helper class for processing javac output.""" + +import os +import pathlib +import re +import sys + +from util import build_utils + +sys.path.insert( + 0, + os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party', 'colorama', 'src')) +import colorama +sys.path.insert( + 0, + os.path.join(build_utils.DIR_SOURCE_ROOT, 'tools', 'android', + 'modularization', 'convenience')) +import lookup_dep + + +class JavacOutputProcessor: + def __init__(self, target_name): + self._target_name = target_name + + # Example: ../../ui/android/java/src/org/chromium/ui/base/Clipboard.java:45: + fileline_prefix = ( + r'(?P<fileline>(?P<file>[-.\w/\\]+.java):(?P<line>[0-9]+):)') + + self._warning_re = re.compile( + fileline_prefix + r'(?P<full_message> warning: (?P<message>.*))$') + self._error_re = re.compile(fileline_prefix + + r'(?P<full_message> (?P<message>.*))$') + self._marker_re = re.compile(r'\s*(?P<marker>\^)\s*$') + + # First element in pair is bool which indicates whether the missing + # class/package is part of the error message. + self._symbol_not_found_re_list = [ + # Example: + # error: package org.chromium.components.url_formatter does not exist + (True, + re.compile(fileline_prefix + + r'( error: package [\w.]+ does not exist)$')), + # Example: error: cannot find symbol + (False, re.compile(fileline_prefix + r'( error: cannot find symbol)$')), + # Example: error: symbol not found org.chromium.url.GURL + (True, + re.compile(fileline_prefix + r'( error: symbol not found [\w.]+)$')), + ] + + # Example: import org.chromium.url.GURL; + self._import_re = re.compile(r'\s*import (?P<imported_class>[\w\.]+);$') + + self._warning_color = [ + 'full_message', colorama.Fore.YELLOW + colorama.Style.DIM + ] + self._error_color = [ + 'full_message', colorama.Fore.MAGENTA + colorama.Style.BRIGHT + ] + self._marker_color = ['marker', colorama.Fore.BLUE + colorama.Style.BRIGHT] + + self._class_lookup_index = None + + colorama.init() + + def Process(self, lines): + """ Processes javac output. + + - Applies colors to output. + - Suggests GN dep to add for 'unresolved symbol in Java import' errors. + """ + lines = self._ElaborateLinesForUnknownSymbol(iter(lines)) + return (self._ApplyColors(l) for l in lines) + + def _ElaborateLinesForUnknownSymbol(self, lines): + """ Elaborates passed-in javac output for unresolved symbols. + + Looks for unresolved symbols in imports. + Adds: + - Line with GN target which cannot compile. + - Mention of unresolved class if not present in error message. + - Line with suggestion of GN dep to add. + + Args: + lines: Generator with javac input. + Returns: + Generator with processed output. + """ + previous_line = next(lines, None) + line = next(lines, None) + while previous_line != None: + elaborated_lines = self._ElaborateLineForUnknownSymbol( + previous_line, line) + for elaborated_line in elaborated_lines: + yield elaborated_line + + previous_line = line + line = next(lines, None) + + def _ApplyColors(self, line): + """Adds colors to passed-in line and returns processed line.""" + if self._warning_re.match(line): + line = self._Colorize(line, self._warning_re, self._warning_color) + elif self._error_re.match(line): + line = self._Colorize(line, self._error_re, self._error_color) + elif self._marker_re.match(line): + line = self._Colorize(line, self._marker_re, self._marker_color) + return line + + def _ElaborateLineForUnknownSymbol(self, line, next_line): + if not next_line: + return [line] + + import_re_match = self._import_re.match(next_line) + if not import_re_match: + return [line] + + symbol_missing = False + has_missing_symbol_in_error_msg = False + for symbol_in_error_msg, regex in self._symbol_not_found_re_list: + if regex.match(line): + symbol_missing = True + has_missing_symbol_in_error_msg = symbol_in_error_msg + break + + if not symbol_missing: + return [line] + + class_to_lookup = import_re_match.group('imported_class') + if self._class_lookup_index == None: + self._class_lookup_index = lookup_dep.ClassLookupIndex(pathlib.Path( + os.getcwd()), + should_build=False) + suggested_deps = self._class_lookup_index.match(class_to_lookup) + + if len(suggested_deps) != 1: + return [line] + suggested_target = suggested_deps[0].target + + target_name = self._RemoveSuffixesIfPresent(["__errorprone", "__header"], + self._target_name) + if not has_missing_symbol_in_error_msg: + line = "{} {}".format(line, class_to_lookup) + + return [ + "{}:".format(target_name), line, + "{} found in dep {}.".format(class_to_lookup, suggested_target) + ] + + @staticmethod + def _RemoveSuffixesIfPresent(suffixes, text): + for suffix in suffixes: + if text.endswith(suffix): + return text[:-len(suffix)] + return text + + @staticmethod + def _Colorize(line, regex, color): + match = regex.match(line) + start = match.start(color[0]) + end = match.end(color[0]) + return (line[:start] + color[1] + line[start:end] + colorama.Fore.RESET + + colorama.Style.RESET_ALL + line[end:])
diff --git a/build/android/gyp/nocompile_test.py b/build/android/gyp/nocompile_test.py index a5739f1..d56b046 100755 --- a/build/android/gyp/nocompile_test.py +++ b/build/android/gyp/nocompile_test.py
@@ -74,21 +74,35 @@ f_out.write('\n'.join(extra_args)) -def _find_lines_after_prefix(text, prefix, num_lines): - """Searches |text| for a line which starts with |prefix|. +def _find_regex_in_test_failure_output(test_output, regex): + """Searches for regex in test output. - Args: - text: String to search in. - prefix: Prefix to search for. - num_lines: Number of lines, starting with line with prefix, to return. - Returns: - Matched lines. Returns None otherwise. + Args: + test_output: test output. + regex: regular expression to search for. + Returns: + Whether the regular expression was found in the part of the test output + after the 'FAILED' message. + + If the regex does not contain '\n': + the first 5 lines after the 'FAILED' message (including the text on the + line after the 'FAILED' message) is searched. + Otherwise: + the entire test output after the 'FAILED' message is searched. """ - lines = text.split('\n') - for i, line in enumerate(lines): - if line.startswith(prefix): - return lines[i:i + num_lines] - return None + failed_index = test_output.find('FAILED') + if failed_index < 0: + return False + + failure_message = test_output[failed_index:] + if regex.find('\n') >= 0: + return re.search(regex, failure_message) + + for line in failure_message.split('\n')[:5]: + if re.search(regex, line): + return True + + return False def main(): @@ -106,7 +120,10 @@ options = parser.parse_args() with open(options.test_configs_path) as f: - test_configs = json.loads(f.read()) + # Escape '\' in '\.' now. This avoids having to do the escaping in the test + # specification. + config_text = f.read().replace(r'\.', r'\\.') + test_configs = json.loads(config_text) if not os.path.exists(options.out_dir): os.makedirs(options.out_dir) @@ -140,15 +157,7 @@ # "Compile successful." is not a compiler log message. test_output = _run_command_get_output(ninja_args, '""\nCompile successful.') - failure_message_lines = _find_lines_after_prefix(test_output, 'FAILED:', 5) - - found_expect_regex = False - if failure_message_lines: - for line in failure_message_lines: - if re.search(expect_regex, line): - found_expect_regex = True - break - if not found_expect_regex: + if not _find_regex_in_test_failure_output(test_output, expect_regex): error_message = '//{} failed.\nExpected compile output pattern:\n'\ '{}\nActual compile output:\n{}'.format( gn_path, expect_regex, test_output)
diff --git a/build/android/gyp/turbine.py b/build/android/gyp/turbine.py index 208cc76..074550e 100755 --- a/build/android/gyp/turbine.py +++ b/build/android/gyp/turbine.py
@@ -5,20 +5,29 @@ """Wraps the turbine jar and expands @FileArgs.""" import argparse +import functools import logging import os import shutil import sys import time +import javac_output_processor from util import build_utils +def ProcessJavacOutput(output, target_name): + output_processor = javac_output_processor.JavacOutputProcessor(target_name) + lines = output_processor.Process(output.split('\n')) + return '\n'.join(lines) + + def main(argv): build_utils.InitLogging('TURBINE_DEBUG') argv = build_utils.ExpandFileArgs(argv[1:]) parser = argparse.ArgumentParser() build_utils.AddDepfileOption(parser) + parser.add_argument('--target-name', help='Fully qualified GN target name.') parser.add_argument( '--turbine-jar-path', required=True, help='Path to the turbine jar file.') parser.add_argument( @@ -135,10 +144,16 @@ with build_utils.AtomicOutput(options.jar_path) as output_jar, \ build_utils.AtomicOutput(options.generated_jar_path) as generated_jar: cmd += ['--output', output_jar.name, '--gensrc_output', generated_jar.name] + + process_javac_output_partial = functools.partial( + ProcessJavacOutput, target_name=options.target_name) + logging.debug('Command: %s', cmd) start = time.time() build_utils.CheckOutput(cmd, print_stdout=True, + stdout_filter=process_javac_output_partial, + stderr_filter=process_javac_output_partial, fail_on_output=options.warnings_as_errors) end = time.time() - start logging.info('Header compilation took %ss', end)
diff --git a/build/android/java/test/missing_symbol/B.java b/build/android/java/test/missing_symbol/B.java new file mode 100644 index 0000000..b53bc239 --- /dev/null +++ b/build/android/java/test/missing_symbol/B.java
@@ -0,0 +1,9 @@ +// Copyright 2021 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. + +package test.missing_symbol; + +public class B { + public void foo() {} +}
diff --git a/build/android/java/test/missing_symbol/D.template b/build/android/java/test/missing_symbol/D.template new file mode 100644 index 0000000..2ea2071 --- /dev/null +++ b/build/android/java/test/missing_symbol/D.template
@@ -0,0 +1,9 @@ +// Copyright 2021 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. + +package test.missing_symbol; + +public class D { + public void foo() {} +}
diff --git a/build/android/java/test/missing_symbol/Importer.template b/build/android/java/test/missing_symbol/Importer.template new file mode 100644 index 0000000..7c4bb895 --- /dev/null +++ b/build/android/java/test/missing_symbol/Importer.template
@@ -0,0 +1,13 @@ +// Copyright 2021 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. + +package _IMPORTER_PACKAGE; + +import _IMPORTEE_PACKAGE._IMPORTEE_CLASS_NAME; + +public class Importer { + public Importer() { + new _IMPORTEE_CLASS_NAME().foo(); + } +}
diff --git a/build/android/java/test/missing_symbol/ImportsSubB.java b/build/android/java/test/missing_symbol/ImportsSubB.java new file mode 100644 index 0000000..7112414 --- /dev/null +++ b/build/android/java/test/missing_symbol/ImportsSubB.java
@@ -0,0 +1,13 @@ +// Copyright 2021 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. + +package test.missing_symbol; + +import test.missing_symbol.sub.SubB; + +public class ImportsSubB { + public ImportsSubB() { + new SubB().foo(); + } +}
diff --git a/build/android/java/test/missing_symbol/c.jar b/build/android/java/test/missing_symbol/c.jar new file mode 100644 index 0000000..5f30be8 --- /dev/null +++ b/build/android/java/test/missing_symbol/c.jar Binary files differ
diff --git a/build/android/java/test/missing_symbol/sub/BInMethodSignature.java b/build/android/java/test/missing_symbol/sub/BInMethodSignature.java new file mode 100644 index 0000000..3198fb8 --- /dev/null +++ b/build/android/java/test/missing_symbol/sub/BInMethodSignature.java
@@ -0,0 +1,13 @@ +// Copyright 2021 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. + +package test.missing_symbol.sub; + +import test.missing_symbol.B; + +public class BInMethodSignature { + public B foo() { + return new B(); + } +}
diff --git a/build/android/java/test/missing_symbol/sub/SubB.java b/build/android/java/test/missing_symbol/sub/SubB.java new file mode 100644 index 0000000..dd217ed --- /dev/null +++ b/build/android/java/test/missing_symbol/sub/SubB.java
@@ -0,0 +1,9 @@ +// Copyright 2021 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. + +package test.missing_symbol.sub; + +public class SubB { + public void foo() {} +}
diff --git a/build/android/list_java_targets.py b/build/android/list_java_targets.py index d0689a6e..112d4da2c 100755 --- a/build/android/list_java_targets.py +++ b/build/android/list_java_targets.py
@@ -36,6 +36,10 @@ sys.path.append(os.path.join(_SRC_ROOT, 'build', 'android')) from pylib import constants +_AUTONINJA_PATH = os.path.join(_SRC_ROOT, 'third_party', 'depot_tools', + 'autoninja') +_NINJA_PATH = os.path.join(_SRC_ROOT, 'third_party', 'depot_tools', 'ninja') + _VALID_TYPES = ( 'android_apk', 'android_app_bundle', @@ -55,7 +59,7 @@ def _run_ninja(output_dir, args): cmd = [ - 'autoninja', + _AUTO_NINJA_PATH, '-C', output_dir, ] @@ -66,7 +70,7 @@ def _query_for_build_config_targets(output_dir): # Query ninja rather than GN since it's faster. - cmd = ['ninja', '-C', output_dir, '-t', 'targets'] + cmd = [_NINJA_PATH, '-C', output_dir, '-t', 'targets'] logging.info('Running: %r', cmd) ninja_output = subprocess.run(cmd, check=True,
diff --git a/build/android/test/BUILD.gn b/build/android/test/BUILD.gn index d5f8609..4ad4b492 100644 --- a/build/android/test/BUILD.gn +++ b/build/android/test/BUILD.gn
@@ -7,9 +7,18 @@ if (enable_java_templates) { android_nocompile_test_suite("android_lint_test") { - # Depend on lint Python script so that the action is re-run whenever the lint script is - # modified. - pydeps = [ "//build/android/gyp/lint.pydeps" ] + # Depend on lint and compile_java Python scripts so that the action is re-run whenever the + # scripts are modified. + pydeps = [ + "//build/android/gyp/compile_java.pydeps", + "//build/android/gyp/lint.pydeps", + ] + + sources = [ rebase_path( + missing_symbol_generated_importer_template_nocompile_source, + "", + "nocompile_gn") ] + tests = [ { target = "nocompile_gn:default_locale_lint_test" @@ -25,6 +34,46 @@ rebase_path(new_api_lint_test_nocompile_sources, "", "nocompile_gn") expected_compile_output_regex = "Error:.*NewApi" }, + { + target = "nocompile_gn:import_child_missing_symbol_test_java" + nocompile_sources = + rebase_path(import_child_missing_symbol_test_nocompile_sources, + "", + "nocompile_gn") + expected_compile_output_regex = + "error: package test\.missing_symbol\.sub does not exist" + + "\ntest\.missing_symbol\.sub\.SubB found in dep " + + "//build/android/test/nocompile_gn:sub_b_java" + }, + { + target = "nocompile_gn:import_parent_missing_symbol_test_java" + nocompile_sources = [] + expected_compile_output_regex = "error: cannot find symbol test\.missing_symbol\.B" + "\ntest\.missing_symbol\.B found in dep //build/android/test/nocompile_gn:b_java" + }, + { + target = "nocompile_gn:import_turbine_missing_symbol_test_java" + nocompile_sources = + rebase_path(import_turbine_missing_symbol_test_nocompile_sources, + "", + "nocompile_gn") + expected_compile_output_regex = "error: symbol not found test\.missing_symbol\.B" + "\ntest\.missing_symbol\.B found in dep //build/android/test/nocompile_gn:b_java" + }, + { + target = "nocompile_gn:prebuilt_missing_symbol_test_java" + nocompile_sources = [] + expected_compile_output_regex = + "error: cannot find symbol test\.missing_symbol\.C" + + "\ntest\.missing_symbol\.C found in dep " + + "//build/android/test/nocompile_gn:c_prebuilt_java" + }, + { + target = "nocompile_gn:cpp_template_missing_symbol_test_java" + nocompile_sources = [] + expected_compile_output_regex = + "error: cannot find symbol test\.missing_symbol\.D" + + "\ntest\.missing_symbol\.D found in dep " + + "//build/android/test/nocompile_gn:d_java" + }, ] } }
diff --git a/build/android/test/nocompile_gn/BUILD.gn b/build/android/test/nocompile_gn/BUILD.gn index d3262fe..e5e2374 100644 --- a/build/android/test/nocompile_gn/BUILD.gn +++ b/build/android/test/nocompile_gn/BUILD.gn
@@ -45,3 +45,107 @@ lint_test("new_api_lint_test") { sources = new_api_lint_test_nocompile_sources } + +template("missing_symbol_test") { + _library_target_name = "${target_name}_library_java" + + android_library(_library_target_name) { + sources = [ "//tools/android/errorprone_plugin/test/src/org/chromium/tools/errorprone/plugin/Empty.java" ] + not_needed(invoker, + [ + "sources", + "importer_srcjar_deps", + ]) + if (enable_android_nocompile_tests) { + if (defined(invoker.sources)) { + sources += invoker.sources + } + if (defined(invoker.importer_srcjar_deps)) { + srcjar_deps = invoker.importer_srcjar_deps + } + } + } + + java_group(target_name) { + # Make java_group() depend on dependencies that |_library_target_name| cannot find so that + # the missing symbol resolver can find and suggest the missing GN dep. + deps = [ ":${_library_target_name}" ] + if (defined(invoker.deps)) { + deps += invoker.deps + } + } +} + +# missing_symbol_test() template wrapper which generates importer class. +template("missing_symbol_generated_importer_test") { + _importer_generator_target = "${target_name}_importer_javagen" + java_cpp_template(_importer_generator_target) { + sources = [ missing_symbol_generated_importer_template_nocompile_source ] + defines = [ + "_IMPORTER_PACKAGE=${invoker.importer_package}", + "_IMPORTEE_PACKAGE=${invoker.imported_package}", + "_IMPORTEE_CLASS_NAME=${invoker.imported_class_name}", + ] + } + + missing_symbol_test(target_name) { + importer_srcjar_deps = [ ":${_importer_generator_target}" ] + + if (defined(invoker.deps)) { + deps = invoker.deps + } + } +} + +missing_symbol_generated_importer_test( + "import_parent_missing_symbol_test_java") { + importer_package = "test.missing_symbol.child_missing" + imported_package = "test.missing_symbol" + imported_class_name = "B" + deps = [ ":b_java" ] +} + +missing_symbol_test("import_child_missing_symbol_test_java") { + sources = import_child_missing_symbol_test_nocompile_sources + deps = [ ":sub_b_java" ] +} + +missing_symbol_test("import_turbine_missing_symbol_test_java") { + sources = import_turbine_missing_symbol_test_nocompile_sources + deps = [ ":b_java" ] +} + +missing_symbol_generated_importer_test("prebuilt_missing_symbol_test_java") { + importer_package = "test.missing_symbol.prebuilt_missing" + imported_package = "test.missing_symbol" + imported_class_name = "C" + deps = [ ":c_prebuilt_java" ] +} + +missing_symbol_generated_importer_test( + "cpp_template_missing_symbol_test_java") { + importer_package = "test.missing_symbol.cpp_template_missing" + imported_package = "test.missing_symbol" + imported_class_name = "D" + deps = [ ":d_java" ] +} + +android_library("b_java") { + sources = [ "../../java/test/missing_symbol/B.java" ] +} + +android_library("sub_b_java") { + sources = [ "../../java/test/missing_symbol/sub/SubB.java" ] +} + +android_java_prebuilt("c_prebuilt_java") { + jar_path = "../../java/test/missing_symbol/c.jar" +} + +android_library("d_java") { + srcjar_deps = [ ":d_template_javagen" ] +} + +java_cpp_template("d_template_javagen") { + sources = [ "../../java/test/missing_symbol/D.template" ] +}
diff --git a/build/android/test/nocompile_gn/nocompile_sources.gni b/build/android/test/nocompile_gn/nocompile_sources.gni index 8fc049e..ff072b2 100644 --- a/build/android/test/nocompile_gn/nocompile_sources.gni +++ b/build/android/test/nocompile_gn/nocompile_sources.gni
@@ -6,3 +6,12 @@ [ "../../java/test/DefaultLocaleLintTest.java" ] new_api_lint_test_nocompile_sources = [ "../../java/test/NewApiLintTest.java" ] + +missing_symbol_generated_importer_template_nocompile_source = + "../../java/test/missing_symbol/Importer.template" + +import_child_missing_symbol_test_nocompile_sources = + [ "../../java/test/missing_symbol/ImportsSubB.java" ] + +import_turbine_missing_symbol_test_nocompile_sources = + [ "../../java/test/missing_symbol/sub/BInMethodSignature.java" ]
diff --git a/build/config/android/android_nocompile.gni b/build/config/android/android_nocompile.gni index a99bad3c..09e2e33e 100644 --- a/build/config/android/android_nocompile.gni +++ b/build/config/android/android_nocompile.gni
@@ -49,17 +49,23 @@ deps += invoker.deps } + sources = [] + if (defined(invoker.sources)) { + sources += invoker.sources + } + inputs = [] if (defined(invoker.pydeps)) { foreach(_pydeps_file, invoker.pydeps) { + _pydeps_file_lines = [] _pydeps_file_lines = read_file(_pydeps_file, "list lines") + _pydeps_entries = [] _pydeps_entries = filter_exclude(_pydeps_file_lines, [ "#*" ]) _pydeps_file_dir = get_path_info(_pydeps_file, "dir") inputs += rebase_path(_pydeps_entries, ".", _pydeps_file_dir) } } - sources = [] _json_test_configs = [] foreach(_test_config, _tests) { _test = _test_config["target"]
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index c3b165d..c486e21 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -3112,6 +3112,8 @@ "--generated-dir=$_rebased_generated_dir", "--jar-path=$_rebased_output_jar_path", "--java-srcjars=$_rebased_java_srcjars", + "--target-name", + get_label_info(target_name, "label_no_toolchain"), ] if (defined(invoker.header_jar_path)) { @@ -3189,8 +3191,6 @@ _rebased_errorprone_buildconfig = rebase_path("$_dep_gen_dir/$_dep_name.build_config", root_build_dir) args += [ - "--target-name", - get_label_info(target_name, "label_no_toolchain"), "--processorpath=@FileArg($_rebased_errorprone_buildconfig:deps_info:host_classpath)", "--enable-errorprone", ]
diff --git a/cc/layers/layer.h b/cc/layers/layer.h index 33918090..e3bc5921 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h
@@ -16,7 +16,6 @@ #include "base/auto_reset.h" #include "base/callback.h" #include "base/memory/ref_counted.h" -#include "base/observer_list.h" #include "cc/base/region.h" #include "cc/benchmarks/micro_benchmark.h" #include "cc/cc_export.h"
diff --git a/cc/metrics/frame_sequence_metrics.cc b/cc/metrics/frame_sequence_metrics.cc index 30259bd..1af597d 100644 --- a/cc/metrics/frame_sequence_metrics.cc +++ b/cc/metrics/frame_sequence_metrics.cc
@@ -19,6 +19,36 @@ namespace cc { +bool ShouldReportForAnimation(FrameSequenceTrackerType sequence_type, + FrameSequenceMetrics::ThreadType thread_type) { + if (sequence_type == FrameSequenceTrackerType::kCompositorAnimation) + return thread_type == FrameSequenceMetrics::ThreadType::kCompositor; + + if (sequence_type == FrameSequenceTrackerType::kMainThreadAnimation || + sequence_type == FrameSequenceTrackerType::kRAF) + return thread_type == FrameSequenceMetrics::ThreadType::kMain; + + return false; +} + +bool ShouldReportForInteraction( + FrameSequenceTrackerType sequence_type, + FrameSequenceMetrics::ThreadType reporting_thread_type, + FrameSequenceMetrics::ThreadType metrics_effective_thread_type) { + // For scrollbar/touch/wheel scroll, the slower thread is the one we want to + // report. For pinch-zoom, it's the compositor-thread. + if (sequence_type == FrameSequenceTrackerType::kScrollbarScroll || + sequence_type == FrameSequenceTrackerType::kTouchScroll || + sequence_type == FrameSequenceTrackerType::kWheelScroll) + return reporting_thread_type == metrics_effective_thread_type; + + if (sequence_type == FrameSequenceTrackerType::kPinchZoom) + return reporting_thread_type == + FrameSequenceMetrics::ThreadType::kCompositor; + + return false; +} + namespace { // Avoid reporting any throughput metric for sequences that do not have a @@ -64,37 +94,6 @@ FrameSequenceTracker::GetFrameSequenceTrackerTypeName(type)}); } -bool ShouldReportForAnimation(FrameSequenceTrackerType sequence_type, - FrameSequenceMetrics::ThreadType thread_type) { - if (sequence_type == FrameSequenceTrackerType::kCompositorAnimation) - return thread_type == FrameSequenceMetrics::ThreadType::kCompositor; - - if (sequence_type == FrameSequenceTrackerType::kCanvasAnimation || - sequence_type == FrameSequenceTrackerType::kJSAnimation || - sequence_type == FrameSequenceTrackerType::kMainThreadAnimation || - sequence_type == FrameSequenceTrackerType::kRAF) - return thread_type == FrameSequenceMetrics::ThreadType::kMain; - - return false; -} - -bool ShouldReportForInteraction(FrameSequenceMetrics* metrics, - FrameSequenceMetrics::ThreadType thread_type) { - const auto sequence_type = metrics->type(); - - // For scrollbar/touch/wheel scroll, the slower thread is the one we want to - // report. For pinch-zoom, it's the compositor-thread. - if (sequence_type == FrameSequenceTrackerType::kScrollbarScroll || - sequence_type == FrameSequenceTrackerType::kTouchScroll || - sequence_type == FrameSequenceTrackerType::kWheelScroll) - return thread_type == metrics->GetEffectiveThread(); - - if (sequence_type == FrameSequenceTrackerType::kPinchZoom) - return thread_type == FrameSequenceMetrics::ThreadType::kCompositor; - - return false; -} - bool IsInteractionType(FrameSequenceTrackerType sequence_type) { return sequence_type == FrameSequenceTrackerType::kScrollbarScroll || sequence_type == FrameSequenceTrackerType::kTouchScroll || @@ -346,12 +345,16 @@ if (jank_reporter_) { if (jank_reporter_->thread_type() == FrameSequenceMetrics::ThreadType::kCompositor && - impl_throughput_.frames_expected >= kMinFramesForThroughputMetric) + impl_throughput_.frames_expected >= kMinFramesForThroughputMetric) { + DCHECK_EQ(jank_reporter_->thread_type(), this->GetEffectiveThread()); jank_reporter_->ReportJankMetrics(impl_throughput_.frames_expected); - else if (jank_reporter_->thread_type() == - FrameSequenceMetrics::ThreadType::kMain && - main_throughput_.frames_expected >= kMinFramesForThroughputMetric) + } else if (jank_reporter_->thread_type() == + FrameSequenceMetrics::ThreadType::kMain && + main_throughput_.frames_expected >= + kMinFramesForThroughputMetric) { + DCHECK_EQ(jank_reporter_->thread_type(), this->GetEffectiveThread()); jank_reporter_->ReportJankMetrics(main_throughput_.frames_expected); + } } // Reset the metrics that reach reporting threshold. @@ -447,7 +450,8 @@ const bool is_animation = ShouldReportForAnimation(sequence_type, thread_type); - const bool is_interaction = ShouldReportForInteraction(metrics, thread_type); + const bool is_interaction = ShouldReportForInteraction( + metrics->type(), thread_type, metrics->GetEffectiveThread()); ThroughputUkmReporter* const ukm_reporter = metrics->ukm_reporter(); @@ -518,7 +522,8 @@ const bool is_animation = ShouldReportForAnimation(sequence_type, thread_type); - const bool is_interaction = ShouldReportForInteraction(metrics, thread_type); + const bool is_interaction = ShouldReportForInteraction( + metrics->type(), thread_type, metrics->GetEffectiveThread()); if (is_animation) { TRACE_EVENT_INSTANT2(
diff --git a/cc/metrics/frame_sequence_metrics.h b/cc/metrics/frame_sequence_metrics.h index 1de8184..e148c385 100644 --- a/cc/metrics/frame_sequence_metrics.h +++ b/cc/metrics/frame_sequence_metrics.h
@@ -230,6 +230,14 @@ std::unique_ptr<JankMetrics> jank_reporter_; }; +bool ShouldReportForAnimation(FrameSequenceTrackerType sequence_type, + FrameSequenceMetrics::ThreadType thread_type); + +bool ShouldReportForInteraction( + FrameSequenceTrackerType sequence_type, + FrameSequenceMetrics::ThreadType reporting_thread_type, + FrameSequenceMetrics::ThreadType metrics_effective_thread_type); + } // namespace cc #endif // CC_METRICS_FRAME_SEQUENCE_METRICS_H_
diff --git a/cc/metrics/jank_metrics.cc b/cc/metrics/jank_metrics.cc index 8922e14..3212403 100644 --- a/cc/metrics/jank_metrics.cc +++ b/cc/metrics/jank_metrics.cc
@@ -237,6 +237,29 @@ GetJankHistogramName(tracker_type_, jank_thread_name), 1, 100, 101, base::HistogramBase::kUmaTargetedHistogramFlag)); + const bool is_animation = + ShouldReportForAnimation(tracker_type_, effective_thread_); + + // Jank reporter's effective thread is guaranteed to be identical to that of + // the owning FrameSequenceMetrics instance. + const bool is_interaction = ShouldReportForInteraction( + tracker_type_, effective_thread_, effective_thread_); + + if (is_animation) { + UMA_HISTOGRAM_PERCENTAGE("Graphics.Smoothness.Jank.AllAnimations", + jank_percent); + } + + if (is_interaction) { + UMA_HISTOGRAM_PERCENTAGE("Graphics.Smoothness.Jank.AllInteractions", + jank_percent); + } + + if (is_animation || is_interaction) { + UMA_HISTOGRAM_PERCENTAGE("Graphics.Smoothness.Jank.AllSequences", + jank_percent); + } + // Report the max staleness metrics STATIC_HISTOGRAM_POINTER_GROUP( GetMaxStaleHistogramName(tracker_type_),
diff --git a/cc/metrics/jank_metrics_unittest.cc b/cc/metrics/jank_metrics_unittest.cc index dbc624e..86e7c35 100644 --- a/cc/metrics/jank_metrics_unittest.cc +++ b/cc/metrics/jank_metrics_unittest.cc
@@ -28,6 +28,12 @@ // This makes it easier to numerically distinguish sequence numbers versus // frame tokens, which always start at 1. const uint32_t kSequenceNumberStartsAt = 100u; + +const char* kAllSequencesMetricName = "Graphics.Smoothness.Jank.AllSequences"; +const char* kAllAnimationsMetricName = "Graphics.Smoothness.Jank.AllAnimations"; +const char* kAllInteractionsMetricName = + "Graphics.Smoothness.Jank.AllInteractions"; + } // namespace namespace cc { @@ -158,6 +164,17 @@ EXPECT_THAT(histogram_tester.GetAllSamples(metric), testing::ElementsAre(base::Bucket(1, 1))); + // Test all-sequence metrics. + histogram_tester.ExpectTotalCount(kAllSequencesMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllSequencesMetricName), + testing::ElementsAre(base::Bucket(1, 1))); + + histogram_tester.ExpectTotalCount(kAllAnimationsMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllSequencesMetricName), + testing::ElementsAre(base::Bucket(1, 1))); + + histogram_tester.ExpectTotalCount(kAllInteractionsMetricName, 0u); + // Stale-frame metrics const char* stale_metric = "Graphics.Smoothness.Stale.CompositorAnimation"; const char* maxstale_metric = @@ -206,6 +223,17 @@ // No jank is reported for "Compositor" histogram_tester.ExpectTotalCount(invalid_metric, 0u); + // Test all-sequence metrics. + histogram_tester.ExpectTotalCount(kAllSequencesMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllSequencesMetricName), + testing::ElementsAre(base::Bucket(1, 1))); + + histogram_tester.ExpectTotalCount(kAllAnimationsMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllSequencesMetricName), + testing::ElementsAre(base::Bucket(1, 1))); + + histogram_tester.ExpectTotalCount(kAllInteractionsMetricName, 0u); + // Stale-frame metrics const char* stale_metric = "Graphics.Smoothness.Stale.MainThreadAnimation"; const char* maxstale_metric = @@ -248,6 +276,11 @@ // No jank is reported for "Main" histogram_tester.ExpectTotalCount(invalid_metric, 0u); + // Test all-sequence metrics. Videos are not counted into AllSequences. + histogram_tester.ExpectTotalCount(kAllSequencesMetricName, 0u); + histogram_tester.ExpectTotalCount(kAllAnimationsMetricName, 0u); + histogram_tester.ExpectTotalCount(kAllInteractionsMetricName, 0u); + // Stale-frame metrics const char* stale_metric = "Graphics.Smoothness.Stale.Video"; const char* maxstale_metric = "Graphics.Smoothness.MaxStale.Video"; @@ -289,6 +322,17 @@ histogram_tester.ExpectTotalCount(invalid_metric, 0u); + // Test all-sequence metrics. + histogram_tester.ExpectTotalCount(kAllSequencesMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllSequencesMetricName), + testing::ElementsAre(base::Bucket(0, 1))); + + histogram_tester.ExpectTotalCount(kAllAnimationsMetricName, 0u); + + histogram_tester.ExpectTotalCount(kAllInteractionsMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllInteractionsMetricName), + testing::ElementsAre(base::Bucket(0, 1))); + // Stale-frame metrics const char* stale_metric = "Graphics.Smoothness.Stale.WheelScroll"; const char* maxstale_metric = "Graphics.Smoothness.MaxStale.WheelScroll"; @@ -332,6 +376,17 @@ // No reporting for "Main". histogram_tester.ExpectTotalCount(invalid_metric, 0u); + // Test all-sequence metrics. + histogram_tester.ExpectTotalCount(kAllSequencesMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllSequencesMetricName), + testing::ElementsAre(base::Bucket(2, 1))); + + histogram_tester.ExpectTotalCount(kAllAnimationsMetricName, 0u); + + histogram_tester.ExpectTotalCount(kAllInteractionsMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllInteractionsMetricName), + testing::ElementsAre(base::Bucket(2, 1))); + // Stale-frame metrics const char* stale_metric = "Graphics.Smoothness.Stale.WheelScroll"; const char* maxstale_metric = "Graphics.Smoothness.MaxStale.WheelScroll"; @@ -378,6 +433,17 @@ histogram_tester.ExpectTotalCount(invalid_metric, 0u); + // Test all-sequence metrics. + histogram_tester.ExpectTotalCount(kAllSequencesMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllSequencesMetricName), + testing::ElementsAre(base::Bucket(4, 1))); + + histogram_tester.ExpectTotalCount(kAllAnimationsMetricName, 0u); + + histogram_tester.ExpectTotalCount(kAllInteractionsMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllInteractionsMetricName), + testing::ElementsAre(base::Bucket(4, 1))); + // Stale-frame metrics const char* stale_metric = "Graphics.Smoothness.Stale.TouchScroll"; const char* maxstale_metric = "Graphics.Smoothness.MaxStale.TouchScroll"; @@ -436,6 +502,17 @@ histogram_tester.ExpectTotalCount(invalid_metric, 0u); + // Test all-sequence metrics. + histogram_tester.ExpectTotalCount(kAllSequencesMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllSequencesMetricName), + testing::ElementsAre(base::Bucket(6, 1))); + + histogram_tester.ExpectTotalCount(kAllAnimationsMetricName, 1u); + EXPECT_THAT(histogram_tester.GetAllSamples(kAllAnimationsMetricName), + testing::ElementsAre(base::Bucket(6, 1))); + + histogram_tester.ExpectTotalCount(kAllInteractionsMetricName, 0u); + // Stale-frame metrics const char* stale_metric = "Graphics.Smoothness.Stale.RAF"; const char* maxstale_metric = "Graphics.Smoothness.MaxStale.RAF"; @@ -472,6 +549,11 @@ histogram_tester.ExpectTotalCount( "Graphics.Smoothness.Jank.Compositor.Custom", 0u); + // Test all-sequence metrics. + histogram_tester.ExpectTotalCount(kAllSequencesMetricName, 0u); + histogram_tester.ExpectTotalCount(kAllAnimationsMetricName, 0u); + histogram_tester.ExpectTotalCount(kAllInteractionsMetricName, 0u); + // Stale-frame metrics histogram_tester.ExpectTotalCount("Graphics.Smoothness.Stale.Custom", 0u); histogram_tester.ExpectTotalCount("Graphics.Smoothness.MaxStale.Custom", 0u);
diff --git a/cc/trees/draw_properties_unittest.cc b/cc/trees/draw_properties_unittest.cc index 4f1c15c..f982efe 100644 --- a/cc/trees/draw_properties_unittest.cc +++ b/cc/trees/draw_properties_unittest.cc
@@ -3575,21 +3575,22 @@ active_child->effect_tree_index())); } -class TransformInteropTest : public DrawPropertiesTestBase, - public testing::Test { +class BackfaceVisibilityInteropTest : public DrawPropertiesTestBase, + public testing::Test { public: - TransformInteropTest() : DrawPropertiesTestBase(TransformInteropSettings()) {} + BackfaceVisibilityInteropTest() + : DrawPropertiesTestBase(BackfaceVisibilityInteropSettings()) {} protected: - LayerTreeSettings TransformInteropSettings() { + LayerTreeSettings BackfaceVisibilityInteropSettings() { LayerListSettings settings; - settings.enable_transform_interop = true; + settings.enable_backface_visibility_interop = true; return settings; } }; -TEST_F(TransformInteropTest, BackfaceInvisibleTransform) { +TEST_F(BackfaceVisibilityInteropTest, BackfaceInvisibleTransform) { LayerImpl* root = root_layer(); root->SetDrawsContent(true); LayerImpl* back_facing = AddLayer<LayerImpl>();
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index 5dd5670..f3d0ac6 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -1285,7 +1285,7 @@ if (!transform_node->node_and_ancestors_are_animated_or_invertible || !effect_node->is_drawn) return true; - if (layer->layer_tree_impl()->settings().enable_transform_interop) { + if (layer->layer_tree_impl()->settings().enable_backface_visibility_interop) { return layer->should_check_backface_visibility() && IsLayerBackFaceVisible(layer, layer->transform_tree_index(), property_trees); @@ -1297,7 +1297,7 @@ bool CC_EXPORT IsLayerBackFaceVisible(LayerImpl* layer, int transform_tree_index, const PropertyTrees* property_trees) { - if (layer->layer_tree_impl()->settings().enable_transform_interop) { + if (layer->layer_tree_impl()->settings().enable_backface_visibility_interop) { return IsTransformToRootOf3DRenderingContextBackFaceVisible( layer, transform_tree_index, property_trees); } else { @@ -1309,7 +1309,9 @@ bool CC_EXPORT IsLayerBackFaceVisible(Layer* layer, int transform_tree_index, const PropertyTrees* property_trees) { - if (layer->layer_tree_host()->GetSettings().enable_transform_interop) { + if (layer->layer_tree_host() + ->GetSettings() + .enable_backface_visibility_interop) { return IsTransformToRootOf3DRenderingContextBackFaceVisible( layer, transform_tree_index, property_trees); } else {
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index f2011d4..d8d57bf 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -2686,7 +2686,7 @@ // Tests that when the LayerTreeHost has received an updated Viewport Rect and // viz::LocalSurfaceId that the Impl Frame does not begin until the new tree has -// been activated. +// been either activated or pushed as the new pending tree. class LayerTreeHostTestViewportRectChangeBlockedMainThread : public LayerTreeHostTest { public: @@ -2709,7 +2709,7 @@ void BeginTest() override { PostSetNeedsCommitToMainThread(); } - void AllowCommits() { scoped_defer_main_frame_update_.reset(); } + void StopDeferringCommits() { scoped_defer_main_frame_update_.reset(); } void ChangeViewportRect() { gfx::Rect rect = layer_tree_host()->device_viewport_rect(); @@ -2753,6 +2753,42 @@ host_impl->active_tree()->local_surface_id_from_parent()); EXPECT_EQ(target_local_surface_id_, host_impl->target_local_surface_id()); + // On slower configurations more than one frame at the original + // |source_frame_number| can be triggered between when we begin allowing + // commits again, and before the commit occurs. + // + // If so do not attempt to re-unblock. Once we have stopped the blocking + // the first time, all subsequent Commit/Activate/BeginMainFramme will + // be allowed to continue as normal. + // + // When this occurs there will be a new pending tree. We also expect + // there to be damage now, to unblock impl frame production ahead of the + // upcoming activation. CC is already build around Activations that can + // arrive mid-frame. It does this by delaying non-immediate mode + // painting until either Activation arrives, or an internal deadline is + // hit. + // + // The normal flow is: + // Main hasn't committed yet, due to explicitly being blocked. + // BeginImplFrame - we don't have damage + // Main is unblocked by StopDeferringCommits + // Main commits + // Main activates + // BeginImplFrame has new active_tree and starts + // + // The slower flow is: + // Main hasn't committed yet, due to explicitly being blocked. + // BeginImplFrame - we don't want have damage + // Main is unblocked by StopDeferringCommits + // Main commits + // BeginImplFrame has new pending_tree and starts + // Main activates + // Impl receives activation + // Painting. + if (host_impl->pending_tree()) { + EXPECT_TRUE(has_damage); + return; + } // When the |active_tree| in the LayerTreeHostImpl is behind the new // |target_local_surface_id| that the LayerTreeHost is processing, // there should be no damage. @@ -2764,7 +2800,7 @@ FROM_HERE, base::BindOnce( &LayerTreeHostTestViewportRectChangeBlockedMainThread:: - AllowCommits, + StopDeferringCommits, base::Unretained(this))); break; case 1:
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h index 7fa2b4da..bd5bcf4a 100644 --- a/cc/trees/layer_tree_settings.h +++ b/cc/trees/layer_tree_settings.h
@@ -193,7 +193,7 @@ // When enabled, enforces new interoperable semantics for 3D transforms. // See crbug.com/1008483. - bool enable_transform_interop = false; + bool enable_backface_visibility_interop = false; // Enables ThrottleDecider which produces a list of FrameSinkIds that are // candidates for throttling.
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index ce3694f..9f1cb90 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -367,6 +367,7 @@ "//chrome/browser/signin/ui/android:java", "//chrome/browser/tab:java", "//chrome/browser/tab_group:java", + "//chrome/browser/tab_provider:java", "//chrome/browser/tabmodel:factory_java", "//chrome/browser/tabmodel:java", "//chrome/browser/tabpersistence:java", @@ -947,6 +948,7 @@ "//chrome/browser/tab:optimization_guide_protos_java", "//chrome/browser/tab_group:java", "//chrome/browser/tab_group:junit", + "//chrome/browser/tab_provider:java", "//chrome/browser/tabmodel:factory_java", "//chrome/browser/tabmodel:java", "//chrome/browser/tabmodel/internal:java", @@ -1258,6 +1260,7 @@ "//chrome/browser/tab:java", "//chrome/browser/tab:optimization_guide_protos_java", "//chrome/browser/tab_group:java", + "//chrome/browser/tab_provider:java", "//chrome/browser/tabmodel:java", "//chrome/browser/tabmodel/internal:java", "//chrome/browser/tabpersistence:java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 28416ead..ccce7610 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -4,7 +4,6 @@ chrome_java_sources = [ "java/src/com/google/android/apps/chrome/appwidget/bookmarks/BookmarkThumbnailWidgetProvider.java", - "java/src/org/chromium/chrome/browser/ActivityTabProvider.java", "java/src/org/chromium/chrome/browser/ActivityUtils.java", "java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java", "java/src/org/chromium/chrome/browser/AppHooks.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni index 679abd2..ac885d0 100644 --- a/chrome/android/chrome_junit_test_java_sources.gni +++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -72,6 +72,7 @@ "junit/src/org/chromium/chrome/browser/customtabs/CustomTabNightModeStateControllerTest.java", "junit/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProviderTest.java", "junit/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTriggerTest.java", + "junit/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java", "junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java", "junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationControllerTest.java", "junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java", @@ -240,6 +241,7 @@ "junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java", "junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java", "junit/src/org/chromium/chrome/browser/webapps/MockWebappDataStorageClockRule.java", + "junit/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialogTest.java", "junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java", "junit/src/org/chromium/chrome/browser/webapps/WebApkShareTargetUtilTest.java", "junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index 7730409..1ddfad8 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -152,7 +152,6 @@ "javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabActivityRenderTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabActivityTestRule.java", - "javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/TrustedCdnPublisherUrlTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java", @@ -619,7 +618,6 @@ "javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTest.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTestRule.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkCurrentPageVerifierTest.java", - "javatests/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialogTest.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkInitializationTest.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn index de4a28b..286bc07 100644 --- a/chrome/android/features/autofill_assistant/BUILD.gn +++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -44,6 +44,7 @@ "//chrome/browser/settings:java", "//chrome/browser/signin/services/android:java", "//chrome/browser/tab:java", + "//chrome/browser/tab_provider:java", "//chrome/browser/ui/android/favicon:java", "//chrome/browser/ui/messages/android:java", "//chrome/browser/util:java", @@ -341,6 +342,7 @@ "//chrome/browser/profiles/android:java", "//chrome/browser/signin/services/android:java", "//chrome/browser/tab:java", + "//chrome/browser/tab_provider:java", "//chrome/browser/tabmodel:java", "//chrome/browser/util:java", "//chrome/test/android:chrome_java_test_support",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantDependenciesImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantDependenciesImpl.java index 425b39f1..b9881c2 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantDependenciesImpl.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantDependenciesImpl.java
@@ -12,7 +12,6 @@ import org.chromium.base.Callback; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.autofill_assistant.onboarding.AssistantOnboardingResult; import org.chromium.chrome.browser.autofill_assistant.onboarding.BaseOnboardingCoordinator; import org.chromium.chrome.browser.autofill_assistant.onboarding.OnboardingCoordinatorFactory; @@ -20,6 +19,7 @@ import org.chromium.chrome.browser.autofill_assistant.trigger_scripts.AssistantTriggerScriptBridge; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.compositor.CompositorViewHolder; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.content_public.browser.WebContents; import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantActionHandlerImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantActionHandlerImpl.java index eaa131d..779fded 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantActionHandlerImpl.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantActionHandlerImpl.java
@@ -10,12 +10,12 @@ import org.chromium.base.Callback; import org.chromium.base.ThreadUtils; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.autofill_assistant.onboarding.AssistantOnboardingResult; import org.chromium.chrome.browser.autofill_assistant.onboarding.BaseOnboardingCoordinator; import org.chromium.chrome.browser.autofill_assistant.onboarding.OnboardingCoordinatorFactory; import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.content_public.browser.WebContents; import java.util.Collections;
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java index f2f0e390..48d4a09d 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java
@@ -9,10 +9,10 @@ import androidx.annotation.NonNull; import org.chromium.base.annotations.UsedByReflection; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.autofill_assistant.onboarding.OnboardingCoordinatorFactory; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.compositor.CompositorViewHolder; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.content_public.browser.WebContents; import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java index dee9b82..df41d29 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -16,7 +16,6 @@ import org.chromium.base.annotations.NativeMethods; import org.chromium.base.task.PostTask; import org.chromium.chrome.autofill_assistant.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip; import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason; @@ -26,6 +25,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabUtils; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.ui.TabObscuringHandler; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager.SnackbarController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java index 06b0a8b8..44d870d7 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java
@@ -9,11 +9,11 @@ import androidx.annotation.NonNull; import org.chromium.base.Callback; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.autofill_assistant.onboarding.OnboardingCoordinatorFactory; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.compositor.CompositorViewHolder; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.content_public.browser.WebContents; import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java index 91c3e79..c6198bd 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java
@@ -11,7 +11,6 @@ import org.chromium.base.Callback; import org.chromium.base.ThreadUtils; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.compositor.CompositorViewHolder; import org.chromium.chrome.browser.directactions.DirectActionHandler; @@ -19,6 +18,7 @@ import org.chromium.chrome.browser.directactions.DirectActionReporter.Definition; import org.chromium.chrome.browser.directactions.DirectActionReporter.Type; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; /**
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java index 9df732c4..a8adaea 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -17,7 +17,6 @@ import org.chromium.base.Callback; import org.chromium.base.Function; import org.chromium.base.Log; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; @@ -27,6 +26,7 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.metrics.UmaSessionStats; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider; import org.chromium.components.external_intents.ExternalNavigationDelegate.IntentToAutofillAllowingAppResult;
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java index cbd27034..eb5766b 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java
@@ -8,9 +8,9 @@ import androidx.annotation.NonNull; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.compositor.CompositorViewHolder; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.module_installer.builder.ModuleInterface; import org.chromium.content_public.browser.WebContents;
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java index e756fd4f..0fff301 100644 --- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java +++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java
@@ -491,7 +491,12 @@ } Toast.makeText(getActivity(), getResources().getString(id), Toast.LENGTH_SHORT).show(); - getActivity().finish(); + // Finish the Activity unless we're connected via USB. In that case + // we continue to show a message advising the user to disconnect + // the cable because the USB connection is in AOA mode. + if (mMode != Mode.USB) { + getActivity().finish(); + } }); }
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn index 2efe4b76..583d556 100644 --- a/chrome/android/features/keyboard_accessory/BUILD.gn +++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -122,6 +122,7 @@ "//chrome/browser/flags:java", "//chrome/browser/password_manager/android:java", "//chrome/browser/tab:java", + "//chrome/browser/tab_provider:java", "//chrome/browser/tabmodel:java", "//chrome/test/android:chrome_java_test_support", "//components/autofill/android:autofill_java",
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn index 8804e0e..4edf795 100644 --- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn +++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -22,6 +22,7 @@ "//chrome/browser/password_manager/android:java", "//chrome/browser/profiles/android:java", "//chrome/browser/tab:java", + "//chrome/browser/tab_provider:java", "//chrome/browser/tabmodel:java", "//chrome/browser/ui/android/favicon:java", "//chrome/browser/util:java",
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java index c651c66d..4cc9732f 100644 --- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java +++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
@@ -56,7 +56,6 @@ import org.chromium.base.UserDataHost; import org.chromium.base.metrics.test.ShadowRecordHistogram; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.ChromeWindow; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.compositor.CompositorViewHolder; @@ -77,6 +76,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabCreationState; import org.chromium.chrome.browser.tab.TabHidingType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
diff --git a/chrome/android/java/res/layout/incognito_history_placeholder.xml b/chrome/android/java/res/layout/incognito_history_placeholder.xml index 4627948..a936f44 100644 --- a/chrome/android/java/res/layout/incognito_history_placeholder.xml +++ b/chrome/android/java/res/layout/incognito_history_placeholder.xml
@@ -24,7 +24,7 @@ android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:text="@string/menu_history" - android:textAppearance="@style/TextAppearance.Headline.Primary"/> + android:textAppearance="@style/TextAppearance.Headline"/> <org.chromium.ui.widget.ChromeImageButton android:id="@+id/close_history_placeholder_button" @@ -63,7 +63,7 @@ android:layout_height="wrap_content" android:layout_marginTop="16dp" android:gravity="center_horizontal" - android:textAppearance="@style/TextAppearance.TextLarge.Primary" + android:textAppearance="@style/TextAppearance.Headline" android:text="@string/incognito_history_placeholder_title" app:leading="@dimen/text_size_large_leading" /> @@ -72,7 +72,7 @@ android:layout_height="wrap_content" android:layout_marginTop="16dp" android:gravity="center_horizontal" - android:textAppearance="@style/TextAppearance.TextSmall.Primary" + android:textAppearance="@style/TextAppearance.TextMedium" android:text="@string/incognito_history_placeholder_description" app:leading="@dimen/text_size_small_leading" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java index cb5193c..327ea9b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeHandler.java
@@ -33,6 +33,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabUtils; import org.chromium.chrome.browser.tab.TabWebContentsObserver; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.user_education.IPHCommandBuilder; import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.components.browser_ui.share.ShareParams;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 0f4d292..00ab843 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2198,10 +2198,8 @@ mOverviewModeController.hideOverview(false); getToolbarManager().finishAnimations(); } - if (TextUtils.equals(externalAppId, getPackageName())) { + if (IntentHandler.wasIntentSenderChrome(intent)) { // If the intent was launched by chrome, open the new tab in the appropriate model. - // Using FROM_LINK ensures the tab is parented to the current tab, which allows - // the back button to close these tabs and restore selection to the previous tab. boolean isIncognito = IntentUtils.safeGetBooleanExtra( intent, IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, false); LoadUrlParams loadUrlParams = new LoadUrlParams(url); @@ -2209,6 +2207,10 @@ loadUrlParams.setVerbatimHeaders(headers); loadUrlParams.setIsRendererInitiated(isRendererInitiated); loadUrlParams.setInitiatorOrigin(initiatorOrigin); + if (referer != null) { + loadUrlParams.setReferrer( + new Referrer(referer, IntentHandler.getReferrerPolicyFromIntent(intent))); + } @TabLaunchType Integer launchType = IntentHandler.getTabLaunchType(intent); if (launchType == null) { @@ -2218,6 +2220,9 @@ } else if (IncognitoTabLauncher.didCreateIntent(intent)) { launchType = TabLaunchType.FROM_LAUNCH_NEW_INCOGNITO_TAB; } else { + // Using FROM_LINK ensures the tab is parented to the current tab, which allows + // the back button to close these tabs and restore selection to the previous + // tab. launchType = TabLaunchType.FROM_LINK; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWindow.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWindow.java index 3b46037f..e4d60228 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWindow.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWindow.java
@@ -15,6 +15,7 @@ import org.chromium.chrome.browser.infobar.InfoBarIdentifier; import org.chromium.chrome.browser.keyboard_accessory.ManualFillingComponent; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.ui.messages.infobar.SimpleConfirmInfoBarBuilder; import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate; import org.chromium.ui.base.ActivityWindowAndroid;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java index 508ad95..9c41e57d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -58,7 +58,6 @@ import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.UnownedUserDataSupplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.ActivityUtils; import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.ChromeActivitySessionTracker; @@ -158,6 +157,7 @@ import org.chromium.chrome.browser.tab.TabSelectionType; import org.chromium.chrome.browser.tab.TabState; import org.chromium.chrome.browser.tab.TabUtils; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.EmptyTabModel; import org.chromium.chrome.browser.tabmodel.TabCreator; import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java index 163588f..9cc9d664 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
@@ -31,7 +31,6 @@ import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.banners.AppMenuVerbiage; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; @@ -50,6 +49,7 @@ import org.chromium.chrome.browser.share.ShareHelper; import org.chromium.chrome.browser.share.ShareUtils; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.tab_management.PriceTrackingUtilities; import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorder.java index 61e2e7f..ed4eef0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorder.java
@@ -6,7 +6,6 @@ import android.os.SystemClock; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browserservices.TrustedWebActivityUmaRecorder; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier.VerificationState; @@ -14,6 +13,7 @@ import org.chromium.chrome.browser.dependency_injection.ActivityScope; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import javax.inject.Inject;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java index 34b2991..327ffbfc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
@@ -16,7 +16,6 @@ import org.chromium.base.SysUtils; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.WebContentsFactory; import org.chromium.chrome.browser.content.ContentUtils; import org.chromium.chrome.browser.dependency_injection.ActivityScope; @@ -25,6 +24,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabCreator; import org.chromium.chrome.browser.ui.favicon.FaviconHelper; import org.chromium.chrome.browser.ui.favicon.FaviconUtils;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java index bcb78ede..dec3f67 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -8,7 +8,6 @@ import org.chromium.base.supplier.OneShotCallback; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.app.reengagement.ReengagementActivity; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; @@ -21,6 +20,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.reengagement.ReengagementNotificationController; import org.chromium.chrome.browser.share.ShareDelegate; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.ui.RootUiCoordinator; import org.chromium.components.feature_engagement.Tracker;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 1a8041da..98091fe 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -213,7 +213,6 @@ if (tab != null) { tab.setAddApi2TransitionToFutureNavigations(false); tab.setHideFutureNavigations(false); - tab.setShouldBlockNewNotificationRequests(false); } mConnection.notifyOpenInBrowser(mSession, webContents); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java index 4472227..d0bc5290 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -19,7 +19,6 @@ import org.chromium.base.ContextUtils; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.DefaultBrowserInfo; import org.chromium.chrome.browser.app.appmenu.AppMenuPropertiesDelegateImpl; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; @@ -29,6 +28,7 @@ import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; import org.chromium.chrome.browser.share.ShareHelper; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.toolbar.ToolbarManager; import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java index a939ebb..53dbb1d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -152,12 +152,6 @@ "androidx.browser.customtabs.extra.TRANSLATE_LANGUAGE"; /** - * Extra that, if set, results in blocking new notification requests while in CCT. - */ - public static final String EXTRA_BLOCK_NEW_NOTIFICATION_REQUESTS_IN_CCT = - "androidx.browser.customtabs.extra.BLOCK_NEW_NOTIFICATION_REQUESTS_IN_CCT"; - - /** * Extra that, if set, results in hiding omnibox suggestions for visits from cct. The value is * a boolean, and is only considered if the feature kSuggestVisitsWithPageTransitionFromApi2 is * enabled. @@ -839,16 +833,6 @@ } @Override - public boolean shouldBlockNewNotificationRequests() { - // Only 1p apps are allowed to hide visits. - String clientPackageName = - CustomTabsConnection.getInstance().getClientPackageNameForSession(getSession()); - if (!GSAState.isGsaPackageName(clientPackageName)) return false; - return IntentUtils.safeGetBooleanExtra( - mIntent, EXTRA_BLOCK_NEW_NOTIFICATION_REQUESTS_IN_CCT, false); - } - - @Override public boolean shouldShowOpenInChromeMenuItemInContextMenu() { // Only 1p apps are allowed to hide visits. String clientPackageName =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java index a7bbfd1..a1539e4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
@@ -201,10 +201,6 @@ if (provider.shouldHideCctVisits()) { tab.setHideFutureNavigations(true); } - - if (provider.shouldBlockNewNotificationRequests()) { - tab.setShouldBlockNewNotificationRequests(true); - } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java index 832082c2..1c9777f1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -19,7 +19,6 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.ServiceTabLauncher; import org.chromium.chrome.browser.WarmupManager; @@ -52,6 +51,7 @@ import org.chromium.chrome.browser.tab.TabCreationState; import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tab.TabObserver; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.AsyncTabParams; import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; import org.chromium.chrome.browser.tabmodel.TabModel;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabProvider.java index a29af1e..3ad642ec 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabProvider.java
@@ -10,10 +10,10 @@ import androidx.annotation.Nullable; import org.chromium.base.ObserverList; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.customtabs.CustomTabsConnection; import org.chromium.chrome.browser.dependency_injection.ActivityScope; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModel; import javax.inject.Inject;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabBrowserControlsVisibilityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabBrowserControlsVisibilityDelegate.java index a35497c..744e9fbd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabBrowserControlsVisibilityDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabBrowserControlsVisibilityDelegate.java
@@ -5,10 +5,10 @@ package org.chromium.chrome.browser.customtabs.features.toolbar; import org.chromium.cc.input.BrowserControlsState; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsVisibilityManager; import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate; import org.chromium.chrome.browser.dependency_injection.ActivityScope; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate; import javax.inject.Inject;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/ChromeActivityCommonsModule.java b/chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/ChromeActivityCommonsModule.java index 954909b..2bab76a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/ChromeActivityCommonsModule.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/ChromeActivityCommonsModule.java
@@ -17,7 +17,6 @@ import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.browser_controls.BrowserControlsSizer; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; @@ -30,6 +29,7 @@ import org.chromium.chrome.browser.init.ChromeActivityNativeDelegate; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.metrics.ActivityTabStartupMetricsTracker; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabCreator; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -80,7 +80,7 @@ private final ChromeActivityNativeDelegate mChromeActivityNativeDelegate; private final BrowserControlsStateProvider mBrowserControlsStateProvider; private final Supplier<Bundle> mSavedInstanceStateSupplier; - private final ObservableSupplier<Integer> mmAutofillUiBottomInsetSupplier; + private final ObservableSupplier<Integer> mAutofillUiBottomInsetSupplier; /** See {@link ModuleFactoryOverrides} */ public interface Factory { @@ -163,7 +163,7 @@ mChromeActivityNativeDelegate = chromeActivityNativeDelegate; mBrowserControlsStateProvider = browserControlsStateProvider; mSavedInstanceStateSupplier = savedInstanceStateSupplier; - mmAutofillUiBottomInsetSupplier = autofillUiBottomInsetSupplier; + mAutofillUiBottomInsetSupplier = autofillUiBottomInsetSupplier; } @Provides @@ -344,6 +344,6 @@ @Provides public ObservableSupplier<Integer> provideAutofillUiBottomInsetSupplier() { - return mmAutofillUiBottomInsetSupplier; + return mAutofillUiBottomInsetSupplier; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java index 527ad7f..34bcea7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java
@@ -12,7 +12,6 @@ import androidx.annotation.Nullable; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantFacade; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; @@ -21,6 +20,7 @@ import org.chromium.chrome.browser.flags.ActivityType; import org.chromium.chrome.browser.lifecycle.DestroyObserver; import org.chromium.chrome.browser.lifecycle.NativeInitObserver; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunStatus.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunStatus.java index 6ca453f..836bc16 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunStatus.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunStatus.java
@@ -4,8 +4,6 @@ package org.chromium.chrome.browser.firstrun; -import org.chromium.base.CommandLine; -import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; @@ -41,18 +39,14 @@ * includes ToS and Sign In pages if necessary. */ public static boolean getFirstRunFlowComplete() { - if (SharedPreferencesManager.getInstance().readBoolean( - ChromePreferenceKeys.FIRST_RUN_FLOW_COMPLETE, false)) { - return true; - } - return CommandLine.getInstance().hasSwitch( - ChromeSwitches.FORCE_FIRST_RUN_FLOW_COMPLETE_FOR_TESTING); + return SharedPreferencesManager.getInstance().readBoolean( + ChromePreferenceKeys.FIRST_RUN_FLOW_COMPLETE, false); } /** - * Sets the preference to skip the welcome page from the main First Run Experience. - * @param isSkip Whether the welcome page should be skpped - */ + * Sets the preference to skip the welcome page from the main First Run Experience. + * @param isSkip Whether the welcome page should be skipped. + */ public static void setSkipWelcomePage(boolean isSkip) { SharedPreferencesManager.getInstance().writeBoolean( ChromePreferenceKeys.FIRST_RUN_SKIP_WELCOME_PAGE, isSkip);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java index 88378a4..7dc5214c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java
@@ -24,8 +24,6 @@ import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.task.PostTask; import org.chromium.cc.input.BrowserControlsState; -import org.chromium.chrome.browser.ActivityTabProvider; -import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.ActivityUtils; import org.chromium.chrome.browser.browser_controls.BrowserControlsSizer; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; @@ -35,6 +33,8 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper; import org.chromium.chrome.browser.tab.TabBrowserControlsOffsetHelper; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; import org.chromium.chrome.browser.tabmodel.TabSwitchMetrics;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java index 7e1cb26..e9098d55 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenHtmlApiHandler.java
@@ -29,8 +29,6 @@ import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.cc.input.BrowserControlsState; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; -import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabAttributeKeys; @@ -38,6 +36,8 @@ import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper; import org.chromium.chrome.browser.tab.TabHidingType; import org.chromium.chrome.browser.tab.TabUtils; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; import org.chromium.chrome.browser.vr.VrModuleProvider;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureController.java index 16190d5..2698daa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureController.java
@@ -23,11 +23,11 @@ import org.chromium.base.annotations.VerifiesOnO; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordHistogram; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.infobar.InfoBarContainer; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.base.WindowAndroid;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/messages/ChromeMessageQueueMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/messages/ChromeMessageQueueMediator.java index f37e9a70..d7d7cd1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/messages/ChromeMessageQueueMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/messages/ChromeMessageQueueMediator.java
@@ -9,7 +9,6 @@ import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.cc.input.BrowserControlsState; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils; import org.chromium.chrome.browser.fullscreen.BrowserControlsManager; @@ -21,6 +20,7 @@ import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.messages.ManagedMessageDispatcher; import org.chromium.components.messages.MessageQueueDelegate; import org.chromium.ui.modaldialog.ModalDialogManager;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java index 776d7492..9467e32 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
@@ -463,10 +463,12 @@ // The component should only be destroyed when the activity has been closed by the user // (e.g. by pressing on the back button) and not when the activity is temporarily destroyed // by the system. - if (getActivity().isFinishing() && mPasswordCheck != null - && mManagePasswordsReferrer != ManagePasswordsReferrer.CHROME_SETTINGS) { + if (getActivity().isFinishing()) { PasswordManagerHandlerProvider.getInstance().removeObserver(this); - PasswordCheckFactory.destroy(); + if (mPasswordCheck != null + && mManagePasswordsReferrer != ManagePasswordsReferrer.CHROME_SETTINGS) { + PasswordCheckFactory.destroy(); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareButtonController.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareButtonController.java index 48d3357..020e056 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareButtonController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareButtonController.java
@@ -14,12 +14,12 @@ import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver; import org.chromium.chrome.browser.share.ShareDelegate.ShareOrigin; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.toolbar.ButtonData; import org.chromium.chrome.browser.toolbar.ButtonDataImpl; import org.chromium.chrome.browser.toolbar.ButtonDataProvider;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java index 076001c..fd8a8b3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java
@@ -42,7 +42,8 @@ private SyncConsentActivityLauncherImpl() {} /** - * Launches the SigninActivity with default sign-in flow from personalized sign-in promo. + * Launches the {@link SyncConsentActivity} with default sign-in flow from personalized sign-in + * promo. * @param accessPoint {@link SigninAccessPoint} for starting sign-in flow. * @param accountName The account to preselect or null to preselect the default account. */ @@ -54,7 +55,7 @@ } /** - * Launches the SigninActivity with "Choose account" sign-in flow from personalized + * Launches the {@link SyncConsentActivity} with "Choose account" sign-in flow from personalized * sign-in promo. * @param accessPoint {@link SigninAccessPoint} for starting sign-in flow. * @param accountName The account to preselect or null to preselect the default account. @@ -68,8 +69,8 @@ } /** - * Launches the SigninActivity with "New account" sign-in flow from personalized sign-in - * promo. + * Launches the {@link SyncConsentActivity} with "New account" sign-in flow from personalized + * sign-in promo. * @param accessPoint {@link SigninAccessPoint} for starting sign-in flow. */ @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/AccessibilityVisibilityHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/AccessibilityVisibilityHandler.java index 93b5539..23a946a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/AccessibilityVisibilityHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/AccessibilityVisibilityHandler.java
@@ -4,9 +4,9 @@ package org.chromium.chrome.browser.tab; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.DestroyObserver; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.ui.TabObscuringHandler; /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/AutofillSessionLifetimeController.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/AutofillSessionLifetimeController.java index 5610ab2..f66ca82 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/AutofillSessionLifetimeController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/AutofillSessionLifetimeController.java
@@ -9,9 +9,9 @@ import android.os.Build; import org.chromium.base.compat.ApiHelperForO; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.DestroyObserver; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.content_public.browser.NavigationHandle; /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS index 9625f4ac..2917a29 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -36,6 +36,7 @@ "+chrome/browser/flags", "+chrome/browser/preferences", "+chrome/browser/tab", + "+chrome/browser/tab_provider", "+chrome/browser/ui/android/native_page", "+chrome/browser/version", "+components/browser_ui/styles/android",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java index 97ccb744..5473b89 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -1237,19 +1237,6 @@ return mPendingLoadParams; } - @Override - public void setShouldBlockNewNotificationRequests(boolean value) { - if (mNativeTabAndroid != 0) { - TabImplJni.get().setShouldBlockNewNotificationRequests(mNativeTabAndroid, value); - } - } - - @Override - public boolean getShouldBlockNewNotificationRequests() { - return mNativeTabAndroid != 0 - && TabImplJni.get().getShouldBlockNewNotificationRequests(mNativeTabAndroid); - } - /** * Performs any subclass-specific tasks when the Tab crashes. */ @@ -1725,8 +1712,6 @@ boolean getAddApi2TransitionToFutureNavigations(long nativeTabAndroid); void setHideFutureNavigations(long nativeTabAndroid, boolean hide); boolean getHideFutureNavigations(long nativeTabAndroid); - void setShouldBlockNewNotificationRequests(long nativeTabAndroid, boolean value); - boolean getShouldBlockNewNotificationRequests(long nativeTabAndroid); boolean handleNonNavigationAboutURL(GURL url); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java index f7a8e99..5d8724a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
@@ -10,7 +10,6 @@ import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.app.appmenu.AppMenuPropertiesDelegateImpl; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; @@ -24,6 +23,7 @@ import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.toolbar.ToolbarManager; import org.chromium.chrome.browser.ui.appmenu.AppMenuDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java index 3af9801..34d5ee14 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -20,8 +20,6 @@ import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; -import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.SwipeRefreshHandler; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.banners.AppBannerInProductHelpController; @@ -72,6 +70,8 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabAssociatedApp; import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities; import org.chromium.chrome.browser.toolbar.ToolbarButtonInProductHelpController;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java index 5b11436..2823b38 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -338,9 +338,11 @@ public Tab launchUrlFromExternalApp(String url, String referer, String headers, String appId, boolean forceNewTab, Intent intent, long intentTimestamp) { assert !mIncognito; + // Don't re-use tabs for intents from Chrome. Note that this can be spoofed so shouldn't be + // relied on for anything security sensitive. boolean isLaunchedFromChrome = TextUtils.equals(appId, mActivity.getPackageName()); - if (forceNewTab && !isLaunchedFromChrome) { + if (forceNewTab || isLaunchedFromChrome) { // We don't associate the tab with that app ID, as it is assumed that if the // application wanted to open this tab as a new tab, it probably does not want it // reused either. @@ -370,7 +372,14 @@ } } loadUrlParams.setVerbatimHeaders(headers); - return createNewTab(loadUrlParams, TabLaunchType.FROM_EXTERNAL_APP, null, intent); + + // Using FROM_LINK ensures the tab is parented to the current tab, which allows + // the back button to close these tabs and restore selection to the previous + // tab. + @TabLaunchType + int launchType = isLaunchedFromChrome ? TabLaunchType.FROM_LINK + : TabLaunchType.FROM_EXTERNAL_APP; + return createNewTab(loadUrlParams, launchType, null, intent); } if (appId == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java index 584e34d..2f06613 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java
@@ -18,7 +18,6 @@ import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.flags.CachedFeatureFlags; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -29,6 +28,7 @@ import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS index d057fe00..ac728bc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS
@@ -9,6 +9,7 @@ "+components/browser_ui/widget/android/java", "+ui/android/java/src/org/chromium/ui", "+url/android", + "+chrome/browser/tab_provider/android/java", "+chrome/browser/tabmodel/android/java", "+chrome/browser/ui/messages/android/java", "+components/browser_ui/bottomsheet/android/java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index ff4b271..35a62591 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -37,7 +37,6 @@ import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton; import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantPreferenceFragment; @@ -91,6 +90,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tab.TabSelectionType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; import org.chromium.chrome.browser.tabmodel.TabModel; @@ -811,7 +811,7 @@ mLayoutStateObserver = new LayoutStateProvider.LayoutStateObserver() { @Override public void onStartedShowing(@LayoutType int layoutType, boolean showToolbar) { - updateForLayout(layoutType, showToolbar, false); + updateForLayout(layoutType, showToolbar); } @Override @@ -834,11 +834,6 @@ updateButtonStatus(); } } - - @Override - public void onFinishedShowing(@LayoutType int layoutType) { - maybeFocusOmnibox(layoutType, mActivityTabProvider.get()); - } }; mOverlayPanelManagerObserver = new OverlayPanelManagerObserver() { @@ -888,10 +883,8 @@ * Handle a layout change event. * @param layoutType The layout being switched to. * @param showToolbar Whether the toolbar should be shown. - * @param shouldFocusOmnibox Whether we should attempt to focus the omnibox. */ - private void updateForLayout( - @LayoutType int layoutType, boolean showToolbar, boolean shouldFocusOmnibox) { + private void updateForLayout(@LayoutType int layoutType, boolean showToolbar) { if (layoutType == LayoutType.TAB_SWITCHER) { mLocationBarModel.setIsShowingTabSwitcher(true); mToolbar.setTabSwitcherMode(true, showToolbar, false); @@ -903,7 +896,7 @@ } mToolbar.setContentAttached(layoutType == LayoutType.BROWSING); - if (shouldFocusOmnibox) maybeFocusOmnibox(layoutType, mActivityTabProvider.get()); + maybeFocusOmnibox(layoutType, mActivityTabProvider.get()); } /** @@ -1783,7 +1776,7 @@ // dependencies are ready. This logic was introduced to move asynchronous // observer events from the infra (LayoutManager) into the feature using // it. - mControlContainer.post(() -> updateForLayout(LayoutType.TAB_SWITCHER, true, true)); + mControlContainer.post(() -> updateForLayout(LayoutType.TAB_SWITCHER, true)); } mAppThemeColorProvider.setLayoutStateProvider(mLayoutStateProvider);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/BottomSheetManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/BottomSheetManager.java index 1e9ea6e..7182169d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/BottomSheetManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/BottomSheetManager.java
@@ -11,7 +11,6 @@ import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsVisibilityManager; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager; @@ -19,6 +18,7 @@ import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserver; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; import org.chromium.chrome.browser.vr.VrModuleProvider;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index 8222613..a5a6d927 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -30,7 +30,6 @@ import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.UnownedUserDataSupplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.ChromeActionModeHandler; import org.chromium.chrome.browser.ChromePowerModeVoter; import org.chromium.chrome.browser.app.ChromeActivity; @@ -73,6 +72,7 @@ import org.chromium.chrome.browser.tab.AutofillSessionLifetimeController; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.theme.TopUiThemeColorProvider; import org.chromium.chrome.browser.toolbar.ButtonDataProvider;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java index 210c7d8e..66de650a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
@@ -17,7 +17,6 @@ import org.chromium.base.CallbackController; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -26,6 +25,7 @@ import org.chromium.chrome.browser.status_indicator.StatusIndicatorCoordinator; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabSelectionType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java index c76016e..b809860 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
@@ -17,7 +17,6 @@ import org.chromium.base.Log; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.NativeMethods; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.intents.WebApkExtras; import org.chromium.chrome.browser.browserservices.intents.WebApkShareTarget; @@ -30,6 +29,7 @@ import org.chromium.chrome.browser.metrics.WebApkUma; import org.chromium.chrome.browser.metrics.WebApkUma.UpdateRequestQueued; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory; import org.chromium.components.background_task_scheduler.TaskIds; import org.chromium.components.background_task_scheduler.TaskInfo;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java index bb9ec2b..5009f2e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java
@@ -7,8 +7,6 @@ import androidx.annotation.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; -import org.chromium.chrome.browser.ActivityTabProvider; -import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier.VerificationState; @@ -16,6 +14,8 @@ import org.chromium.chrome.browser.metrics.WebApkUma; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.state.CriticalPersistedTabData; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.content_public.browser.NavigationHandle; /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivityCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivityCoordinator.java index 46f6893..424d2d6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivityCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivityCoordinator.java
@@ -9,7 +9,6 @@ import androidx.annotation.NonNull; import org.chromium.base.StrictModeContext; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.ui.SharedActivityCoordinator; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier; @@ -20,6 +19,7 @@ import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver; import org.chromium.chrome.browser.lifecycle.StartStopWithNativeObserver; import org.chromium.chrome.browser.metrics.LaunchMetrics; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.util.AndroidTaskUtils; import javax.inject.Inject;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ActivityTabProviderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ActivityTabProviderTest.java index 2fb8a2a..3b1747c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ActivityTabProviderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ActivityTabProviderTest.java
@@ -19,12 +19,13 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; -import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.layouts.LayoutTestUtils; import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabSelectionType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider.ActivityTabTabObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java index 089eb47c..6edd4e5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java
@@ -34,6 +34,7 @@ import org.chromium.chrome.browser.share.ShareDelegateImpl; import org.chromium.chrome.browser.share.ShareHelper; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.ui.RootUiCoordinator; import org.chromium.chrome.browser.util.ChromeFileProvider;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java index 549a670..fdf1dad 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java
@@ -34,7 +34,7 @@ * mode. */ @RunWith(ChromeJUnit4ClassRunner.class) -@CommandLineFlags.Add({ChromeSwitches.FORCE_FIRST_RUN_FLOW_COMPLETE_FOR_TESTING}) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class CustomTabActivityIncognitoMetricTest { private static final String UMA_KEY = "CustomTabs.IncognitoCCTCallerId"; private static final String FIRST_PARTY_UMA_KEY = "CustomTabs.ClientAppId.Incognito";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java index 179f9d6..77dcb15 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
@@ -59,6 +59,7 @@ import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils.OnFinishedForTest; import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar; +import org.chromium.chrome.browser.firstrun.FirstRunStatus; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.incognito.IncognitoDataTestUtils; @@ -79,7 +80,7 @@ * in the first place. Screenshot of the Custom tab menu item is broken. */ @RunWith(ChromeJUnit4ClassRunner.class) -@CommandLineFlags.Add({ChromeSwitches.FORCE_FIRST_RUN_FLOW_COMPLETE_FOR_TESTING}) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class CustomTabActivityIncognitoTest { private static final String TEST_PAGE = "/chrome/test/data/android/google.html"; private static final String TEST_MENU_TITLE = "testMenuTitle"; @@ -99,6 +100,7 @@ @Before public void setUp() throws TimeoutException { + FirstRunStatus.setFirstRunFlowComplete(true); mTestPage = mEmbeddedTestServerRule.getServer().getURL(TEST_PAGE); // Ensuring native is initialized before we access the CCT_INCOGNITO feature flag. IncognitoDataTestUtils.fireAndWaitForCctWarmup(); @@ -160,11 +162,11 @@ Menu menu = mCustomTabActivityTestRule.getMenu(); MenuItem iconRow = menu.findItem(R.id.icon_row_menu_id); - assertEquals(4, CustomTabsTestUtils.getVisibleMenuSize(iconRow.getSubMenu())); assertTrue(iconRow.getSubMenu().findItem(R.id.forward_menu_id).isVisible()); assertTrue(iconRow.getSubMenu().findItem(R.id.reload_menu_id).isVisible()); assertTrue(iconRow.getSubMenu().findItem(R.id.bookmark_this_page_id).isVisible()); assertTrue(iconRow.getSubMenu().findItem(R.id.info_menu_id).isVisible()); + assertEquals(4, CustomTabsTestUtils.getVisibleMenuSize(iconRow.getSubMenu())); } private CustomTabActivity launchIncognitoCustomTab(Intent intent) throws InterruptedException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 2d40584a..1cb7d21 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -1988,41 +1988,6 @@ @Test @SmallTest - public void testShouldBlockNewNotificationRequestsDefaultsToFalse() throws Exception { - Context context = InstrumentationRegistry.getInstrumentation() - .getTargetContext() - .getApplicationContext(); - Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage); - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - Assert.assertFalse(mCustomTabActivityTestRule.getActivity() - .getActivityTab() - .getShouldBlockNewNotificationRequests()); - } - - @Test - @SmallTest - public void testShouldBlockNewNotificationRequests() throws Exception { - Context context = InstrumentationRegistry.getInstrumentation() - .getTargetContext() - .getApplicationContext(); - Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage); - intent.setData(Uri.parse(mTestPage)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra( - CustomTabIntentDataProvider.EXTRA_BLOCK_NEW_NOTIFICATION_REQUESTS_IN_CCT, true); - CustomTabsSessionToken token = CustomTabsSessionToken.getSessionTokenFromIntent(intent); - CustomTabsConnection connection = CustomTabsConnection.getInstance(); - connection.newSession(token); - connection.overridePackageNameForSessionForTesting( - token, "com.google.android.googlequicksearchbox"); - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); - Assert.assertTrue(mCustomTabActivityTestRule.getActivity() - .getActivityTab() - .getShouldBlockNewNotificationRequests()); - } - - @Test - @SmallTest public void testHideOpenInChromeMenuItemInContextMenu() throws Exception { Context context = InstrumentationRegistry.getInstrumentation() .getTargetContext()
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java index 717c3e3..9365f3f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java
@@ -73,7 +73,7 @@ import java.io.IOException; /** - * Render tests for signin fragment. + * Render tests for sync consent fragment. */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @@ -134,7 +134,7 @@ @After public void tearDown() throws Exception { - // Since SigninActivity is launched inside this test class, we need to + // Since {@link SyncConsentActivity} is launched inside this test class, we need to // tear it down inside the class as well. if (mSyncConsentActivity != null) { ApplicationTestUtils.finishActivity(mSyncConsentActivity);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java index faab649..b3c61e4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -18,7 +18,6 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.intents.WebApkDistributor; @@ -28,6 +27,7 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.util.browser.webapps.WebappTestPage;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java index 4bb7401..6448f3a 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
@@ -36,7 +36,6 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.app.appmenu.AppMenuPropertiesDelegateImpl.MenuGroup; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; @@ -47,6 +46,7 @@ import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelFilter; import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorderTest.java index d0261ab..73fa60f9 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorderTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorderTest.java
@@ -23,12 +23,12 @@ import org.robolectric.annotation.Config; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browserservices.TrustedWebActivityUmaRecorder; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier.VerificationState; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier.VerificationStatus; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import java.util.concurrent.TimeUnit;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/CompositorViewHolderUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/CompositorViewHolderUnitTest.java index a1813e1..c4751e8 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/CompositorViewHolderUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/CompositorViewHolderUnitTest.java
@@ -34,10 +34,10 @@ import org.chromium.base.ApplicationStatus; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils; import org.chromium.chrome.browser.fullscreen.BrowserControlsManager; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; import org.chromium.chrome.browser.toolbar.ControlContainer;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java similarity index 88% rename from chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java rename to chrome/android/junit/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java index 1468857..e14575d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java
@@ -5,8 +5,8 @@ package org.chromium.chrome.browser.customtabs; import android.content.Context; -import android.support.test.InstrumentationRegistry; +import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import org.junit.After; @@ -14,15 +14,15 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; -import org.chromium.base.test.UiThreadTest; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.base.test.BaseRobolectricTestRunner; -/** Tests for RequestThrottler. - * - * Note: tests are @UiThreadTest because RequestThrottler is not thread-safe. +/** + * Tests for RequestThrottler. */ -@RunWith(ChromeJUnit4ClassRunner.class) +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) public class RequestThrottlerTest { private static final int UID = 1234; private static final int UID2 = 12345; @@ -33,7 +33,7 @@ @Before public void setUp() { - mContext = InstrumentationRegistry.getTargetContext(); + mContext = ApplicationProvider.getApplicationContext(); RequestThrottler.purgeAllEntriesForTesting(); } @@ -45,7 +45,6 @@ /** Tests that a client starts not banned. */ @Test @SmallTest - @UiThreadTest public void testIsInitiallyNotBanned() { Assert.assertTrue(RequestThrottler.getForUid(UID).isPrerenderingAllowed()); } @@ -53,7 +52,6 @@ /** Tests that a misbehaving client gets banned. */ @Test @SmallTest - @UiThreadTest public void testBansUid() { RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); @@ -64,7 +62,6 @@ /** Tests that the URL needs to match to avoid getting banned. */ @Test @SmallTest - @UiThreadTest public void testBanningMatchesUrls() { RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); @@ -79,7 +76,6 @@ /** Tests that a client can send a lot of requests, as long as they are matched by successes. */ @Test @SmallTest - @UiThreadTest public void testDontBanAccurateClients() { RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); @@ -93,7 +89,6 @@ /** Tests that partially accurate clients are not banned. */ @Test @SmallTest - @UiThreadTest public void testDontBanPartiallyAccurateClients() { RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed()); @@ -109,7 +104,6 @@ /** Tests that banning a UID doesn't ban another one. */ @Test @SmallTest - @UiThreadTest public void testThrottlingBanIsByUid() { RequestThrottler throttler = RequestThrottler.getForUid(UID); Assert.assertTrue(throttler.isPrerenderingAllowed());
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java index 20847938..354e5ec 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
@@ -26,7 +26,6 @@ import org.chromium.base.Callback; import org.chromium.base.UserDataHost; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.WarmupManager; import org.chromium.chrome.browser.WebContentsFactory; @@ -51,6 +50,7 @@ import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabImpl; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.AsyncTabCreationParams; import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManagerFactory;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java index f167998..ab1474d0 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManagerUnitTest.java
@@ -36,9 +36,9 @@ import org.chromium.base.UserDataHost; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.toolbar.ControlContainer; import org.chromium.chrome.test.util.browser.Features;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/messages/ChromeMessageQueueMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/messages/ChromeMessageQueueMediatorTest.java index 412ab9e..4a916e696 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/messages/ChromeMessageQueueMediatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/messages/ChromeMessageQueueMediatorTest.java
@@ -19,12 +19,12 @@ import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.fullscreen.BrowserControlsManager; import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.layouts.LayoutStateProvider.LayoutStateObserver; import org.chromium.chrome.browser.layouts.LayoutType; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.components.messages.ManagedMessageDispatcher; import org.chromium.ui.modaldialog.ModalDialogManager;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java index b6355ce..cce6601 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
@@ -37,7 +37,6 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; import org.chromium.chrome.browser.enterprise.util.ManagedBrowserUtils; @@ -53,6 +52,7 @@ import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; import org.chromium.chrome.browser.signin.services.SigninManager; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelFilter; import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialogTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialogTest.java similarity index 80% rename from chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialogTest.java rename to chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialogTest.java index 946b0ec1..6c6d18d9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialogTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialogTest.java
@@ -9,26 +9,26 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; -import android.os.Looper; import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.test.core.app.ActivityScenario; import androidx.test.filters.SmallTest; +import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; -import org.chromium.base.test.BaseJUnit4ClassRunner; +import org.chromium.base.CommandLine; +import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.CallbackHelper; -import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; -import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogProperties; @@ -36,17 +36,15 @@ /** * Test for the dialog warning that WebApks have an updated name/icon. */ -// TODO(crbug/1209230): Investigate converting this to Roboelectric test. -@RunWith(BaseJUnit4ClassRunner.class) -@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) public class WebApkIconNameUpdateDialogTest { // A callback that fires when an action is taken in a dialog. public final CallbackHelper mOnActionCallback = new CallbackHelper(); private Integer mLastDismissalCause; - @Rule - public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + private ActivityScenario<ChromeTabbedActivity> mActivityScenario; static class DialogParams { public static DialogParams createDefault() { @@ -80,14 +78,22 @@ @Before public void setUp() { - Looper.prepare(); - mActivityTestRule.startMainActivityOnBlankPage(); + // Command line switches required to use ActivityScenario<ChromeTabbedActivity>. + CommandLine.getInstance().appendSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE); + CommandLine.getInstance().appendSwitch(ChromeSwitches.DISABLE_NATIVE_INITIALIZATION); + + mActivityScenario = ActivityScenario.launch(ChromeTabbedActivity.class); + } + + @After + public void tearDown() { + mActivityScenario.close(); } /** * Generates a 320x320 test single-colored bitmap. */ - private Bitmap generateTestBitmap(int color) { + private static Bitmap generateTestBitmap(int color) { int width = 320; int height = 320; Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); @@ -100,29 +106,22 @@ return bitmap; } - private View getDialogCustomView() { - return mActivityTestRule.getActivity() - .getModalDialogManager() - .getCurrentDialogForTest() - .get(ModalDialogProperties.CUSTOM_VIEW); + private static View getDialogCustomView(ModalDialogManager dialogManager) { + return dialogManager.getCurrentDialogForTest().get(ModalDialogProperties.CUSTOM_VIEW); } - private String getDialogTitle() { - return mActivityTestRule.getActivity() - .getModalDialogManager() - .getCurrentDialogForTest() - .get(ModalDialogProperties.TITLE) - .toString(); + private static String getDialogTitle(ModalDialogManager dialogManager) { + return dialogManager.getCurrentDialogForTest().get(ModalDialogProperties.TITLE).toString(); } - private Bitmap getUpdateDialogBitmap(int resId) { - ImageView imageView = getDialogCustomView().findViewById(resId); + private static Bitmap getUpdateDialogBitmap(ModalDialogManager dialogManager, int resId) { + ImageView imageView = getDialogCustomView(dialogManager).findViewById(resId); if (imageView.getVisibility() != View.VISIBLE) return null; return ((BitmapDrawable) imageView.getDrawable()).getBitmap(); } - private String getUpdateDialogAppNameLabel(int resId) { - TextView textView = getDialogCustomView().findViewById(resId); + private static String getUpdateDialogAppNameLabel(ModalDialogManager dialogManager, int resId) { + TextView textView = getDialogCustomView(dialogManager).findViewById(resId); if (textView.getVisibility() != View.VISIBLE) return null; return textView.getText().toString(); @@ -137,11 +136,10 @@ mOnActionCallback.notifyCalled(); } - public void verifyValues(boolean clickAccept, DialogParams dialogParams) throws Exception { - TestThreadUtils.runOnUiThreadBlocking(() -> { + public void verifyValues(boolean clickAccept, DialogParams dialogParams) { + mActivityScenario.onActivity(activity -> { int callCount = mOnActionCallback.getCallCount(); - ModalDialogManager modalDialogManager = - mActivityTestRule.getActivity().getModalDialogManager(); + ModalDialogManager modalDialogManager = activity.getModalDialogManager(); WebApkIconNameUpdateDialog dialog = new WebApkIconNameUpdateDialog(); @@ -155,24 +153,24 @@ dialogParams.shortNameChanged || dialogParams.expectShortNameShownAnyway ? dialogParams.shortNameBefore : null, - getUpdateDialogAppNameLabel(R.id.short_app_name_old)); + getUpdateDialogAppNameLabel(modalDialogManager, R.id.short_app_name_old)); Assert.assertEquals( dialogParams.shortNameChanged || dialogParams.expectShortNameShownAnyway ? dialogParams.shortNameAfter : null, - getUpdateDialogAppNameLabel(R.id.short_app_name_new)); + getUpdateDialogAppNameLabel(modalDialogManager, R.id.short_app_name_new)); Assert.assertEquals(dialogParams.nameChanged ? dialogParams.nameBefore : null, - getUpdateDialogAppNameLabel(R.id.app_name_old)); + getUpdateDialogAppNameLabel(modalDialogManager, R.id.app_name_old)); Assert.assertEquals(dialogParams.nameChanged ? dialogParams.nameAfter : null, - getUpdateDialogAppNameLabel(R.id.app_name_new)); + getUpdateDialogAppNameLabel(modalDialogManager, R.id.app_name_new)); Assert.assertEquals(dialogParams.iconChanged || dialogParams.expectIconShownAnyway ? dialogParams.bitmapBefore : null, - getUpdateDialogBitmap(R.id.app_icon_old)); + getUpdateDialogBitmap(modalDialogManager, R.id.app_icon_old)); Assert.assertEquals(dialogParams.iconChanged || dialogParams.expectIconShownAnyway ? dialogParams.bitmapAfter : null, - getUpdateDialogBitmap(R.id.app_icon_new)); + getUpdateDialogBitmap(modalDialogManager, R.id.app_icon_new)); modalDialogManager.getCurrentPresenterForTest().dismissCurrentDialog(clickAccept ? DialogDismissalCause.POSITIVE_BUTTON_CLICKED @@ -187,17 +185,16 @@ public void verifyReportAbuseValues( boolean clickAccept, String shortAppName, String expectedTitle) throws Exception { - TestThreadUtils.runOnUiThreadBlocking(() -> { + mActivityScenario.onActivity(activity -> { int callCount = mOnActionCallback.getCallCount(); - ModalDialogManager modalDialogManager = - mActivityTestRule.getActivity().getModalDialogManager(); + ModalDialogManager modalDialogManager = activity.getModalDialogManager(); WebApkUpdateReportAbuseDialog dialog = new WebApkUpdateReportAbuseDialog(modalDialogManager, /* packageName= */ "", shortAppName, this::onAbuseDialogResult); dialog.show(); - Assert.assertEquals(expectedTitle, getDialogTitle()); + Assert.assertEquals(expectedTitle, getDialogTitle(modalDialogManager)); modalDialogManager.getCurrentPresenterForTest().dismissCurrentDialog(clickAccept ? DialogDismissalCause.POSITIVE_BUTTON_CLICKED
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java index 28ded53..7a95822 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
@@ -40,7 +40,6 @@ import org.chromium.base.task.PostTask; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.background_task_scheduler.ChromeBackgroundTaskFactory; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; @@ -51,6 +50,7 @@ import org.chromium.chrome.browser.browserservices.intents.WebappIcon; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab_provider.ActivityTabProvider; import org.chromium.components.embedder_support.util.ShadowUrlUtilities; import org.chromium.components.webapk.lib.common.WebApkMetaDataKeys; import org.chromium.device.mojom.ScreenOrientationLockType;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index d0a06c3..1181830 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1035,6 +1035,14 @@ Please retry. If you see this error again please contact your support representative. </message> + <!-- Strings for OS install --> + <message name="IDS_OS_INSTALL_SCREEN_ERROR_TITLE" desc="Title of the error page of the OS install screen"> + Installation failed + </message> + <message name="IDS_OS_INSTALL_SCREEN_SUCCESS_TITLE" desc="Title of the success page of the OS install screen"> + Installation complete + </message> + <!-- Strings for parental handoff login screen --> <message name="IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_TITLE" desc="Title of screen which tells user that the parent can handoff the device to supervised user."> Now it's <ph name="SUPERVISED_USER_NAME">$1<ex>Child 1</ex></ph>'s turn
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OS_INSTALL_SCREEN_ERROR_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OS_INSTALL_SCREEN_ERROR_TITLE.png.sha1 new file mode 100644 index 0000000..9b289339 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_OS_INSTALL_SCREEN_ERROR_TITLE.png.sha1
@@ -0,0 +1 @@ +cb79cc5fa1763ef942be3c93d6e648e207473530 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OS_INSTALL_SCREEN_SUCCESS_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OS_INSTALL_SCREEN_SUCCESS_TITLE.png.sha1 new file mode 100644 index 0000000..cc8300f --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_OS_INSTALL_SCREEN_SUCCESS_TITLE.png.sha1
@@ -0,0 +1 @@ +4ce9c774b83811ac8c3c4d7ae0418b923bba7b2b \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 3b831c777..519eba1 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1457,8 +1457,6 @@ "reputation/safety_tip_ui.h", "reputation/safety_tip_ui_helper.cc", "reputation/safety_tip_ui_helper.h", - "reputation/url_elision_policy.cc", - "reputation/url_elision_policy.h", "resource_coordinator/resource_coordinator_parts.cc", "resource_coordinator/resource_coordinator_parts.h", "resource_coordinator/session_restore_policy.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 20d44cf..460b876 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4402,28 +4402,6 @@ kOmniboxDefaultTypedNavigationsToHttpsVariations, "OmniboxDefaultTypedNavigationsToHttps")}, - {"omnibox-ui-sometimes-elide-to-registrable-domain", - flag_descriptions::kOmniboxUIMaybeElideToRegistrableDomainName, - flag_descriptions::kOmniboxUIMaybeElideToRegistrableDomainDescription, - kOsDesktop, FEATURE_VALUE_TYPE(omnibox::kMaybeElideToRegistrableDomain)}, - - {"omnibox-ui-reveal-steady-state-url-path-query-and-ref-on-hover", - flag_descriptions:: - kOmniboxUIRevealSteadyStateUrlPathQueryAndRefOnHoverName, - flag_descriptions:: - kOmniboxUIRevealSteadyStateUrlPathQueryAndRefOnHoverDescription, - kOsDesktop, - FEATURE_VALUE_TYPE(omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover)}, - - {"omnibox-ui-hide-steady-state-url-path-query-and-ref-on-interaction", - flag_descriptions:: - kOmniboxUIHideSteadyStateUrlPathQueryAndRefOnInteractionName, - flag_descriptions:: - kOmniboxUIHideSteadyStateUrlPathQueryAndRefOnInteractionDescription, - kOsDesktop, - FEATURE_VALUE_TYPE( - omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction)}, - {"omnibox-max-zero-suggest-matches", flag_descriptions::kOmniboxMaxZeroSuggestMatchesName, flag_descriptions::kOmniboxMaxZeroSuggestMatchesDescription,
diff --git a/chrome/browser/android/autofill_assistant/interaction_handler_android.h b/chrome/browser/android/autofill_assistant/interaction_handler_android.h index 47d6f835..40937f1 100644 --- a/chrome/browser/android/autofill_assistant/interaction_handler_android.h +++ b/chrome/browser/android/autofill_assistant/interaction_handler_android.h
@@ -14,7 +14,6 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "components/autofill_assistant/browser/event_handler.h" #include "components/autofill_assistant/browser/service.pb.h"
diff --git a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java index ba88b587..f66441852 100644 --- a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java +++ b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
@@ -464,13 +464,6 @@ } /** - * Returns true if new notification requests from cct should be blocked. - */ - public boolean shouldBlockNewNotificationRequests() { - return false; - } - - /** * Returns true if 'open in chrome' should be shown in the tab context menu. */ public boolean shouldShowOpenInChromeMenuItemInContextMenu() {
diff --git a/chrome/browser/android/compositor/scene_layer/continuous_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/continuous_search_scene_layer.cc index d363c890..4529683 100644 --- a/chrome/browser/android/compositor/scene_layer/continuous_search_scene_layer.cc +++ b/chrome/browser/android/compositor/scene_layer/continuous_search_scene_layer.cc
@@ -33,7 +33,9 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& jresource_manager, jint view_resource_id, - jint y_offset) { + jint y_offset, + jboolean shadow_visible, + jint shadow_height) { ui::ResourceManager* resource_manager = ui::ResourceManagerImpl::FromJavaObject(jresource_manager); ui::Resource* resource = resource_manager->GetResource( @@ -45,7 +47,14 @@ view_layer_->SetUIResourceId(resource->ui_resource()->id()); - view_container_->SetBounds(resource->size()); + int container_height = resource->size().height(); + + if (!shadow_visible) { + container_height -= shadow_height; + } + + view_container_->SetBounds( + gfx::Size(resource->size().width(), container_height)); view_container_->SetPosition(gfx::PointF(0, y_offset)); // The view's layer should be the same size as the texture.
diff --git a/chrome/browser/android/compositor/scene_layer/continuous_search_scene_layer.h b/chrome/browser/android/compositor/scene_layer/continuous_search_scene_layer.h index 3a1f3b2..5d7409f 100644 --- a/chrome/browser/android/compositor/scene_layer/continuous_search_scene_layer.h +++ b/chrome/browser/android/compositor/scene_layer/continuous_search_scene_layer.h
@@ -30,7 +30,9 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& jresource_manager, jint view_resource_id, - jint y_offset); + jint y_offset, + jboolean shadow_visible, + jint shadow_height); void SetContentTree( JNIEnv* env,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc index 4f83f78..241b7be 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/flags/android/chrome_feature_list.h" #include "chrome/common/chrome_switches.h" #include "components/search_engines/template_url_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/base/escape.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" @@ -297,6 +298,8 @@ base::test::SingleThreadTaskEnvironment task_environment_{ base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<TemplateURLService> template_url_service_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_url_loader_factory_;
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc index e2a60e6..5275857 100644 --- a/chrome/browser/android/tab_android.cc +++ b/chrome/browser/android/tab_android.cc
@@ -284,7 +284,6 @@ AttachTabHelpers(web_contents_.get()); PropagateHideFutureNavigationsToHistoryTabHelper(); - PropagateBlockNewNotificationRequestsToWebContents(); SetWindowSessionID(session_window_id_); @@ -422,15 +421,6 @@ PropagateHideFutureNavigationsToHistoryTabHelper(); } -void TabAndroid::SetShouldBlockNewNotificationRequests(JNIEnv* env, - jboolean value) { - if (should_block_new_notification_requests_ == value) - return; - - should_block_new_notification_requests_ = value; - PropagateBlockNewNotificationRequestsToWebContents(); -} - void TabAndroid::SetDevToolsAgentHost( scoped_refptr<content::DevToolsAgentHost> host) { devtools_host_ = std::move(host); @@ -444,13 +434,6 @@ history_tab_helper->set_hide_all_navigations(hide_future_navigations_); } -void TabAndroid::PropagateBlockNewNotificationRequestsToWebContents() { - if (!web_contents()) - return; - NotificationPermissionContext::SetBlockNewNotificationRequests( - web_contents(), should_block_new_notification_requests_); -} - base::android::ScopedJavaLocalRef<jobject> JNI_TabImpl_FromWebContents( JNIEnv* env, const JavaParamRef<jobject>& jweb_contents) {
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h index 494af22..cebc483 100644 --- a/chrome/browser/android/tab_android.h +++ b/chrome/browser/android/tab_android.h
@@ -116,9 +116,6 @@ bool hide_future_navigations() const { return hide_future_navigations_; } - bool should_block_new_notification_requests() const { - return should_block_new_notification_requests_; - } // Observers ----------------------------------------------------------------- // Adds/Removes an Observer. @@ -164,11 +161,6 @@ jboolean GetHideFutureNavigations(JNIEnv* env) { return hide_future_navigations_; } - void SetShouldBlockNewNotificationRequests(JNIEnv* env, jboolean value); - jboolean GetShouldBlockNewNotificationRequests(JNIEnv* env) { - return should_block_new_notification_requests_; - } - scoped_refptr<content::DevToolsAgentHost> GetDevToolsAgentHost(); void SetDevToolsAgentHost(scoped_refptr<content::DevToolsAgentHost> host); @@ -178,9 +170,6 @@ // with |web_contents_|. void PropagateHideFutureNavigationsToHistoryTabHelper(); - // Calls SetBlockNewNotificationRequests() on NotificationPermissionContext. - void PropagateBlockNewNotificationRequestsToWebContents(); - JavaObjectWeakGlobalRef weak_java_tab_; // Identifier of the window the tab is in. @@ -195,7 +184,6 @@ std::unique_ptr<browser_sync::SyncedTabDelegateAndroid> synced_tab_delegate_; bool should_add_api2_transition_to_future_navigations_ = false; bool hide_future_navigations_ = false; - bool should_block_new_notification_requests_ = false; base::ObserverList<Observer> observers_;
diff --git a/chrome/browser/apps/app_service/notifications_browsertest.cc b/chrome/browser/apps/app_service/notifications_browsertest.cc index 367a31a..c3a0d94e 100644 --- a/chrome/browser/apps/app_service/notifications_browsertest.cc +++ b/chrome/browser/apps/app_service/notifications_browsertest.cc
@@ -37,9 +37,9 @@ #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" #include "components/arc/session/connection_holder.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "components/ukm/test_ukm_recorder.h"
diff --git a/chrome/browser/apps/app_service/uninstall_dialog.h b/chrome/browser/apps/app_service/uninstall_dialog.h index 18f02904..246c68f 100644 --- a/chrome/browser/apps/app_service/uninstall_dialog.h +++ b/chrome/browser/apps/app_service/uninstall_dialog.h
@@ -10,7 +10,6 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "ui/gfx/native_widget_types.h"
diff --git a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc index 7bf63cf..d78224d7 100644 --- a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc +++ b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
@@ -14,8 +14,8 @@ #include "chrome/common/chrome_paths.h" #include "chromeos/dbus/session_manager/fake_session_manager_client.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ash/accessibility/dictation_browsertest.cc b/chrome/browser/ash/accessibility/dictation_browsertest.cc index b17c58f..80f4778 100644 --- a/chrome/browser/ash/accessibility/dictation_browsertest.cc +++ b/chrome/browser/ash/accessibility/dictation_browsertest.cc
@@ -84,7 +84,7 @@ // Fake that SODA is installed so Dictation uses OnDeviceSpeechRecognizer. static_cast<speech::SodaInstallerImplChromeOS*>( speech::SodaInstaller::GetInstance()) - ->soda_installed_for_test_ = true; + ->set_soda_installed_for_test(true); } InProcessBrowserTest::SetUp(); } @@ -114,7 +114,7 @@ ash::Shell::Get()->accessibility_controller()->dictation().SetEnabled(true); if (GetParam().second == kOnDeviceRecognition) { // Replaces normal CrosSpeechRecognitionService with a fake one. - CrosSpeechRecognitionServiceFactory::GetInstance() + CrosSpeechRecognitionServiceFactory::GetInstanceForTest() ->SetTestingFactoryAndUse( browser()->profile(), base::BindRepeating(
diff --git a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc index b965d8dd..1634255 100644 --- a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc +++ b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
@@ -237,7 +237,12 @@ IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, WorksWithTouchSelectionOnNonPrimaryMonitor) { - // Don't observe error messages while setting up the screens. + // Don't observe error messages. + // An error message is observed consistently on MSAN, see crbug.com/1201212, + // and flakily on other builds, see crbug.com/1213451. + // Run the rest of this test on but don't try to catch console errors. + // TODO: Figure out why the "unable to load tab" error is occurring + // and bring back the console observer. console_observer_.reset(); ash::ShellTestApi shell_test_api; @@ -252,14 +257,6 @@ screen->SetDisplayForNewWindows(display2); Browser* browser_on_secondary_display = CreateBrowser(browser()->profile()); -#if !defined(MEMORY_SANITIZER) - // An error message is observed on MSAN, see crbug.com/1201212. - // Run the rest of this test on MSAN but don't try to catch - // console errors. - console_observer_ = std::make_unique<ExtensionConsoleErrorObserver>( - browser()->profile(), extension_misc::kSelectToSpeakExtensionId); -#endif - base::RepeatingCallback<void()> callback = base::BindRepeating( &SelectToSpeakTest::SetSelectToSpeakState, GetWeakPtr()); AccessibilityManager::Get()->SetSelectToSpeakStateObserverForTest(callback);
diff --git a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h index ca9b710..ce2633c 100644 --- a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h +++ b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager.h
@@ -10,7 +10,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "chrome/browser/ash/app_mode/arc/arc_kiosk_app_data.h" #include "chrome/browser/ash/app_mode/kiosk_app_manager_base.h" #include "chrome/browser/ash/settings/cros_settings.h"
diff --git a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager_browsertest.cc b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager_browsertest.cc index 70670eb1..a134e3a6 100644 --- a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager_browsertest.cc +++ b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_manager_browsertest.cc
@@ -19,7 +19,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/settings/cros_settings_names.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/prefs/scoped_user_pref_update.h" #include "content/public/test/browser_test.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ash/app_mode/kiosk_cryptohome_remover.cc b/chrome/browser/ash/app_mode/kiosk_cryptohome_remover.cc index e15374e4..b14897c3 100644 --- a/chrome/browser/ash/app_mode/kiosk_cryptohome_remover.cc +++ b/chrome/browser/ash/app_mode/kiosk_cryptohome_remover.cc
@@ -50,40 +50,6 @@ local_state->CommitPendingWrite(); } -// Functions to deal with legacy prefs -- update the current list from the old -// pref values(dict for regular kiosk and list for arc kiosk). -void UpdateFromDictValue(const char* dict_pref_name) { - PrefService* local_state = g_browser_process->local_state(); - const base::DictionaryValue* const users_to_remove = - local_state->GetDictionary(dict_pref_name); - { - DictionaryPrefUpdate dict_update(local_state, - prefs::kAllKioskUsersToRemove); - for (const auto& element : users_to_remove->DictItems()) { - std::string app_id; - element.second.GetAsString(&app_id); - dict_update->SetKey(element.first, base::Value(app_id)); - } - } - local_state->ClearPref(dict_pref_name); - local_state->CommitPendingWrite(); -} - -void UpdateFromListValue(const std::string& list_pref_name) { - PrefService* local_state = g_browser_process->local_state(); - const base::ListValue* const users_to_remove = - local_state->GetList(list_pref_name); - { - DictionaryPrefUpdate dict_update(local_state, - prefs::kAllKioskUsersToRemove); - for (const auto& element : users_to_remove->GetList()) { - dict_update->SetKey(element.GetString(), base::Value("")); - } - } - local_state->ClearPref(list_pref_name); - local_state->CommitPendingWrite(); -} - void OnRemoveAppCryptohomeComplete( const cryptohome::Identification& id, base::OnceClosure callback, @@ -103,13 +69,6 @@ return; } - // Legacy: we need to support cases when the prefs are stored in the old - // format. - // TODO(crbug.com/1014431): Remove this where the migration is - // completed. - UpdateFromDictValue(prefs::kRegularKioskUsersToRemove); - UpdateFromListValue(prefs::kArcKioskUsersToRemove); - PrefService* local_state = g_browser_process->local_state(); const base::DictionaryValue* const dict = local_state->GetDictionary(prefs::kAllKioskUsersToRemove); @@ -135,8 +94,6 @@ void KioskCryptohomeRemover::RegisterPrefs(PrefRegistrySimple* registry) { registry->RegisterDictionaryPref(prefs::kAllKioskUsersToRemove); - registry->RegisterListPref(prefs::kArcKioskUsersToRemove); - registry->RegisterDictionaryPref(prefs::kRegularKioskUsersToRemove); } void KioskCryptohomeRemover::RemoveObsoleteCryptohomes() {
diff --git a/chrome/browser/ash/app_mode/pref_names.cc b/chrome/browser/ash/app_mode/pref_names.cc index 391f780..05efe4b 100644 --- a/chrome/browser/ash/app_mode/pref_names.cc +++ b/chrome/browser/ash/app_mode/pref_names.cc
@@ -12,16 +12,5 @@ // describe the app this cryptohome is associated to. const char kAllKioskUsersToRemove[] = "all-kiosk-users-to-remove"; -// Legacy prefs that will only be set when some cryptohomes were scheduled -// to be removed, but chrome update happened. -// TODO(crbug.com/1014431): Remove these prefs where the migration is -// completed. -// Dictionary that stores the list of Chrome kiosk cryptohomes to -// be deleted along with their app_ids. -const char kRegularKioskUsersToRemove[] = "kiosk-users-to-remove"; -// List of Android kiosk cryptohomes scheduled to be removed upon next -// startup. -const char kArcKioskUsersToRemove[] = "arc-kiosk-users-to-remove"; - } // namespace prefs } // namespace ash
diff --git a/chrome/browser/ash/app_mode/pref_names.h b/chrome/browser/ash/app_mode/pref_names.h index b7d631cb..d9a83bb 100644 --- a/chrome/browser/ash/app_mode/pref_names.h +++ b/chrome/browser/ash/app_mode/pref_names.h
@@ -12,8 +12,6 @@ // Prefs related to kiosk mode. // --------------------------------------------------------------------------- extern const char kAllKioskUsersToRemove[]; -extern const char kRegularKioskUsersToRemove[]; -extern const char kArcKioskUsersToRemove[]; } // namespace prefs } // namespace ash
diff --git a/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc b/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc index ccf9465..d1a60a705 100644 --- a/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc +++ b/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc
@@ -27,7 +27,7 @@ #include "chrome/browser/web_applications/components/install_finalizer.h" #include "chrome/browser/web_applications/components/web_app_id.h" #include "chrome/browser/web_applications/web_app_provider.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "components/webapps/browser/installable/installable_metrics.h"
diff --git a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc index de07fab5..f508d1e 100644 --- a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc +++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
@@ -15,8 +15,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_accessibility_helper_instance.h" #include "components/exo/buffer.h"
diff --git a/chrome/browser/ash/arc/arc_ui_availability_reporter_unittest.cc b/chrome/browser/ash/arc/arc_ui_availability_reporter_unittest.cc index 48a635e..3f232c40 100644 --- a/chrome/browser/ash/arc/arc_ui_availability_reporter_unittest.cc +++ b/chrome/browser/ash/arc/arc_ui_availability_reporter_unittest.cc
@@ -11,9 +11,9 @@ #include "chrome/browser/ui/app_list/arc/arc_app_test.h" #include "chrome/test/base/testing_profile.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/intent_helper/arc_intent_helper_bridge.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_app_instance.h" #include "components/arc/test/fake_intent_helper_instance.h" #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/ash/arc/arc_util.cc b/chrome/browser/ash/arc/arc_util.cc index 22872755..f502ca18 100644 --- a/chrome/browser/ash/arc/arc_util.cc +++ b/chrome/browser/ash/arc/arc_util.cc
@@ -462,7 +462,7 @@ !ShouldShowOptInForTesting()) { VLOG(1) << "Skip ARC Terms of Service negotiation for managed user. " << "Don't record B&R and GLS if admin leave it as user to decide " - << "and user sikps the opt-in dialog."; + << "and user skips the opt-in dialog."; return false; }
diff --git a/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc b/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc index 70bf8f2..8a3f0c8 100644 --- a/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc +++ b/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
@@ -22,7 +22,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/dbus/userdataauth/fake_cryptohome_misc_client.h" #include "chromeos/dbus/userdataauth/userdataauth_client.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/core/common/policy_switches.h" #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc index 6054e66..20c94243 100644 --- a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc +++ b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
@@ -47,10 +47,10 @@ #include "components/arc/arc_features.h" #include "components/arc/arc_prefs.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" #include "components/arc/session/arc_data_remover.h" #include "components/arc/session/arc_session_runner.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_arc_session.h" #include "components/policy/core/common/cloud/device_management_service.h"
diff --git a/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc b/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc index a0d57a0..11ad58a 100644 --- a/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc +++ b/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
@@ -20,7 +20,7 @@ #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/test/base/in_process_browser_test.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
diff --git a/chrome/browser/ash/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc b/chrome/browser/ash/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc index 429d192..3a47cda3 100644 --- a/chrome/browser/ash/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc +++ b/chrome/browser/ash/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc
@@ -19,7 +19,7 @@ #include "chromeos/dbus/session_manager/fake_session_manager_client.h" #include "components/arc/arc_prefs.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/user_manager/scoped_user_manager.h"
diff --git a/chrome/browser/ash/arc/enterprise/arc_data_snapshotd_delegate_unittest.cc b/chrome/browser/ash/arc/enterprise/arc_data_snapshotd_delegate_unittest.cc index 7d31a95..48bd2fa 100644 --- a/chrome/browser/ash/arc/enterprise/arc_data_snapshotd_delegate_unittest.cc +++ b/chrome/browser/ash/arc/enterprise/arc_data_snapshotd_delegate_unittest.cc
@@ -15,7 +15,7 @@ #include "chromeos/dbus/concierge/concierge_client.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "components/arc/arc_prefs.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/prefs/pref_service.h" #include "components/user_manager/scoped_user_manager.h"
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc index a20415fe..c923bb0 100644 --- a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc +++ b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
@@ -33,8 +33,8 @@ #include "chrome/test/base/testing_profile.h" #include "chromeos/network/network_cert_loader.h" #include "components/arc/arc_prefs.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/policy/policy_constants.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc b/chrome/browser/ash/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc index 46ec27e..920d347 100644 --- a/chrome/browser/ash/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc +++ b/chrome/browser/ash/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc
@@ -17,8 +17,8 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "components/arc/arc_prefs.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_session_runner.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/user_manager/scoped_user_manager.h"
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_instance_throttle_unittest.cc b/chrome/browser/ash/arc/instance_throttle/arc_instance_throttle_unittest.cc index 02502d3..2a6283c 100644 --- a/chrome/browser/ash/arc/instance_throttle/arc_instance_throttle_unittest.cc +++ b/chrome/browser/ash/arc/instance_throttle/arc_instance_throttle_unittest.cc
@@ -20,7 +20,7 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "components/arc/arc_prefs.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc index e0019c5..ef10996b 100644 --- a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc +++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
@@ -31,8 +31,8 @@ #include "chromeos/network/proxy/proxy_config_handler.h" #include "components/arc/arc_prefs.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_backup_settings_instance.h" #include "components/arc/test/fake_intent_helper_instance.h"
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service_unittest.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service_unittest.cc index 464a459..c91bff0 100644 --- a/chrome/browser/ash/arc/intent_helper/arc_settings_service_unittest.cc +++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service_unittest.cc
@@ -24,9 +24,9 @@ #include "chromeos/services/network_config/public/cpp/cros_network_config_test_helper.h" #include "components/arc/arc_prefs.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/intent_helper/arc_intent_helper_bridge.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_arc_session.h" #include "components/arc/test/fake_backup_settings_instance.h"
diff --git a/chrome/browser/ash/arc/intent_helper/custom_tab_session_impl_browsertest.cc b/chrome/browser/ash/arc/intent_helper/custom_tab_session_impl_browsertest.cc index 27ce5b04..3cd87e4 100644 --- a/chrome/browser/ash/arc/intent_helper/custom_tab_session_impl_browsertest.cc +++ b/chrome/browser/ash/arc/intent_helper/custom_tab_session_impl_browsertest.cc
@@ -10,8 +10,8 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_list_observer.h" #include "chrome/test/base/in_process_browser_test.h" -#include "components/arc/arc_util.h" #include "components/arc/intent_helper/custom_tab.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/exo/shell_surface.h" #include "components/exo/test/shell_surface_builder.h" #include "components/exo/wm_helper.h"
diff --git a/chrome/browser/ash/arc/notification/arc_provision_notification_service_unittest.cc b/chrome/browser/ash/arc/notification/arc_provision_notification_service_unittest.cc index b626ad59..5fc3489 100644 --- a/chrome/browser/ash/arc/notification/arc_provision_notification_service_unittest.cc +++ b/chrome/browser/ash/arc/notification/arc_provision_notification_service_unittest.cc
@@ -24,7 +24,7 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "components/arc/arc_prefs.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/prefs/pref_service.h" #include "components/session_manager/core/session_manager.h"
diff --git a/chrome/browser/ash/arc/session/arc_play_store_enabled_preference_handler_unittest.cc b/chrome/browser/ash/arc/session/arc_play_store_enabled_preference_handler_unittest.cc index 58b9cc4..7de15a1 100644 --- a/chrome/browser/ash/arc/session/arc_play_store_enabled_preference_handler_unittest.cc +++ b/chrome/browser/ash/arc/session/arc_play_store_enabled_preference_handler_unittest.cc
@@ -27,8 +27,8 @@ #include "chromeos/dbus/session_manager/session_manager_client.h" #include "chromeos/dbus/upstart/upstart_client.h" #include "components/arc/arc_prefs.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_session_runner.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/consent_auditor/fake_consent_auditor.h" #include "components/signin/public/identity_manager/consent_level.h"
diff --git a/chrome/browser/ash/arc/session/arc_session_manager_browsertest.cc b/chrome/browser/ash/arc/session/arc_session_manager_browsertest.cc index 651a5dd..4819a0b0 100644 --- a/chrome/browser/ash/arc/session/arc_session_manager_browsertest.cc +++ b/chrome/browser/ash/arc/session/arc_session_manager_browsertest.cc
@@ -40,8 +40,8 @@ #include "components/account_id/account_id.h" #include "components/arc/arc_prefs.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_session_runner.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
diff --git a/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc b/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc index 3623ab73..d09373a 100644 --- a/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc +++ b/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc
@@ -58,6 +58,7 @@ #include "components/arc/arc_service_manager.h" #include "components/arc/arc_util.h" #include "components/arc/session/arc_session_runner.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/policy/proto/chrome_device_policy.pb.h" #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ash/arc/user_session/arc_user_session_service_browsertest.cc b/chrome/browser/ash/arc/user_session/arc_user_session_service_browsertest.cc index 7ed3888a..ad8885a 100644 --- a/chrome/browser/ash/arc/user_session/arc_user_session_service_browsertest.cc +++ b/chrome/browser/ash/arc/user_session/arc_user_session_service_browsertest.cc
@@ -11,8 +11,8 @@ #include "chrome/browser/ui/ash/chrome_shelf_prefs.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_intent_helper_instance.h" #include "components/session_manager/core/session_manager.h"
diff --git a/chrome/browser/ash/borealis/borealis_installer.h b/chrome/browser/ash/borealis/borealis_installer.h index ddda90f7..b1e0aebb 100644 --- a/chrome/browser/ash/borealis/borealis_installer.h +++ b/chrome/browser/ash/borealis/borealis_installer.h
@@ -11,7 +11,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "chrome/browser/ash/borealis/borealis_metrics.h" #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/ash/borealis/borealis_installer_impl.h b/chrome/browser/ash/borealis/borealis_installer_impl.h index 4f841f9..593e8fb 100644 --- a/chrome/browser/ash/borealis/borealis_installer_impl.h +++ b/chrome/browser/ash/borealis/borealis_installer_impl.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/observer_list.h" #include "chrome/browser/ash/borealis/borealis_installer.h" #include "chrome/browser/ash/borealis/borealis_metrics.h" #include "chrome/browser/ash/borealis/infra/expected.h"
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_time_browsertest.cc b/chrome/browser/ash/child_accounts/time_limits/app_time_browsertest.cc index 55d5b45..ee0cc49 100644 --- a/chrome/browser/ash/child_accounts/time_limits/app_time_browsertest.cc +++ b/chrome/browser/ash/child_accounts/time_limits/app_time_browsertest.cc
@@ -28,9 +28,9 @@ #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_features.h" #include "chrome/test/base/mixin_based_in_process_browser_test.h" -#include "components/arc/arc_util.h" #include "components/arc/mojom/app.mojom.h" #include "components/arc/mojom/app_permissions.mojom.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "components/user_manager/user.h"
diff --git a/chrome/browser/ash/child_accounts/time_limits/web_time_activity_provider.h b/chrome/browser/ash/child_accounts/time_limits/web_time_activity_provider.h index 95592c4..d1674dc9 100644 --- a/chrome/browser/ash/child_accounts/time_limits/web_time_activity_provider.h +++ b/chrome/browser/ash/child_accounts/time_limits/web_time_activity_provider.h
@@ -7,7 +7,6 @@ #include <set> -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.h" #include "chrome/browser/ash/child_accounts/time_limits/web_time_navigation_observer.h"
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn index 19f5a0e..6002ecf9 100644 --- a/chrome/browser/ash/crosapi/BUILD.gn +++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -150,6 +150,7 @@ "browser_loader_unittest.cc", "browser_manager_unittest.cc", "browser_util_unittest.cc", + "keystore_service_ash_unittest.cc", "local_printer_ash_unittest.cc", "message_center_ash_unittest.cc", "metrics_reporting_ash_unittest.cc", @@ -165,10 +166,12 @@ "//base", "//base/test:test_config", "//base/test:test_support", + "//chrome/browser/chromeos:test_support", "//chrome/common/printing", "//chrome/test:browser_tests", "//chrome/test:test_support", "//chromeos", + "//chromeos/crosapi/cpp:cpp", "//chromeos/dbus/upstart", "//chromeos/login/login_state", "//chromeos/startup:constants",
diff --git a/chrome/browser/ash/crosapi/keystore_service_ash.cc b/chrome/browser/ash/crosapi/keystore_service_ash.cc index 473cfac1..47ada0c 100644 --- a/chrome/browser/ash/crosapi/keystore_service_ash.cc +++ b/chrome/browser/ash/crosapi/keystore_service_ash.cc
@@ -136,11 +136,17 @@ } // namespace -KeystoreServiceAsh::KeystoreServiceAsh(content::BrowserContext* context) - : platform_keys_service_( +KeystoreServiceAsh::KeystoreServiceAsh(content::BrowserContext* fixed_context) + : fixed_platform_keys_service_( chromeos::platform_keys::PlatformKeysServiceFactory:: - GetForBrowserContext(context)) { - CHECK(platform_keys_service_); + GetForBrowserContext(fixed_context)) { + CHECK(fixed_platform_keys_service_); +} + +KeystoreServiceAsh::KeystoreServiceAsh( + chromeos::platform_keys::PlatformKeysService* platform_keys_service) + : fixed_platform_keys_service_(platform_keys_service) { + CHECK(fixed_platform_keys_service_); } KeystoreServiceAsh::KeystoreServiceAsh() = default; @@ -152,8 +158,8 @@ } PlatformKeysService* KeystoreServiceAsh::GetPlatformKeys() { - if (platform_keys_service_) { - return platform_keys_service_; + if (fixed_platform_keys_service_) { + return fixed_platform_keys_service_; } PlatformKeysService* service =
diff --git a/chrome/browser/ash/crosapi/keystore_service_ash.h b/chrome/browser/ash/crosapi/keystore_service_ash.h index e2e3c61..e3036c6 100644 --- a/chrome/browser/ash/crosapi/keystore_service_ash.h +++ b/chrome/browser/ash/crosapi/keystore_service_ash.h
@@ -42,10 +42,13 @@ using KeystoreType = mojom::KeystoreType; using SigningScheme = mojom::KeystoreSigningScheme; - explicit KeystoreServiceAsh(content::BrowserContext* context); + explicit KeystoreServiceAsh(content::BrowserContext* fixed_context); // Allows to create the service early. It will use the current primary profile // whenever used. The profile should be specified explicitly when possible. KeystoreServiceAsh(); + // For testing only. + explicit KeystoreServiceAsh( + chromeos::platform_keys::PlatformKeysService* platform_keys_service); KeystoreServiceAsh(const KeystoreServiceAsh&) = delete; KeystoreServiceAsh& operator=(const KeystoreServiceAsh&) = delete; ~KeystoreServiceAsh() override; @@ -91,6 +94,10 @@ SignCallback callback) override; private: + // Returns a correct instance of PlatformKeysService to use. If a specific + // browser context was passed into constructor, the corresponding + // PlatformKeysService instance will be used for all operations. + // Otherwise the class will use an instance for the primary profile. chromeos::platform_keys::PlatformKeysService* GetPlatformKeys(); // |challenge| is used as a opaque identifier to match against the @@ -126,7 +133,9 @@ chromeos::platform_keys::Status status); // Can be nullptr, should not be used directly, use GetPlatformKeys() instead. - chromeos::platform_keys::PlatformKeysService* platform_keys_service_ = + // Stores a pointer to a specific PlatformKeysService if it was specified in + // constructor. + chromeos::platform_keys::PlatformKeysService* fixed_platform_keys_service_ = nullptr; // Container to keep outstanding challenges alive.
diff --git a/chrome/browser/ash/crosapi/keystore_service_ash_unittest.cc b/chrome/browser/ash/crosapi/keystore_service_ash_unittest.cc new file mode 100644 index 0000000..352a03d7 --- /dev/null +++ b/chrome/browser/ash/crosapi/keystore_service_ash_unittest.cc
@@ -0,0 +1,233 @@ +// Copyright 2021 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/ash/crosapi/keystore_service_ash.h" + +#include "base/base64.h" +#include "base/bind.h" +#include "base/no_destructor.h" +#include "base/notreached.h" +#include "base/test/gmock_callback_support.h" +#include "base/test/gmock_move_support.h" +#include "chrome/browser/chromeos/platform_keys/mock_platform_keys_service.h" +#include "chrome/browser/chromeos/platform_keys/platform_keys.h" +#include "chromeos/crosapi/cpp/keystore_service_util.h" +#include "content/public/test/browser_task_environment.h" +#include "net/cert/asn1_util.h" +#include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" +#include "net/ssl/ssl_info.h" +#include "net/test/cert_test_util.h" +#include "net/test/test_data_directory.h" +#include "testing/gtest/include/gtest/gtest.h" + +// The tests in this file mostly focus on verifying that KeystoreService can +// forward messages to and from PlatformKeysService and correctly re-encode +// arguments in both directions. + +namespace crosapi { +namespace { + +using base::test::RunOnceCallback; +using chromeos::platform_keys::BuildMockPlatformKeysService; +using chromeos::platform_keys::HashAlgorithm; +using chromeos::platform_keys::MockPlatformKeysService; +using chromeos::platform_keys::Status; +using chromeos::platform_keys::TokenId; +using crosapi::keystore_service_util::MakeEcKeystoreSigningAlgorithm; +using crosapi::keystore_service_util::MakeRsaKeystoreSigningAlgorithm; +using testing::_; +using testing::StrictMock; + +constexpr char kData[] = "\1\2\3\4\5\6\7"; + +std::string Base64Decode(const char* input) { + std::string result; + CHECK(base::Base64Decode(input, &result)); + return result; +} + +std::string GetSubjectPublicKeyInfo( + const scoped_refptr<net::X509Certificate> certificate) { + base::StringPiece spki_der_piece; + bool ok = net::asn1::ExtractSPKIFromDERCert( + net::x509_util::CryptoBufferAsStringPiece(certificate->cert_buffer()), + &spki_der_piece); + CHECK(ok && !spki_der_piece.empty()); + return std::string(spki_der_piece); +} + +// Returns a list with one certificate. +std::unique_ptr<net::CertificateList> GetCertificateList() { + static base::NoDestructor<net::CertificateList> cert_list; + if (cert_list->empty()) { + net::SSLInfo ssl_info = net::SSLInfo(); + ssl_info.cert = + net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); + CHECK(ssl_info.is_valid()); + cert_list->push_back(ssl_info.cert); + } + return std::make_unique<net::CertificateList>(*cert_list); +} + +const std::string& GetPublicKeyStr() { + static base::NoDestructor<const std::string> result( + GetSubjectPublicKeyInfo(*GetCertificateList()->begin())); + return *result; +} + +const std::vector<uint8_t>& GetPublicKeyBin() { + static base::NoDestructor<const std::vector<uint8_t>> result( + GetPublicKeyStr().begin(), GetPublicKeyStr().end()); + return *result; +} + +const std::string& GetDataStr() { + static base::NoDestructor<const std::string> result(kData); + return *result; +} + +const std::vector<uint8_t>& GetDataBin() { + static base::NoDestructor<const std::vector<uint8_t>> result( + GetDataStr().begin(), GetDataStr().end()); + return *result; +} + +void AssertBlobEq(const mojom::KeystoreBinaryResultPtr& result, + const std::vector<uint8_t>& expected_blob) { + ASSERT_TRUE(result); + ASSERT_EQ(result->which(), mojom::KeystoreBinaryResult::Tag::kBlob); + EXPECT_EQ(result->get_blob(), expected_blob); +} + +void AssertErrorEq(const mojom::KeystoreBinaryResultPtr& result, + mojom::KeystoreError expected_error) { + ASSERT_TRUE(result); + ASSERT_EQ(result->which(), mojom::KeystoreBinaryResult::Tag::kError); + EXPECT_EQ(result->get_error(), expected_error); +} + +class KeystoreServiceAshTest : public testing::Test { + public: + KeystoreServiceAshTest() : keystore_service_(&platform_keys_service_) {} + KeystoreServiceAshTest(const KeystoreServiceAshTest&) = delete; + auto operator=(const KeystoreServiceAshTest&) = delete; + ~KeystoreServiceAshTest() override = default; + + protected: + content::BrowserTaskEnvironment task_environment_{ + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + + StrictMock<MockPlatformKeysService> platform_keys_service_; + KeystoreServiceAsh keystore_service_; +}; + +// A mock for observing binary results returned via a callback. +struct BinaryCallbackObserver { + MOCK_METHOD(void, Callback, (mojom::KeystoreBinaryResultPtr result)); + + auto GetCallback() { + EXPECT_CALL(*this, Callback).WillOnce(MoveArg<0>(&result)); + return base::BindOnce(&BinaryCallbackObserver::Callback, + base::Unretained(this)); + } + + mojom::KeystoreBinaryResultPtr result; +}; + +TEST_F(KeystoreServiceAshTest, GenerateUserRsaKeySuccess) { + const unsigned int modulus_length = 2048; + + EXPECT_CALL(platform_keys_service_, + GenerateRSAKey(TokenId::kUser, modulus_length, /*callback=*/_)) + .WillOnce(RunOnceCallback<2>(GetPublicKeyStr(), Status::kSuccess)); + BinaryCallbackObserver observer; + keystore_service_.GenerateKey(mojom::KeystoreType::kUser, + MakeRsaKeystoreSigningAlgorithm(modulus_length), + observer.GetCallback()); + + AssertBlobEq(observer.result, GetPublicKeyBin()); +} + +TEST_F(KeystoreServiceAshTest, GenerateDeviceEcKeySuccess) { + const std::string named_curve = "test_named_curve"; + + EXPECT_CALL(platform_keys_service_, + GenerateECKey(TokenId::kSystem, named_curve, /*callback=*/_)) + .WillOnce(RunOnceCallback<2>(GetPublicKeyStr(), Status::kSuccess)); + + BinaryCallbackObserver observer; + keystore_service_.GenerateKey(mojom::KeystoreType::kDevice, + MakeEcKeystoreSigningAlgorithm(named_curve), + observer.GetCallback()); + + AssertBlobEq(observer.result, GetPublicKeyBin()); +} + +TEST_F(KeystoreServiceAshTest, GenerateKeyFail) { + EXPECT_CALL(platform_keys_service_, GenerateECKey) + .WillOnce(RunOnceCallback<2>("", Status::kErrorInternal)); + + BinaryCallbackObserver observer; + keystore_service_.GenerateKey(mojom::KeystoreType::kUser, + MakeEcKeystoreSigningAlgorithm("named_curve_1"), + observer.GetCallback()); + + AssertErrorEq(observer.result, mojom::KeystoreError::kInternal); +} + +TEST_F(KeystoreServiceAshTest, SignRsaSuccess) { + // Accepted and returned data are the same. This is not realistic, but doesn't + // matter here. + EXPECT_CALL(platform_keys_service_, + SignRSAPKCS1Digest(absl::optional<TokenId>(TokenId::kUser), + GetDataStr(), GetPublicKeyStr(), + HashAlgorithm::HASH_ALGORITHM_SHA256, + /*callback=*/_)) + .WillOnce(RunOnceCallback<4>(GetDataStr(), Status::kSuccess)); + + BinaryCallbackObserver observer; + keystore_service_.Sign( + /*is_keystore_provided=*/true, mojom::KeystoreType::kUser, + GetPublicKeyBin(), mojom::KeystoreSigningScheme::kRsassaPkcs1V15Sha256, + GetDataBin(), observer.GetCallback()); + + AssertBlobEq(observer.result, GetDataBin()); +} + +TEST_F(KeystoreServiceAshTest, SignEcSuccess) { + // Accepted and returned data are the same. This is not realistic, but doesn't + // matter here. + EXPECT_CALL( + platform_keys_service_, + SignECDSADigest(absl::optional<TokenId>(TokenId::kSystem), GetDataStr(), + GetPublicKeyStr(), HashAlgorithm::HASH_ALGORITHM_SHA512, + /*callback=*/_)) + .WillOnce(RunOnceCallback<4>(GetDataStr(), Status::kSuccess)); + + BinaryCallbackObserver observer; + keystore_service_.Sign( + /*is_keystore_provided=*/true, mojom::KeystoreType::kDevice, + GetPublicKeyBin(), mojom::KeystoreSigningScheme::kEcdsaSha512, + GetDataBin(), observer.GetCallback()); + + AssertBlobEq(observer.result, GetDataBin()); +} + +TEST_F(KeystoreServiceAshTest, SignFail) { + EXPECT_CALL(platform_keys_service_, SignECDSADigest) + .WillOnce(RunOnceCallback<4>("", Status::kErrorKeyNotAllowedForSigning)); + + BinaryCallbackObserver observer; + keystore_service_.Sign( + /*is_keystore_provided=*/true, mojom::KeystoreType::kDevice, + GetPublicKeyBin(), mojom::KeystoreSigningScheme::kEcdsaSha512, + GetDataBin(), observer.GetCallback()); + + AssertErrorEq(observer.result, + mojom::KeystoreError::kKeyNotAllowedForSigning); +} + +} // namespace +} // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/local_printer_ash.cc b/chrome/browser/ash/crosapi/local_printer_ash.cc index 556ae904..e95582e 100644 --- a/chrome/browser/ash/crosapi/local_printer_ash.cc +++ b/chrome/browser/ash/crosapi/local_printer_ash.cc
@@ -36,6 +36,7 @@ #include "chromeos/printing/ppd_provider.h" #include "components/prefs/pref_service.h" #include "components/printing/browser/prefs_util.h" +#include "components/user_manager/user.h" #include "printing/backend/print_backend.h" #include "printing/print_settings.h" #include "printing/printing_features.h" @@ -345,6 +346,19 @@ std::move(callback).Run(std::move(policies)); } +void LocalPrinterAsh::IsSendUsernameFilenameEnabled( + IsSendUsernameFilenameEnabledCallback callback) { + Profile* profile = ProfileManager::GetActiveUserProfile(); + PrefService* prefs = profile->GetPrefs(); + const std::string username = chromeos::ProfileHelper::Get() + ->GetUserByProfile(profile) + ->display_email(); + std::move(callback).Run( + prefs->GetBoolean(prefs::kPrintingSendUsernameAndFilenameEnabled) + ? absl::optional<std::string>(username) + : absl::nullopt); +} + Profile* LocalPrinterAsh::GetActiveUserProfile() { return ProfileManager::GetActiveUserProfile(); }
diff --git a/chrome/browser/ash/crosapi/local_printer_ash.h b/chrome/browser/ash/crosapi/local_printer_ash.h index 8bb7c7c..751fdbfd 100644 --- a/chrome/browser/ash/crosapi/local_printer_ash.h +++ b/chrome/browser/ash/crosapi/local_printer_ash.h
@@ -55,6 +55,8 @@ void AddObserver(mojo::PendingRemote<mojom::PrintServerObserver> remote, AddObserverCallback callback) override; void GetPolicies(GetPoliciesCallback callback) override; + void IsSendUsernameFilenameEnabled( + IsSendUsernameFilenameEnabledCallback callback) override; private: // Exposed so that unit tests can override them.
diff --git a/chrome/browser/ash/file_system_provider/provided_file_system_interface.h b/chrome/browser/ash/file_system_provider/provided_file_system_interface.h index 9655eb1..a3b219e6 100644 --- a/chrome/browser/ash/file_system_provider/provided_file_system_interface.h +++ b/chrome/browser/ash/file_system_provider/provided_file_system_interface.h
@@ -17,7 +17,6 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "chrome/browser/ash/file_system_provider/abort_callback.h" #include "chrome/browser/ash/file_system_provider/provided_file_system_observer.h" #include "chrome/browser/ash/file_system_provider/watcher.h"
diff --git a/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc b/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc index d7e784a..cb2e91a 100644 --- a/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc +++ b/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
@@ -68,11 +68,11 @@ // profile creation callbacks, and to provide a way to override profile creation // result. // An instance can be passed to TestingProfile as delegate - when the testing -// profile creation is done, i.e. when the delegate's |OnProfileCreated| is -// called this will remember the result. The creation result will be forwarded -// to the actual (wrapped) delegate when |WaitForCreationAndOverrideResponse| is -// called. This method will additionally wait until the profile creation -// finishes. +// profile creation is done, i.e. when the delegate's +// |OnProfileCreationFinished| is called this will remember the result. The +// creation result will be forwarded to the actual (wrapped) delegate when +// |WaitForCreationAndOverrideResponse| is called. This method will additionally +// wait until the profile creation finishes. class PendingProfileCreation : public Profile::Delegate { public: PendingProfileCreation() {} @@ -131,15 +131,20 @@ Profile* profile = profile_; profile_ = nullptr; - delegate->OnProfileCreated(profile, success, is_new_profile_); + delegate->OnProfileCreationFinished( + profile, Profile::CREATE_MODE_ASYNCHRONOUS, success, is_new_profile_); return true; } + void OnProfileCreationStarted(Profile* profile, + Profile::CreateMode create_mode) override {} + // Called when the profile is created - it caches the result, and quits the // run loop potentially set in |WaitForCreationAndOverrideResponse|. - void OnProfileCreated(Profile* profile, - bool success, - bool is_new_profile) override { + void OnProfileCreationFinished(Profile* profile, + Profile::CreateMode create_mode, + bool success, + bool is_new_profile) override { ASSERT_FALSE(profile_); profile_ = profile;
diff --git a/chrome/browser/ash/login/enrollment/enterprise_enrollment_helper_impl.cc b/chrome/browser/ash/login/enrollment/enterprise_enrollment_helper_impl.cc index 6c22b49..4fa5275 100644 --- a/chrome/browser/ash/login/enrollment/enterprise_enrollment_helper_impl.cc +++ b/chrome/browser/ash/login/enrollment/enterprise_enrollment_helper_impl.cc
@@ -41,6 +41,9 @@ // TODO(https://crbug.com/1164001): remove when migrated to ash:: using ::chromeos::InstallAttributes; +// The OAuth token consumer name. +const char kOAuthConsumerName[] = "enterprise_enrollment"; + // A helper class that takes care of asynchronously revoking a given token. class TokenRevoker : public GaiaAuthConsumer { public: @@ -105,7 +108,8 @@ const std::string& auth_code) { DCHECK(oauth_status_ == OAUTH_NOT_STARTED); oauth_status_ = OAUTH_STARTED_WITH_AUTH_CODE; - oauth_fetcher_ = policy::PolicyOAuth2TokenFetcher::CreateInstance(); + oauth_fetcher_ = + policy::PolicyOAuth2TokenFetcher::CreateInstance(kOAuthConsumerName); oauth_fetcher_->StartWithAuthCode( auth_code, g_browser_process->system_network_context_manager()
diff --git a/chrome/browser/ash/login/existing_user_controller_browsertest.cc b/chrome/browser/ash/login/existing_user_controller_browsertest.cc index 3013c778..d2593d4 100644 --- a/chrome/browser/ash/login/existing_user_controller_browsertest.cc +++ b/chrome/browser/ash/login/existing_user_controller_browsertest.cc
@@ -72,8 +72,8 @@ #include "chromeos/settings/cros_settings_provider.h" #include "chromeos/strings/grit/chromeos_strings.h" #include "components/account_id/account_id.h" -#include "components/arc/arc_util.h" #include "components/arc/enterprise/arc_data_snapshotd_manager.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" #include "components/policy/core/common/cloud/cloud_policy_core.h"
diff --git a/chrome/browser/ash/login/oobe_interactive_ui_test.cc b/chrome/browser/ash/login/oobe_interactive_ui_test.cc index 77ebb270..57ba604d 100644 --- a/chrome/browser/ash/login/oobe_interactive_ui_test.cc +++ b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
@@ -61,8 +61,8 @@ #include "chromeos/dbus/update_engine_client.h" #include "chromeos/system/fake_statistics_provider.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_session_runner.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h"
diff --git a/chrome/browser/ash/login/reporting/login_logout_record.proto b/chrome/browser/ash/login/reporting/login_logout_record.proto new file mode 100644 index 0000000..61510a2 --- /dev/null +++ b/chrome/browser/ash/login/reporting/login_logout_record.proto
@@ -0,0 +1,34 @@ +// Copyright 2021 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package chromeos.reporting; + +message SessionAffiliatedUser { + optional string user_email = 1; +} + +message LoginFailure { + optional string reason = 1; +} + +message LoginEvent { + optional LoginFailure failure = 1; +} + +message LogoutEvent {} + +message LoginLogoutRecord { + optional int64 event_timestamp = 1; + + optional SessionAffiliatedUser affiliated_user = 2; + + oneof event { + LoginEvent login_event = 3; + LogoutEvent logout_event = 4; + } +}
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter.cc b/chrome/browser/ash/login/reporting/login_logout_reporter.cc new file mode 100644 index 0000000..272fb56 --- /dev/null +++ b/chrome/browser/ash/login/reporting/login_logout_reporter.cc
@@ -0,0 +1,132 @@ +// Copyright 2021 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/ash/login/reporting/login_logout_reporter.h" + +#include "base/bind_post_task.h" +#include "base/logging.h" +#include "chrome/browser/ash/login/users/chrome_user_manager.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part_chromeos.h" +#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" + +namespace chromeos { +namespace reporting { + +bool LoginLogoutReporter::Delegate::ShouldReportUser( + base::StringPiece user_email) const { + return ash::ChromeUserManager::Get()->ShouldReportUser( + std::string(user_email)); +} + +bool LoginLogoutReporter::Delegate::ShouldReportEvent() const { + // TODO(crbug.com/1215406): add login/logout reporting policy check. + return false; +} + +policy::DMToken LoginLogoutReporter::Delegate::GetDMToken() const { + policy::DMToken dm_token(policy::DMToken::Status::kEmpty, ""); + + auto* const connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + if (!connector) { + return dm_token; + } + + auto* const policy_manager = connector->GetDeviceCloudPolicyManager(); + if (policy_manager && policy_manager->IsClientRegistered()) { + dm_token = policy::DMToken(policy::DMToken::Status::kValid, + policy_manager->core()->client()->dm_token()); + } + + return dm_token; +} + +void LoginLogoutReporter::Delegate::CreateReportingQueue( + std::unique_ptr<::reporting::ReportQueueConfiguration> config, + ::reporting::ReportQueueProvider::CreateReportQueueCallback + create_queue_cb) { + base::ThreadPool::PostTask( + FROM_HERE, base::BindOnce(::reporting::ReportQueueProvider::CreateQueue, + std::move(config), std::move(create_queue_cb))); +} + +LoginLogoutReporter::LoginLogoutReporter(std::unique_ptr<Delegate> delegate) + : delegate_(std::move(delegate)) {} + +LoginLogoutReporter::~LoginLogoutReporter() = default; + +// static +void LoginLogoutReporter::OnReportQueueCreated( + LoginLogoutRecord record, + ::reporting::StatusOr<std::unique_ptr<::reporting::ReportQueue>> + report_queue_result) { + if (!report_queue_result.ok()) { + DVLOG(1) << "ReportQueue could not be created: " + << report_queue_result.status(); + return; + } + auto* const report_queue = report_queue_result.ValueOrDie().release(); + auto enqueue_cb = base::BindOnce(&LoginLogoutReporter::OnRecordEnqueued, + base::Owned(report_queue)); + report_queue->Enqueue(&record, ::reporting::Priority::IMMEDIATE, + std::move(enqueue_cb)); +} + +// static +void LoginLogoutReporter::OnRecordEnqueued( + ::reporting::ReportQueue* report_queue, + ::reporting::Status status) { + if (!status.ok()) { + DVLOG(1) + << "Could not enqueue login/logout event to reporting queue because of " + << status; + } +} + +void LoginLogoutReporter::MaybeReportEvent(base::StringPiece user_email, + LoginLogoutRecord record) const { + if (delegate_->ShouldReportEvent()) { + const policy::DMToken dm_token = delegate_->GetDMToken(); + if (!dm_token.is_valid()) { + DVLOG(1) << "Cannot initialize login/logout reporting. Invalid DMToken."; + return; + } + + record.set_event_timestamp(base::Time::Now().ToTimeT()); + if (delegate_->ShouldReportUser(user_email)) { + record.mutable_affiliated_user()->set_user_email(std::string(user_email)); + } + + auto config_result = ::reporting::ReportQueueConfiguration::Create( + dm_token.value(), ::reporting::Destination::LOGIN_LOGOUT_EVENTS, + base::BindRepeating([]() { return ::reporting::Status::StatusOK(); })); + + if (!config_result.ok()) { + DVLOG(1) << "Cannot initialize login/logout reporting. " + << "Invalid ReportQueueConfiguration"; + return; + } + + auto create_queue_cb = base::BindOnce( + &LoginLogoutReporter::OnReportQueueCreated, std::move(record)); + delegate_->CreateReportingQueue(std::move(config_result.ValueOrDie()), + std::move(create_queue_cb)); + } +} + +void LoginLogoutReporter::MaybeReportLogin(base::StringPiece user_email) const { + LoginLogoutRecord record; + record.mutable_login_event(); + MaybeReportEvent(user_email, std::move(record)); +} + +void LoginLogoutReporter::MaybeReportLogout( + base::StringPiece user_email) const { + LoginLogoutRecord record; + record.mutable_logout_event(); + MaybeReportEvent(user_email, std::move(record)); +} +} // namespace reporting +} // namespace chromeos
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter.h b/chrome/browser/ash/login/reporting/login_logout_reporter.h new file mode 100644 index 0000000..b1ec3d1 --- /dev/null +++ b/chrome/browser/ash/login/reporting/login_logout_reporter.h
@@ -0,0 +1,74 @@ +// Copyright 2021 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_ASH_LOGIN_REPORTING_LOGIN_LOGOUT_REPORTER_H_ +#define CHROME_BROWSER_ASH_LOGIN_REPORTING_LOGIN_LOGOUT_REPORTER_H_ + +#include "chrome/browser/ash/login/reporting/login_logout_record.pb.h" +#include "components/policy/core/common/cloud/dm_token.h" +#include "components/reporting/client/report_queue_provider.h" + +namespace chromeos { +namespace reporting { + +class LoginLogoutReporter { + public: + class Delegate { + public: + virtual ~Delegate() = default; + + // Return whether the login/logout event reporting is allowed by policy. + virtual bool ShouldReportEvent() const; + + // Return whether the user email can be included the login/logout report, + // only affiliated user emails are included. Function can accept + // canonicalized and non canonicalized user_email. + virtual bool ShouldReportUser(base::StringPiece user_email) const; + + // Return the device DM token. + virtual policy::DMToken GetDMToken() const; + + // Create a new reporting pipeline queue to be used for reporting the + // login/logout event. + virtual void CreateReportingQueue( + std::unique_ptr<::reporting::ReportQueueConfiguration> config, + ::reporting::ReportQueueProvider::CreateReportQueueCallback + create_queue_cb); + }; + + // Default parameter value used in production, and set in testing. + explicit LoginLogoutReporter( + std::unique_ptr<Delegate> delegate = std::make_unique<Delegate>()); + + LoginLogoutReporter(const LoginLogoutReporter& other) = delete; + LoginLogoutReporter& operator=(const LoginLogoutReporter& other) = delete; + + virtual ~LoginLogoutReporter(); + + // Report user device login if allowed by policy. Function can accept + // canonicalized and non canonicalized user_email. + void MaybeReportLogin(base::StringPiece user_email) const; + + // Report user device logout if allowed by policy. Function can accept + // canonicalized and non canonicalized user_email. + void MaybeReportLogout(base::StringPiece user_email) const; + + private: + std::unique_ptr<Delegate> delegate_; + + static void OnReportQueueCreated( + LoginLogoutRecord record, + ::reporting::StatusOr<std::unique_ptr<::reporting::ReportQueue>> + report_queue_result); + + static void OnRecordEnqueued(::reporting::ReportQueue* report_queue, + ::reporting::Status status); + + void MaybeReportEvent(base::StringPiece user_email, + LoginLogoutRecord record) const; +}; +} // namespace reporting +} // namespace chromeos + +#endif // CHROME_BROWSER_ASH_LOGIN_REPORTING_LOGIN_LOGOUT_REPORTER_H_
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter_test_delegate.cc b/chrome/browser/ash/login/reporting/login_logout_reporter_test_delegate.cc new file mode 100644 index 0000000..261c9b8 --- /dev/null +++ b/chrome/browser/ash/login/reporting/login_logout_reporter_test_delegate.cc
@@ -0,0 +1,42 @@ +// Copyright 2021 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/ash/login/reporting/login_logout_reporter_test_delegate.h" + +namespace chromeos { +namespace reporting { + +LoginLogoutReporterTestDelegate::~LoginLogoutReporterTestDelegate() = default; + +LoginLogoutReporterTestDelegate::LoginLogoutReporterTestDelegate( + bool should_report_event, + bool should_report_user, + policy::DMToken dm_token, + std::unique_ptr<::reporting::MockReportQueue> mock_queue) + : should_report_event_(should_report_event), + should_report_user_(should_report_user), + dm_token_(dm_token), + mock_queue_(std::move(mock_queue)) {} + +bool LoginLogoutReporterTestDelegate::ShouldReportEvent() const { + return should_report_event_; +} + +bool LoginLogoutReporterTestDelegate::ShouldReportUser( + base::StringPiece) const { + return should_report_user_; +} + +policy::DMToken LoginLogoutReporterTestDelegate::GetDMToken() const { + return dm_token_; +} + +void LoginLogoutReporterTestDelegate::CreateReportingQueue( + std::unique_ptr<::reporting::ReportQueueConfiguration> config, + ::reporting::ReportQueueProvider::CreateReportQueueCallback + create_queue_cb) { + std::move(create_queue_cb).Run(std::move(mock_queue_)); +} +} // namespace reporting +} // namespace chromeos
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter_test_delegate.h b/chrome/browser/ash/login/reporting/login_logout_reporter_test_delegate.h new file mode 100644 index 0000000..4f26308 --- /dev/null +++ b/chrome/browser/ash/login/reporting/login_logout_reporter_test_delegate.h
@@ -0,0 +1,46 @@ +// Copyright 2021 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_ASH_LOGIN_REPORTING_LOGIN_LOGOUT_REPORTER_TEST_DELEGATE_H_ +#define CHROME_BROWSER_ASH_LOGIN_REPORTING_LOGIN_LOGOUT_REPORTER_TEST_DELEGATE_H_ + +#include "chrome/browser/ash/login/reporting/login_logout_reporter.h" + +#include "components/policy/core/common/cloud/dm_token.h" +#include "components/reporting/client/mock_report_queue.h" + +namespace chromeos { +namespace reporting { + +class LoginLogoutReporterTestDelegate : public LoginLogoutReporter::Delegate { + public: + LoginLogoutReporterTestDelegate( + bool should_report_event, + bool should_report_user, + policy::DMToken dm_token, + std::unique_ptr<::reporting::MockReportQueue> mock_queue); + ~LoginLogoutReporterTestDelegate() override; + + void CreateReportingQueue( + std::unique_ptr<::reporting::ReportQueueConfiguration> config, + ::reporting::ReportQueueProvider::CreateReportQueueCallback + create_queue_cb) override; + + bool ShouldReportEvent() const override; + + bool ShouldReportUser(base::StringPiece) const override; + + policy::DMToken GetDMToken() const override; + + private: + const bool should_report_event_; + const bool should_report_user_; + const policy::DMToken dm_token_; + + std::unique_ptr<::reporting::MockReportQueue> mock_queue_; +}; +} // namespace reporting +} // namespace chromeos + +#endif // CHROME_BROWSER_ASH_LOGIN_REPORTING_LOGIN_LOGOUT_REPORTER_TEST_DELEGATE_H_
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc b/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc new file mode 100644 index 0000000..e107ec6 --- /dev/null +++ b/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc
@@ -0,0 +1,198 @@ +// Copyright 2021 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/ash/login/reporting/login_logout_reporter_test_delegate.h" + +#include "base/memory/ptr_util.h" +#include "base/test/task_environment.h" +#include "components/policy/core/common/cloud/dm_token.h" +#include "components/reporting/client/mock_report_queue.h" + +namespace chromeos { +namespace reporting { + +TEST(LoginLogoutReporterTest, ReportAffiliatedLogin) { + static constexpr char user_email[] = "affiliated@managed.org"; + auto mock_queue = + std::make_unique<testing::StrictMock<::reporting::MockReportQueue>>(); + + LoginLogoutRecord record; + ::reporting::Priority priority; + EXPECT_CALL(*mock_queue, AddRecord) + .WillOnce( + [&record, &priority](base::StringPiece record_string, + ::reporting::Priority event_priority, + ::reporting::ReportQueue::EnqueueCallback) { + record.ParseFromString(std::string(record_string)); + priority = event_priority; + }); + + auto test_delegate = std::make_unique<LoginLogoutReporterTestDelegate>( + /* should_report_event= */ true, + /* should_report_user= */ true, + policy::DMToken::CreateValidTokenForTesting("token"), + std::move(mock_queue)); + + LoginLogoutReporter reporter(std::move(test_delegate)); + reporter.MaybeReportLogin(user_email); + + EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE)); + EXPECT_TRUE(record.has_event_timestamp()); + EXPECT_FALSE(record.has_logout_event()); + ASSERT_TRUE(record.has_affiliated_user()); + ASSERT_TRUE(record.affiliated_user().has_user_email()); + EXPECT_THAT(record.affiliated_user().user_email(), testing::Eq(user_email)); + ASSERT_TRUE(record.has_login_event()); + EXPECT_FALSE(record.login_event().has_failure()); +} + +TEST(LoginLogoutReporterTest, ReportUnaffiliatedLogin) { + static constexpr char user_email[] = "unaffiliated@unmanaged.org"; + auto mock_queue = + std::make_unique<testing::StrictMock<::reporting::MockReportQueue>>(); + + LoginLogoutRecord record; + ::reporting::Priority priority; + EXPECT_CALL(*mock_queue, AddRecord) + .WillOnce( + [&record, &priority](base::StringPiece record_string, + ::reporting::Priority event_priority, + ::reporting::ReportQueue::EnqueueCallback) { + record.ParseFromString(std::string(record_string)); + priority = event_priority; + }); + + auto test_delegate = std::make_unique<LoginLogoutReporterTestDelegate>( + /* should_report_event= */ true, + /* should_report_user= */ false, + policy::DMToken::CreateValidTokenForTesting("token"), + std::move(mock_queue)); + + LoginLogoutReporter reporter(std::move(test_delegate)); + reporter.MaybeReportLogin(user_email); + + EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE)); + EXPECT_TRUE(record.has_event_timestamp()); + EXPECT_FALSE(record.has_logout_event()); + EXPECT_FALSE(record.has_affiliated_user()); + ASSERT_TRUE(record.has_login_event()); + EXPECT_FALSE(record.login_event().has_failure()); +} + +TEST(LoginLogoutReporterTest, ReportAffiliatedLogout) { + static constexpr char user_email[] = "affiliated@managed.org"; + auto mock_queue = + std::make_unique<testing::StrictMock<::reporting::MockReportQueue>>(); + + LoginLogoutRecord record; + ::reporting::Priority priority; + EXPECT_CALL(*mock_queue, AddRecord) + .WillOnce( + [&record, &priority](base::StringPiece record_string, + ::reporting::Priority event_priority, + ::reporting::ReportQueue::EnqueueCallback) { + record.ParseFromString(std::string(record_string)); + priority = event_priority; + }); + + auto test_delegate = std::make_unique<LoginLogoutReporterTestDelegate>( + /* should_report_event= */ true, + /* should_report_user= */ true, + policy::DMToken::CreateValidTokenForTesting("token"), + std::move(mock_queue)); + + LoginLogoutReporter reporter(std::move(test_delegate)); + reporter.MaybeReportLogout(user_email); + + EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE)); + EXPECT_TRUE(record.has_event_timestamp()); + EXPECT_FALSE(record.has_login_event()); + EXPECT_TRUE(record.has_logout_event()); + ASSERT_TRUE(record.has_affiliated_user()); + ASSERT_TRUE(record.affiliated_user().has_user_email()); + EXPECT_THAT(record.affiliated_user().user_email(), testing::Eq(user_email)); +} + +TEST(LoginLogoutReporterTest, ReportUnaffiliatedLogout) { + static constexpr char user_email[] = "unaffiliated@unmanaged.org"; + auto mock_queue = + std::make_unique<testing::StrictMock<::reporting::MockReportQueue>>(); + + LoginLogoutRecord record; + ::reporting::Priority priority; + EXPECT_CALL(*mock_queue, AddRecord) + .WillOnce( + [&record, &priority](base::StringPiece record_string, + ::reporting::Priority event_priority, + ::reporting::ReportQueue::EnqueueCallback) { + record.ParseFromString(std::string(record_string)); + priority = event_priority; + }); + + auto test_delegate = std::make_unique<LoginLogoutReporterTestDelegate>( + /* should_report_event= */ true, + /* should_report_user= */ false, + policy::DMToken::CreateValidTokenForTesting("token"), + std::move(mock_queue)); + + LoginLogoutReporter reporter(std::move(test_delegate)); + reporter.MaybeReportLogout(user_email); + + EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE)); + EXPECT_TRUE(record.has_event_timestamp()); + EXPECT_FALSE(record.has_login_event()); + EXPECT_TRUE(record.has_logout_event()); + EXPECT_FALSE(record.has_affiliated_user()); +} + +TEST(LoginLogoutReporterTest, InvalidDMToken) { + static constexpr char user_email[] = "affiliated@managed.org"; + auto mock_queue = + std::make_unique<testing::StrictMock<::reporting::MockReportQueue>>(); + + EXPECT_CALL(*mock_queue, AddRecord).Times(0); + + auto test_delegate = std::make_unique<LoginLogoutReporterTestDelegate>( + /* should_report_event= */ true, + /* should_report_user= */ true, + policy::DMToken::CreateInvalidTokenForTesting(), std::move(mock_queue)); + + LoginLogoutReporter reporter(std::move(test_delegate)); + reporter.MaybeReportLogout(user_email); +} + +TEST(LoginLogoutReporterTest, EmptyDMToken) { + static constexpr char user_email[] = "affiliated@managed.org"; + auto mock_queue = + std::make_unique<testing::StrictMock<::reporting::MockReportQueue>>(); + + EXPECT_CALL(*mock_queue, AddRecord).Times(0); + + auto test_delegate = std::make_unique<LoginLogoutReporterTestDelegate>( + /* should_report_event= */ true, + /* should_report_user= */ true, + policy::DMToken::CreateEmptyTokenForTesting(), std::move(mock_queue)); + + LoginLogoutReporter reporter(std::move(test_delegate)); + reporter.MaybeReportLogout(user_email); +} + +TEST(LoginLogoutReporterTest, ShouldNotReportEvent) { + static constexpr char user_email[] = "affiliated@managed.org"; + auto mock_queue = + std::make_unique<testing::StrictMock<::reporting::MockReportQueue>>(); + + EXPECT_CALL(*mock_queue, AddRecord).Times(0); + + auto test_delegate = std::make_unique<LoginLogoutReporterTestDelegate>( + /* should_report_event= */ false, + /* should_report_user= */ true, + policy::DMToken::CreateValidTokenForTesting("token"), + std::move(mock_queue)); + + LoginLogoutReporter reporter(std::move(test_delegate)); + reporter.MaybeReportLogout(user_email); +} +} // namespace reporting +} // namespace chromeos
diff --git a/chrome/browser/ash/login/saml/in_session_password_sync_manager.h b/chrome/browser/ash/login/saml/in_session_password_sync_manager.h index 89e976b..093cd2d 100644 --- a/chrome/browser/ash/login/saml/in_session_password_sync_manager.h +++ b/chrome/browser/ash/login/saml/in_session_password_sync_manager.h
@@ -8,7 +8,6 @@ #include <memory> #include <string> -#include "base/observer_list.h" #include "base/time/clock.h" #include "chrome/browser/ash/login/saml/password_sync_token_fetcher.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.h b/chrome/browser/ash/login/users/chrome_user_manager_impl.h index 2d622789..6c90872 100644 --- a/chrome/browser/ash/login/users/chrome_user_manager_impl.h +++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.h
@@ -13,7 +13,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/scoped_observation.h" #include "base/synchronization/lock.h" #include "chrome/browser/ash/login/user_flow.h"
diff --git a/chrome/browser/ash/notifications/screen_capture_notification_ui_ash.h b/chrome/browser/ash/notifications/screen_capture_notification_ui_ash.h index 7420f863..ec4f5302 100644 --- a/chrome/browser/ash/notifications/screen_capture_notification_ui_ash.h +++ b/chrome/browser/ash/notifications/screen_capture_notification_ui_ash.h
@@ -6,7 +6,6 @@ #define CHROME_BROWSER_ASH_NOTIFICATIONS_SCREEN_CAPTURE_NOTIFICATION_UI_ASH_H_ #include "base/macros.h" -#include "base/observer_list.h" #include "chrome/browser/ui/screen_capture_notification_ui.h" namespace ash {
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_manager.h b/chrome/browser/ash/plugin_vm/plugin_vm_manager.h index e51848a..9f57192 100644 --- a/chrome/browser/ash/plugin_vm/plugin_vm_manager.h +++ b/chrome/browser/ash/plugin_vm/plugin_vm_manager.h
@@ -8,7 +8,6 @@ #include <string> #include "base/callback_forward.h" -#include "base/observer_list.h" #include "chromeos/dbus/vm_plugin_dispatcher/vm_plugin_dispatcher.pb.h" #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/ash/web_applications/personalization_app/OWNERS b/chrome/browser/ash/web_applications/personalization_app/OWNERS new file mode 100644 index 0000000..3230dba1 --- /dev/null +++ b/chrome/browser/ash/web_applications/personalization_app/OWNERS
@@ -0,0 +1 @@ +file://chromeos/components/personalization_app/OWNERS
diff --git a/chrome/browser/ash/web_applications/chrome_personalization_app_ui_delegate.cc b/chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.cc similarity index 98% rename from chrome/browser/ash/web_applications/chrome_personalization_app_ui_delegate.cc rename to chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.cc index f54f12d..3566b3a 100644 --- a/chrome/browser/ash/web_applications/chrome_personalization_app_ui_delegate.cc +++ b/chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/web_applications/chrome_personalization_app_ui_delegate.h" +#include "chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.h" #include <stdint.h>
diff --git a/chrome/browser/ash/web_applications/chrome_personalization_app_ui_delegate.h b/chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.h similarity index 90% rename from chrome/browser/ash/web_applications/chrome_personalization_app_ui_delegate.h rename to chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.h index 4d1166b..40e3e9e 100644 --- a/chrome/browser/ash/web_applications/chrome_personalization_app_ui_delegate.h +++ b/chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_ASH_WEB_APPLICATIONS_CHROME_PERSONALIZATION_APP_UI_DELEGATE_H_ -#define CHROME_BROWSER_ASH_WEB_APPLICATIONS_CHROME_PERSONALIZATION_APP_UI_DELEGATE_H_ +#ifndef CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_CHROME_PERSONALIZATION_APP_UI_DELEGATE_H_ +#define CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_CHROME_PERSONALIZATION_APP_UI_DELEGATE_H_ #include "chromeos/components/personalization_app/personalization_app_ui_delegate.h" @@ -97,4 +97,4 @@ Profile* const profile_ = nullptr; }; -#endif // CHROME_BROWSER_ASH_WEB_APPLICATIONS_CHROME_PERSONALIZATION_APP_UI_DELEGATE_H_ +#endif // CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_CHROME_PERSONALIZATION_APP_UI_DELEGATE_H_
diff --git a/chrome/browser/ash/web_applications/personalization_app_info.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_info.cc similarity index 97% rename from chrome/browser/ash/web_applications/personalization_app_info.cc rename to chrome/browser/ash/web_applications/personalization_app/personalization_app_info.cc index caf7e43..0ef796f 100644 --- a/chrome/browser/ash/web_applications/personalization_app_info.cc +++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_info.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/web_applications/personalization_app_info.h" +#include "chrome/browser/ash/web_applications/personalization_app/personalization_app_info.h" #include <memory>
diff --git a/chrome/browser/ash/web_applications/personalization_app_info.h b/chrome/browser/ash/web_applications/personalization_app/personalization_app_info.h similarity index 85% rename from chrome/browser/ash/web_applications/personalization_app_info.h rename to chrome/browser/ash/web_applications/personalization_app/personalization_app_info.h index 323391c..0dd86ad 100644 --- a/chrome/browser/ash/web_applications/personalization_app_info.h +++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_info.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_INFO_H_ -#define CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_INFO_H_ +#ifndef CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_PERSONALIZATION_APP_INFO_H_ +#define CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_PERSONALIZATION_APP_INFO_H_ #include <memory> @@ -12,4 +12,4 @@ // Return a WebApplicationInfo used to install the app. std::unique_ptr<WebApplicationInfo> CreateWebAppInfoForPersonalizationApp(); -#endif // CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_INFO_H_ +#endif // CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_PERSONALIZATION_APP_INFO_H_
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc index 798585e3..f5ff97fb 100644 --- a/chrome/browser/autocomplete/search_provider_unittest.cc +++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -48,6 +48,7 @@ #include "components/search_engines/search_terms_data.h" #include "components/search_engines/template_url.h" #include "components/search_engines/template_url_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_associated_data.h" #include "content/public/test/browser_task_environment.h" #include "net/base/escape.h" @@ -324,6 +325,8 @@ // to avoid a possible race. SearchProviderFeatureTestComponent feature_test_component_; content::BrowserTaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; network::TestURLLoaderFactory test_url_loader_factory_; std::unique_ptr<TestingProfile> profile_;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 54e8cca..910db816 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/browser_process_impl.h" #include <stddef.h> +#include <stdio.h> #include <algorithm> #include <map> @@ -759,6 +760,14 @@ // StartupBrowserCreator::LaunchBrowser can be run multiple times when browser // is started with several profiles or existing browser process is reused. if (!remote_debugging_server_) { + if (!local_state_->GetBoolean(prefs::kDevToolsRemoteDebuggingAllowed)) { + // Follow content/browser/devtools/devtools_http_handler.cc that reports + // its remote debugging port on stderr for symmetry. + fputs("\nDevTools remote debugging is disallowed by the system admin.\n", + stderr); + fflush(stderr); + return; + } remote_debugging_server_ = std::make_unique<RemoteDebuggingServer>(); } #endif @@ -944,6 +953,7 @@ registry->RegisterBooleanPref(metrics::prefs::kMetricsReportingEnabled, GoogleUpdateSettings::GetCollectStatsConsent()); + registry->RegisterBooleanPref(prefs::kDevToolsRemoteDebuggingAllowed, true); } DownloadRequestLimiter* BrowserProcessImpl::download_request_limiter() {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 406bdea1..7c9c03da 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -70,6 +70,7 @@ ":device_policy_remover_generated", ":dlp_policy_event_proto", ":key_permissions_proto", + ":login_logout_record_proto", ":print_job_info_proto", ":screen_brightness_event_proto", ":user_activity_event_proto", @@ -1455,6 +1456,8 @@ "../ash/login/quick_unlock/quick_unlock_utils.h", "../ash/login/reauth_stats.cc", "../ash/login/reauth_stats.h", + "../ash/login/reporting/login_logout_reporter.cc", + "../ash/login/reporting/login_logout_reporter.h", "../ash/login/saml/in_session_password_change_manager.cc", "../ash/login/saml/in_session_password_change_manager.h", "../ash/login/saml/in_session_password_sync_manager.cc", @@ -2021,8 +2024,6 @@ "../ash/web_applications/chrome_camera_app_ui_constants.h", "../ash/web_applications/chrome_camera_app_ui_delegate.cc", "../ash/web_applications/chrome_camera_app_ui_delegate.h", - "../ash/web_applications/chrome_personalization_app_ui_delegate.cc", - "../ash/web_applications/chrome_personalization_app_ui_delegate.h", "../ash/web_applications/connectivity_diagnostics_system_web_app_info.cc", "../ash/web_applications/connectivity_diagnostics_system_web_app_info.h", "../ash/web_applications/crosh_loader.cc", @@ -2053,8 +2054,10 @@ "../ash/web_applications/os_feedback_system_web_app_info.h", "../ash/web_applications/os_settings_web_app_info.cc", "../ash/web_applications/os_settings_web_app_info.h", - "../ash/web_applications/personalization_app_info.cc", - "../ash/web_applications/personalization_app_info.h", + "../ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.cc", + "../ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.h", + "../ash/web_applications/personalization_app/personalization_app_info.cc", + "../ash/web_applications/personalization_app/personalization_app_info.h", "../ash/web_applications/print_management_web_app_info.cc", "../ash/web_applications/print_management_web_app_info.h", "../ash/web_applications/scanning_system_web_app_info.cc", @@ -3399,6 +3402,8 @@ "../ash/login/enrollment/mock_enrollment_screen.h", "../ash/login/mock_network_state_helper.cc", "../ash/login/mock_network_state_helper.h", + "../ash/login/reporting/login_logout_reporter_test_delegate.cc", + "../ash/login/reporting/login_logout_reporter_test_delegate.h", "../ash/login/screens/mock_error_screen.cc", "../ash/login/screens/mock_error_screen.h", "../ash/login/screens/mock_network_screen.cc", @@ -3518,6 +3523,7 @@ "//components/policy/core/common:test_support", "//components/policy/proto", "//components/policy/test_support", + "//components/reporting/client:test_support", "//components/session_manager/core", "//crypto:platform", "//google_apis", @@ -3807,6 +3813,7 @@ "../ash/login/quick_unlock/pin_storage_cryptohome_unittest.cc", "../ash/login/quick_unlock/pin_storage_prefs_unittest.cc", "../ash/login/quick_unlock/quick_unlock_storage_unittest.cc", + "../ash/login/reporting/login_logout_reporter_unittest.cc", "../ash/login/saml/in_session_password_change_manager_unittest.cc", "../ash/login/saml/in_session_password_sync_manager_unittest.cc", "../ash/login/saml/mock_lock_handler.cc", @@ -4478,6 +4485,10 @@ sources = [ "printing/history/print_job_info.proto" ] } +proto_library("login_logout_record_proto") { + sources = [ "../ash/login/reporting/login_logout_record.proto" ] +} + device_policy_remover_path = "$target_gen_dir/device_policy_remover.cc" action("device_policy_remover_generate") {
diff --git a/chrome/browser/chromeos/chromebox_for_meetings/cfm_chrome_services.h b/chrome/browser/chromeos/chromebox_for_meetings/cfm_chrome_services.h index d719d34..6ec99ab 100644 --- a/chrome/browser/chromeos/chromebox_for_meetings/cfm_chrome_services.h +++ b/chrome/browser/chromeos/chromebox_for_meetings/cfm_chrome_services.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_CHROMEOS_CHROMEBOX_FOR_MEETINGS_CFM_CHROME_SERVICES_H_ #define CHROME_BROWSER_CHROMEOS_CHROMEBOX_FOR_MEETINGS_CFM_CHROME_SERVICES_H_ -#include "base/observer_list.h" #include "base/observer_list_types.h" namespace chromeos {
diff --git a/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.cc b/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.cc index c05fc77..d8b81918 100644 --- a/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.cc +++ b/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.cc
@@ -83,6 +83,7 @@ std::move(response), std::move(response_sender), borealis::Expected<borealis::BorealisDiskManager::GetDiskInfoResponse, std::string>::Unexpected(std::move(error))); + return; } borealis::BorealisService::GetForProfile( @@ -122,6 +123,7 @@ OnRequestSpace(std::move(response), std::move(response_sender), borealis::Expected<uint64_t, std::string>::Unexpected( std::move(error))); + return; } borealis::BorealisService::GetForProfile( @@ -162,12 +164,13 @@ OnReleaseSpace(std::move(response), std::move(response_sender), borealis::Expected<uint64_t, std::string>::Unexpected( std::move(error))); + return; } borealis::BorealisService::GetForProfile( ProfileManager::GetPrimaryUserProfile()) ->DiskManagerDispatcher() - .RequestSpace( + .ReleaseSpace( request.origin().vm_name(), request.origin().container_name(), request.space_to_release(), base::BindOnce(&VmDiskManagementServiceProvider::OnReleaseSpace,
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc index 735ecd27..bbd0f04e 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc
@@ -24,8 +24,8 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h" #include "components/arc/arc_prefs.h" -#include "components/arc/arc_util.h" #include "components/arc/session/connection_holder.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "components/feature_engagement/public/feature_constants.h"
diff --git a/chrome/browser/chromeos/extensions/info_private_apitest.cc b/chrome/browser/chromeos/extensions/info_private_apitest.cc index fe7b884a..9bc2291 100644 --- a/chrome/browser/chromeos/extensions/info_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/info_private_apitest.cc
@@ -15,7 +15,7 @@ #include "chrome/common/pref_names.h" #include "chromeos/settings/cros_settings_names.h" #include "chromeos/tpm/stub_install_attributes.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/prefs/pref_service.h" #include "content/public/test/browser_test.h" #include "ui/aura/window.h"
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 04ce1f2..fc8deaf1 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -85,6 +85,7 @@ #include "components/arc/arc_service_manager.h" #include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_file_system_instance.h" #include "components/drive/drive_pref_names.h"
diff --git a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc index bd20fef..edf0069 100644 --- a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc +++ b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc
@@ -38,9 +38,9 @@ #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/mojom/app.mojom.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_app_instance.h" #include "components/exo/buffer.h" #include "components/exo/shell_surface_util.h" @@ -224,8 +224,10 @@ return apps; } -// Creates an exo app window and sets its shell application id. -views::Widget* CreateExoWindow(const std::string& window_app_id) { +// Creates an exo app window, and sets `window_app_id` for its shell application +// id, `app_id` for the window property `::full_restore::kAppIdKey`. +views::Widget* CreateExoWindow(const std::string& window_app_id, + const std::string& app_id) { views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(5, 5, 20, 20); params.context = ash::Shell::GetPrimaryRootWindow(); @@ -236,6 +238,10 @@ ExoAppTypeResolver().PopulateProperties(resolver_params, params.init_properties_container); + if (!app_id.empty()) + params.init_properties_container.SetProperty(::full_restore::kAppIdKey, + app_id); + views::Widget* widget = new views::Widget(); widget->Init(std::move(params)); @@ -251,6 +257,12 @@ return widget; } +// Calls the above function to create an exo app window, and sets +// `window_app_id` for its shell application id, with an empty app id. +views::Widget* CreateExoWindow(const std::string& window_app_id) { + return CreateExoWindow(window_app_id, std::string()); +} + // Gets the browser whose restore window id is same as `window_id`. Browser* GetBrowserForWindowId(int32_t window_id) { for (Browser* browser : *BrowserList::GetInstance()) { @@ -898,7 +910,8 @@ void Restore() { test_full_restore_info_observer_.Reset(); - app_launch_handler()->SetShouldRestore(); + app_launch_handler_ = std::make_unique<AppLaunchHandler>(profile()); + app_launch_handler_->SetShouldRestore(); content::RunAllTasksUntilIdle(); } @@ -1093,6 +1106,178 @@ RemoveInactiveDesks(); } +// Test restoration when the ARC ghost window is created before OnTaskCreated is +// called. +IN_PROC_BROWSER_TEST_F(AppLaunchHandlerArcAppBrowserTest, + RestoreArcGhostWindow) { + SetProfile(); + InstallTestApps(kTestAppPackage, false); + + const std::string app_id = GetTestApp1Id(kTestAppPackage); + int32_t session_id1 = + ::full_restore::FullRestoreSaveHandler::GetInstance()->GetArcSessionId(); + ::full_restore::FullRestoreInfo::GetInstance()->AddObserver( + test_full_restore_info_observer()); + + SaveAppLaunchInfo(app_id, session_id1); + + // Create the window for app1. The task id needs to match the |window_app_id| + // arg of CreateExoWindow. + int32_t kTaskId1 = 100; + views::Widget* widget = CreateExoWindow("org.chromium.arc.100"); + aura::Window* window = widget->GetNativeWindow(); + + VerifyObserver(window, /*launch_count=*/0, /*init_count=*/0); + VerifyWindowProperty(window, kTaskId1, /*restore_window_id=*/0, + /*hidden=*/false); + + // Simulate creating the task. + CreateTask(app_id, kTaskId1, session_id1); + + VerifyObserver(window, /*launch_count=*/1, /*init_count=*/0); + + SaveWindowInfo(window); + + WaitForAppLaunchInfoSaved(); + + Restore(); + widget->CloseNow(); + + app_host()->OnTaskDestroyed(kTaskId1); + + int32_t session_id2 = + ::full_restore::FullRestoreReadHandler::GetInstance()->GetArcSessionId(); + ::full_restore::FullRestoreReadHandler::GetInstance() + ->SetArcSessionIdForWindowId(session_id2, kTaskId1); + + // Create the window with the ghost window session to simulate the ghost + // window restoration for the app. + widget = CreateExoWindow( + base::StringPrintf("org.chromium.arc.session.%d", session_id2), app_id); + window = widget->GetNativeWindow(); + + SaveAppLaunchInfo(app_id, session_id2); + + // The ghost window should not be hidden. + VerifyWindowProperty(window, /*window_id*/ 0, + /*restore_window_id*/ kTaskId1, + /*hidden=*/false); + + // Simulate creating the task for the restored window. + int32_t kTaskId2 = 200; + window->SetProperty(::full_restore::kWindowIdKey, kTaskId2); + CreateTask(app_id, kTaskId2, session_id2); + + VerifyWindowProperty(window, kTaskId2, kTaskId1, /*hidden=*/false); + VerifyWindowInfo(window, kActivationIndex); + + // Destroy the task and close the window. + app_host()->OnTaskDestroyed(kTaskId2); + widget->CloseNow(); + + ::full_restore::FullRestoreInfo::GetInstance()->RemoveObserver( + test_full_restore_info_observer()); + StopInstance(); + + RemoveInactiveDesks(); +} + +// Test the ARC ghost window is saved if the task is not created. +IN_PROC_BROWSER_TEST_F(AppLaunchHandlerArcAppBrowserTest, SaveArcGhostWindow) { + SetProfile(); + InstallTestApps(kTestAppPackage, false); + + const std::string app_id = GetTestApp1Id(kTestAppPackage); + int32_t session_id1 = + ::full_restore::FullRestoreSaveHandler::GetInstance()->GetArcSessionId(); + ::full_restore::FullRestoreInfo::GetInstance()->AddObserver( + test_full_restore_info_observer()); + + SaveAppLaunchInfo(app_id, session_id1); + + // Create the window for app1. The task id needs to match the |window_app_id| + // arg of CreateExoWindow. + int32_t kTaskId1 = 100; + views::Widget* widget = CreateExoWindow("org.chromium.arc.100"); + aura::Window* window = widget->GetNativeWindow(); + + VerifyObserver(window, /*launch_count=*/0, /*init_count=*/0); + VerifyWindowProperty(window, kTaskId1, /*restore_window_id=*/0, + /*hidden=*/false); + + // Simulate creating the task. + CreateTask(app_id, kTaskId1, session_id1); + + VerifyObserver(window, /*launch_count=*/1, /*init_count=*/0); + + SaveWindowInfo(window); + + WaitForAppLaunchInfoSaved(); + + // Simulate the system reboot. + Restore(); + widget->CloseNow(); + + app_host()->OnTaskDestroyed(kTaskId1); + + int32_t session_id2 = + ::full_restore::FullRestoreReadHandler::GetInstance()->GetArcSessionId(); + ::full_restore::FullRestoreReadHandler::GetInstance() + ->SetArcSessionIdForWindowId(session_id2, kTaskId1); + + // Create the window with the ghost window session to simulate the ghost + // window restoration for the app. + widget = CreateExoWindow( + base::StringPrintf("org.chromium.arc.session.%d", session_id2), app_id); + window = widget->GetNativeWindow(); + + SaveAppLaunchInfo(app_id, session_id2); + SaveWindowInfo(window); + + // The ghost window should not be hidden. + VerifyWindowProperty(window, /*window_id*/ 0, + /*restore_window_id*/ kTaskId1, + /*hidden=*/false); + + WaitForAppLaunchInfoSaved(); + + // Simulate the system reboot before the task id is created. + Restore(); + widget->CloseNow(); + + int32_t session_id3 = + ::full_restore::FullRestoreReadHandler::GetInstance()->GetArcSessionId(); + ::full_restore::FullRestoreReadHandler::GetInstance() + ->SetArcSessionIdForWindowId(session_id3, session_id2); + + // Create the window with the ghost window session to simulate the ghost + // window restoration for the app. + widget = CreateExoWindow( + base::StringPrintf("org.chromium.arc.session.%d", session_id3), app_id); + window = widget->GetNativeWindow(); + + SaveAppLaunchInfo(app_id, session_id3); + SaveWindowInfo(window); + + // Simulate creating the task for the restored window. + int32_t kTaskId2 = 200; + CreateTask(app_id, kTaskId2, session_id3); + window->SetProperty(::full_restore::kWindowIdKey, kTaskId2); + + VerifyWindowProperty(window, kTaskId2, session_id2, /*hidden=*/false); + VerifyWindowInfo(window, kActivationIndex); + + // Destroy the task and close the window. + app_host()->OnTaskDestroyed(kTaskId2); + widget->CloseNow(); + + ::full_restore::FullRestoreInfo::GetInstance()->RemoveObserver( + test_full_restore_info_observer()); + StopInstance(); + + RemoveInactiveDesks(); +} + // Test restoration with multiple ARC apps, when the ARC windows are created // before and after OnTaskCreated is called. IN_PROC_BROWSER_TEST_F(AppLaunchHandlerArcAppBrowserTest,
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service_factory.cc b/chrome/browser/chromeos/full_restore/full_restore_service_factory.cc index fbcdc81..768bb72 100644 --- a/chrome/browser/chromeos/full_restore/full_restore_service_factory.cc +++ b/chrome/browser/chromeos/full_restore/full_restore_service_factory.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/chromeos/full_restore/full_restore_service_factory.h" #include "ash/public/cpp/ash_features.h" +#include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/chromeos/full_restore/full_restore_service.h" @@ -42,6 +43,9 @@ if (!ash::features::IsFullRestoreEnabled()) return nullptr; + if (chrome::IsRunningInForcedAppMode()) + return nullptr; + // No service for non-regular user profile, or ephemeral user profile, system // profile. Profile* profile = Profile::FromBrowserContext(context);
diff --git a/chrome/browser/chromeos/platform_keys/extension_platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/extension_platform_keys_service.cc index b23272f..fd35717 100644 --- a/chrome/browser/chromeos/platform_keys/extension_platform_keys_service.cc +++ b/chrome/browser/chromeos/platform_keys/extension_platform_keys_service.cc
@@ -25,6 +25,7 @@ #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h" #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chromeos/crosapi/cpp/keystore_service_util.h" #include "chromeos/crosapi/mojom/keystore_error.mojom.h" #include "chromeos/crosapi/mojom/keystore_service.mojom.h" #include "content/public/browser/browser_context.h" @@ -50,6 +51,8 @@ #endif // #if BUILDFLAG(IS_CHROMEOS_ASH) using content::BrowserThread; +using crosapi::keystore_service_util::MakeEcKeystoreSigningAlgorithm; +using crosapi::keystore_service_util::MakeRsaKeystoreSigningAlgorithm; using crosapi::mojom::KeystoreBinaryResult; using crosapi::mojom::KeystoreBinaryResultPtr; using crosapi::mojom::KeystoreECDSAParams; @@ -328,14 +331,9 @@ private: // Generates the RSA key. void GenerateKey(KeystoreService::GenerateKeyCallback callback) override { - KeystoreSigningAlgorithmPtr algorithm = KeystoreSigningAlgorithm::New(); - KeystorePKCS115ParamsPtr params = KeystorePKCS115Params::New(); - params->modulus_length = modulus_length_; - algorithm->set_pkcs115(std::move(params)); - - service_->keystore_service_->GenerateKey(KeystoreTypeFromTokenId(token_id_), - std::move(algorithm), - std::move(callback)); + service_->keystore_service_->GenerateKey( + KeystoreTypeFromTokenId(token_id_), + MakeRsaKeystoreSigningAlgorithm(modulus_length_), std::move(callback)); } const unsigned int modulus_length_; @@ -359,14 +357,9 @@ private: // Generates the EC key. void GenerateKey(KeystoreService::GenerateKeyCallback callback) override { - KeystoreSigningAlgorithmPtr algorithm = KeystoreSigningAlgorithm::New(); - KeystoreECDSAParamsPtr params = KeystoreECDSAParams::New(); - params->named_curve = named_curve_; - algorithm->set_ecdsa(std::move(params)); - - service_->keystore_service_->GenerateKey(KeystoreTypeFromTokenId(token_id_), - std::move(algorithm), - std::move(callback)); + service_->keystore_service_->GenerateKey( + KeystoreTypeFromTokenId(token_id_), + MakeEcKeystoreSigningAlgorithm(named_curve_), std::move(callback)); } const std::string named_curve_;
diff --git a/chrome/browser/chromeos/policy/arc/unaffiliated_arc_allowed_browsertest.cc b/chrome/browser/chromeos/policy/arc/unaffiliated_arc_allowed_browsertest.cc index 32236e5..ef92d13 100644 --- a/chrome/browser/chromeos/policy/arc/unaffiliated_arc_allowed_browsertest.cc +++ b/chrome/browser/chromeos/policy/arc/unaffiliated_arc_allowed_browsertest.cc
@@ -20,7 +20,7 @@ #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h" #include "chromeos/settings/cros_settings_names.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/policy/proto/chrome_device_policy.pb.h" #include "content/public/test/browser_test.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc index a4ea8ffe..d710d23 100644 --- a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc +++ b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
@@ -24,7 +24,7 @@ #include "chromeos/settings/cros_settings_names.h" #include "components/account_id/account_id.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/policy/proto/chrome_device_policy.pb.h" #include "components/user_manager/scoped_user_manager.h"
diff --git a/chrome/browser/chromeos/policy/login/wildcard_login_checker.cc b/chrome/browser/chromeos/policy/login/wildcard_login_checker.cc index 2da5d84e..a8b94f0 100644 --- a/chrome/browser/chromeos/policy/login/wildcard_login_checker.cc +++ b/chrome/browser/chromeos/policy/login/wildcard_login_checker.cc
@@ -18,6 +18,9 @@ namespace { +// The oauth token consumer name. +const char kOAuthConsumerName[] = "policy_wildcard_login_checker"; + // Presence of this key in the userinfo response indicates whether the user is // on a hosted domain. const char kHostedDomainKey[] = "hd"; @@ -36,7 +39,7 @@ callback_ = std::move(callback); - token_fetcher_ = PolicyOAuth2TokenFetcher::CreateInstance(); + token_fetcher_ = PolicyOAuth2TokenFetcher::CreateInstance(kOAuthConsumerName); token_fetcher_->StartWithRefreshToken( refresh_token, g_browser_process->system_network_context_manager()
diff --git a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc index 0fd942ab..b4d0164b 100644 --- a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc +++ b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc
@@ -41,7 +41,7 @@ public GaiaAuthConsumer, public OAuth2AccessTokenConsumer { public: - PolicyOAuth2TokenFetcherImpl(); + explicit PolicyOAuth2TokenFetcherImpl(const std::string& consumer_name); ~PolicyOAuth2TokenFetcherImpl() override; private: @@ -75,6 +75,7 @@ void OnGetTokenSuccess( const OAuth2AccessTokenConsumer::TokenResponse& token_response) override; void OnGetTokenFailure(const GoogleServiceAuthError& error) override; + std::string GetConsumerName() const override { return consumer_name_; } // Starts fetching OAuth2 refresh token. void StartFetchingRefreshToken(); @@ -116,12 +117,16 @@ // The callback to invoke when done. TokenCallback callback_; + const std::string consumer_name_; + base::WeakPtrFactory<PolicyOAuth2TokenFetcherImpl> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(PolicyOAuth2TokenFetcherImpl); }; -PolicyOAuth2TokenFetcherImpl::PolicyOAuth2TokenFetcherImpl() {} +PolicyOAuth2TokenFetcherImpl::PolicyOAuth2TokenFetcherImpl( + const std::string& consumer_name) + : consumer_name_(consumer_name) {} PolicyOAuth2TokenFetcherImpl::~PolicyOAuth2TokenFetcherImpl() {} @@ -294,10 +299,10 @@ // static std::unique_ptr<PolicyOAuth2TokenFetcher> -PolicyOAuth2TokenFetcher::CreateInstance() { +PolicyOAuth2TokenFetcher::CreateInstance(const std::string& consumer_name) { if (use_fake_tokens_for_testing_) return std::make_unique<PolicyOAuth2TokenFetcherFake>(); - return std::make_unique<PolicyOAuth2TokenFetcherImpl>(); + return std::make_unique<PolicyOAuth2TokenFetcherImpl>(consumer_name); } PolicyOAuth2TokenFetcher::PolicyOAuth2TokenFetcher() {}
diff --git a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h index 3e5dd166..c18aa35d 100644 --- a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h +++ b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h
@@ -27,7 +27,8 @@ class PolicyOAuth2TokenFetcher { public: // Allocates a PolicyOAuth2TokenFetcher instance. - static std::unique_ptr<PolicyOAuth2TokenFetcher> CreateInstance(); + static std::unique_ptr<PolicyOAuth2TokenFetcher> CreateInstance( + const std::string& consumer_name); // Makes CreateInstance() return a fake token fetcher that does not make // network calls so tests can avoid a dependency on GAIA.
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc index bce58e5b..e9cc91c 100644 --- a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc +++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
@@ -29,6 +29,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #include "base/posix/eintr_wrapper.h" +#include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -716,6 +717,7 @@ cros_healthd_data_fetcher, bool report_system_info, bool report_vpd_info) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); cros_healthd_data_fetcher.Run( CrosHealthdCollectionMode::kFull, base::BindOnce(&DeviceStatusCollectorState::OnCrosHealthdDataReceived, @@ -748,6 +750,7 @@ void FetchGraphicsStatus( const policy::DeviceStatusCollector::GraphicsStatusFetcher& graphics_status_fetcher) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); graphics_status_fetcher.Run(base::BindOnce( &DeviceStatusCollectorState::OnGraphicsStatusReceived, this)); } @@ -755,12 +758,19 @@ void FetchCrashReportInfo( const policy::DeviceStatusCollector::CrashReportInfoFetcher& crash_report_fetcher) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); crash_report_fetcher.Run(base::BindOnce( &DeviceStatusCollectorState::OnCrashReportInfoReceived, this)); } + void SetDeviceStatusReported() { device_status_reported_ = true; } + private: - ~DeviceStatusCollectorState() override = default; + ~DeviceStatusCollectorState() override { + if (!device_status_reported_) { + response_params_.device_status.reset(); + } + } void OnVolumeInfoReceived(const std::vector<em::VolumeInfo>& volume_info) { response_params_.device_status->clear_volume_infos(); @@ -838,9 +848,13 @@ std::move(kv.second)); } } + if (!response_params_.device_status->mutable_cpu_temp_infos()->empty()) { + SetDeviceStatusReported(); + } - if (probe_result.is_null()) + if (probe_result.is_null()) { return; + } // Process NonRemovableBlockDeviceResult. const auto& block_device_result = probe_result->block_device_result; @@ -969,6 +983,8 @@ break; } } + + SetDeviceStatusReported(); break; } } @@ -1018,6 +1034,7 @@ battery_info_out->add_samples()->CheckTypeAndMergeFrom( it->second); } + SetDeviceStatusReported(); break; } } @@ -1093,6 +1110,7 @@ } } } + SetDeviceStatusReported(); break; } } @@ -1114,6 +1132,7 @@ response_params_.device_status->mutable_timezone_info(); timezone_info_out->set_posix(timezone_info->posix); timezone_info_out->set_region(timezone_info->region); + SetDeviceStatusReported(); break; } } @@ -1139,6 +1158,7 @@ memory_info->available_memory_kib); memory_info_out->set_page_faults_since_last_boot( memory_info->page_faults_since_last_boot); + SetDeviceStatusReported(); break; } } @@ -1162,6 +1182,9 @@ backlight_info_out->set_max_brightness(backlight->max_brightness); backlight_info_out->set_brightness(backlight->brightness); } + if (response_params_.device_status->backlight_info_size() > 0) { + SetDeviceStatusReported(); + } break; } } @@ -1183,6 +1206,9 @@ response_params_.device_status->add_fan_info(); fan_info_out->set_speed_rpm(fan->speed_rpm); } + if (response_params_.device_status->fan_info_size() > 0) { + SetDeviceStatusReported(); + } break; } } @@ -1209,6 +1235,11 @@ adapter_info_out->set_num_connected_devices( adapter->num_connected_devices); } + + if (response_params_.device_status->bluetooth_adapter_info_size() > + 0) { + SetDeviceStatusReported(); + } break; } } @@ -1232,18 +1263,22 @@ if (system_info->first_power_date.has_value()) { system_status_out->set_first_power_date( system_info->first_power_date.value()); + SetDeviceStatusReported(); } if (system_info->manufacture_date.has_value()) { system_status_out->set_manufacture_date( system_info->manufacture_date.value()); + SetDeviceStatusReported(); } if (system_info->product_sku_number.has_value()) { system_status_out->set_vpd_sku_number( system_info->product_sku_number.value()); + SetDeviceStatusReported(); } if (system_info->product_serial_number.has_value()) { system_status_out->set_vpd_serial_number( system_info->product_serial_number.value()); + SetDeviceStatusReported(); } } if (report_system_info) { @@ -1268,6 +1303,7 @@ system_status_out->set_product_name( system_info->product_name.value()); } + SetDeviceStatusReported(); } break; } @@ -1327,6 +1363,7 @@ void OnGraphicsStatusReceived(const em::GraphicsStatus& gs) { *response_params_.device_status->mutable_graphics_status() = gs; + SetDeviceStatusReported(); } void OnCrashReportInfoReceived( @@ -1335,7 +1372,19 @@ for (const em::CrashReportInfo& info : crash_report_infos) { *response_params_.device_status->add_crash_report_infos() = info; } + if (response_params_.device_status->crash_report_infos_size() > 0) { + SetDeviceStatusReported(); + } } + + SEQUENCE_CHECKER(sequence_checker_); + + // Every time the device status is to be reported, the shared object, + // DeviceStatusCollector` is created with this being false. asynchronous + // status collectors then set this variable to true if any data is collected. + // Then, When the `DeviceStatusCollector` object is released, A response is + // generated only if this is true. + bool device_status_reported_ = false; }; TpmStatusInfo::TpmStatusInfo() = default; @@ -2351,10 +2400,7 @@ if (report_storage_status_) state->FetchEMMCLifeTime(emmc_lifetime_fetcher_); - if (ShouldFetchCrosHealthdData()) { - state->FetchCrosHealthdData(cros_healthd_data_fetcher_, report_system_info_, - report_vpd_info_); - } else { + if (!ShouldFetchCrosHealthdData()) { // Sample CPU temperature in a background thread. state->SampleCPUTempInfo(cpu_temp_fetcher_); } @@ -2485,19 +2531,15 @@ return true; } -bool DeviceStatusCollector::GetGraphicsStatus( +void DeviceStatusCollector::GetGraphicsStatus( scoped_refptr<DeviceStatusCollectorState> state) { // Fetch Graphics status on a background thread. state->FetchGraphicsStatus(graphics_status_fetcher_); - - return true; } -bool DeviceStatusCollector::GetCrashReportInfo( +void DeviceStatusCollector::GetCrashReportInfo( scoped_refptr<DeviceStatusCollectorState> state) { state->FetchCrashReportInfo(crash_report_info_fetcher_); - - return true; } void DeviceStatusCollector::GetStatusAsync(StatusCollectorCallback response) { @@ -2562,15 +2604,23 @@ if (report_running_kiosk_app_) anything_reported |= GetRunningKioskApp(status); + // Mark if any of the above functions reported data so that the response is + // sent. + if (anything_reported) + state->SetDeviceStatusReported(); + + // The below calls gather data asynchronously. Because they are asynchronous + // they cannot set anything_reported. Instead They will call + // SetDeviceStatusReported if data is collected. + if (ShouldFetchCrosHealthdData()) + state->FetchCrosHealthdData(cros_healthd_data_fetcher_, report_system_info_, + report_vpd_info_); + if (report_graphics_status_) - anything_reported |= GetGraphicsStatus(state); + GetGraphicsStatus(state); if (report_crash_report_info_ && stat_reporting_pref_) - anything_reported |= GetCrashReportInfo(state); - - // Wipe pointer if we didn't actually add any data. - if (!anything_reported) - state->response_params().device_status.reset(); + GetCrashReportInfo(state); } bool DeviceStatusCollector::GetSessionStatusForUser(
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector.h b/chrome/browser/chromeos/policy/status_collector/device_status_collector.h index 09886f86..b64d0cd7 100644 --- a/chrome/browser/chromeos/policy/status_collector/device_status_collector.h +++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector.h
@@ -283,9 +283,9 @@ enterprise_management::DeviceStatusReportRequest* status); bool GetRunningKioskApp( enterprise_management::DeviceStatusReportRequest* status); - bool GetGraphicsStatus(scoped_refptr<DeviceStatusCollectorState> + void GetGraphicsStatus(scoped_refptr<DeviceStatusCollectorState> state); // Queues async queries! - bool GetCrashReportInfo(scoped_refptr<DeviceStatusCollectorState> + void GetCrashReportInfo(scoped_refptr<DeviceStatusCollectorState> state); // Queues async queries! // Helpers for the various portions of SESSION STATUS. Return true if they
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc index 8fff7e0..4d62100f 100644 --- a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc +++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
@@ -3252,11 +3252,10 @@ base::BindRepeating(&FetchFakeFullCrosHealthdData); RestartStatusCollector(std::move(options)); - // If the ReportDeviceHardwareStatus policy is false, the policies - // corresponding to cros_healthd data are ignored. The policy is true by - // default, but set it explicitly to ensure the other policies are tested. + // Policies set by fetching Cros Healthd Data were once dependent on + // ReportDeviceHardwareStatus being set. Ensure this is no longer the case. scoped_testing_cros_settings_.device_settings()->SetBoolean( - chromeos::kReportDeviceHardwareStatus, true); + chromeos::kReportDeviceHardwareStatus, false); // If none of the relevant policies are set to true, expect that the data from // cros_healthd isn't present in the protobuf. @@ -3464,6 +3463,10 @@ base::BindRepeating(&FetchFakeOptionalCrosHealthdData); RestartStatusCollector(std::move(options)); + // Policies set by fetching Cros Healthd Data were once dependent on + // ReportDeviceHardwareStatus being set. Ensure this is no longer the case. + scoped_testing_cros_settings_.device_settings()->SetBoolean( + chromeos::kReportDeviceHardwareStatus, false); scoped_testing_cros_settings_.device_settings()->SetBoolean( chromeos::kReportDeviceCpuInfo, true); scoped_testing_cros_settings_.device_settings()->SetBoolean( @@ -3488,6 +3491,10 @@ base::BindRepeating(&FetchFakePartialCrosHealthdData); RestartStatusCollector(std::move(options)); + // Policies set by fetching Cros Healthd Data were once dependent on + // ReportDeviceHardwareStatus being set. Ensure this is no longer the case. + scoped_testing_cros_settings_.device_settings()->SetBoolean( + chromeos::kReportDeviceHardwareStatus, false); scoped_testing_cros_settings_.device_settings()->SetBoolean( chromeos::kReportDeviceCpuInfo, true); scoped_testing_cros_settings_.device_settings()->SetBoolean( @@ -3546,12 +3553,10 @@ base::BindRepeating(&FetchFakeFullCrosHealthdData); RestartStatusCollector(std::move(options)); - // If the ReportDeviceHardwareStatus policy is false, the policies - // corresponding to cros_healthd data are ignored. The policy is true by - // default, but set it explicitly to ensure the other policies are tested. + // Policies set by fetching Cros Healthd Data were once dependent on + // ReportDeviceHardwareStatus being set. Ensure this is no longer the case. scoped_testing_cros_settings_.device_settings()->SetBoolean( - chromeos::kReportDeviceHardwareStatus, true); - + chromeos::kReportDeviceHardwareStatus, false); // When the vpd reporting policy is turned on and the system reporting // property is turned off, we only expect the protobuf to only have vpd info. scoped_testing_cros_settings_.device_settings()->SetBoolean(
diff --git a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h index 17c076a8..837db48 100644 --- a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h +++ b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "chrome/browser/ash/notifications/tpm_auto_update_notification.h" #include "chrome/browser/ash/settings/cros_settings.h"
diff --git a/chrome/browser/chromeos/policy/upload_job_unittest.cc b/chrome/browser/chromeos/policy/upload_job_unittest.cc index 19622fe..de9d370 100644 --- a/chrome/browser/chromeos/policy/upload_job_unittest.cc +++ b/chrome/browser/chromeos/policy/upload_job_unittest.cc
@@ -81,6 +81,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& client_id, const std::string& client_secret, + const std::string& consumer_name, const OAuth2AccessTokenManager::ScopeSet& scopes) override; void InvalidateAccessTokenImpl( const CoreAccountId& account_id, @@ -114,6 +115,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& client_id, const std::string& client_secret, + const std::string& consumer_name, const OAuth2AccessTokenManager::ScopeSet& scopes) { GoogleServiceAuthError response_error = GoogleServiceAuthError::AuthErrorNone();
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc index 922fac1..2d3589c 100644 --- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc +++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
@@ -88,6 +88,9 @@ const char kUMAReregistrationResult[] = "Enterprise.UserPolicyChromeOS.ReregistrationResult"; +// The oauth token consumer name. +const char kOAuthConsumerName[] = "user_cloud_policy_manager_chromeos"; + // This enum is used in UMA, items should not be reordered/deleted. New values // should also be added to enums.xml. enum class RegistrationResult { @@ -612,7 +615,8 @@ ash::UserSessionManager::GetInstance()->user_context().GetRefreshToken()); if (!refresh_token.empty()) { - token_fetcher_ = PolicyOAuth2TokenFetcher::CreateInstance(); + token_fetcher_ = + PolicyOAuth2TokenFetcher::CreateInstance(kOAuthConsumerName); token_fetcher_->StartWithRefreshToken( refresh_token, system_url_loader_factory, base::BindOnce(
diff --git a/chrome/browser/chromeos/printing/synced_printers_manager.h b/chrome/browser/chromeos/printing/synced_printers_manager.h index 15d15086..869c39fe 100644 --- a/chrome/browser/chromeos/printing/synced_printers_manager.h +++ b/chrome/browser/chromeos/printing/synced_printers_manager.h
@@ -10,7 +10,6 @@ #include <vector> #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "chromeos/printing/printer_configuration.h" #include "chromeos/printing/printer_translator.h" #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.h b/chrome/browser/chromeos/smb_client/smb_file_system.h index b31f211..b6e44b73 100644 --- a/chrome/browser/chromeos/smb_client/smb_file_system.h +++ b/chrome/browser/chromeos/smb_client/smb_file_system.h
@@ -14,7 +14,6 @@ #include "base/callback.h" #include "base/files/file.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/timer/elapsed_timer.h" #include "chrome/browser/ash/file_system_provider/abort_callback.h" #include "chrome/browser/ash/file_system_provider/provided_file_system_info.h"
diff --git a/chrome/browser/chromeos/throttle_observer.h b/chrome/browser/chromeos/throttle_observer.h index 9f5431d..bae57afd 100644 --- a/chrome/browser/chromeos/throttle_observer.h +++ b/chrome/browser/chromeos/throttle_observer.h
@@ -9,7 +9,6 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" namespace content {
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationDialog.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationDialog.java index 7062bcd4..eb5ea3f6 100644 --- a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationDialog.java +++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationDialog.java
@@ -95,7 +95,6 @@ View background = parent.findViewById(R.id.background); template.mainBackground.apply(background); background.setClipToOutline(true); - ((TextView) parent.findViewById(R.id.title)).setText(template.localizedName); Typeface typeface = model.get(NoteProperties.TYPEFACE); TextView noteText = (TextView) parent.findViewById(R.id.text);
diff --git a/chrome/browser/continuous_search/BUILD.gn b/chrome/browser/continuous_search/BUILD.gn index b6f03542..722da66 100644 --- a/chrome/browser/continuous_search/BUILD.gn +++ b/chrome/browser/continuous_search/BUILD.gn
@@ -143,6 +143,7 @@ "//chrome/browser/ui/android/layouts:java", "//chrome/browser/ui/android/theme:java", "//chrome/test/android:chrome_java_test_support", + "//components/browser_ui/widget/android:java", "//components/url_formatter/android:url_formatter_java", "//content/public/android:content_java", "//third_party/android_deps:robolectric_all_java",
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinator.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinator.java index 81327ab40..bed6713 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinator.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerCoordinator.java
@@ -42,7 +42,7 @@ private final ContinuousSearchContainerMediator mContainerMediator; private final ContinuousSearchListCoordinator mListCoordinator; - private final ContinuousSearchSceneLayer mSceneLayer; + private ContinuousSearchSceneLayer mSceneLayer; private int mResourceId; private final LayoutManager mLayoutManager; private ViewResourceAdapter mResourceAdapter; @@ -63,8 +63,6 @@ mViewStub = containerViewStub; mLayoutManager = layoutManager; mResourceManager = resourceManager; - mSceneLayer = new ContinuousSearchSceneLayer(mResourceManager); - mLayoutManager.addSceneOverlay(mSceneLayer); mContainerMediator = new ContinuousSearchContainerMediator(browserControlsStateProvider, layoutManager, canAnimateNativeBrowserControls, defaultTopContainerHeightSupplier, this::initializeLayout, hideToolbarShadow); @@ -81,6 +79,9 @@ if (mLayoutInitialized) return; mRootView = (ContinuousSearchViewResourceFrameLayout) mViewStub.inflate(); + mSceneLayer = new ContinuousSearchSceneLayer( + mResourceManager, mRootView, mRootView.getShadowHeight()); + mLayoutManager.addSceneOverlay(mSceneLayer); mResourceId = mRootView.getId(); mSceneLayer.setResourceId(mResourceId); mListCoordinator.initializeLayout(mRootView.findViewById(R.id.container_view));
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediator.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediator.java index ee0f888..275d52f 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediator.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediator.java
@@ -139,25 +139,24 @@ + mDefaultTopContainerHeightSupplier.get(); mModel.set(ContinuousSearchContainerProperties.VERTICAL_OFFSET, yOffset); - // Only show the composited view when the UI is partly visible (mid transition) and native - // can run animations. - mModel.set(ContinuousSearchContainerProperties.COMPOSITED_VIEW_VISIBLE, - !mIsTabObscured - && (!uiFullyVisible && isUiVisible - && mCanAnimateNativeBrowserControls.get())); + // Show the composited view when the UI is at least partly visible and native + // can run animations. This change will happen on the next composited frame. + final boolean showCompositedView = + !mIsTabObscured && isUiVisible && mCanAnimateNativeBrowserControls.get(); + mModel.set(ContinuousSearchContainerProperties.COMPOSITED_VIEW_VISIBLE, showCompositedView); // If we're running the animations in native, the Android view should only be visible when // the container is fully shown. Otherwise, the Android view will be visible if it's within - // screen boundaries. - mModel.set(ContinuousSearchContainerProperties.ANDROID_VIEW_VISIBILITY, - mIsTabObscured - ? View.INVISIBLE - : !uiFullyVisible && isUiVisible && mCanAnimateNativeBrowserControls.get() - ? View.GONE - : ((isUiVisible && !mCanAnimateNativeBrowserControls.get()) - || uiFullyVisible - ? View.VISIBLE - : View.GONE)); + // screen boundaries. This change will happen immediately. + final int androidViewState = mIsTabObscured + ? View.INVISIBLE + : !uiFullyVisible && isUiVisible && mCanAnimateNativeBrowserControls.get() + ? View.GONE + : ((isUiVisible && !mCanAnimateNativeBrowserControls.get()) + || uiFullyVisible + ? View.VISIBLE + : View.GONE); + mModel.set(ContinuousSearchContainerProperties.ANDROID_VIEW_VISIBILITY, androidViewState); final boolean doneHiding = !isUiVisible && !mIsVisible; if (doneHiding) {
diff --git a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayer.java b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayer.java index 4cd97db..99d726f 100644 --- a/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayer.java +++ b/chrome/browser/continuous_search/android/java/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayer.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.continuous_search; import android.graphics.RectF; +import android.view.View; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; @@ -12,6 +13,7 @@ import org.chromium.chrome.browser.layouts.components.VirtualView; import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer; import org.chromium.chrome.browser.layouts.scene_layer.SceneOverlayLayer; +import org.chromium.components.browser_ui.widget.ViewResourceFrameLayout; import org.chromium.ui.resources.ResourceManager; import java.util.List; @@ -27,11 +29,16 @@ /** The resource ID used to reference the view bitmap in native. */ private int mResourceId; private int mVerticalOffset; + private int mShadowHeight; private boolean mIsVisible; private final ResourceManager mResourceManager; + private ViewResourceFrameLayout mContainerView; - public ContinuousSearchSceneLayer(ResourceManager resourceManager) { + public ContinuousSearchSceneLayer(ResourceManager resourceManager, + ViewResourceFrameLayout containerView, int shadowHeight) { mResourceManager = resourceManager; + mContainerView = containerView; + mShadowHeight = shadowHeight; } public void setVerticalOffset(int verticalOffset) { @@ -62,8 +69,11 @@ @Override public SceneOverlayLayer getUpdatedSceneOverlayTree( RectF viewport, RectF visibleViewport, ResourceManager resourceManager, float yOffset) { - ContinuousSearchSceneLayerJni.get().updateContinuousSearchLayer( - mNativePtr, mResourceManager, mResourceId, mVerticalOffset); + // The composited view shadow should only be visible if the android toolbar isn't. + boolean isShadowVisible = mContainerView.getVisibility() != View.VISIBLE; + + ContinuousSearchSceneLayerJni.get().updateContinuousSearchLayer(mNativePtr, + mResourceManager, mResourceId, mVerticalOffset, isShadowVisible, mShadowHeight); return this; } @@ -109,6 +119,7 @@ long init(ContinuousSearchSceneLayer caller); void setContentTree(long nativeContinuousSearchSceneLayer, SceneLayer contentTree); void updateContinuousSearchLayer(long nativeContinuousSearchSceneLayer, - ResourceManager resourceManager, int viewResourceId, int offset); + ResourceManager resourceManager, int viewResourceId, int offset, + boolean shadowVisible, int shadowHeight); } }
diff --git a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediatorTest.java b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediatorTest.java index f8e87b7..e1dcaf09 100644 --- a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediatorTest.java +++ b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchContainerMediatorTest.java
@@ -153,7 +153,7 @@ // State 3. Top controls are fully visible. updateBrowserControlParamsAndAssertModel( DEFAULT_CONTAINER_HEIGHT + JAVA_HEIGHT + DEFAULT_MIN_HEIGHT, DEFAULT_MIN_HEIGHT, - true, 0, DEFAULT_CONTAINER_HEIGHT + DEFAULT_MIN_HEIGHT, false, View.VISIBLE); + true, 0, DEFAULT_CONTAINER_HEIGHT + DEFAULT_MIN_HEIGHT, true, View.VISIBLE); Assert.assertNotNull( "Mediator should be registered as a BrowserControlsStateProvider.Observer.", @@ -202,7 +202,7 @@ // State 3. Top controls are fully visible. updateBrowserControlParamsAndAssertModel(DEFAULT_CONTAINER_HEIGHT + JAVA_HEIGHT, 0, true, 0, - DEFAULT_CONTAINER_HEIGHT, false, View.VISIBLE); + DEFAULT_CONTAINER_HEIGHT, true, View.VISIBLE); Assert.assertNotNull( "Mediator should be registered as a BrowserControlsStateProvider.Observer.", @@ -276,12 +276,12 @@ // Top controls are fully visible. updateBrowserControlParamsAndAssertModel(DEFAULT_CONTAINER_HEIGHT + JAVA_HEIGHT, 0, true, 0, - DEFAULT_CONTAINER_HEIGHT, false, View.VISIBLE); + DEFAULT_CONTAINER_HEIGHT, true, View.VISIBLE); mMediator.updateTabObscured(true); Assert.assertTrue("Tab obscurity shouldn't change mMediator.mIsVisible.", mMediator.isVisibleForTesting()); - Assert.assertFalse("Composited view should only be visible while animating.", + Assert.assertTrue("Composited view should be visible.", mModel.get(ContinuousSearchContainerProperties.COMPOSITED_VIEW_VISIBLE)); Assert.assertEquals("Android view should be View.INVISIBLE when tab is obscured.", View.INVISIBLE, @@ -290,7 +290,7 @@ mMediator.updateTabObscured(false); Assert.assertTrue("Tab obscurity shouldn't change mMediator.mIsVisible.", mMediator.isVisibleForTesting()); - Assert.assertFalse("Composited view should only be visible while animating.", + Assert.assertTrue("Composited view should be visible.", mModel.get(ContinuousSearchContainerProperties.COMPOSITED_VIEW_VISIBLE)); Assert.assertEquals("Android view should be View.VISIBLE when tab is not obscured", View.VISIBLE, @@ -338,7 +338,7 @@ // State 3. Top controls are fully visible. updateBrowserControlParamsAndAssertModel(DEFAULT_CONTAINER_HEIGHT + JAVA_HEIGHT, 0, true, 0, - DEFAULT_CONTAINER_HEIGHT, false, View.VISIBLE); + DEFAULT_CONTAINER_HEIGHT, true, View.VISIBLE); } private void triggerShow() {
diff --git a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayerTest.java b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayerTest.java index 2e0631b..16e3a5d 100644 --- a/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayerTest.java +++ b/chrome/browser/continuous_search/android/junit/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchSceneLayerTest.java
@@ -11,6 +11,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.view.View; + import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -26,6 +28,7 @@ import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.browser.layouts.components.VirtualView; import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer; +import org.chromium.components.browser_ui.widget.ViewResourceFrameLayout; import org.chromium.ui.resources.ResourceManager; import java.util.ArrayList; @@ -37,12 +40,15 @@ @RunWith(BaseRobolectricTestRunner.class) public class ContinuousSearchSceneLayerTest { private static final long FAKE_NATIVE_ADDRESS = 123L; + private static final int SHADOW_HEIGHT = 7; @Mock private ResourceManager mResourceManagerMock; @Mock private SceneLayer mContentTree; @Mock private ContinuousSearchSceneLayer.Natives mContinuousSearchSceneLayerJniMock; + @Mock + private ViewResourceFrameLayout mContainerView; private ContinuousSearchSceneLayer mSceneLayer; @@ -57,7 +63,8 @@ ContinuousSearchSceneLayerJni.TEST_HOOKS, mContinuousSearchSceneLayerJniMock); when(mContinuousSearchSceneLayerJniMock.init(any())).thenReturn(FAKE_NATIVE_ADDRESS); - mSceneLayer = new ContinuousSearchSceneLayer(mResourceManagerMock); + mSceneLayer = + new ContinuousSearchSceneLayer(mResourceManagerMock, mContainerView, SHADOW_HEIGHT); verify(mContinuousSearchSceneLayerJniMock, times(1)).init(eq(mSceneLayer)); mSceneLayer.initializeNative(); @@ -91,11 +98,21 @@ mSceneLayer.setResourceId(resourceId); mSceneLayer.onSizeChanged(1f, 2f, 3f, 0); // Should have no effect. + + // Show and hide the composited shadow depending on if the Android view is visible. + when(mContainerView.getVisibility()).thenReturn(View.VISIBLE); Assert.assertEquals( mSceneLayer, mSceneLayer.getUpdatedSceneOverlayTree(null, null, null, 0f)); inOrder.verify(mContinuousSearchSceneLayerJniMock) .updateContinuousSearchLayer(eq(FAKE_NATIVE_ADDRESS), eq(mResourceManagerMock), - eq(resourceId), eq(verticalOffset)); + eq(resourceId), eq(verticalOffset), eq(false), eq(SHADOW_HEIGHT)); + + when(mContainerView.getVisibility()).thenReturn(View.GONE); + Assert.assertEquals( + mSceneLayer, mSceneLayer.getUpdatedSceneOverlayTree(null, null, null, 0f)); + inOrder.verify(mContinuousSearchSceneLayerJniMock) + .updateContinuousSearchLayer(eq(FAKE_NATIVE_ADDRESS), eq(mResourceManagerMock), + eq(resourceId), eq(verticalOffset), eq(true), eq(SHADOW_HEIGHT)); } /**
diff --git a/chrome/browser/continuous_search/internal/android/java/src/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducer.java b/chrome/browser/continuous_search/internal/android/java/src/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducer.java index 191758fb..01fcd8a 100644 --- a/chrome/browser/continuous_search/internal/android/java/src/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducer.java +++ b/chrome/browser/continuous_search/internal/android/java/src/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducer.java
@@ -74,6 +74,8 @@ int urlCount = 0; List<PageGroup> groups = new ArrayList<PageGroup>(); for (int i = 0; i < groupLabel.length; i++) { + if (isAdGroup[i]) continue; + List<PageItem> results = new ArrayList<PageItem>(); Set<GURL> groupUrls = new HashSet<>(); for (int j = 0; j < groupSize[i]; j++) {
diff --git a/chrome/browser/continuous_search/internal/android/junit/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducerTest.java b/chrome/browser/continuous_search/internal/android/junit/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducerTest.java index 7bae3b71..8bff8be 100644 --- a/chrome/browser/continuous_search/internal/android/junit/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducerTest.java +++ b/chrome/browser/continuous_search/internal/android/junit/org/chromium/chrome/browser/continuous_search/SearchResultExtractorProducerTest.java
@@ -91,11 +91,13 @@ GURL url2 = JUnitTestGURLs.getGURL(JUnitTestGURLs.BLUE_1); GURL url3 = JUnitTestGURLs.getGURL(JUnitTestGURLs.BLUE_2); GURL url4 = JUnitTestGURLs.getGURL(JUnitTestGURLs.BLUE_3); + GURL url5 = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL); mSearchResultProducer.onResultsAvailable(mTestUrl, TEST_QUERY, TEST_RESULT_TYPE, - new String[] {"Foo", "Bar"}, new boolean[] {false, true}, new int[] {1, 3}, - new String[] {"Foo.com 1", "Bar.com 1", "Bar.com 2", "Bar.com 3"}, - new GURL[] {url1, url2, url3, url4}); + new String[] {"Foo", "Bar", "Baz"}, new boolean[] {false, false, true}, + new int[] {1, 3, 1}, + new String[] {"Foo.com 1", "Bar.com 1", "Bar.com 2", "Bar.com 3", "Baz.com 1"}, + new GURL[] {url1, url2, url3, url4, url5}); if (cancelled) { verify(mListenerMock, never()).onResult(any()); @@ -110,7 +112,7 @@ results2.add(new PageItem(url2, "Bar.com 1")); results2.add(new PageItem(url3, "Bar.com 2")); results2.add(new PageItem(url4, "Bar.com 3")); - groups.add(new PageGroup("Bar", true, results2)); + groups.add(new PageGroup("Bar", false, results2)); verify(mListenerMock, times(1)) .onResult(new ContinuousNavigationMetadata(
diff --git a/chrome/browser/data_saver/subresource_redirect_browsertest.cc b/chrome/browser/data_saver/subresource_redirect_browsertest.cc index 755ec7a..b1897f3f 100644 --- a/chrome/browser/data_saver/subresource_redirect_browsertest.cc +++ b/chrome/browser/data_saver/subresource_redirect_browsertest.cc
@@ -1338,10 +1338,10 @@ EXPECT_EQ(GURL(RunScriptExtractString("imageSrc()")).port(), https_url().port()); - VerifyCompressibleImageUkm(1); + VerifyCompressibleImageUkm(0); VerifyIneligibleImageHintsUnavailableUkm(0); VerifyIneligibleMissingInImageHintsUkm(0); - VerifyIneligibleOtherImageUkm(0); + VerifyIneligibleOtherImageUkm(1); VerifyImageCompressionPageInfoState(false); } @@ -1670,9 +1670,9 @@ "SubresourceRedirect.DidCompress.CompressionPercent", 0); WaitForImageCompressionUkmMetrics(1); - VerifyCompressibleImageUkm(1); + VerifyCompressibleImageUkm(0); VerifyIneligibleImageHintsUnavailableUkm(0); VerifyIneligibleMissingInImageHintsUkm(0); - VerifyIneligibleOtherImageUkm(0); + VerifyIneligibleOtherImageUkm(1); VerifyImageCompressionPageInfoState(false); }
diff --git a/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc b/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc index f9a87e9..a425e902 100644 --- a/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc +++ b/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc
@@ -146,6 +146,24 @@ return merged_metrics; } + void VerifyRobotsRulesFetch( + const std::set<std::string>& expected_robots_requests) { + if (!expected_robots_requests.empty()) { + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, + expected_robots_requests.size()); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, + expected_robots_requests.size()); + } else { + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); + } + robots_rules_server_.VerifyRequestedOrigins(expected_robots_requests); + } + protected: bool enable_lite_mode_; bool enable_login_robots_compression_feature_; @@ -219,14 +237,10 @@ net::HTTP_TEMPORARY_REDIRECT, 1); histogram_tester_.ExpectUniqueSample( "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); @@ -272,14 +286,10 @@ net::HTTP_TEMPORARY_REDIRECT, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths({}); using ImageCompressionUkm = ukm::builders::PublicImageCompressionImageLoad; @@ -326,13 +336,9 @@ histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); - histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({}); + VerifyRobotsRulesFetch({}); image_compression_server_.VerifyRequestedImagePaths({}); VerifyImageCompressionPageInfoState(false); } @@ -353,13 +359,9 @@ histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); - histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({}); + VerifyRobotsRulesFetch({}); image_compression_server_.VerifyRequestedImagePaths({}); VerifyImageCompressionPageInfoState(false); } @@ -387,17 +389,13 @@ RetryForHistogramUntilCountReached( &histogram_tester_, "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); histogram_tester_.ExpectUniqueSample( "SubresourceRedirect.LoginRobotsDeciderAgent.RedirectResult", SubresourceRedirectResult::kIneligibleRobotsTimeout, 1); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths({}); using ImageCompressionUkm = ukm::builders::PublicImageCompressionImageLoad; @@ -444,14 +442,10 @@ net::HTTP_TEMPORARY_REDIRECT, 2); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); VerifyImageCompressionPageInfoState(true); @@ -474,14 +468,10 @@ net::HTTP_TEMPORARY_REDIRECT, 2); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 2); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png", "/load_image/image.png?foo"}); VerifyImageCompressionPageInfoState(true); @@ -506,10 +496,8 @@ net::HTTP_TEMPORARY_REDIRECT, 1); histogram_tester_.ExpectUniqueSample( "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); @@ -554,10 +542,8 @@ "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); @@ -583,9 +569,7 @@ "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 2); // Another robots rules fetch happened. - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 2); - robots_rules_server_.VerifyRequestedOrigins( + VerifyRobotsRulesFetch( {GetHttpsTestURL("/").spec(), https_test_server_.GetURL("differentorigin.com", "/").spec()}); image_compression_server_.VerifyRequestedImagePaths( @@ -682,10 +666,6 @@ NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); // Robots rules fetch was success. - histogram_tester_.ExpectUniqueSample( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1); @@ -707,7 +687,7 @@ histogram_tester_.ExpectBucketCount( "SubresourceRedirect.LitePagesService.BypassResult", false, 2); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); @@ -727,12 +707,10 @@ "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1); - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 1); EXPECT_TRUE(RunScriptExtractBool("checkImage()")); // No more additional fetches. - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); VerifyImageCompressionPageInfoState(true); @@ -777,13 +755,9 @@ histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); - histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({}); + VerifyRobotsRulesFetch({}); image_compression_server_.VerifyRequestedImagePaths({}); VerifyImageCompressionPageInfoState(false); } @@ -813,14 +787,10 @@ "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 2); // The robots rules are fetched once, since both images are from the same // origin. - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png?mainframe", "/load_image/image.png"}); VerifyImageCompressionPageInfoState(true); @@ -855,16 +825,11 @@ net::HTTP_TEMPORARY_REDIRECT, 2); histogram_tester_.ExpectUniqueSample( "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 2); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 2); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 2); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins( - {GetHttpsTestURL("/").spec(), - https_test_server_.GetURL("foo.com", "/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec(), + https_test_server_.GetURL("foo.com", "/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png?mainframe", "/load_image/image.png"}); VerifyImageCompressionPageInfoState(true); @@ -904,14 +869,10 @@ net::HTTP_TEMPORARY_REDIRECT, 1); histogram_tester_.ExpectUniqueSample( "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png?mainframe"}); // Main frame still enables image compression. @@ -944,13 +905,9 @@ histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); - histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({}); + VerifyRobotsRulesFetch({}); image_compression_server_.VerifyRequestedImagePaths({}); VerifyImageCompressionPageInfoState(false); } @@ -1028,10 +985,6 @@ RetryForHistogramUntilCountReached( &histogram_tester_, "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); histogram_tester_.ExpectTotalCount( @@ -1043,7 +996,7 @@ histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths({}); // Now start loading the image. @@ -1064,14 +1017,10 @@ net::HTTP_TEMPORARY_REDIRECT, 1); histogram_tester_.ExpectUniqueSample( "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); } @@ -1131,13 +1080,9 @@ histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); - histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({}); + VerifyRobotsRulesFetch({}); image_compression_server_.VerifyRequestedImagePaths({}); VerifyImageCompressionPageInfoState(false); return; @@ -1153,14 +1098,10 @@ net::HTTP_TEMPORARY_REDIRECT, 1); histogram_tester_.ExpectUniqueSample( "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); @@ -1230,14 +1171,10 @@ net::HTTP_TEMPORARY_REDIRECT, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); - histogram_tester_.ExpectBucketCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); - robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png?foo"}); VerifyImageCompressionPageInfoState(true); @@ -1306,11 +1243,8 @@ net::HTTP_TEMPORARY_REDIRECT, 1); histogram_tester_.ExpectUniqueSample( "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); - histogram_tester_.ExpectUniqueSample( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); - robots_rules_server_.VerifyRequestedOrigins( - {image_url.GetWithEmptyPath().spec()}); + VerifyRobotsRulesFetch({image_url.GetWithEmptyPath().spec()}); image_compression_server_.VerifyRequestedImagePaths( {"/load_image/image.png"}); } else { @@ -1320,12 +1254,8 @@ "SubresourceRedirect.CompressionAttempt.ResponseCode", 0); histogram_tester_.ExpectTotalCount( "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); - histogram_tester_.ExpectTotalCount( - "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); - robots_rules_server_.VerifyRequestedOrigins({}); + VerifyRobotsRulesFetch({}); image_compression_server_.VerifyRequestedImagePaths({}); } histogram_tester_.ExpectTotalCount( @@ -1366,4 +1296,107 @@ testing::Combine(testing::Bool() /* allow_javascript_crossorigin_images */, testing::Bool() /* is_crossorigin_image */)); +// Disables the actual subresource redirect and enables only recording metrics. +class SubresourceRedirectLoginRobotsRedirectDisabledBrowserTest + : public SubresourceRedirectLoginRobotsBrowserTest { + public: + SubresourceRedirectLoginRobotsRedirectDisabledBrowserTest() + : SubresourceRedirectLoginRobotsBrowserTest( + {{"enable_subresource_server_redirect", "false"}}, + true, /* enable_lite_mode */ + true /* enable_login_robots_compression_feature */ + ) {} +}; + +IN_PROC_BROWSER_TEST_F( + SubresourceRedirectLoginRobotsRedirectDisabledBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestImageAllowedByRobots)) { + CreateUkmRecorder(); + robots_rules_server_.AddRobotsRules( + GetHttpsTestURL("/"), + {{kRuleTypeAllow, "/load_image/image.png"}, {kRuleTypeDisallow, ""}}); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); + + // The image will not be redirected. + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.LoginRobotsDeciderAgent.RedirectResult", + SubresourceRedirectResult::kIneligibleCompressionDisabled, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + image_compression_server_.VerifyRequestedImagePaths({}); + + // Image load UKM should get recorded. + using ImageCompressionUkm = ukm::builders::PublicImageCompressionImageLoad; + auto ukm_metrics = GetImageCompressionUkmMetrics(); + EXPECT_LT(100U, ukm_metrics[ImageCompressionUkm::kOriginalBytesNameHash]); + EXPECT_THAT(ukm_metrics, + testing::Not(testing::Contains(testing::Key( + ImageCompressionUkm::kCompressionPercentageNameHash)))); + EXPECT_THAT(ukm_metrics, + testing::Contains(testing::Key( + ImageCompressionUkm::kNavigationToRequestStartNameHash))); + EXPECT_THAT(ukm_metrics, + testing::Contains(testing::Key( + ImageCompressionUkm::kNavigationToRequestSentNameHash))); + EXPECT_THAT(ukm_metrics, + testing::Contains(testing::Key( + ImageCompressionUkm::kNavigationToResponseReceivedNameHash))); + EXPECT_THAT(ukm_metrics, + testing::Contains(testing::Key( + ImageCompressionUkm::kRobotsRulesFetchLatencyNameHash))); + EXPECT_EQ(SubresourceRedirectResult::kIneligibleCompressionDisabled, + static_cast<SubresourceRedirectResult>( + ukm_metrics[ImageCompressionUkm::kRedirectResultNameHash])); + VerifyImageCompressionPageInfoState(false); +} + +IN_PROC_BROWSER_TEST_F( + SubresourceRedirectLoginRobotsRedirectDisabledBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestImageDisallowedByRobots)) { + CreateUkmRecorder(); + robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"), + {{kRuleTypeDisallow, ""}}); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + VerifyRobotsRulesFetch({GetHttpsTestURL("/").spec()}); + + // The image will not be redirected. + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.LoginRobotsDeciderAgent.RedirectResult", + SubresourceRedirectResult::kIneligibleRobotsDisallowed, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + image_compression_server_.VerifyRequestedImagePaths({}); + + // Image load UKM should get recorded. + using ImageCompressionUkm = ukm::builders::PublicImageCompressionImageLoad; + auto ukm_metrics = GetImageCompressionUkmMetrics(); + EXPECT_LT(100U, ukm_metrics[ImageCompressionUkm::kOriginalBytesNameHash]); + EXPECT_THAT(ukm_metrics, + testing::Not(testing::Contains(testing::Key( + ImageCompressionUkm::kCompressionPercentageNameHash)))); + EXPECT_THAT(ukm_metrics, + testing::Contains(testing::Key( + ImageCompressionUkm::kNavigationToRequestStartNameHash))); + EXPECT_THAT(ukm_metrics, + testing::Contains(testing::Key( + ImageCompressionUkm::kNavigationToRequestSentNameHash))); + EXPECT_THAT(ukm_metrics, + testing::Contains(testing::Key( + ImageCompressionUkm::kNavigationToResponseReceivedNameHash))); + EXPECT_THAT(ukm_metrics, + testing::Contains(testing::Key( + ImageCompressionUkm::kRobotsRulesFetchLatencyNameHash))); + EXPECT_EQ(SubresourceRedirectResult::kIneligibleRobotsDisallowed, + static_cast<SubresourceRedirectResult>( + ukm_metrics[ImageCompressionUkm::kRedirectResultNameHash])); + VerifyImageCompressionPageInfoState(false); +} + } // namespace subresource_redirect
diff --git a/chrome/browser/device_identity/device_oauth2_token_service.cc b/chrome/browser/device_identity/device_oauth2_token_service.cc index 5709308..7df782d6 100644 --- a/chrome/browser/device_identity/device_oauth2_token_service.cc +++ b/chrome/browser/device_identity/device_oauth2_token_service.cc
@@ -313,7 +313,7 @@ scoped_request->request.get(), scoped_request->request->GetAccountId(), GetURLLoaderFactory(), scoped_request->client_id, scoped_request->client_secret, - scoped_request->scopes); + scoped_request->request->GetConsumerId(), scoped_request->scopes); } else { FailRequest(scoped_request->request.get(), error); }
diff --git a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.cc b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.cc index 27ea0277..6c83518a 100644 --- a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.cc +++ b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.cc
@@ -81,6 +81,7 @@ const GURL& token_endpoint, const std::string& refresh_token, const std::string& auth_code, + const std::string& consumer_name, TokenCallback callback) : OAuth2AccessTokenFetcherImpl(this, url_loader_factory, @@ -88,6 +89,7 @@ auth_code), token_endpoint_(token_endpoint), annotation_(GetAnnotation(service_provder)), + consumer_name_(consumer_name), callback_(std::move(callback)) {} AccessTokenFetcher::~AccessTokenFetcher() = default; @@ -115,6 +117,10 @@ std::move(callback_).Run(error, std::string(), std::string()); } +std::string AccessTokenFetcher::GetConsumerName() const { + return consumer_name_; +} + void RegisterFileSystemPrefsForServiceProvider( PrefRegistrySimple* registry, const std::string& service_provider) {
diff --git a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h index 89ed87a..2b2e874 100644 --- a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h +++ b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h
@@ -36,6 +36,7 @@ const GURL& token_endpoint, const std::string& refresh_token, const std::string& auth_code, + const std::string& consumer_name, TokenCallback callback); ~AccessTokenFetcher() override; @@ -48,10 +49,12 @@ // OAuth2AccessTokenConsumer interface. void OnGetTokenSuccess(const TokenResponse& token_response) override; void OnGetTokenFailure(const GoogleServiceAuthError& error) override; + std::string GetConsumerName() const override; private: GURL token_endpoint_; net::NetworkTrafficAnnotationTag annotation_; + const std::string consumer_name_; TokenCallback callback_; };
diff --git a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher_unittest.cc b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher_unittest.cc index 4b408f45..ad4794b 100644 --- a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher_unittest.cc +++ b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher_unittest.cc
@@ -61,6 +61,7 @@ url_loader_factory_.GetSafeWeakWrapper(), // dummy; not for unit tests. "box", GURL(kTokenEndpoint), "refresh token", "", // use existing refresh token to get access token. + /*consumer_name=*/"file_system_access_token_fetcher_unittest", base::BindOnce(&AccessTokenFetcherTest::OnResponse, factory_.GetWeakPtr())); }
diff --git a/chrome/browser/enterprise/connectors/file_system/rename_handler.cc b/chrome/browser/enterprise/connectors/file_system/rename_handler.cc index 5a9c902a..afbf320 100644 --- a/chrome/browser/enterprise/connectors/file_system/rename_handler.cc +++ b/chrome/browser/enterprise/connectors/file_system/rename_handler.cc
@@ -24,6 +24,9 @@ namespace { +// The OAuth token consumer name. +const char kOAuthConsumerName[] = "file_system_rename_handler"; + PrefService* PrefsFromBrowserContext(content::BrowserContext* context) { return Profile::FromBrowserContext(context)->GetPrefs(); } @@ -135,7 +138,8 @@ const std::string& refresh_token) { token_fetcher_ = std::make_unique<AccessTokenFetcher>( GetURLLoaderFactory(context), settings_.service_provider, - settings_.token_endpoint, refresh_token, std::string(), + settings_.token_endpoint, refresh_token, /*auth_code=*/std::string(), + kOAuthConsumerName, base::BindOnce(&FileSystemRenameHandler::OnAccessTokenFetched, weak_factory_.GetWeakPtr())); token_fetcher_->Start(settings_.client_id, settings_.client_secret,
diff --git a/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.cc b/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.cc index 5af4616..6ba0e60 100644 --- a/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.cc +++ b/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.cc
@@ -29,6 +29,9 @@ namespace { +// The OAuth token consumer name. +const char kOAuthConsumerName[] = "file_system_signin_dialog"; + // The OAuth2 configuration of the Box App used for the file system integration // uses https://google.com/generate_204 as the redirect URI. // This URI is used because: @@ -183,7 +186,8 @@ // No refresh_token, so need to get both tokens with authorization code. token_fetcher_ = std::make_unique<AccessTokenFetcher>( url_loader, settings_.service_provider, settings_.token_endpoint, - std::string(), auth_code, std::move(callback)); + /*refresh_token=*/std::string(), auth_code, kOAuthConsumerName, + std::move(callback)); token_fetcher_->Start(settings_.client_id, settings_.client_secret, settings_.scopes); }
diff --git a/chrome/browser/extensions/api/identity/identity_api.h b/chrome/browser/extensions/api/identity/identity_api.h index 902c5cf..3f77671 100644 --- a/chrome/browser/extensions/api/identity/identity_api.h +++ b/chrome/browser/extensions/api/identity/identity_api.h
@@ -13,7 +13,6 @@ #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "build/build_config.h" #include "build/buildflag.h" #include "chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.h"
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h index 37c00c7..76fa8b3 100644 --- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h +++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
@@ -14,7 +14,6 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "build/build_config.h" #include "chrome/browser/extensions/api/passwords_private/password_check_delegate.h" #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc index 1e24b7df..077c399 100644 --- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc +++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
@@ -44,6 +44,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" +#include "chrome/browser/ash/login/users/scoped_test_user_manager.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h" #include "chromeos/tpm/stub_install_attributes.h" @@ -109,18 +110,26 @@ new SafeBrowsingPrivateEventRouter(context)); } -class SafeBrowsingPrivateEventRouterTest : public testing::Test { +class SafeBrowsingPrivateEventRouterTestBase : public testing::Test { public: - SafeBrowsingPrivateEventRouterTest() + SafeBrowsingPrivateEventRouterTestBase() : profile_manager_(TestingBrowserProcess::GetGlobal()) { EXPECT_TRUE(profile_manager_.SetUp()); + } + + SafeBrowsingPrivateEventRouterTestBase( + const SafeBrowsingPrivateEventRouterTestBase&) = delete; + SafeBrowsingPrivateEventRouterTestBase& operator=( + const SafeBrowsingPrivateEventRouterTestBase&) = delete; + + ~SafeBrowsingPrivateEventRouterTestBase() override = default; + + void SetUp() override { profile_ = profile_manager_.CreateTestingProfile("test-user"); policy::SetDMTokenForTesting( policy::DMToken::CreateValidTokenForTesting("fake-token")); } - ~SafeBrowsingPrivateEventRouterTest() override = default; - void TriggerOnPolicySpecifiedPasswordReuseDetectedEvent() { SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile_) ->OnPolicySpecifiedPasswordReuseDetected(GURL("https://phishing.com/"), @@ -241,15 +250,27 @@ content::BrowserTaskEnvironment task_environment_; std::unique_ptr<policy::MockCloudPolicyClient> client_; TestingProfileManager profile_manager_; - TestingProfile* profile_; + TestingProfile* profile_ = nullptr; extensions::TestEventRouter* event_router_ = nullptr; private: #if !BUILDFLAG(IS_CHROMEOS_ASH) policy::FakeBrowserDMTokenStorage dm_token_storage_; #endif // !BUILDFLAG(IS_CHROMEOS_ASH) +}; - DISALLOW_COPY_AND_ASSIGN(SafeBrowsingPrivateEventRouterTest); +class SafeBrowsingPrivateEventRouterTest + : public SafeBrowsingPrivateEventRouterTestBase { +#if BUILDFLAG(IS_CHROMEOS_ASH) + public: + SafeBrowsingPrivateEventRouterTest() { + test_user_manager_ = std::make_unique<ash::ScopedTestUserManager>(); + } + + protected: + ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_; + std::unique_ptr<ash::ScopedTestUserManager> test_user_manager_; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) }; TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnReuseDetected) { @@ -1074,7 +1095,7 @@ // bool: whether the policy is enabled. // bool: whether the server has authorized this browser instance. class SafeBrowsingIsRealtimeReportingEnabledTest - : public SafeBrowsingPrivateEventRouterTest, + : public SafeBrowsingPrivateEventRouterTestBase, public testing::WithParamInterface< testing::tuple<bool, bool, bool, bool>> { public: @@ -1102,7 +1123,10 @@ switches::kEnableChromeBrowserCloudManagement); } #endif + } + void SetUp() override { + SafeBrowsingPrivateEventRouterTestBase::SetUp(); if (is_policy_enabled_) { profile_->GetPrefs()->Set(enterprise_connectors::kOnSecurityEventPref, *base::JSONReader::Read(kConnectorsPrefValue)); @@ -1204,7 +1228,7 @@ // std::string: the name of the event to enable. // int: How many triggers use this event name. class SafeBrowsingIsRealtimeReportingEventDisabledTest - : public SafeBrowsingPrivateEventRouterTest, + : public SafeBrowsingPrivateEventRouterTestBase, public testing::WithParamInterface<testing::tuple<std::string, int>> { public: SafeBrowsingIsRealtimeReportingEventDisabledTest()
diff --git a/chrome/browser/extensions/api/storage/settings_apitest.cc b/chrome/browser/extensions/api/storage/settings_apitest.cc index 69b4820..6402a93 100644 --- a/chrome/browser/extensions/api/storage/settings_apitest.cc +++ b/chrome/browser/extensions/api/storage/settings_apitest.cc
@@ -345,8 +345,9 @@ // TODO(crbug.com/1185226): Change parent class to `ExtensionSettingsApiTest` // when chrome.storage.session is released in stable. +// Flaky across multiple platforms: https://crbug.com/1216449. IN_PROC_BROWSER_TEST_F(ExtensionSettingsTrunkApiTest, - OnChangedNotificationsBetweenBackgroundPages) { + DISABLED_OnChangedNotificationsBetweenBackgroundPages) { // We need 2 ResultCatchers because we'll be running the same test in both // regular and incognito mode. ResultCatcher catcher;
diff --git a/chrome/browser/extensions/tab_helper.h b/chrome/browser/extensions/tab_helper.h index 61ac854a..45ffcf3f 100644 --- a/chrome/browser/extensions/tab_helper.h +++ b/chrome/browser/extensions/tab_helper.h
@@ -12,7 +12,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/scoped_observation.h" #include "chrome/browser/extensions/active_tab_permission_granter.h" #include "chrome/common/extensions/webstore_install_result.h"
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc index f13c162..9f45c73 100644 --- a/chrome/browser/extensions/updater/extension_updater.cc +++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -28,6 +28,8 @@ #include "chrome/browser/extensions/forced_extensions/install_stage_tracker.h" #include "chrome/browser/extensions/pending_extension_manager.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_keep_alive_types.h" +#include "chrome/browser/profiles/scoped_profile_keep_alive.h" #include "components/prefs/pref_service.h" #include "components/update_client/update_query_params.h" #include "content/public/browser/browser_task_traits.h" @@ -305,7 +307,7 @@ update_check_params->update_info[extension_id] = ExtensionUpdateData(); } else if (AddExtensionToDownloader(extension, request_id, fetch_priority)) { - request.in_progress_ids_.insert(extension_id); + request.in_progress_ids.insert(extension_id); } } } @@ -358,6 +360,8 @@ InProgressCheck& request = requests_in_progress_[request_id]; request.callback = std::move(params.callback); request.install_immediately = params.install_immediately; + request.profile_keep_alive = std::make_unique<ScopedProfileKeepAlive>( + profile_, ProfileKeepAliveOrigin::kExtensionUpdater); EnsureDownloaderCreated(); @@ -423,7 +427,7 @@ is_high_priority_extension_pending ? ManifestFetchData::FOREGROUND : params.fetch_priority)) { - request.in_progress_ids_.insert(pending_id); + request.in_progress_ids.insert(pending_id); InstallStageTracker::Get(profile_)->ReportInstallationStage( pending_id, InstallStageTracker::Stage::DOWNLOADING); } else { @@ -454,7 +458,7 @@ update_check_params.update_info[id] = ExtensionUpdateData(); } else if (AddExtensionToDownloader(*extension, request_id, params.fetch_priority)) { - request.in_progress_ids_.insert(extension->id()); + request.in_progress_ids.insert(extension->id()); } } } @@ -465,7 +469,7 @@ // send out a notification. So check before we call StartAllPending if any // extensions are going to be updated, and use that to figure out if // NotifyIfFinished should be called. - bool empty_downloader = request.in_progress_ids_.empty(); + bool empty_downloader = request.in_progress_ids.empty(); bool awaiting_update_service = !update_check_params.update_info.empty(); request.awaiting_update_service = awaiting_update_service; @@ -551,7 +555,7 @@ for (const int request_id : request_ids) { InProgressCheck& request = requests_in_progress_[request_id]; install_immediately |= request.install_immediately; - request.in_progress_ids_.erase(id); + request.in_progress_ids.erase(id); NotifyIfFinished(request_id); } @@ -584,7 +588,7 @@ FetchedCRXFile fetched(file, file_ownership_passed, request_ids, std::move(callback)); - // InstallCRXFile() removes extensions from |in_progress_ids_| after starting + // InstallCRXFile() removes extensions from |in_progress_ids| after starting // the crx installer. InstallCRXFile(std::move(fetched)); } @@ -722,7 +726,7 @@ } else { for (const int request_id : crx_file.request_ids) { InProgressCheck& request = requests_in_progress_[request_id]; - request.in_progress_ids_.erase(crx_file.info.extension_id); + request.in_progress_ids.erase(crx_file.info.extension_id); } request_ids.insert(crx_file.request_ids.begin(), crx_file.request_ids.end()); @@ -757,7 +761,7 @@ } else { for (const int request_id : crx_file.request_ids) { InProgressCheck& request = requests_in_progress_[request_id]; - request.in_progress_ids_.erase(crx_file.info.extension_id); + request.in_progress_ids.erase(crx_file.info.extension_id); NotifyIfFinished(request_id); } if (!crx_file.callback.is_null()) { @@ -786,7 +790,7 @@ void ExtensionUpdater::NotifyIfFinished(int request_id) { DCHECK(base::Contains(requests_in_progress_, request_id)); InProgressCheck& request = requests_in_progress_[request_id]; - if (!request.in_progress_ids_.empty() || request.awaiting_update_service) + if (!request.in_progress_ids.empty() || request.awaiting_update_service) return; // This request is not done yet. VLOG(2) << "Finished update check " << request_id; if (!request.callback.is_null())
diff --git a/chrome/browser/extensions/updater/extension_updater.h b/chrome/browser/extensions/updater/extension_updater.h index 76648987..751b7e0a 100644 --- a/chrome/browser/extensions/updater/extension_updater.h +++ b/chrome/browser/extensions/updater/extension_updater.h
@@ -28,6 +28,7 @@ class PrefService; class Profile; +class ScopedProfileKeepAlive; namespace extensions { @@ -186,8 +187,13 @@ bool install_immediately = false; bool awaiting_update_service = false; FinishedCallback callback; + // Prevents the destruction of the Profile* while an update check is in + // progress. + // TODO(crbug.com/1191460): Find a way to pass the keepalive to UpdateClient + // instead of holding it here. + std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive; // The ids of extensions that have in-progress update checks. - std::set<ExtensionId> in_progress_ids_; + std::set<ExtensionId> in_progress_ids; }; // Ensure that we have a valid ExtensionDownloader instance referenced by
diff --git a/chrome/browser/extensions/updater/update_service_browsertest.cc b/chrome/browser/extensions/updater/update_service_browsertest.cc index 8fe5e46e..88e6ca3 100644 --- a/chrome/browser/extensions/updater/update_service_browsertest.cc +++ b/chrome/browser/extensions/updater/update_service_browsertest.cc
@@ -8,12 +8,15 @@ #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" +#include "chrome/browser/browser_features.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/content_verifier_test_utils.h" #include "chrome/browser/extensions/extension_management_test_util.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/updater/chrome_update_client_config.h" #include "chrome/browser/extensions/updater/extension_update_client_base_browsertest.h" #include "chrome/browser/extensions/updater/extension_updater.h" +#include "chrome/browser/profiles/profile_keep_alive_types.h" #include "chrome/common/chrome_switches.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" @@ -56,6 +59,14 @@ } bool ShouldEnableContentVerification() override { return true; } + + void ExpectProfileKeepAlive(bool expected) { + if (!base::FeatureList::IsEnabled(features::kDestroyProfileOnBrowserClose)) + return; + EXPECT_EQ(expected, + g_browser_process->profile_manager()->HasKeepAliveForTesting( + profile(), ProfileKeepAliveOrigin::kExtensionUpdater)); + } }; IN_PROC_BROWSER_TEST_F(UpdateServiceTest, NoUpdate) { @@ -215,6 +226,8 @@ return true; })); + ExpectProfileKeepAlive(false); + const Extension* extension = InstallExtension(crx_path, 1, ManifestLocation::kExternalPolicyDownload); ASSERT_TRUE(extension); @@ -227,6 +240,8 @@ params.callback = run_loop.QuitClosure(); extension_service()->updater()->CheckNow(std::move(params)); + ExpectProfileKeepAlive(true); + EXPECT_EQ(UpdateClientEvents::COMPONENT_UPDATED, WaitOnComponentUpdaterCompleteEvent(kExtensionId));
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 8e674c91..81243d5 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -5371,7 +5371,7 @@ { "name": "wifi-sync-android", "owners": [ "jonmann", "cvandermerwe@google.com", "cros-system-services@google.com" ], - "expiry_milestone": 92 + "expiry_milestone": 97 }, { "name": "win-use-native-spellchecker",
diff --git a/chrome/browser/flags/android/java_templates/ChromeSwitches.java.tmpl b/chrome/browser/flags/android/java_templates/ChromeSwitches.java.tmpl index 9b14a89..c367854 100644 --- a/chrome/browser/flags/android/java_templates/ChromeSwitches.java.tmpl +++ b/chrome/browser/flags/android/java_templates/ChromeSwitches.java.tmpl
@@ -36,12 +36,6 @@ /** Disable promos shown on startup. */ public static final String DISABLE_STARTUP_PROMOS = "disable-startup-promos-for-testing"; - /** - * Forces the First Run Experience (FRE) flow complete check to always return true. - */ - public static final String FORCE_FIRST_RUN_FLOW_COMPLETE_FOR_TESTING = - "force-first-run-flow-complete"; - /** Force the crash dump to be uploaded regardless of preferences. */ public static final String FORCE_CRASH_DUMP_UPLOAD = "force-dump-upload";
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h index f4624666..e2044f22 100644 --- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h +++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h
@@ -11,7 +11,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" #include "components/media_router/common/discovery/media_sink_internal.h"
diff --git a/chrome/browser/notifications/notification_permission_context.cc b/chrome/browser/notifications/notification_permission_context.cc index 8f34a89..6d1b347 100644 --- a/chrome/browser/notifications/notification_permission_context.cc +++ b/chrome/browser/notifications/notification_permission_context.cc
@@ -19,7 +19,6 @@ #include "components/content_settings/core/common/content_settings_types.h" #include "components/permissions/permission_request_id.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/web_contents_user_data.h" #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h" #include "url/gurl.h" @@ -34,35 +33,6 @@ #include "ui/message_center/public/cpp/notifier_id.h" #endif // BUILDFLAG(ENABLE_EXTENSIONS) -namespace { - -class NotificationTabHelper - : public content::WebContentsUserData<NotificationTabHelper> { - public: - ~NotificationTabHelper() override = default; - - void set_should_block_new_notification_requests(bool value) { - should_block_new_notification_requests_ = value; - } - - bool should_block_new_notification_requests() { - return should_block_new_notification_requests_; - } - - private: - explicit NotificationTabHelper(content::WebContents* contents) {} - - friend class content::WebContentsUserData<NotificationTabHelper>; - - bool should_block_new_notification_requests_ = false; - - WEB_CONTENTS_USER_DATA_KEY_DECL(); -}; - -WEB_CONTENTS_USER_DATA_KEY_IMPL(NotificationTabHelper) - -} // namespace - // static void NotificationPermissionContext::UpdatePermission( content::BrowserContext* browser_context, @@ -91,15 +61,6 @@ NotificationPermissionContext::~NotificationPermissionContext() {} -// static -void NotificationPermissionContext::SetBlockNewNotificationRequests( - content::WebContents* web_contents, - bool value) { - NotificationTabHelper::CreateForWebContents(web_contents); - NotificationTabHelper::FromWebContents(web_contents) - ->set_should_block_new_notification_requests(value); -} - ContentSetting NotificationPermissionContext::GetPermissionStatusInternal( content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, @@ -198,12 +159,6 @@ return; } - auto* tab_helper = NotificationTabHelper::FromWebContents(web_contents); - if (tab_helper && tab_helper->should_block_new_notification_requests()) { - std::move(callback).Run(CONTENT_SETTING_BLOCK); - return; - } - permissions::PermissionContextBase::DecidePermission( web_contents, id, requesting_origin, embedding_origin, user_gesture, std::move(callback));
diff --git a/chrome/browser/notifications/notification_permission_context.h b/chrome/browser/notifications/notification_permission_context.h index 626f8df..afce47c 100644 --- a/chrome/browser/notifications/notification_permission_context.h +++ b/chrome/browser/notifications/notification_permission_context.h
@@ -94,10 +94,6 @@ content::BrowserContext* browser_context); ~NotificationPermissionContext() override; - static void SetBlockNewNotificationRequests( - content::WebContents* web_contents, - bool value); - // PermissionContextBase implementation. ContentSetting GetPermissionStatusInternal( content::RenderFrameHost* render_frame_host,
diff --git a/chrome/browser/notifications/notification_permission_context_unittest.cc b/chrome/browser/notifications/notification_permission_context_unittest.cc index cdccf48..e6b3e306 100644 --- a/chrome/browser/notifications/notification_permission_context_unittest.cc +++ b/chrome/browser/notifications/notification_permission_context_unittest.cc
@@ -511,55 +511,6 @@ EXPECT_EQ(CONTENT_SETTING_ASK, settings[4].GetContentSetting()); } -TEST_F(NotificationPermissionContextTest, BlockNewNotificationRequests) { - GURL url("https://example.com"); - NavigateAndCommit(url); - - NotificationPermissionContext context(profile()); - const permissions::PermissionRequestID id( - web_contents()->GetMainFrame()->GetProcess()->GetID(), - web_contents()->GetMainFrame()->GetRoutingID(), - permissions::PermissionRequestID::RequestLocalId()); - ContentSetting result = CONTENT_SETTING_DEFAULT; - context.RequestPermission(web_contents(), id, url, true /* user_gesture */, - base::BindOnce(&StoreContentSetting, &result)); - EXPECT_NE(result, CONTENT_SETTING_BLOCK); - - NotificationPermissionContext::SetBlockNewNotificationRequests(web_contents(), - true); - context.RequestPermission(web_contents(), id, url, true /* user_gesture */, - base::BindOnce(&StoreContentSetting, &result)); - EXPECT_EQ(result, CONTENT_SETTING_BLOCK); - - NotificationPermissionContext::SetBlockNewNotificationRequests(web_contents(), - false); - result = CONTENT_SETTING_DEFAULT; - context.RequestPermission(web_contents(), id, url, true /* user_gesture */, - base::BindOnce(&StoreContentSetting, &result)); - EXPECT_NE(result, CONTENT_SETTING_BLOCK); -} - -TEST_F(NotificationPermissionContextTest, - BlockNewNotificationRequestsDoesNothingIfGranted) { - GURL url("https://example.com"); - NavigateAndCommit(url); - - NotificationPermissionContext::UpdatePermission(profile(), url, - CONTENT_SETTING_ALLOW); - - NotificationPermissionContext context(profile()); - const permissions::PermissionRequestID id( - web_contents()->GetMainFrame()->GetProcess()->GetID(), - web_contents()->GetMainFrame()->GetRoutingID(), - permissions::PermissionRequestID::RequestLocalId()); - NotificationPermissionContext::SetBlockNewNotificationRequests(web_contents(), - true); - ContentSetting result = CONTENT_SETTING_DEFAULT; - context.RequestPermission(web_contents(), id, url, true /* user_gesture */, - base::BindOnce(&StoreContentSetting, &result)); - EXPECT_EQ(result, CONTENT_SETTING_ALLOW); -} - #if BUILDFLAG(ENABLE_EXTENSIONS) TEST_F(NotificationPermissionContextTest, ExtensionPermissionAskByDefault) { // Verifies that notification permission is not granted to extensions by
diff --git a/chrome/browser/notifications/screen_lock_notification_blocker.h b/chrome/browser/notifications/screen_lock_notification_blocker.h index 64bef0a30..6631c14 100644 --- a/chrome/browser/notifications/screen_lock_notification_blocker.h +++ b/chrome/browser/notifications/screen_lock_notification_blocker.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_NOTIFICATIONS_SCREEN_LOCK_NOTIFICATION_BLOCKER_H_ #define CHROME_BROWSER_NOTIFICATIONS_SCREEN_LOCK_NOTIFICATION_BLOCKER_H_ -#include "base/observer_list.h" #include "base/timer/timer.h" #include "ui/message_center/notification_blocker.h"
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc index bbe3614f4..a750639 100644 --- a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc +++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
@@ -40,6 +40,7 @@ #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/ukm/test_ukm_recorder.h" #include "components/unified_consent/unified_consent_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/mock_navigation_handle.h" #include "content/public/test/test_web_contents_factory.h" @@ -2257,6 +2258,8 @@ } private: + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; base::test::ScopedFeatureList scoped_list_; };
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc b/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc index a89b66f..f3df73c 100644 --- a/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc +++ b/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc
@@ -34,6 +34,7 @@ #include "components/optimization_guide/proto/hint_cache.pb.h" #include "components/optimization_guide/proto/models.pb.h" #include "components/prefs/testing_pref_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/mock_navigation_handle.h" #include "content/public/test/test_web_contents_factory.h" @@ -654,6 +655,10 @@ feature_list_.InitAndEnableFeature( features::kRemoteOptimizationGuideFetching); } + + private: + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; }; TEST_F(PredictionManagerTest, OptimizationTargetNotRegisteredForNavigation) {
diff --git a/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc b/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc index 3c6137ed..d121c52 100644 --- a/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc +++ b/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc
@@ -45,6 +45,10 @@ return nullptr; } void ShowProfileCustomizationBubble(Browser* browser) override {} + void ShowEnterpriseProfileInterceptionDialog( + const std::string& email, + base::OnceCallback<void(bool)> callback, + Browser* browser) override {} }; class TestPasswordManagerClient
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc index 92f2902..bddcf11d 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -17,8 +17,10 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/account_id_from_account_info.h" #include "chrome/browser/signin/signin_util.h" +#include "chrome/common/pref_names.h" #include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h" #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" +#include "components/prefs/pref_change_registrar.h" #include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/consent_level.h" #include "content/public/browser/notification_details.h" @@ -49,6 +51,13 @@ // happens in the background after PKS initialization - so this service // should always be created before the oauth token is available. DCHECK(!CanApplyPoliciesForSignedInUser(/*check_for_refresh_token=*/true)); + + profile_pref_change_registrar_.Init(profile->GetPrefs()); + profile_pref_change_registrar_.Add( + prefs::kUserAcceptedAccountManagement, + base::BindRepeating( + &UserPolicySigninService::OnAccountManagementPrefChange, + base::Unretained(this))); } UserPolicySigninService::~UserPolicySigninService() { @@ -146,6 +155,8 @@ return; } + profile_pref_change_registrar_.RemoveAll(); + InitializeForSignedInUser( AccountIdFromAccountInfo( identity_manager()->GetPrimaryAccountInfo(consent_level())), @@ -154,6 +165,11 @@ ->GetURLLoaderFactoryForBrowserProcess()); } +void UserPolicySigninService::OnAccountManagementPrefChange() { + if (CanApplyPoliciesForSignedInUser(/*check_for_refresh_token=*/true)) + TryInitializeForSignedInUser(); +} + void UserPolicySigninService::InitializeUserCloudPolicyManager( const AccountId& account_id, std::unique_ptr<CloudPolicyClient> client) {
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.h b/chrome/browser/policy/cloud/user_policy_signin_service.h index 6d9c042..8a8b83c 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service.h +++ b/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "chrome/browser/policy/cloud/user_policy_signin_service_base.h" +#include "components/prefs/pref_change_registrar.h" #include "components/signin/public/identity_manager/identity_manager.h" class AccountId; @@ -86,6 +87,9 @@ // cloud policy. void ProhibitSignoutIfNeeded(); + // Called when the value of the `profile.account_management` pref changes. + void OnAccountManagementPrefChange(); + // Helper method that attempts calls |InitializeForSignedInUser| only if // |policy_manager| is not-nul. Expects that there is a refresh token for // the primary account. @@ -96,6 +100,7 @@ PolicyRegistrationCallback callback); std::unique_ptr<CloudPolicyClientRegistrationHelper> registration_helper_; + PrefChangeRegistrar profile_pref_change_registrar_; DISALLOW_COPY_AND_ASSIGN(UserPolicySigninService); };
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index b066c11..90fbf6e2 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -436,6 +436,9 @@ { key::kImportAutofillFormData, prefs::kImportAutofillFormData, base::Value::Type::BOOLEAN }, + { key::kRemoteDebuggingAllowed, + prefs::kDevToolsRemoteDebuggingAllowed, + base::Value::Type::BOOLEAN }, // Import data dialog: controlled by same policies as first run import, but // uses different prefs.
diff --git a/chrome/browser/policy/test/arc_policy_browsertest.cc b/chrome/browser/policy/test/arc_policy_browsertest.cc index 428414ff..b69f342d 100644 --- a/chrome/browser/policy/test/arc_policy_browsertest.cc +++ b/chrome/browser/policy/test/arc_policy_browsertest.cc
@@ -9,8 +9,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "components/arc/arc_prefs.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_session_runner.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_arc_session.h" #include "components/policy/policy_constants.h" #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc b/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc index ce00373a5..7b7c0e6 100644 --- a/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc +++ b/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc
@@ -18,6 +18,7 @@ #include "chrome/test/base/testing_profile.h" #include "components/optimization_guide/core/optimization_guide_features.h" #include "components/sessions/content/session_tab_helper.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/browser/navigation_handle.h" #include "content/public/test/navigation_simulator.h" #include "services/network/public/mojom/fetch_api.mojom.h" @@ -702,6 +703,8 @@ private: base::test::ScopedFeatureList scoped_feature_list_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; }; // Tests that document on load completed is recorded with correct navigation
diff --git a/chrome/browser/predictors/prefetch_manager_unittest.cc b/chrome/browser/predictors/prefetch_manager_unittest.cc index 4e47416..ae5ccf6 100644 --- a/chrome/browser/predictors/prefetch_manager_unittest.cc +++ b/chrome/browser/predictors/prefetch_manager_unittest.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/predictors/predictors_features.h" #include "chrome/browser/predictors/predictors_switches.h" #include "chrome/test/base/testing_profile.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/navigation_ui_data.h" #include "content/public/common/content_client.h" @@ -117,6 +118,8 @@ // IO_MAINLOOP is needed for the EmbeddedTestServer. content::BrowserTaskEnvironment task_environment_{ content::BrowserTaskEnvironment::IO_MAINLOOP}; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<TestingProfile> profile_; std::unique_ptr<FakePrefetchManagerDelegate> fake_delegate_; std::unique_ptr<PrefetchManager> prefetch_manager_;
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h index 3e276fa..b9b94402 100644 --- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h +++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
@@ -11,7 +11,6 @@ #include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/values.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h"
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h index 92baa51c..2450759 100644 --- a/chrome/browser/profiles/profile.h +++ b/chrome/browser/profiles/profile.h
@@ -186,10 +186,15 @@ public: virtual ~Delegate(); + // Called when creation of the profile is started. + virtual void OnProfileCreationStarted(Profile* profile, + CreateMode create_mode) = 0; + // Called when creation of the profile is finished. - virtual void OnProfileCreated(Profile* profile, - bool success, - bool is_new_profile) = 0; + virtual void OnProfileCreationFinished(Profile* profile, + CreateMode create_mode, + bool success, + bool is_new_profile) = 0; }; // Key used to bind profile to the widget with which it is associated.
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc index 0273a40..ba70df6a 100644 --- a/chrome/browser/profiles/profile_browsertest.cc +++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -155,8 +155,9 @@ class MockProfileDelegate : public Profile::Delegate { public: - MOCK_METHOD1(OnPrefsLoaded, void(Profile*)); - MOCK_METHOD3(OnProfileCreated, void(Profile*, bool, bool)); + MOCK_METHOD2(OnProfileCreationStarted, void(Profile*, Profile::CreateMode)); + MOCK_METHOD4(OnProfileCreationFinished, + void(Profile*, Profile::CreateMode, bool, bool)); }; class ProfileDestructionWatcher : public ProfileObserver { @@ -356,7 +357,9 @@ ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); MockProfileDelegate delegate; - EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); + EXPECT_CALL(delegate, OnProfileCreationFinished( + testing::NotNull(), + Profile::CREATE_MODE_SYNCHRONOUS, true, true)); { std::unique_ptr<Profile> profile(CreateProfile( @@ -381,7 +384,9 @@ CreatePrefsFileInDirectory(temp_dir.GetPath()); MockProfileDelegate delegate; - EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, false)); + EXPECT_CALL(delegate, OnProfileCreationFinished( + testing::NotNull(), + Profile::CREATE_MODE_SYNCHRONOUS, true, false)); { std::unique_ptr<Profile> profile(CreateProfile( @@ -408,7 +413,9 @@ MockProfileDelegate delegate; base::RunLoop run_loop; - EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)) + EXPECT_CALL(delegate, OnProfileCreationFinished( + testing::NotNull(), + Profile::CREATE_MODE_ASYNCHRONOUS, true, true)) .WillOnce(testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); { @@ -436,7 +443,9 @@ MockProfileDelegate delegate; base::RunLoop run_loop; - EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, false)) + EXPECT_CALL(delegate, OnProfileCreationFinished( + testing::NotNull(), + Profile::CREATE_MODE_ASYNCHRONOUS, true, false)) .WillOnce(testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); { @@ -460,7 +469,9 @@ MockProfileDelegate delegate; base::RunLoop run_loop; - EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)) + EXPECT_CALL(delegate, OnProfileCreationFinished( + testing::NotNull(), + Profile::CREATE_MODE_ASYNCHRONOUS, true, true)) .WillOnce(testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); { @@ -485,7 +496,9 @@ ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); MockProfileDelegate delegate; - EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); + EXPECT_CALL(delegate, OnProfileCreationFinished( + testing::NotNull(), + Profile::CREATE_MODE_SYNCHRONOUS, true, true)); { std::unique_ptr<Profile> profile(CreateProfile( temp_dir.GetPath(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 3fd507a..480de2d 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -566,6 +566,9 @@ } #endif + if (delegate_) + delegate_->OnProfileCreationStarted(this, create_mode); + if (async_prefs) { // Wait for the notification that prefs has been loaded // (successfully or not). Note that we can use base::Unretained @@ -673,7 +676,7 @@ key_->SetPrefs(prefs_.get()); } -void ProfileImpl::DoFinalInit() { +void ProfileImpl::DoFinalInit(CreateMode create_mode) { TRACE_EVENT0("browser", "ProfileImpl::DoFinalInit"); PrefService* prefs = GetPrefs(); @@ -797,14 +800,16 @@ std::make_unique<PrefsInternalsSource>(this)); if (delegate_) { - TRACE_EVENT0("browser", "ProfileImpl::DoFileInit:DelegateOnProfileCreated"); + TRACE_EVENT0("browser", + "ProfileImpl::DoFinalInit:DelegateOnProfileCreationFinished"); // Fails if the browser is shutting down. This is done to avoid // launching new UI, finalising profile creation, etc. which // would trigger a crash down the line. See ... const bool shutting_down = g_browser_process->IsShuttingDown(); - delegate_->OnProfileCreated(this, !shutting_down, IsNewProfile()); + delegate_->OnProfileCreationFinished(this, create_mode, !shutting_down, + IsNewProfile()); // The current Profile may be immediately deleted as part of - // the call to OnProfileCreated(...) if the initialisation is + // the call to OnProfileCreationFinished(...) if the initialisation is // reported as a failure, thus no code should be executed past // that point. if (shutting_down) @@ -1060,7 +1065,7 @@ #endif } -void ProfileImpl::OnLocaleReady() { +void ProfileImpl::OnLocaleReady(CreateMode create_mode) { TRACE_EVENT0("browser", "ProfileImpl::OnLocaleReady"); // Migrate obsolete prefs. @@ -1097,14 +1102,14 @@ this); ChromeVersionService::OnProfileLoaded(prefs_.get(), IsNewProfile()); - DoFinalInit(); + DoFinalInit(create_mode); } void ProfileImpl::OnPrefsLoaded(CreateMode create_mode, bool success) { TRACE_EVENT0("browser", "ProfileImpl::OnPrefsLoaded"); if (!success) { if (delegate_) - delegate_->OnProfileCreated(this, false, false); + delegate_->OnProfileCreationFinished(this, create_mode, false, false); return; } @@ -1113,7 +1118,7 @@ // the line. See crbug.com/625646 if (g_browser_process->IsShuttingDown()) { if (delegate_) - delegate_->OnProfileCreated(this, false, false); + delegate_->OnProfileCreationFinished(this, create_mode, false, false); return; } @@ -1121,14 +1126,14 @@ if (create_mode == CREATE_MODE_SYNCHRONOUS) { // Synchronous create mode implies that either it is restart after crash, // or we are in tests. In both cases the first loaded locale is correct. - OnLocaleReady(); + OnLocaleReady(create_mode); } else { ash::UserSessionManager::GetInstance()->RespectLocalePreferenceWrapper( - this, - base::BindOnce(&ProfileImpl::OnLocaleReady, base::Unretained(this))); + this, base::BindOnce(&ProfileImpl::OnLocaleReady, + base::Unretained(this), create_mode)); } #else - OnLocaleReady(); + OnLocaleReady(create_mode); #endif }
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h index 4b6af24..30293e9 100644 --- a/chrome/browser/profiles/profile_impl.h +++ b/chrome/browser/profiles/profile_impl.h
@@ -204,13 +204,13 @@ void LoadPrefsForNormalStartup(bool async_prefs); // Does final initialization. Should be called after prefs were loaded. - void DoFinalInit(); + void DoFinalInit(CreateMode create_mode); // Switch locale (when possible) and proceed to OnLocaleReady(). void OnPrefsLoaded(CreateMode create_mode, bool success); // Does final prefs initialization and calls Init(). - void OnLocaleReady(); + void OnLocaleReady(CreateMode create_mode); #if BUILDFLAG(ENABLE_SESSION_SERVICE) void StopCreateSessionServiceTimer();
diff --git a/chrome/browser/profiles/profile_keep_alive_types.cc b/chrome/browser/profiles/profile_keep_alive_types.cc index e9eddc9..7f73e3c 100644 --- a/chrome/browser/profiles/profile_keep_alive_types.cc +++ b/chrome/browser/profiles/profile_keep_alive_types.cc
@@ -45,6 +45,8 @@ return out << "kSessionDataDeleter"; case ProfileKeepAliveOrigin::kWebAppProtocolHandlerLaunch: return out << "kWebAppProtocolHandlerLaunch"; + case ProfileKeepAliveOrigin::kExtensionUpdater: + return out << "kExtensionUpdater"; } NOTREACHED(); return out << static_cast<int>(origin);
diff --git a/chrome/browser/profiles/profile_keep_alive_types.h b/chrome/browser/profiles/profile_keep_alive_types.h index bb8b5e57..41b0973 100644 --- a/chrome/browser/profiles/profile_keep_alive_types.h +++ b/chrome/browser/profiles/profile_keep_alive_types.h
@@ -80,7 +80,10 @@ // Waiting for the provider to be ready in protocol handler web app launch. kWebAppProtocolHandlerLaunch = 17, - kMaxValue = kWebAppProtocolHandlerLaunch, + // An extension is being updated. + kExtensionUpdater = 18, + + kMaxValue = kExtensionUpdater, }; std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index 1307094..40303f1 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc
@@ -526,7 +526,8 @@ for (const auto& path_and_profile_info : profiles_info_) { const ProfileInfo* profile_info = path_and_profile_info.second.get(); - if (profile_info->profile && profile_info->profile->IsSystemProfile()) + Profile* profile = profile_info->GetRawProfile(); + if (profile && profile->IsSystemProfile()) continue; for (const auto& origin_and_count : profile_info->keep_alives) { @@ -817,13 +818,13 @@ info = iter->second.get(); } else { // Initiate asynchronous creation process. - info = RegisterProfile(CreateProfileAsyncHelper(profile_path), false); + info = RegisterOwnedProfile(CreateProfileAsyncHelper(profile_path)); } // Call or enqueue the callback. if (!callback.is_null()) { - if (iter != profiles_info_.end() && info->created) { - Profile* profile = info->profile.get(); + if (iter != profiles_info_.end() && info->GetCreatedProfile()) { + Profile* profile = info->GetCreatedProfile(); // If this was the non-ephemeral Guest profile, apply settings and go // OffTheRecord. // The system profile also needs characteristics of being off the record, @@ -848,15 +849,15 @@ bool ProfileManager::IsValidProfile(const void* profile) { for (auto iter = profiles_info_.begin(); iter != profiles_info_.end(); ++iter) { - if (iter->second->created) { - Profile* candidate = iter->second->profile.get(); - if (candidate == profile) - return true; - std::vector<Profile*> otr_profiles = - candidate->GetAllOffTheRecordProfiles(); - if (base::Contains(otr_profiles, profile)) - return true; - } + Profile* candidate = iter->second->GetCreatedProfile(); + if (!candidate) + continue; + if (candidate == profile) + return true; + std::vector<Profile*> otr_profiles = + candidate->GetAllOffTheRecordProfiles(); + if (base::Contains(otr_profiles, profile)) + return true; } return false; } @@ -879,8 +880,9 @@ std::vector<Profile*> profiles; for (auto iter = profiles_info_.begin(); iter != profiles_info_.end(); ++iter) { - if (iter->second->created) - profiles.push_back(iter->second->profile.get()); + Profile* profile = iter->second->GetCreatedProfile(); + if (profile) + profiles.push_back(profile); } return profiles; } @@ -889,7 +891,7 @@ const base::FilePath& path) const { TRACE_EVENT0("browser", "ProfileManager::GetProfileByPathInternal"); ProfileInfo* profile_info = GetProfileInfoByPath(path); - return profile_info ? profile_info->profile.get() : nullptr; + return profile_info ? profile_info->GetRawProfile() : nullptr; } bool ProfileManager::IsAllowedProfilePath(const base::FilePath& path) const { @@ -915,8 +917,7 @@ Profile* ProfileManager::GetProfileByPath(const base::FilePath& path) const { TRACE_EVENT0("browser", "ProfileManager::GetProfileByPath"); ProfileInfo* profile_info = GetProfileInfoByPath(path); - return (profile_info && profile_info->created) ? profile_info->profile.get() - : nullptr; + return profile_info ? profile_info->GetCreatedProfile() : nullptr; } // static @@ -1356,66 +1357,19 @@ void ProfileManager::RegisterTestingProfile(std::unique_ptr<Profile> profile, bool add_to_storage) { - Profile* profile_ptr = profile.get(); - RegisterProfile(std::move(profile), true); + ProfileInfo* profile_info = RegisterOwnedProfile(std::move(profile)); + profile_info->MarkProfileAsCreated(profile_info->GetRawProfile()); if (add_to_storage) { - InitProfileUserPrefs(profile_ptr); - AddProfileToStorage(profile_ptr); + InitProfileUserPrefs(profile_info->GetCreatedProfile()); + AddProfileToStorage(profile_info->GetCreatedProfile()); } } -void ProfileManager::OnProfileCreated(Profile* profile, - bool success, - bool is_new_profile) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - auto iter = profiles_info_.find(profile->GetPath()); - DCHECK(iter != profiles_info_.end()); - ProfileInfo* info = iter->second.get(); - - std::vector<CreateCallback> callbacks; - info->callbacks.swap(callbacks); - - // Invoke CREATED callback for normal profiles. - bool go_off_the_record = ShouldGoOffTheRecord(profile); - if (success && !go_off_the_record) - RunCallbacks(callbacks, profile, Profile::CREATE_STATUS_CREATED); - - // Perform initialization. - if (success) { - DoFinalInit(info, go_off_the_record); - if (go_off_the_record) - profile = profile->GetPrimaryOTRProfile(/*create_if_needed=*/true); - } else { - profile = nullptr; - profiles_info_.erase(iter); - } - - if (profile) { - // If this was the guest or system profile, finish setting its special - // status. - if (profile->IsGuestSession() || profile->IsSystemProfile() || - profile->IsEphemeralGuestProfile()) { - SetNonPersonalProfilePrefs(profile); - } - - // Invoke CREATED callback for incognito profiles. - if (go_off_the_record) - RunCallbacks(callbacks, profile, Profile::CREATE_STATUS_CREATED); - } - - // Invoke INITIALIZED or FAIL for all profiles. - RunCallbacks(callbacks, profile, - profile ? Profile::CREATE_STATUS_INITIALIZED : - Profile::CREATE_STATUS_LOCAL_FAIL); -} - std::unique_ptr<Profile> ProfileManager::CreateProfileHelper( const base::FilePath& path) { TRACE_EVENT0("browser", "ProfileManager::CreateProfileHelper"); - return Profile::CreateProfile(path, nullptr, - Profile::CREATE_MODE_SYNCHRONOUS); + return Profile::CreateProfile(path, this, Profile::CREATE_MODE_SYNCHRONOUS); } std::unique_ptr<Profile> ProfileManager::CreateProfileAsyncHelper( @@ -1523,8 +1477,14 @@ if (GetTotalRefCount(info->keep_alives) != 0) return; - VLOG(1) << "Deleting profile " << info->profile->GetDebugName(); - RemoveProfile(info->profile->GetPath()); + if (!info->GetCreatedProfile()) { + NOTREACHED() << "Attempted to delete profile " + << info->GetRawProfile()->GetDebugName() + << " before it was created. This is not valid."; + } + + VLOG(1) << "Deleting profile " << info->GetCreatedProfile()->GetDebugName(); + RemoveProfile(info->GetCreatedProfile()->GetPath()); #endif // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) } @@ -1532,14 +1492,17 @@ bool go_off_the_record) { TRACE_EVENT0("browser", "ProfileManager::DoFinalInit"); - Profile* profile = profile_info->profile.get(); + Profile* profile = profile_info->GetRawProfile(); DoFinalInitForServices(profile, go_off_the_record); AddProfileToStorage(profile); DoFinalInitLogging(profile); // Set the |created| flag now so that PROFILE_ADDED handlers can use // GetProfileByPath(). - profile_info->created = true; + // + // TODO(nicolaso): De-spaghettify MarkProfileAsCreated() by only calling it + // here, and nowhere else. + profile_info->MarkProfileAsCreated(profile); for (auto& observer : observers_) observer.OnProfileAdded(profile); @@ -1680,16 +1643,50 @@ base::TimeDelta::FromSeconds(112)); } -ProfileManager::ProfileInfo::ProfileInfo(std::unique_ptr<Profile> profile, - bool created) - : profile(std::move(profile)), created(created) { +ProfileManager::ProfileInfo::ProfileInfo() { // The profile should have a refcount >=1 until AddKeepAlive() is called. if (base::FeatureList::IsEnabled(features::kDestroyProfileOnBrowserClose)) keep_alives[ProfileKeepAliveOrigin::kWaitingForFirstBrowserWindow] = 1; } ProfileManager::ProfileInfo::~ProfileInfo() { - ProfileDestroyer::DestroyProfileWhenAppropriate(profile.release()); + // Regardless of sync or async creation, we always take ownership right after + // Profile::CreateProfile(). So we should always own the Profile by this + // point. + DCHECK(owned_profile_); + DCHECK_EQ(owned_profile_.get(), unowned_profile_); + unowned_profile_ = nullptr; + ProfileDestroyer::DestroyProfileWhenAppropriate(owned_profile_.release()); +} + +// static +std::unique_ptr<ProfileManager::ProfileInfo> +ProfileManager::ProfileInfo::FromUnownedProfile(Profile* profile) { + // ProfileInfo's constructor is private, can't make_unique(). + std::unique_ptr<ProfileInfo> info(new ProfileInfo()); + info->unowned_profile_ = profile; + return info; +} + +void ProfileManager::ProfileInfo::TakeOwnershipOfProfile( + std::unique_ptr<Profile> profile) { + DCHECK_EQ(unowned_profile_, profile.get()); + DCHECK(!owned_profile_); + owned_profile_ = std::move(profile); +} + +void ProfileManager::ProfileInfo::MarkProfileAsCreated(Profile* profile) { + DCHECK_EQ(GetRawProfile(), profile); + created_ = true; +} + +Profile* ProfileManager::ProfileInfo::GetCreatedProfile() const { + return created_ ? GetRawProfile() : nullptr; +} + +Profile* ProfileManager::ProfileInfo::GetRawProfile() const { + DCHECK(owned_profile_ == nullptr || owned_profile_.get() == unowned_profile_); + return unowned_profile_; } Profile* ProfileManager::GetActiveUserOrOffTheRecordProfile() { @@ -1713,7 +1710,7 @@ ProfileInfo* profile_info = GetProfileInfoByPath(default_profile_dir); // Fallback to default off-the-record profile, if user profile has not started // loading or has not fully loaded yet. - if (!profile_info || !profile_info->created) + if (!profile_info || !profile_info->GetCreatedProfile()) default_profile_dir = profiles::GetDefaultProfileDir(user_data_dir_); Profile* profile = GetProfile(default_profile_dir); @@ -1743,9 +1740,12 @@ return false; } - ProfileInfo* profile_info = RegisterProfile(std::move(profile), true); - InitProfileUserPrefs(profile_info->profile.get()); - DoFinalInit(profile_info, ShouldGoOffTheRecord(profile_info->profile.get())); + ProfileInfo* profile_info = RegisterOwnedProfile(std::move(profile)); + profile_info->MarkProfileAsCreated(profile_info->GetRawProfile()); + + InitProfileUserPrefs(profile_info->GetCreatedProfile()); + DoFinalInit(profile_info, + ShouldGoOffTheRecord(profile_info->GetCreatedProfile())); return true; } @@ -1803,17 +1803,93 @@ if (!profile) return nullptr; - if (profile->IsGuestSession() || profile->IsEphemeralGuestProfile() || - profile->IsSystemProfile()) { - SetNonPersonalProfilePrefs(profile.get()); + // Place the unique_ptr inside ProfileInfo, which was added by + // OnProfileCreationStarted(). + ProfileInfo* info = GetProfileInfoByPath(profile->GetPath()); + DCHECK(info); + info->TakeOwnershipOfProfile(std::move(profile)); + info->MarkProfileAsCreated(info->GetRawProfile()); + Profile* profile_ptr = info->GetCreatedProfile(); + + if (profile_ptr->IsGuestSession() || profile_ptr->IsEphemeralGuestProfile() || + profile_ptr->IsSystemProfile()) { + SetNonPersonalProfilePrefs(profile_ptr); } - Profile* profile_ptr = profile.get(); - bool result = AddProfile(std::move(profile)); - DCHECK(result); + bool go_off_the_record = ShouldGoOffTheRecord(profile_ptr); + DoFinalInit(info, go_off_the_record); return profile_ptr; } +void ProfileManager::OnProfileCreationFinished(Profile* profile, + Profile::CreateMode create_mode, + bool success, + bool is_new_profile) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + auto iter = profiles_info_.find(profile->GetPath()); + DCHECK(iter != profiles_info_.end()); + ProfileInfo* info = iter->second.get(); + + if (create_mode == Profile::CREATE_MODE_SYNCHRONOUS) { + // Already initialized in OnProfileCreationStarted(). + // TODO(nicolaso): Figure out why this would break browser tests: + // DCHECK_EQ(profile, profiles_info_->GetCreatedProfile()); + return; + } + + std::vector<CreateCallback> callbacks; + info->callbacks.swap(callbacks); + + // Invoke CREATED callback for normal profiles. + bool go_off_the_record = ShouldGoOffTheRecord(profile); + if (success && !go_off_the_record) + RunCallbacks(callbacks, profile, Profile::CREATE_STATUS_CREATED); + + // Perform initialization. + if (success) { + DoFinalInit(info, go_off_the_record); + if (go_off_the_record) + profile = profile->GetPrimaryOTRProfile(/*create_if_needed=*/true); + } else { + profile = nullptr; + profiles_info_.erase(iter); + } + + if (profile) { + // If this was the guest or system profile, finish setting its special + // status. + if (profile->IsGuestSession() || profile->IsSystemProfile() || + profile->IsEphemeralGuestProfile()) { + SetNonPersonalProfilePrefs(profile); + } + + // Invoke CREATED callback for incognito profiles. + if (go_off_the_record) + RunCallbacks(callbacks, profile, Profile::CREATE_STATUS_CREATED); + } + + // Invoke INITIALIZED or FAIL for all profiles. + RunCallbacks(callbacks, profile, + profile ? Profile::CREATE_STATUS_INITIALIZED + : Profile::CREATE_STATUS_LOCAL_FAIL); +} + +void ProfileManager::OnProfileCreationStarted(Profile* profile, + Profile::CreateMode create_mode) { + if (create_mode == Profile::CREATE_MODE_ASYNCHRONOUS) { + // Profile will be registered later, in CreateProfileAsync(). + return; + } + + if (profiles_info_.find(profile->GetPath()) != profiles_info_.end()) + return; + + // Make sure the Profile is in |profiles_info_| early enough during Profile + // initialization. + RegisterUnownedProfile(profile); +} + #if !defined(OS_ANDROID) void ProfileManager::EnsureActiveProfileExistsBeforeDeletion( ProfileLoadedCallback callback, @@ -2010,12 +2086,23 @@ #endif // !defined(OS_ANDROID) -ProfileManager::ProfileInfo* ProfileManager::RegisterProfile( - std::unique_ptr<Profile> profile, - bool created) { - TRACE_EVENT0("browser", "ProfileManager::RegisterProfile"); +ProfileManager::ProfileInfo* ProfileManager::RegisterOwnedProfile( + std::unique_ptr<Profile> profile) { + TRACE_EVENT0("browser", "ProfileManager::RegisterOwnedProfile"); + Profile* profile_ptr = profile.get(); + auto info = ProfileInfo::FromUnownedProfile(profile_ptr); + info->TakeOwnershipOfProfile(std::move(profile)); + ProfileInfo* info_raw = info.get(); + profiles_info_.insert( + std::make_pair(profile_ptr->GetPath(), std::move(info))); + return info_raw; +} + +ProfileManager::ProfileInfo* ProfileManager::RegisterUnownedProfile( + Profile* profile) { + TRACE_EVENT0("browser", "ProfileManager::RegisterUnownedProfile"); base::FilePath path = profile->GetPath(); - auto info = std::make_unique<ProfileInfo>(std::move(profile), created); + auto info = ProfileInfo::FromUnownedProfile(profile); ProfileInfo* info_raw = info.get(); profiles_info_.insert(std::make_pair(path, std::move(info))); return info_raw;
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h index cd6fdbb..1384f54 100644 --- a/chrome/browser/profiles/profile_manager.h +++ b/chrome/browser/profiles/profile_manager.h
@@ -253,9 +253,12 @@ const base::FilePath& user_data_dir() const { return user_data_dir_; } // Profile::Delegate implementation: - void OnProfileCreated(Profile* profile, - bool success, - bool is_new_profile) override; + void OnProfileCreationStarted(Profile* profile, + Profile::CreateMode create_mode) override; + void OnProfileCreationFinished(Profile* profile, + Profile::CreateMode create_mode, + bool success, + bool is_new_profile) override; // Used for testing. Returns true if |profile| has at least one ref of type // |origin|. @@ -288,26 +291,59 @@ // For AddKeepAlive() and RemoveKeepAlive(). friend class ScopedProfileKeepAlive; - // This struct contains information about profiles which are being loaded or + // This class contains information about profiles which are being loaded or // were loaded. - struct ProfileInfo { - ProfileInfo(std::unique_ptr<Profile> profile, bool created); + class ProfileInfo { + public: ProfileInfo(const ProfileInfo&) = delete; ProfileInfo& operator=(const ProfileInfo&) = delete; ~ProfileInfo(); - std::unique_ptr<Profile> profile; - // Strong references to this Profile once it's been created (e.g. a Browser - // object, a BackgroundModeManager, ...) + // Returns a non-created ProfileInfo that does not own |profile|. + static std::unique_ptr<ProfileInfo> FromUnownedProfile(Profile* profile); + + // Takes ownership of |profile|, so it gets destroyed when this ProfileInfo + // is deleted. + void TakeOwnershipOfProfile(std::unique_ptr<Profile> profile); + + // Marks the Profile as created, so GetCreatedProfile() returns non-null. + void MarkProfileAsCreated(Profile* profile); + + // Returns the owned Profile, if creation is complete (i.e., prefs are + // loaded). Returns null otherwise. + Profile* GetCreatedProfile() const; + + // Returns the Profile, regardless of whether it's owned/unowned or whether + // prefs are loaded. + Profile* GetRawProfile() const; + + // TODO(nicolaso): Make |keep_alives| and |callbacks| private with + // accessors. + + // Strong references to this Profile (e.g. a Browser object, a + // BackgroundModeManager, ...) // // Initially contains a kWaitingForFirstBrowserWindow entry, which gets // removed when a kBrowserWindow keepalive is added. std::map<ProfileKeepAliveOrigin, int> keep_alives; - // Whether profile has been fully loaded (created and initialized). - bool created; // List of callbacks to run when profile initialization is done. Note, when // profile is fully loaded this vector will be empty. std::vector<CreateCallback> callbacks; + + private: + // Callers should use FromOwned/UnownedProfile() instead. + ProfileInfo(); + + // The Profile pointed to by this ProfileInfo. + Profile* unowned_profile_ = nullptr; + + // For when the Profile is owned, via FromOwnedProfile() or + // TakeOwnershipOfProfile(). + std::unique_ptr<Profile> owned_profile_; + + // Whether profile has been fully loaded (created and initialized). See + // MarkProfileAsCreated(). + bool created_ = false; }; // Increments/decrements the refcount on a |profile|. (it must not be an @@ -378,7 +414,8 @@ // Registers profile with given info. Returns pointer to created ProfileInfo // entry. - ProfileInfo* RegisterProfile(std::unique_ptr<Profile> profile, bool created); + ProfileInfo* RegisterUnownedProfile(Profile* profile); + ProfileInfo* RegisterOwnedProfile(std::unique_ptr<Profile> profile); // Returns ProfileInfo associated with given |path|, registered earlier with // RegisterProfile.
diff --git a/chrome/browser/reading_list/android/reading_list_manager.h b/chrome/browser/reading_list/android/reading_list_manager.h index 28b589a3..8d76f35 100644 --- a/chrome/browser/reading_list/android/reading_list_manager.h +++ b/chrome/browser/reading_list/android/reading_list_manager.h
@@ -7,7 +7,7 @@ #include <string> -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "components/keyed_service/core/keyed_service.h" namespace bookmarks {
diff --git a/chrome/browser/reading_list/android/reading_list_manager_impl.h b/chrome/browser/reading_list/android/reading_list_manager_impl.h index bea69d8..469d52e 100644 --- a/chrome/browser/reading_list/android/reading_list_manager_impl.h +++ b/chrome/browser/reading_list/android/reading_list_manager_impl.h
@@ -9,6 +9,7 @@ #include <memory> +#include "base/observer_list.h" #include "components/reading_list/core/reading_list_model_observer.h" class ReadingListModel;
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h index b6d55e7..b0b04af 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.h +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/files/file_path.h" -#include "base/observer_list.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/custom_handlers/protocol_handler_registry.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/reputation/url_elision_policy.cc b/chrome/browser/reputation/url_elision_policy.cc deleted file mode 100644 index e3497fdf..0000000 --- a/chrome/browser/reputation/url_elision_policy.cc +++ /dev/null
@@ -1,57 +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/reputation/url_elision_policy.h" - -#include "base/feature_list.h" -#include "base/metrics/field_trial_params.h" -#include "chrome/browser/reputation/local_heuristics.h" -#include "components/lookalikes/core/lookalike_url_util.h" -#include "components/omnibox/common/omnibox_features.h" -#include "components/reputation/core/safety_tips_config.h" -#include "components/url_formatter/spoof_checks/top_domains/top500_domains.h" - -#include "url/gurl.h" - -namespace { - -const base::FeatureParam<int> kMaximumUnelidedHostnameLength{ - &omnibox::kMaybeElideToRegistrableDomain, "max_unelided_host_length", 25}; -const base::FeatureParam<bool> kEnableKeywordBasedElision{ - &omnibox::kMaybeElideToRegistrableDomain, "enable_keyword_elision", true}; -const base::FeatureParam<bool> kSearchE2LDForKeywords{ - &omnibox::kMaybeElideToRegistrableDomain, "search_e2ld_for_keywords", true}; - -} // namespace - -bool ShouldElideToRegistrableDomain(const GURL& url) { - DCHECK(base::FeatureList::IsEnabled(omnibox::kMaybeElideToRegistrableDomain)); - if (url.HostIsIPAddress()) { - return false; - } - - auto* proto = reputation::GetSafetyTipsRemoteConfigProto(); - if (!proto || reputation::IsUrlAllowlistedBySafetyTipsComponent(proto, url)) { - // Not having a proto happens when the component hasn't downloaded yet. This - // should only happen for a short window following initial Chrome install. - return false; - } - - auto host = url.host(); - if (static_cast<int>(host.length()) > kMaximumUnelidedHostnameLength.Get()) { - return true; - } - - // Hostnames using sensitive keywords (typically, brandnames) are often social - // engineering, and thus should only show the registrable domain. - auto eTLD_plus_one = GetETLDPlusOne(host); - if (kEnableKeywordBasedElision.Get() && - HostnameContainsKeyword(url, eTLD_plus_one, top500_domains::kTopKeywords, - top500_domains::kNumTopKeywords, - kSearchE2LDForKeywords.Get())) { - return true; - } - - return false; -}
diff --git a/chrome/browser/reputation/url_elision_policy.h b/chrome/browser/reputation/url_elision_policy.h deleted file mode 100644 index c2746b6..0000000 --- a/chrome/browser/reputation/url_elision_policy.h +++ /dev/null
@@ -1,14 +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_REPUTATION_URL_ELISION_POLICY_H_ -#define CHROME_BROWSER_REPUTATION_URL_ELISION_POLICY_H_ - -class GURL; - -// Called by omnibox code (when enabled) to check whether |url| should be elided -// to show just the eTLD+1 due to failing any number of heuristics. -bool ShouldElideToRegistrableDomain(const GURL& url); - -#endif // CHROME_BROWSER_REPUTATION_URL_ELISION_POLICY_H_
diff --git a/chrome/browser/reputation/url_elision_policy_unittest.cc b/chrome/browser/reputation/url_elision_policy_unittest.cc deleted file mode 100644 index e130de59..0000000 --- a/chrome/browser/reputation/url_elision_policy_unittest.cc +++ /dev/null
@@ -1,176 +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/reputation/url_elision_policy.h" - -#include "base/test/scoped_feature_list.h" -#include "components/omnibox/common/omnibox_features.h" -#include "components/reputation/core/safety_tip_test_utils.h" -#include "components/url_formatter/spoof_checks/common_words/common_words_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -namespace test { -#include "components/url_formatter/spoof_checks/common_words/common_words_test-inc.cc" -} - -namespace { - -// Note: This number is arbitrary; we just need to be able to build -// hostnames that are reliably shorter/longer than the limit. -const char* kMaxUnelidedHostLengthParam = "20"; - -enum class KeywordSearchConfig { - kDisabled, - kEnabledWithE2LD, - kEnabledWithoutE2LD -}; - -} // namespace - -class UrlElisionPolicyTest : public testing::Test { - public: - UrlElisionPolicyTest() { - scoped_feature_list_.InitWithFeaturesAndParameters( - {{omnibox::kMaybeElideToRegistrableDomain, - {{"max_unelided_host_length", kMaxUnelidedHostLengthParam}}}}, - {}); - url_formatter::common_words::SetCommonWordDAFSAForTesting( - test::kDafsa, sizeof(test::kDafsa)); - - // Ensure that the allowlist exists (as otherwise we'll never elide). - reputation::InitializeBlankLookalikeAllowlistForTesting(); - } - - ~UrlElisionPolicyTest() override = default; - - void TearDown() override { - url_formatter::common_words::ResetCommonWordDAFSAForTesting(); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; - - DISALLOW_COPY_AND_ASSIGN(UrlElisionPolicyTest); -}; - -// Ensure that long domains are elided. -TEST_F(UrlElisionPolicyTest, ElidesLongDomains) { - GURL kUrl = GURL("http://abcdefghijklmnopqrs.tu/xyz"); - EXPECT_TRUE(ShouldElideToRegistrableDomain(kUrl)); -} - -// Ensure that short domains are not elided. -TEST_F(UrlElisionPolicyTest, DoesntElideShortDomains) { - GURL kUrl = GURL("http://abc.d/xyz"); - EXPECT_FALSE(ShouldElideToRegistrableDomain(kUrl)); -} - -// Ensure that domains are allowlisted are not elided. -TEST_F(UrlElisionPolicyTest, DoesntElideAllowlistedDomains) { - GURL kUrl = GURL("http://alongbutstillallowlisteddomain.com/xyz"); - - // This domain should be elided normally... - EXPECT_TRUE(ShouldElideToRegistrableDomain(kUrl)); - - // ...but not when allowlisted. - reputation::SetSafetyTipAllowlistPatterns( - {"alongbutstillallowlisteddomain.com/"}, {}, {}); - EXPECT_FALSE(ShouldElideToRegistrableDomain(kUrl)); -} - -// Ensure that sensitive keywords cause elision when expected and not otherwise. -// Note further tests in SafetyTipHeuristicsTest.SensitiveKeywordsTest. -TEST_F(UrlElisionPolicyTest, ElidesKeywordedDomainsAppropriately) { - // Note: "google" is a sensitive keyword, taken from top500-domains-inc.cc. - EXPECT_TRUE( - ShouldElideToRegistrableDomain(GURL("http://google-evil.com/xyz"))); - EXPECT_TRUE( - ShouldElideToRegistrableDomain(GURL("http://google.evil.com/xyz"))); - - // Elision shouldn't happen when the keyword is the e2LD. - EXPECT_FALSE( - ShouldElideToRegistrableDomain(GURL("http://www.google.com/xyz"))); - EXPECT_FALSE(ShouldElideToRegistrableDomain(GURL("http://google.com/xyz"))); - // But those domains aren't exempt in other parts of the domain. - EXPECT_TRUE( - ShouldElideToRegistrableDomain(GURL("http://google.google.com/xyz"))); - - // If there are no keywords, there should be no elision. - EXPECT_FALSE( - ShouldElideToRegistrableDomain(GURL("http://cupcake-login.com/xyz"))); - EXPECT_FALSE( - ShouldElideToRegistrableDomain(GURL("http://cupcake.login.com/xyz"))); - - // We don't elide on invalid/missing TLDs. - EXPECT_FALSE(ShouldElideToRegistrableDomain(GURL("http://google/xyz"))); - EXPECT_FALSE( - ShouldElideToRegistrableDomain(GURL("http://google.notreal/xyz"))); - // Nor on non-HTTP(s) - EXPECT_FALSE( - ShouldElideToRegistrableDomain(GURL("ftp://google.login.com/xyz"))); -} - -class UrlElisionKeywordPolicyTest - : public UrlElisionPolicyTest, - public testing::WithParamInterface<KeywordSearchConfig> { - public: - UrlElisionKeywordPolicyTest() { - switch (GetParam()) { - case KeywordSearchConfig::kDisabled: - scoped_feature_list_.InitWithFeaturesAndParameters( - {{omnibox::kMaybeElideToRegistrableDomain, - {{"max_unelided_host_length", kMaxUnelidedHostLengthParam}, - {"enable_keyword_elision", "false"}}}}, - {}); - break; - case KeywordSearchConfig::kEnabledWithE2LD: - scoped_feature_list_.InitWithFeaturesAndParameters( - {{omnibox::kMaybeElideToRegistrableDomain, - {{"max_unelided_host_length", kMaxUnelidedHostLengthParam}, - {"enable_keyword_elision", "true"}, - {"search_e2ld_for_keywords", "true"}}}}, - {}); - break; - case KeywordSearchConfig::kEnabledWithoutE2LD: - scoped_feature_list_.InitWithFeaturesAndParameters( - {{omnibox::kMaybeElideToRegistrableDomain, - {{"max_unelided_host_length", kMaxUnelidedHostLengthParam}, - {"enable_keyword_elision", "true"}, - {"search_e2ld_for_keywords", "false"}}}}, - {}); - break; - } - } - - ~UrlElisionKeywordPolicyTest() override = default; - - bool IsKeywordElisionEnabled() { - return GetParam() != KeywordSearchConfig::kDisabled; - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; - - DISALLOW_COPY_AND_ASSIGN(UrlElisionKeywordPolicyTest); -}; - -INSTANTIATE_TEST_SUITE_P( - All, - UrlElisionKeywordPolicyTest, - ::testing::Values(KeywordSearchConfig::kDisabled, - KeywordSearchConfig::kEnabledWithE2LD, - KeywordSearchConfig::kEnabledWithoutE2LD)); - -// Verify that keyword elision follows the feature parameter. -TEST_P(UrlElisionKeywordPolicyTest, ElidesOnKeywords) { - EXPECT_EQ(IsKeywordElisionEnabled(), - ShouldElideToRegistrableDomain(GURL("http://google.evil.com/xyz"))); -} - -// Verify that keyword elision respects the e2LD inclusion parameter. -TEST_P(UrlElisionKeywordPolicyTest, RespectsE2LDParam) { - EXPECT_EQ(GetParam() == KeywordSearchConfig::kEnabledWithE2LD, - ShouldElideToRegistrableDomain(GURL("http://google-evil.com/xyz"))); -}
diff --git a/chrome/browser/resources/chromeos/login/os_install.html b/chrome/browser/resources/chromeos/login/os_install.html index 3e2cfb6..fc2a295 100644 --- a/chrome/browser/resources/chromeos/login/os_install.html +++ b/chrome/browser/resources/chromeos/login/os_install.html
@@ -19,7 +19,8 @@ <template> <style include="oobe-dialog-host"></style> - <oobe-adaptive-dialog id="osInstallDialog" role="dialog" for-step="intro" + <oobe-adaptive-dialog id="osInstallDialogIntro" + role="dialog" for-step="intro" aria-label$="[[i18nDynamic(locale, 'osInstallDialogIntroTitle')]]"> <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> <h1 slot="title">[[i18nDynamic(locale, 'osInstallDialogIntroTitle')]]</h1> @@ -41,7 +42,8 @@ </div> </oobe-adaptive-dialog> - <oobe-adaptive-dialog id="osInstallDialog" role="dialog" for-step="confirm" + <oobe-adaptive-dialog id="osInstallDialogConfirm" + role="dialog" for-step="confirm" aria-label$="[[i18nDynamic(locale, 'osInstallDialogConfirmTitle')]]"> <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> <h1 slot="title">[[i18nDynamic(locale, 'osInstallDialogConfirmTitle')]] @@ -58,10 +60,26 @@ </div> </oobe-adaptive-dialog> - <oobe-loading-dialog id="osInstallDialog" for-step="in_progress" + <oobe-loading-dialog id="osInstallDialogInProgress" + role="dialog" for-step="in_progress" text-key="osInstallDialogInProgressTitle" aria-label$="[[i18nDynamic(locale, 'enableDebuggingScreenTitle')]]"> <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> </oobe-loading-dialog> + + <oobe-adaptive-dialog id="osInstallDialogError" + role="dialog" for-step="error" + aria-label$="[[i18nDynamic(locale, 'osInstallDialogErrorTitle')]]"> + <iron-icon slot="icon" icon="oobe-32:warning"></iron-icon> + <h1 slot="title">[[i18nDynamic(locale, 'osInstallDialogErrorTitle')]]</h1> + </oobe-adaptive-dialog> + + <oobe-adaptive-dialog id="osInstallDialogSuccess" + role="dialog" for-step="success" + aria-label$="[[i18nDynamic(locale, 'osInstallDialogSuccessTitle')]]"> + <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> + <h1 slot="title">[[i18nDynamic(locale, 'osInstallDialogSuccessTitle')]] + </h1> + </oobe-adaptive-dialog> </template> </dom-module>
diff --git a/chrome/browser/resources/chromeos/login/os_install.js b/chrome/browser/resources/chromeos/login/os_install.js index 9e18989..acc6dfbd 100644 --- a/chrome/browser/resources/chromeos/login/os_install.js +++ b/chrome/browser/resources/chromeos/login/os_install.js
@@ -11,6 +11,8 @@ INTRO: 'intro', CONFIRM: 'confirm', IN_PROGRESS: 'in_progress', + ERROR: 'error', + SUCCESS: 'success', }; Polymer({
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn index bae9844..9ac90ea 100644 --- a/chrome/browser/resources/extensions/BUILD.gn +++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -77,40 +77,40 @@ } preprocess_if_expr("preprocess_generated") { - deps = [ ":web_components" ] + public_deps = [ ":web_components" ] in_folder = target_gen_dir out_folder = "$target_gen_dir/$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_gen_manifest" in_files = [ "checkup.ts", - "code_section.js", - "activity_log/activity_log_history_item.js", - "activity_log/activity_log_history.js", - "activity_log/activity_log.js", - "activity_log/activity_log_stream_item.js", - "activity_log/activity_log_stream.js", - "detail_view.js", + "code_section.ts", + "activity_log/activity_log_history_item.ts", + "activity_log/activity_log_history.ts", + "activity_log/activity_log.ts", + "activity_log/activity_log_stream_item.ts", + "activity_log/activity_log_stream.ts", + "detail_view.ts", "drop_overlay.ts", - "error_page.js", - "host_permissions_toggle_list.js", + "error_page.ts", + "host_permissions_toggle_list.ts", "icons.ts", "install_warnings_dialog.ts", - "item.js", - "item_list.js", + "item.ts", + "item_list.ts", "keyboard_shortcuts.ts", - "load_error.js", - "manager.js", + "load_error.ts", + "manager.ts", "options_dialog.ts", "pack_dialog_alert.ts", "pack_dialog.ts", - "runtime_host_permissions.js", + "runtime_host_permissions.ts", "runtime_hosts_dialog.ts", "shared_style.ts", "shared_vars.ts", - "shortcut_input.js", + "shortcut_input.ts", "sidebar.ts", "toggle_row.ts", - "toolbar.js", + "toolbar.ts", ] if (is_chromeos_ash) { @@ -128,29 +128,29 @@ html_to_js("web_components_local") { js_files = [ "checkup.ts", - "code_section.js", - "detail_view.js", + "code_section.ts", + "detail_view.ts", "drop_overlay.ts", - "error_page.js", - "host_permissions_toggle_list.js", + "error_page.ts", + "host_permissions_toggle_list.ts", "icons.ts", "install_warnings_dialog.ts", - "item.js", - "item_list.js", + "item.ts", + "item_list.ts", "keyboard_shortcuts.ts", - "load_error.js", - "manager.js", + "load_error.ts", + "manager.ts", "options_dialog.ts", "pack_dialog.ts", "pack_dialog_alert.ts", - "runtime_host_permissions.js", + "runtime_host_permissions.ts", "runtime_hosts_dialog.ts", "shared_style.ts", "shared_vars.ts", - "shortcut_input.js", + "shortcut_input.ts", "sidebar.ts", "toggle_row.ts", - "toolbar.js", + "toolbar.ts", ] if (is_chromeos_ash) { @@ -180,43 +180,43 @@ out_dir = "$target_gen_dir/tsc" tsconfig_base = "tsconfig_base.json" in_files = [ - "activity_log/activity_log_history_item.js", - "activity_log/activity_log_history.js", - "activity_log/activity_log.js", - "activity_log/activity_log_stream_item.js", - "activity_log/activity_log_stream.js", + "activity_log/activity_log_history_item.ts", + "activity_log/activity_log_history.ts", + "activity_log/activity_log.ts", + "activity_log/activity_log_stream_item.ts", + "activity_log/activity_log_stream.ts", "checkup.ts", - "code_section.js", - "detail_view.js", + "code_section.ts", + "detail_view.ts", "drag_and_drop_handler.ts", "drop_overlay.ts", - "error_page.js", + "error_page.ts", "extensions.ts", - "host_permissions_toggle_list.js", + "host_permissions_toggle_list.ts", "icons.ts", "install_warnings_dialog.ts", "item_mixin.ts", - "item.js", - "item_list.js", + "item.ts", + "item_list.ts", "item_util.ts", "keyboard_shortcut_delegate.ts", "keyboard_shortcuts.ts", - "load_error.js", - "manager.js", + "load_error.ts", + "manager.ts", "navigation_helper.ts", "options_dialog.ts", "pack_dialog_alert.ts", "pack_dialog.ts", - "runtime_host_permissions.js", + "runtime_host_permissions.ts", "runtime_hosts_dialog.ts", "service.ts", "shared_style.ts", "shared_vars.ts", - "shortcut_input.js", + "shortcut_input.ts", "shortcut_util.ts", "sidebar.ts", "toggle_row.ts", - "toolbar.js", + "toolbar.ts", ] definitions = [ "//tools/typescript/definitions/activity_log_private.d.ts",
diff --git a/chrome/browser/resources/extensions/activity_log/BUILD.gn b/chrome/browser/resources/extensions/activity_log/BUILD.gn index b5ae50b..7745d6b7 100644 --- a/chrome/browser/resources/extensions/activity_log/BUILD.gn +++ b/chrome/browser/resources/extensions/activity_log/BUILD.gn
@@ -6,10 +6,10 @@ html_to_js("web_components") { js_files = [ - "activity_log.js", - "activity_log_history.js", - "activity_log_history_item.js", - "activity_log_stream.js", - "activity_log_stream_item.js", + "activity_log.ts", + "activity_log_history.ts", + "activity_log_history_item.ts", + "activity_log_stream.ts", + "activity_log_stream_item.ts", ] }
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log.js b/chrome/browser/resources/extensions/activity_log/activity_log.ts similarity index 75% rename from chrome/browser/resources/extensions/activity_log/activity_log.js rename to chrome/browser/resources/extensions/activity_log/activity_log.ts index c2f2187..250255c 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log.ts
@@ -16,7 +16,7 @@ import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js'; import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; +import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {afterNextRender, html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -29,34 +29,34 @@ * fetched from the activity log database with some fields such as args * omitted. STREAM displays extension activities in a more verbose format in * real time. NONE is used when user is away from the page. - * @enum {number} */ -const ActivityLogSubpage = { - NONE: -1, - HISTORY: 0, - STREAM: 1 -}; +const enum ActivityLogSubpage { + NONE = -1, + HISTORY = 0, + STREAM = 1, +} + /** * A struct used as a placeholder for chrome.developerPrivate.ExtensionInfo * for this component if the extensionId from the URL does not correspond to * installed extension. - * @typedef {{ - * id: string, - * isPlaceholder: boolean, - * }} */ -export let ActivityLogExtensionPlaceholder; +export type ActivityLogExtensionPlaceholder = { + id: string, + isPlaceholder: boolean, +} -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ +interface ExtensionsActivityLogElement { + $: { + closeButton: HTMLElement, + }; +} + const ExtensionsActivityLogElementBase = - mixinBehaviors([CrContainerShadowBehavior, I18nBehavior], PolymerElement); + mixinBehaviors([CrContainerShadowBehavior, I18nBehavior], PolymerElement) as + {new (): PolymerElement & I18nBehavior}; -/** @polymer */ class ExtensionsActivityLogElement extends ExtensionsActivityLogElementBase { static get is() { return 'extensions-activity-log'; @@ -70,22 +70,17 @@ return { /** * The underlying ExtensionInfo for the details being displayed. - * @type {!chrome.developerPrivate.ExtensionInfo| - * !ActivityLogExtensionPlaceholder} */ extensionInfo: Object, - /** @type {!ActivityLogDelegate} */ delegate: Object, - /** @private {!ActivityLogSubpage} */ selectedSubpage_: { type: Number, value: ActivityLogSubpage.NONE, observer: 'onSelectedSubpageChanged_', }, - /** @private {Array<string>} */ tabNames_: { type: Array, value: () => ([ @@ -96,7 +91,12 @@ }; } - /** @override */ + extensionInfo: chrome.developerPrivate.ExtensionInfo| + ActivityLogExtensionPlaceholder; + delegate: ActivityLogDelegate; + selectedSubpage_: ActivityLogSubpage; + private tabNames_: string[]; + ready() { super.ready(); this.addEventListener('view-enter-start', this.onViewEnterStart_); @@ -106,62 +106,45 @@ /** * Focuses the back button when page is loaded and set the activie view to * be HISTORY when we navigate to the page. - * @private */ - onViewEnterStart_() { + private onViewEnterStart_() { this.selectedSubpage_ = ActivityLogSubpage.HISTORY; afterNextRender(this, () => focusWithoutInk(this.$.closeButton)); } /** * Set |selectedSubpage_| to NONE to remove the active view from the DOM. - * @private */ - onViewExitFinish_() { + private onViewExitFinish_() { this.selectedSubpage_ = ActivityLogSubpage.NONE; // clear the stream if the user is exiting the activity log page. const activityLogStream = - this.shadowRoot.querySelector('activity-log-stream'); + this.shadowRoot!.querySelector('activity-log-stream'); if (activityLogStream) { activityLogStream.clearStream(); } } - /** - * @private - * @return {string} - */ - getActivityLogHeading_() { - const headingName = this.extensionInfo.isPlaceholder ? + private getActivityLogHeading_(): string { + const headingName = + (this.extensionInfo as ActivityLogExtensionPlaceholder).isPlaceholder ? this.i18n('missingOrUninstalledExtension') : - this.extensionInfo.name; + (this.extensionInfo as chrome.developerPrivate.ExtensionInfo).name; return this.i18n('activityLogPageHeading', headingName); } - /** - * @private - * @return {boolean} - */ - isHistoryTabSelected_() { + private isHistoryTabSelected_(): boolean { return this.selectedSubpage_ === ActivityLogSubpage.HISTORY; } - /** - * @private - * @return {boolean} - */ - isStreamTabSelected_() { + private isStreamTabSelected_(): boolean { return this.selectedSubpage_ === ActivityLogSubpage.STREAM; } - /** - * @private - * @param {!ActivityLogSubpage} newTab - * @param {!ActivityLogSubpage} oldTab - */ - onSelectedSubpageChanged_(newTab, oldTab) { + private onSelectedSubpageChanged_( + newTab: ActivityLogSubpage, oldTab: ActivityLogSubpage) { const activityLogStream = - this.shadowRoot.querySelector('activity-log-stream'); + this.shadowRoot!.querySelector('activity-log-stream'); if (activityLogStream) { if (newTab === ActivityLogSubpage.STREAM) { // Start the stream if the user is switching to the real-time tab. @@ -177,9 +160,8 @@ } } - /** @private */ - onCloseButtonTap_() { - if (this.extensionInfo.isPlaceholder) { + private onCloseButtonTap_() { + if ((this.extensionInfo as ActivityLogExtensionPlaceholder).isPlaceholder) { navigation.navigateTo({page: Page.LIST}); } else { navigation.navigateTo(
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_history.js b/chrome/browser/resources/extensions/activity_log/activity_log_history.ts similarity index 69% rename from chrome/browser/resources/extensions/activity_log/activity_log_history.js rename to chrome/browser/resources/extensions/activity_log/activity_log_history.ts index c4e11fe..1edb6571 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log_history.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log_history.ts
@@ -20,56 +20,29 @@ * LOADING because we call the activity log API whenever a user navigates to * the page. LOADED is the state where the API call has returned a successful * result. - * @enum {string} */ -export const ActivityLogPageState = { - LOADING: 'loading', - LOADED: 'loaded' -}; +export enum ActivityLogPageState { + LOADING = 'loading', + LOADED = 'loaded', +} -/** @interface */ -export class ActivityLogDelegate { - /** - * @param {string} extensionId - * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>} - */ - getExtensionActivityLog(extensionId) {} - - /** - * @param {string} extensionId - * @param {string} searchTerm - * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>} - */ - getFilteredExtensionActivityLog(extensionId, searchTerm) {} - - /** - * @param {!Array<string>} activityIds - * @return {!Promise<void>} - */ - deleteActivitiesById(activityIds) {} - - /** - * @param {string} extensionId - * @return {!Promise<void>} - */ - deleteActivitiesFromExtension(extensionId) {} - - /** - * @param {string} rawActivityData - * @param {string} fileName - */ - downloadActivities(rawActivityData, fileName) {} +export interface ActivityLogDelegate { + getExtensionActivityLog(extensionId: string): + Promise<chrome.activityLogPrivate.ActivityResultSet>; + getFilteredExtensionActivityLog(extensionId: string, searchTerm: string): + Promise<chrome.activityLogPrivate.ActivityResultSet>; + deleteActivitiesById(activityIds: string[]): Promise<void>; + deleteActivitiesFromExtension(extensionId: string): Promise<void>; + downloadActivities(rawActivityData: string, fileName: string): void; } /** * Content scripts activities do not have an API call, so we use the names of * the scripts executed (specified as a stringified JSON array in the args * field) as the keys for an activity group instead. - * @private - * @param {!chrome.activityLogPrivate.ExtensionActivity} activity - * @return {!Array<string>} */ -function getActivityGroupKeysForContentScript_(activity) { +function getActivityGroupKeysForContentScript_( + activity: chrome.activityLogPrivate.ExtensionActivity): string[] { assert( activity.activityType === chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT); @@ -80,7 +53,7 @@ const parsedArgs = JSON.parse(activity.args); assert(Array.isArray(parsedArgs), 'Invalid API data.'); - return /** @type {!Array<string>} */ (parsedArgs); + return parsedArgs; } /** @@ -88,11 +61,9 @@ * web request does in more detail than just the api_call. This information * is in activity.other.webRequest and we use this to generate more activity * group keys if possible. - * @private - * @param {!chrome.activityLogPrivate.ExtensionActivity} activity - * @return {!Array<string>} */ -function getActivityGroupKeysForWebRequest_(activity) { +function getActivityGroupKeysForWebRequest_( + activity: chrome.activityLogPrivate.ExtensionActivity): Array<string> { assert( activity.activityType === chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST); @@ -101,17 +72,17 @@ const other = activity.other; if (!other || !other.webRequest) { - return [apiCall]; + return [apiCall!]; } - const webRequest = /** @type {!Object} */ (JSON.parse(other.webRequest)); + const webRequest = JSON.parse(other.webRequest); assert(typeof webRequest === 'object', 'Invalid API data'); // If there is extra information in the other.webRequest object, // construct a group for each consisting of the API call and each object key // in other.webRequest. Otherwise we default to just the API call. return Object.keys(webRequest).length === 0 ? - [apiCall] : + [apiCall!] : Object.keys(webRequest).map(field => `${apiCall} (${field})`); } @@ -120,11 +91,10 @@ * this would be the activity's API call though content script and web * requests have different keys. We currently assume that every API call * matches to one activity type. - * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>} - * activityData - * @return {!Map<string, !ActivityGroup>} */ -function groupActivities(activityData) { +function groupActivities( + activityData: Array<chrome.activityLogPrivate.ExtensionActivity>): + Map<string, ActivityGroup> { const groupedActivities = new Map(); for (const activity of activityData) { @@ -175,10 +145,9 @@ /** * Sort activities by the total count for each activity group key. Resolve * ties by the alphabetical order of the key. - * @param {!Map<string, !ActivityGroup>} groupedActivities - * @return {!Array<!ActivityGroup>} */ -function sortActivitiesByCallCount(groupedActivities) { +function sortActivitiesByCallCount( + groupedActivities: Map<string, ActivityGroup>): Array<ActivityGroup> { return Array.from(groupedActivities.values()).sort((a, b) => { if (a.count !== b.count) { return b.count - a.count; @@ -193,8 +162,12 @@ }); } +declare global { + interface HTMLElementEventMap { + 'delete-activity-log-item': CustomEvent<Array<string>>; + } +} -/** @polymer */ class ActivityLogHistoryElement extends PolymerElement { static get is() { return 'activity-log-history'; @@ -206,30 +179,24 @@ static get properties() { return { - /** @type {!string} */ extensionId: String, - - /** @type {!ActivityLogDelegate} */ delegate: Object, /** * An array representing the activity log. Stores activities grouped by * API call or content script name sorted in descending order of the call * count. - * @private {!Array<!ActivityGroup>} */ activityData_: { type: Array, value: () => [], }, - /** @private {ActivityLogPageState} */ pageState_: { type: String, value: ActivityLogPageState.LOADING, }, - /** @private */ lastSearch_: { type: String, value: '', @@ -237,6 +204,14 @@ }; } + extensionId: string; + delegate: ActivityLogDelegate; + private activityData_: Array<ActivityGroup>; + private pageState_: ActivityLogPageState; + private lastSearch_: string; + private dataFetchedResolver_: PromiseResolver<void>|null; + private rawActivities_: string; + constructor() { super(); @@ -244,7 +219,6 @@ * A promise resolver for any external files waiting for the * GetExtensionActivity API call to finish. * Currently only used for extension_settings_browsertest.cc - * @private {PromiseResolver} */ this.dataFetchedResolver_ = null; @@ -252,78 +226,54 @@ * The stringified API response from the activityLogPrivate API with * individual activities sorted in ascending order by timestamp; used for * exporting the activity log. - * @private {string} */ this.rawActivities_ = ''; } - /** @override */ ready() { super.ready(); - this.addEventListener( - 'delete-activity-log-item', - e => this.deleteItem_(/** @type {!CustomEvent<!Array<string>>} */ (e))); + this.addEventListener('delete-activity-log-item', e => this.deleteItem_(e)); } /** * Expose only the promise of dataFetchedResolver_. - * @return {!Promise<void>} */ - whenDataFetched() { - return this.dataFetchedResolver_.promise; + whenDataFetched(): Promise<void> { + return this.dataFetchedResolver_!.promise; } - /** @override */ connectedCallback() { super.connectedCallback(); this.dataFetchedResolver_ = new PromiseResolver(); this.refreshActivities_(); } - /** - * @private - * @return {boolean} - */ - shouldShowEmptyActivityLogMessage_() { + private shouldShowEmptyActivityLogMessage_(): boolean { return this.pageState_ === ActivityLogPageState.LOADED && this.activityData_.length === 0; } - /** - * @private - * @return {boolean} - */ - shouldShowLoadingMessage_() { + private shouldShowLoadingMessage_(): boolean { return this.pageState_ === ActivityLogPageState.LOADING; } - /** - * @private - * @return {boolean} - */ - shouldShowActivities_() { + private shouldShowActivities_(): boolean { return this.pageState_ === ActivityLogPageState.LOADED && this.activityData_.length > 0; } - /** @private */ - onClearActivitiesClick_() { + private onClearActivitiesClick_() { this.delegate.deleteActivitiesFromExtension(this.extensionId).then(() => { this.processActivities_([]); }); } - /** @private */ - onMoreActionsClick_() { - this.shadowRoot.querySelector('cr-action-menu') - .showAt(assert(this.shadowRoot.querySelector('cr-icon-button'))); + private onMoreActionsClick_() { + this.shadowRoot!.querySelector('cr-action-menu')!.showAt( + assert(this.shadowRoot!.querySelector('cr-icon-button')!)); } - /** - * @private - * @param {boolean} expanded - */ - expandItems_(expanded) { + private expandItems_(expanded: boolean) { // Do not use .filter here as we need the original index of the item // in |activityData_|. this.activityData_.forEach((item, index) => { @@ -331,30 +281,23 @@ this.set(`activityData_.${index}.expanded`, expanded); } }); - this.shadowRoot.querySelector('cr-action-menu').close(); + this.shadowRoot!.querySelector('cr-action-menu')!.close(); } - /** @private */ - onExpandAllClick_() { + private onExpandAllClick_() { this.expandItems_(true); } - /** @private */ - onCollapseAllClick_() { + private onCollapseAllClick_() { this.expandItems_(false); } - /** @private */ - onExportClick_() { + private onExportClick_() { const fileName = `exported_activity_log_${this.extensionId}.json`; this.delegate.downloadActivities(this.rawActivities_, fileName); } - /** - * @private - * @param {!CustomEvent<!Array<string>>} e - */ - deleteItem_(e) { + private deleteItem_(e: CustomEvent<Array<string>>) { const activityIds = e.detail; this.delegate.deleteActivitiesById(activityIds).then(() => { // It is possible for multiple activities displayed to have the same @@ -365,31 +308,23 @@ }); } - /** - * @private - * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>} - * activityData - */ - processActivities_(activityData) { + private processActivities_( + activityData: Array<chrome.activityLogPrivate.ExtensionActivity>) { this.pageState_ = ActivityLogPageState.LOADED; // Sort |activityData| in ascending order based on the activity's // timestamp; Used for |this.encodedRawActivities|. - activityData.sort((a, b) => a.time - b.time); + activityData.sort((a, b) => a.time! - b.time!); this.rawActivities_ = JSON.stringify(activityData); this.activityData_ = sortActivitiesByCallCount(groupActivities(activityData)); - if (!this.dataFetchedResolver_.isFulfilled) { - this.dataFetchedResolver_.resolve(); + if (!this.dataFetchedResolver_!.isFulfilled) { + this.dataFetchedResolver_!.resolve(); } } - /** - * @private - * @return {!Promise<void>} - */ - refreshActivities_() { + private refreshActivities_(): Promise<void> { if (this.lastSearch_ === '') { return this.getActivityLog_(); } @@ -397,11 +332,7 @@ return this.getFilteredActivityLog_(this.lastSearch_); } - /** - * @private - * @return {!Promise<void>} - */ - getActivityLog_() { + private getActivityLog_(): Promise<void> { this.pageState_ = ActivityLogPageState.LOADING; return this.delegate.getExtensionActivityLog(this.extensionId) .then(result => { @@ -409,12 +340,7 @@ }); } - /** - * @private - * @param {string} searchTerm - * @return {!Promise<void>} - */ - getFilteredActivityLog_(searchTerm) { + private getFilteredActivityLog_(searchTerm: string): Promise<void> { this.pageState_ = ActivityLogPageState.LOADING; return this.delegate .getFilteredExtensionActivityLog(this.extensionId, searchTerm) @@ -423,11 +349,7 @@ }); } - /** - * @private - * @param {!CustomEvent<string>} e - */ - onSearchChanged_(e) { + private onSearchChanged_(e: CustomEvent<string>) { // Remove all whitespaces from the search term, as API call names and // urls should not contain any whitespace. As of now, only single term // search queries are allowed.
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js b/chrome/browser/resources/extensions/activity_log/activity_log_history_item.ts similarity index 77% rename from chrome/browser/resources/extensions/activity_log/activity_log_history_item.js rename to chrome/browser/resources/extensions/activity_log/activity_log_history_item.ts index f44a235..a57ac1cf 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log_history_item.ts
@@ -11,29 +11,24 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -/** - * @typedef {{ - * activityIds: !Set<string>, - * key: string, - * count: number, - * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter, - * countsByUrl: !Map<string, number>, - * expanded: boolean - * }} - */ -export let ActivityGroup; +export type ActivityGroup = { + activityIds: Set<string>, + key: string, + count: number, + activityType: chrome.activityLogPrivate.ExtensionActivityFilter, + countsByUrl: Map<string, number>, + expanded: boolean, +}; /** * A struct used to describe each url and its associated counts. The id is * unique for each item in the list of URLs and is used for the tooltip. - * @typedef {{ - * page: string, - * count: number - * }} */ -let PageUrlItem; +export type PageUrlItem = { + page: string, + count: number, +}; -/** @polymer */ class ActivityLogHistoryItemElement extends PolymerElement { static get is() { return 'activity-log-history-item'; @@ -48,11 +43,9 @@ /** * The underlying ActivityGroup that provides data for the * ActivityLogItem displayed. - * @type {!ActivityGroup} */ data: Object, - /** @private */ isExpandable_: { type: Boolean, computed: 'computeIsExpandable_(data.countsByUrl)', @@ -60,11 +53,10 @@ }; } - /** - * @private - * @return {boolean} - */ - computeIsExpandable_() { + data: ActivityGroup; + private isExpandable_: boolean; + + private computeIsExpandable_(): boolean { return this.data.countsByUrl.size > 0; } @@ -72,10 +64,8 @@ * Sort the page URLs by the number of times it was associated with the key * for this ActivityGroup (API call or content script invocation.) Resolve * ties by the alphabetical order of the page URL. - * @private - * @return {!Array<PageUrlItem>} */ - getPageUrls_() { + private getPageUrls_(): Array<PageUrlItem> { return Array.from(this.data.countsByUrl.entries()) .map(e => ({page: e[0], count: e[1]})) .sort(function(a, b) { @@ -86,8 +76,7 @@ }); } - /** @private */ - onDeleteTap_(e) { + private onDeleteTap_(e: Event) { e.stopPropagation(); this.dispatchEvent(new CustomEvent('delete-activity-log-item', { bubbles: true, @@ -96,8 +85,7 @@ })); } - /** @private */ - onExpandTap_() { + private onExpandTap_() { if (this.isExpandable_) { this.set('data.expanded', !this.data.expanded); } @@ -106,10 +94,8 @@ /** * Show the call count for a particular page URL if more than one page * URL is associated with the key for this ActivityGroup. - * @private - * @return {boolean} */ - shouldShowPageUrlCount_() { + private shouldShowPageUrlCount_(): boolean { return this.data.countsByUrl.size > 1; } }
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_stream.js b/chrome/browser/resources/extensions/activity_log/activity_log_stream.ts similarity index 75% rename from chrome/browser/resources/extensions/activity_log/activity_log_stream.js rename to chrome/browser/resources/extensions/activity_log/activity_log_stream.ts index 0acbff2..ff4b15f 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log_stream.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log_stream.ts
@@ -14,28 +14,24 @@ import {StreamArgItem, StreamItem} from './activity_log_stream_item.js'; -/** @interface */ -export class ActivityLogEventDelegate { - /** @return {!ChromeEvent} */ - getOnExtensionActivity() {} +export interface ActivityLogEventDelegate { + getOnExtensionActivity(): any; } /** * Process activity for the stream. In the case of content scripts, we split * the activity for every script invoked. - * @param {!chrome.activityLogPrivate.ExtensionActivity} - * activity - * @return {!Array<!StreamItem>} */ -function processActivityForStream(activity) { +function processActivityForStream( + activity: chrome.activityLogPrivate.ExtensionActivity): Array<StreamItem> { const activityType = activity.activityType; - const timestamp = activity.time; + const timestamp = activity.time!; const isContentScript = activityType === chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT; - const args = isContentScript ? JSON.stringify([]) : activity.args; + const args = isContentScript ? JSON.stringify([]) : activity.args!; - let streamItemNames = [activity.apiCall]; + let streamItemNames = [activity.apiCall!]; // TODO(kelvinjiang): Reuse logic from activity_log_history and refactor // some of the processing code into a separate file in a follow up CL. @@ -49,7 +45,7 @@ return streamItemNames.map(name => ({ args, - argUrl: activity.argUrl, + argUrl: activity.argUrl!, activityType, name, pageUrl: activity.pageUrl, @@ -59,7 +55,6 @@ })); } -/** @polymer */ class ActivityLogStreamElement extends PolymerElement { static get is() { return 'activity-log-stream'; @@ -71,32 +66,25 @@ static get properties() { return { - /** @type {string} */ extensionId: String, - - /** @type {!ActivityLogEventDelegate} */ delegate: Object, - /** @private */ isStreamOn_: { type: Boolean, value: false, }, - /** @private {!Array<!StreamItem>} */ activityStream_: { type: Array, value: () => [], }, - /** @private {!Array<!StreamItem>} */ filteredActivityStream_: { type: Array, computed: 'computeFilteredActivityStream_(activityStream_.*, lastSearch_)', }, - /** @private */ lastSearch_: { type: String, value: '', @@ -104,17 +92,24 @@ }; } + extensionId: string; + delegate: ActivityLogEventDelegate; + private isStreamOn_: boolean; + private activityStream_: Array<StreamItem>; + private filteredActivityStream_: Array<StreamItem>; + private lastSearch_: string; + private listenerInstance_: + (type: chrome.activityLogPrivate.ExtensionActivity) => void; + constructor() { super(); /** * Instance of |extensionActivityListener_| bound to |this|. - * @private {!Function} */ this.listenerInstance_ = () => {}; } - /** @override */ connectedCallback() { super.connectedCallback(); @@ -124,9 +119,8 @@ this.startStream(); } - /** @private */ - onResizeStream_(e) { - this.shadowRoot.querySelector('iron-list').notifyResize(); + private onResizeStream_() { + this.shadowRoot!.querySelector('iron-list')!.notifyResize(); } clearStream() { @@ -152,8 +146,7 @@ this.isStreamOn_ = false; } - /** @private */ - onToggleButtonClick_() { + private onToggleButtonClick_() { if (this.isStreamOn_) { this.pauseStream(); } else { @@ -161,35 +154,20 @@ } } - /** - * @private - * @return {boolean} - */ - isStreamEmpty_() { + private isStreamEmpty_(): boolean { return this.activityStream_.length === 0; } - /** - * @private - * @return {boolean} - */ - isFilteredStreamEmpty_() { + private isFilteredStreamEmpty_(): boolean { return this.filteredActivityStream_.length === 0; } - /** - * @private - * @return {boolean} - */ - shouldShowEmptySearchMessage_() { + private shouldShowEmptySearchMessage_(): boolean { return !this.isStreamEmpty_() && this.isFilteredStreamEmpty_(); } - /** - * @private - * @param {!chrome.activityLogPrivate.ExtensionActivity} activity - */ - extensionActivityListener_(activity) { + private extensionActivityListener_( + activity: chrome.activityLogPrivate.ExtensionActivity) { if (activity.extensionId !== this.extensionId) { return; } @@ -199,14 +177,10 @@ ...processActivityForStream(activity)); // Used to update the scrollbar. - this.shadowRoot.querySelector('iron-list').notifyResize(); + this.shadowRoot!.querySelector('iron-list')!.notifyResize(); } - /** - * @private - * @param {!CustomEvent<string>} e - */ - onSearchChanged_(e) { + private onSearchChanged_(e: CustomEvent<string>) { // Remove all whitespaces from the search term, as API call names and // URLs should not contain any whitespace. As of now, only single term // search queries are allowed. @@ -218,11 +192,7 @@ this.lastSearch_ = searchTerm; } - /** - * @private - * @return {!Array<!StreamItem>} - */ - computeFilteredActivityStream_() { + private computeFilteredActivityStream_(): Array<StreamItem> { if (!this.lastSearch_) { return this.activityStream_.slice(); } @@ -236,10 +206,17 @@ return this.activityStream_.filter(act => { return propNames.some(prop => { - return act[prop] && act[prop].toLowerCase().includes(this.lastSearch_); + const value = (act as {[index: string]: any})[prop]; + return value && value.toLowerCase().includes(this.lastSearch_); }); }); } } +declare global { + interface HTMLElementTagNameMap { + 'activity-log-stream': ActivityLogStreamElement; + } +} + customElements.define(ActivityLogStreamElement.is, ActivityLogStreamElement);
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js b/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.ts similarity index 74% rename from chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js rename to chrome/browser/resources/extensions/activity_log/activity_log_stream_item.ts index e073e0e6..5523a3b 100644 --- a/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js +++ b/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.ts
@@ -10,49 +10,42 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -/** - * @typedef {{ - * name: string, - * timestamp: number, - * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter, - * pageUrl: string, - * argUrl: string, - * args: string, - * webRequestInfo: (string|undefined), - * expanded: boolean - * }} - */ -export let StreamItem; +export type StreamItem = { + name?: string, + timestamp: number, + activityType: chrome.activityLogPrivate.ExtensionActivityType, + pageUrl?: string, + argUrl: string, + args: string, + webRequestInfo?: string, + expanded: boolean, +}; /** * A struct used to describe each argument for an activity (each item in * the parsed version of |data.args|). Contains the argument's value itself * and its index. - * @typedef {{ - * arg: string, - * index: number - * }} */ -export let StreamArgItem; +export type StreamArgItem = { + arg: string, + index: number, +} /** * Placeholder for arg_url that can occur in |StreamItem.args|. Sometimes we * see this as '\u003Carg_url>' (opening arrow is unicode converted) but * string comparison with the non-unicode value still returns true so we * don't need to convert. - * @type {string} */ -export const ARG_URL_PLACEHOLDER = '<arg_url>'; +export const ARG_URL_PLACEHOLDER: string = '<arg_url>'; /** * Regex pattern for |ARG_URL_PLACEHOLDER| for String.replace. A regex of the * exact string with a global search flag is needed to replace all * occurrences. - * @type {!RegExp} */ -const ARG_URL_PLACEHOLDER_REGEX = /"<arg_url>"/g; +const ARG_URL_PLACEHOLDER_REGEX: RegExp = /"<arg_url>"/g; -/** @polymer */ class ActivityLogStreamItemElement extends PolymerElement { static get is() { return 'activity-log-stream-item'; @@ -67,17 +60,14 @@ /** * The underlying ActivityGroup that provides data for the * ActivityLogItem displayed. - * @type {!StreamItem} */ data: Object, - /** @private {!Array<!StreamArgItem>} */ argsList_: { type: Array, computed: 'computeArgsList_(data.args)', }, - /** @private */ isExpandable_: { type: Boolean, computed: 'computeIsExpandable_(data)', @@ -85,19 +75,15 @@ }; } - /** - * @private - * @return {boolean} - */ - computeIsExpandable_() { + data: StreamItem; + private argsList_: Array<StreamArgItem>; + private isExpandable_: boolean; + + private computeIsExpandable_(): boolean { return this.hasPageUrl_() || this.hasArgs_() || this.hasWebRequestInfo_(); } - /** - * @private - * @return {string} - */ - getFormattedTime_() { + private getFormattedTime_(): string { // Format the activity's time to HH:MM:SS.mmm format. Use ToLocaleString // for HH:MM:SS and padLeft for milliseconds. const activityDate = new Date(this.data.timestamp); @@ -112,35 +98,19 @@ return `${timeString}.${ms}`; } - /** - * @private - * @return {boolean} - */ - hasPageUrl_() { + private hasPageUrl_(): boolean { return !!this.data.pageUrl; } - /** - * @private - * @return {boolean} - */ - hasArgs_() { + private hasArgs_(): boolean { return this.argsList_.length > 0; } - /** - * @private - * @return {boolean} - */ - hasWebRequestInfo_() { + private hasWebRequestInfo_(): boolean { return !!this.data.webRequestInfo && this.data.webRequestInfo !== '{}'; } - /** - * @private - * @return {!Array<!StreamArgItem>} - */ - computeArgsList_() { + private computeArgsList_(): Array<StreamArgItem> { const parsedArgs = JSON.parse(this.data.args); if (!Array.isArray(parsedArgs)) { return []; @@ -158,8 +128,7 @@ })); } - /** @private */ - onExpandClick_() { + private onExpandClick_() { if (this.isExpandable_) { this.set('data.expanded', !this.data.expanded); this.dispatchEvent(new CustomEvent('resize-stream'));
diff --git a/chrome/browser/resources/extensions/code_section.js b/chrome/browser/resources/extensions/code_section.ts similarity index 72% rename from chrome/browser/resources/extensions/code_section.js rename to chrome/browser/resources/extensions/code_section.ts index fcd18b2..46b9bb73 100644 --- a/chrome/browser/resources/extensions/code_section.js +++ b/chrome/browser/resources/extensions/code_section.ts
@@ -7,17 +7,12 @@ import 'chrome://resources/polymer/v3_0/paper-styles/color.js'; import './strings.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; +import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -/** - * @param {number} totalCount - * @param {number} oppositeCount - * @return {number} - */ -function visibleLineCount(totalCount, oppositeCount) { +function visibleLineCount(totalCount: number, oppositeCount: number): number { // We limit the number of lines shown for DOM performance. const MAX_VISIBLE_LINES = 1000; const max = @@ -25,16 +20,12 @@ return Math.min(max, totalCount); } -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ const ExtensionsCodeSectionElementBase = - mixinBehaviors([I18nBehavior], PolymerElement); + mixinBehaviors([I18nBehavior], PolymerElement) as + {new (): PolymerElement & I18nBehavior}; -/** @polymer */ -class ExtensionsCodeSectionElement extends ExtensionsCodeSectionElementBase { +export class ExtensionsCodeSectionElement extends + ExtensionsCodeSectionElementBase { static get is() { return 'extensions-code-section'; } @@ -45,10 +36,6 @@ static get properties() { return { - /** - * The code this object is displaying. - * @type {?chrome.developerPrivate.RequestFileSourceResponse} - */ code: { type: Object, value: null, @@ -56,50 +43,52 @@ isActive: Boolean, - /** @private Highlighted code. */ + /** Highlighted code. */ highlighted_: String, - /** @private Code before the highlighted section. */ + /** Code before the highlighted section. */ before_: String, - /** @private Code after the highlighted section. */ + /** Code after the highlighted section. */ after_: String, - /** @private */ showNoCode_: { type: Boolean, computed: 'computeShowNoCode_(isActive, highlighted_)', }, - /** @private Description for the highlighted section. */ + /** Description for the highlighted section. */ highlightDescription_: String, - /** @private */ lineNumbers_: String, - - /** @private */ truncatedBefore_: Number, - - /** @private */ truncatedAfter_: Number, /** * The string to display if no |code| is set (e.g. because we couldn't * load the relevant source file). - * @type {string} */ couldNotDisplayCode: String, }; } + code: chrome.developerPrivate.RequestFileSourceResponse|null; + isActive: boolean; + couldNotDisplayCode: string; + private highlighted_: string; + private before_: string; + private after_: string; + private showNoCode_: boolean; + private highlightDescription_: string; + private lineNumbers_: string; + private truncatedBefore_: number; + private truncatedAfter_: number; + static get observers() { return ['onCodeChanged_(code.*)']; } - /** - * @private - */ - onCodeChanged_() { + private onCodeChanged_() { if (!this.code || (!this.code.beforeHighlight && !this.code.highlight && !this.code.afterHighlight)) { @@ -147,25 +136,15 @@ this.scrollToHighlight_(visibleLineCountBefore); } - /** - * @param {number} lineCount - * @param {string} stringSingular - * @param {string} stringPluralTemplate - * @return {string} - * @private - */ - getLinesNotShownLabel_(lineCount, stringSingular, stringPluralTemplate) { + private getLinesNotShownLabel_( + lineCount: number, stringSingular: string, + stringPluralTemplate: string): string { return lineCount === 1 ? stringSingular : loadTimeData.substituteString(stringPluralTemplate, lineCount); } - /** - * @param {number} start - * @param {number} end - * @private - */ - setLineNumbers_(start, end) { + private setLineNumbers_(start: number, end: number) { let lineNumbers = ''; for (let i = start; i <= end; ++i) { lineNumbers += i + '\n'; @@ -174,11 +153,7 @@ this.lineNumbers_ = lineNumbers; } - /** - * @param {number} linesBeforeHighlight - * @private - */ - scrollToHighlight_(linesBeforeHighlight) { + private scrollToHighlight_(linesBeforeHighlight: number) { const CSS_LINE_HEIGHT = 20; // Count how many pixels is above the highlighted code. @@ -190,13 +165,8 @@ this.$['scroll-container'].scrollTo({top: targetTop}); } - /** - * @param {number} lineStart - * @param {number} numLines - * @return {string} - * @private - */ - getAccessibilityHighlightDescription_(lineStart, numLines) { + private getAccessibilityHighlightDescription_( + lineStart: number, numLines: number): string { if (numLines > 1) { return this.i18n( 'accessibilityErrorMultiLine', lineStart.toString(), @@ -206,11 +176,7 @@ } } - /** - * @private - * @return {boolean} - */ - computeShowNoCode_() { + private computeShowNoCode_(): boolean { return this.isActive && !this.highlighted_; } }
diff --git a/chrome/browser/resources/extensions/detail_view.js b/chrome/browser/resources/extensions/detail_view.ts similarity index 65% rename from chrome/browser/resources/extensions/detail_view.js rename to chrome/browser/resources/extensions/detail_view.ts index f30ce10..456efa5 100644 --- a/chrome/browser/resources/extensions/detail_view.js +++ b/chrome/browser/resources/extensions/detail_view.ts
@@ -25,6 +25,7 @@ import './toggle_row.js'; import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js'; +import {CrToggleElement} from 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js'; import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {afterNextRender, html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -33,16 +34,29 @@ import {ItemMixin} from './item_mixin.js'; import {computeInspectableViewLabel, EnableControl, getEnableControl, getItemSource, getItemSourceString, isEnabled, userCanChangeEnablement} from './item_util.js'; import {navigation, Page} from './navigation_helper.js'; +import {ExtensionsToggleRowElement} from './toggle_row.js'; -/** - * @constructor - * @extends {PolymerElement} - */ +export interface ExtensionsDetailViewElement { + $: { + closeButton: HTMLElement, + enableToggle: CrToggleElement, + extensionsActivityLogLink: HTMLElement, + }; +} + +/** Event interface for dom-repeat. */ +interface RepeaterEvent extends CustomEvent { + model: { + item: chrome.developerPrivate.ExtensionView, + }; +} + const ExtensionsDetailViewElementBase = - mixinBehaviors([CrContainerShadowBehavior], ItemMixin(PolymerElement)); + mixinBehaviors([CrContainerShadowBehavior], ItemMixin(PolymerElement)) as + {new (): PolymerElement}; -/** @polymer */ -class ExtensionsDetailViewElement extends ExtensionsDetailViewElementBase { +export class ExtensionsDetailViewElement extends + ExtensionsDetailViewElementBase { static get is() { return 'extensions-detail-view'; } @@ -55,14 +69,11 @@ return { /** * The underlying ExtensionInfo for the details being displayed. - * @type {!chrome.developerPrivate.ExtensionInfo} */ data: Object, - /** @private */ size_: String, - /** @type {!ItemDelegate} */ delegate: Object, /** Whether the user has enabled the UI's developer mode. */ @@ -83,7 +94,14 @@ return ['onItemIdChanged_(data.id, delegate)']; } - /** @override */ + data: chrome.developerPrivate.ExtensionInfo; + delegate: ItemDelegate; + inDevMode: boolean; + incognitoAvailable: boolean; + showActivityLog: boolean; + fromActivityLog: boolean; + private size_: string; + ready() { super.ready(); this.addEventListener('view-enter-start', this.onViewEnterStart_); @@ -94,14 +112,13 @@ * dialog closes. */ focusOptionsButton() { - this.shadowRoot.querySelector('#extensions-options').focus(); + this.shadowRoot!.querySelector<HTMLElement>('#extensions-options')!.focus(); } /** * Focuses the back button when page is loaded. - * @private */ - onViewEnterStart_() { + private onViewEnterStart_() { const elementToFocus = this.fromActivityLog ? this.$.extensionsActivityLogLink : this.$.closeButton; @@ -109,8 +126,7 @@ afterNextRender(this, () => focusWithoutInk(elementToFocus)); } - /** @private */ - onItemIdChanged_() { + private onItemIdChanged_() { // Clear the size, since this view is reused, such that no obsolete size // is displayed.: this.size_ = ''; @@ -119,273 +135,173 @@ }); } - /** @private */ - onActivityLogTap_() { + private onActivityLogTap_() { navigation.navigateTo({page: Page.ACTIVITY_LOG, extensionId: this.data.id}); } - /** - * @param {string} description - * @param {string} fallback - * @return {string} - * @private - */ - getDescription_(description, fallback) { + private getDescription_(description: string, fallback: string): string { return description || fallback; } - /** @private */ - onCloseButtonTap_() { + private onCloseButtonTap_() { navigation.navigateTo({page: Page.LIST}); } - /** - * @return {boolean} - * @private - */ - isEnabled_() { + private isEnabled_(): boolean { return isEnabled(this.data.state); } - /** - * @return {boolean} - * @private - */ - isEnableToggleEnabled_() { + private isEnableToggleEnabled_(): boolean { return userCanChangeEnablement(this.data); } - /** - * @return {boolean} - * @private - */ - hasDependentExtensions_() { + private hasDependentExtensions_(): boolean { return this.data.dependentExtensions.length > 0; } - /** - * @return {boolean} - * @private - */ - hasSevereWarnings_() { + private hasSevereWarnings_(): boolean { return this.data.disableReasons.corruptInstall || this.data.disableReasons.suspiciousInstall || this.data.disableReasons.updateRequired || !!this.data.blacklistText || this.data.runtimeWarnings.length > 0; } - /** - * @return {string} - * @private - */ - computeEnabledStyle_() { + private computeEnabledStyle_(): string { return this.isEnabled_() ? 'enabled-text' : ''; } - /** - * @param {!chrome.developerPrivate.ExtensionState} state - * @param {string} onText - * @param {string} offText - * @return {string} - * @private - */ - computeEnabledText_(state, onText, offText) { + private computeEnabledText_( + state: chrome.developerPrivate.ExtensionState, onText: string, + offText: string): string { // TODO(devlin): Get the full spectrum of these strings from bettes. return isEnabled(state) ? onText : offText; } - /** - * @param {!chrome.developerPrivate.ExtensionView} view - * @return {string} - * @private - */ - computeInspectLabel_(view) { + private computeInspectLabel_(view: chrome.developerPrivate.ExtensionView): + string { return computeInspectableViewLabel(view); } - /** - * @return {boolean} - * @private - */ - shouldShowOptionsLink_() { + private shouldShowOptionsLink_(): boolean { return !!this.data.optionsPage; } - /** - * @return {boolean} - * @private - */ - shouldShowOptionsSection_() { + private shouldShowOptionsSection_(): boolean { return this.data.incognitoAccess.isEnabled || this.data.fileAccess.isEnabled || this.data.errorCollection.isEnabled; } - /** - * @return {boolean} - * @private - */ - shouldShowIncognitoOption_() { + private shouldShowIncognitoOption_(): boolean { return this.data.incognitoAccess.isEnabled && this.incognitoAvailable; } - /** @private */ - onEnableToggleChange_() { + private onEnableToggleChange_() { this.delegate.setItemEnabled(this.data.id, this.$.enableToggle.checked); this.$.enableToggle.checked = this.isEnabled_(); } - /** - * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e - * @private - */ - onInspectTap_(e) { + private onInspectTap_(e: RepeaterEvent) { this.delegate.inspectItemView(this.data.id, e.model.item); } - /** @private */ - onExtensionOptionsTap_() { + private onExtensionOptionsTap_() { this.delegate.showItemOptionsPage(this.data); } - /** @private */ - onReloadTap_() { + private onReloadTap_() { this.delegate.reloadItem(this.data.id).catch(loadError => { this.dispatchEvent(new CustomEvent( 'load-error', {bubbles: true, composed: true, detail: loadError})); }); } - /** @private */ - onRemoveTap_() { + private onRemoveTap_() { this.delegate.deleteItem(this.data.id); } - /** @private */ - onRepairTap_() { + private onRepairTap_() { this.delegate.repairItem(this.data.id); } - /** @private */ - onLoadPathTap_() { + private onLoadPathTap_() { this.delegate.showInFolder(this.data.id); } - /** @private */ - onAllowIncognitoChange_() { + private onAllowIncognitoChange_() { this.delegate.setItemAllowedIncognito( this.data.id, - this.shadowRoot.querySelector('#allow-incognito').checked); + this.shadowRoot! + .querySelector<ExtensionsToggleRowElement>( + '#allow-incognito')!.checked); } - /** @private */ - onAllowOnFileUrlsChange_() { + private onAllowOnFileUrlsChange_() { this.delegate.setItemAllowedOnFileUrls( this.data.id, - this.shadowRoot.querySelector('#allow-on-file-urls').checked); + this.shadowRoot! + .querySelector<ExtensionsToggleRowElement>( + '#allow-on-file-urls')!.checked); } - /** @private */ - onCollectErrorsChange_() { + private onCollectErrorsChange_() { this.delegate.setItemCollectsErrors( - this.data.id, this.shadowRoot.querySelector('#collect-errors').checked); + this.data.id, + this.shadowRoot! + .querySelector<ExtensionsToggleRowElement>( + '#collect-errors')!.checked); } - /** @private */ - onExtensionWebSiteTap_() { + private onExtensionWebSiteTap_() { this.delegate.openUrl(this.data.manifestHomePageUrl); } - /** @private */ - onViewInStoreTap_() { + private onViewInStoreTap_() { this.delegate.openUrl(this.data.webStoreUrl); } - /** - * @param {!chrome.developerPrivate.DependentExtension} item - * @return {string} - * @private - */ - computeDependentEntry_(item) { + private computeDependentEntry_( + item: chrome.developerPrivate.DependentExtension): string { return loadTimeData.getStringF('itemDependentEntry', item.name, item.id); } - /** - * @return {string} - * @private - */ - computeSourceString_() { + private computeSourceString_(): string { return this.data.locationText || getItemSourceString(getItemSource(this.data)); } - /** - * @return {boolean} - * @private - */ - hasPermissions_() { + private hasPermissions_(): boolean { return this.data.permissions.simplePermissions.length > 0 || this.hasRuntimeHostPermissions_(); } - /** - * @return {boolean} - * @private - */ - hasRuntimeHostPermissions_() { + private hasRuntimeHostPermissions_(): boolean { return !!this.data.permissions.runtimeHostPermissions; } - /** - * @return {boolean} - * @private - */ - showSiteAccessContent_() { + private showSiteAccessContent_(): boolean { return this.showFreeformRuntimeHostPermissions_() || this.showHostPermissionsToggleList_(); } - /** - * @return {boolean} - * @private - */ - showFreeformRuntimeHostPermissions_() { + private showFreeformRuntimeHostPermissions_(): boolean { return this.hasRuntimeHostPermissions_() && - this.data.permissions.runtimeHostPermissions.hasAllHosts; + this.data.permissions.runtimeHostPermissions!.hasAllHosts; } - /** - * @return {boolean} - * @private - */ - showHostPermissionsToggleList_() { + private showHostPermissionsToggleList_(): boolean { return this.hasRuntimeHostPermissions_() && - !this.data.permissions.runtimeHostPermissions.hasAllHosts; + !this.data.permissions.runtimeHostPermissions!.hasAllHosts; } - /** - * Returns true if the reload button should be shown. - * @return {boolean} - * @private - */ - showReloadButton_() { + private showReloadButton_(): boolean { return getEnableControl(this.data) === EnableControl.RELOAD; } - /** - * Returns true if the repair button should be shown. - * @return {boolean} - * @private - */ - showRepairButton_() { + private showRepairButton_(): boolean { return getEnableControl(this.data) === EnableControl.REPAIR; } - /** - * Returns true if the enable toggle should be shown. - * @return {boolean} - * @private - */ - showEnableToggle_() { + private showEnableToggle_(): boolean { const enableControl = getEnableControl(this.data); // We still show the toggle even if we also show the repair button in the // detail view, because the repair button appears just beneath it. @@ -393,11 +309,7 @@ enableControl === EnableControl.REPAIR; } - /** - * @return {boolean} Whether the allowlist warning should be shown. - * @private - */ - showAllowlistWarning_() { + private showAllowlistWarning_(): boolean { // Only show the allowlist warning if there is no blocklist warning. It // would be redundant since all blocklisted items are necessarily not // included in the Safe Browsing allowlist. @@ -406,5 +318,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'extensions-detail-view': ExtensionsDetailViewElement; + } +} + customElements.define( ExtensionsDetailViewElement.is, ExtensionsDetailViewElement);
diff --git a/chrome/browser/resources/extensions/drop_overlay.ts b/chrome/browser/resources/extensions/drop_overlay.ts index 8f6eb8b..48c5352 100644 --- a/chrome/browser/resources/extensions/drop_overlay.ts +++ b/chrome/browser/resources/extensions/drop_overlay.ts
@@ -23,7 +23,6 @@ static get properties() { return { - /** @private {boolean} */ dragEnabled: { type: Boolean, observer: 'dragEnabledChanged_',
diff --git a/chrome/browser/resources/extensions/error_page.js b/chrome/browser/resources/extensions/error_page.ts similarity index 62% rename from chrome/browser/resources/extensions/error_page.js rename to chrome/browser/resources/extensions/error_page.ts index 29cb601..4a5855a 100644 --- a/chrome/browser/resources/extensions/error_page.js +++ b/chrome/browser/resources/extensions/error_page.ts
@@ -23,35 +23,32 @@ import {navigation, Page} from './navigation_helper.js'; -/** @typedef {chrome.developerPrivate.ManifestError} */ -let ManifestError; -/** @typedef {chrome.developerPrivate.RuntimeError} */ -let RuntimeError; +type ManifestError = chrome.developerPrivate.ManifestError; +type RuntimeError = chrome.developerPrivate.RuntimeError; -/** @interface */ -export class ErrorPageDelegate { - /** - * @param {string} extensionId - * @param {!Array<number>=} errorIds - * @param {chrome.developerPrivate.ErrorType=} type - */ - deleteErrors(extensionId, errorIds, type) {} +/** Event interface for dom-repeat. */ +interface RepeaterEvent<T> extends CustomEvent { + model: { + item: T, + index: number, + }; +} - /** - * @param {chrome.developerPrivate.RequestFileSourceProperties} args - * @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>} - */ - requestFileSource(args) {} +export interface ErrorPageDelegate { + deleteErrors( + extensionId: string, errorIds?: number[], + type?: chrome.developerPrivate.ErrorType): void; + + requestFileSource(args: chrome.developerPrivate.RequestFileSourceProperties): + Promise<chrome.developerPrivate.RequestFileSourceResponse>; } /** * Get the URL relative to the main extension url. If the url is * unassociated with the extension, this will be the full url. - * @param {string} url - * @param {?(ManifestError|RuntimeError)} error - * @return {string} */ -function getRelativeUrl(url, error) { +function getRelativeUrl( + url: string, error: ManifestError|RuntimeError): string { const fullUrl = 'chrome-extension://' + error.extensionId + '/'; return url.startsWith(fullUrl) ? url.substring(fullUrl.length) : url; } @@ -59,16 +56,12 @@ /** * Given 3 strings, this function returns the correct one for the type of * error that |item| is. - * @param {!ManifestError|!RuntimeError} item - * @param {string} log - * @param {string} warn - * @param {string} error - * @return {string} - * @private */ -function getErrorSeverityText_(item, log, warn, error) { +function getErrorSeverityText_( + item: ManifestError|RuntimeError, log: string, warn: string, + error: string): string { if (item.type === chrome.developerPrivate.ErrorType.RUNTIME) { - switch (item.severity) { + switch ((item as RuntimeError).severity) { case chrome.developerPrivate.ErrorLevel.LOG: return log; case chrome.developerPrivate.ErrorLevel.WARN: @@ -82,29 +75,24 @@ return warn; } -/** - * @constructor - * @extends {PolymerElement} - */ -const ExtensionsErrorPageElementBase = - mixinBehaviors([CrContainerShadowBehavior], PolymerElement); +interface ExtensionsErrorPageElement { + $: { + closeButton: HTMLElement, + }; +} -/** @polymer */ +const ExtensionsErrorPageElementBase = + mixinBehaviors([CrContainerShadowBehavior], PolymerElement) as + {new (): PolymerElement}; + class ExtensionsErrorPageElement extends ExtensionsErrorPageElementBase { static get is() { return 'extensions-error-page'; } - static get template() { - return html`{__html_template__}`; - } - static get properties() { return { - /** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */ data: Object, - - /** @type {!ErrorPageDelegate|undefined} */ delegate: Object, // Whether or not dev mode is enabled. @@ -114,22 +102,18 @@ observer: 'onInDevModeChanged_', }, - /** @private {!Array<!(ManifestError|RuntimeError)>} */ entries_: Array, - /** @private {?chrome.developerPrivate.RequestFileSourceResponse} */ code_: Object, /** * Index into |entries_|. - * @private */ selectedEntry_: { type: Number, observer: 'onSelectedErrorChanged_', }, - /** @private {?chrome.developerPrivate.StackFrame}*/ selectedStackFrame_: { type: Object, value() { @@ -143,96 +127,78 @@ return ['observeDataChanges_(data.*)']; } - /** @override */ + data: chrome.developerPrivate.ExtensionInfo; + delegate: ErrorPageDelegate; + inDevMode: boolean; + private entries_: Array<ManifestError|RuntimeError>; + private code_: chrome.developerPrivate.RequestFileSourceResponse|null; + private selectedEntry_: number; + private selectedStackFrame_: chrome.developerPrivate.StackFrame|null; + ready() { super.ready(); this.addEventListener('view-enter-start', this.onViewEnterStart_); FocusOutlineManager.forDocument(document); } - /** @return {!ManifestError|!RuntimeError} */ - getSelectedError() { + getSelectedError(): ManifestError|RuntimeError { return this.entries_[this.selectedEntry_]; } /** * Focuses the back button when page is loaded. - * @private */ - onViewEnterStart_() { + private onViewEnterStart_() { afterNextRender(this, () => focusWithoutInk(this.$.closeButton)); chrome.metricsPrivate.recordUserAction('Options_ViewExtensionErrors'); } - /** - * @param {!ManifestError|!RuntimeError} error - * @param {string} unknown - * @return {string} - * @private - */ - getContextUrl_(error, unknown) { - return error.contextUrl ? getRelativeUrl(error.contextUrl, error) : unknown; + private getContextUrl_(error: ManifestError|RuntimeError, unknown: string): + string { + return (error as RuntimeError).contextUrl ? + getRelativeUrl((error as RuntimeError).contextUrl, error) : + unknown; } /** * Watches for changes to |data| in order to fetch the corresponding * file source. - * @private */ - observeDataChanges_() { - const errors = this.data.manifestErrors.concat(this.data.runtimeErrors); - this.entries_ = errors; + private observeDataChanges_() { + this.entries_ = [...this.data.manifestErrors, ...this.data.runtimeErrors]; this.selectedEntry_ = -1; // This also help reset code-section content. if (this.entries_.length) { this.selectedEntry_ = 0; } } - /** @private */ - onCloseButtonTap_() { + private onCloseButtonTap_() { navigation.navigateTo({page: Page.LIST}); } - /** @private */ - onClearAllTap_() { + private onClearAllTap_() { const ids = this.entries_.map(entry => entry.id); this.delegate.deleteErrors(this.data.id, ids); } - /** - * @param {!ManifestError|!RuntimeError} error - * @return {string} - * @private - */ - computeErrorIcon_(error) { + private computeErrorIcon_(error: ManifestError|RuntimeError): string { // Do not i18n these strings, they're CSS classes. return getErrorSeverityText_(error, 'info', 'warning', 'error'); } - /** - * @param {!ManifestError|!RuntimeError} error - * @return {string} - * @private - */ - computeErrorTypeLabel_(error) { + private computeErrorTypeLabel_(error: ManifestError|RuntimeError): string { return getErrorSeverityText_( error, loadTimeData.getString('logLevel'), loadTimeData.getString('warnLevel'), loadTimeData.getString('errorLevel')); } - /** - * @param {!Event} e - * @private - */ - onDeleteErrorAction_(e) { - this.delegate.deleteErrors( - this.data.id, [(/** @type {!{model:Object}} */ (e)).model.item.id]); + private onDeleteErrorAction_(e: RepeaterEvent<ManifestError|RuntimeError>) { + this.delegate.deleteErrors(this.data.id, [e.model.item.id]); e.stopPropagation(); } - /** private */ - onInDevModeChanged_() { + private onInDevModeChanged_() { if (!this.inDevMode) { // Wait until next render cycle in case error page is loading. setTimeout(() => { @@ -243,9 +209,8 @@ /** * Fetches the source for the selected error and populates the code section. - * @private */ - onSelectedErrorChanged_() { + private onSelectedErrorChanged_() { this.code_ = null; if (this.selectedEntry_ < 0) { @@ -253,35 +218,36 @@ } const error = this.getSelectedError(); - const args = { + const args: chrome.developerPrivate.RequestFileSourceProperties = { extensionId: error.extensionId, message: error.message, + pathSuffix: '', }; switch (error.type) { case chrome.developerPrivate.ErrorType.MANIFEST: - args.pathSuffix = error.source; - args.manifestKey = error.manifestKey; - args.manifestSpecific = error.manifestSpecific; + const manifestError = error as ManifestError; + args.pathSuffix = manifestError.source; + args.manifestKey = manifestError.manifestKey; + args.manifestSpecific = manifestError.manifestSpecific; break; case chrome.developerPrivate.ErrorType.RUNTIME: + const runtimeError = error as RuntimeError; // slice(1) because pathname starts with a /. - args.pathSuffix = new URL(error.source).pathname.slice(1); - args.lineNumber = error.stackTrace && error.stackTrace[0] ? - error.stackTrace[0].lineNumber : + args.pathSuffix = new URL(runtimeError.source).pathname.slice(1); + args.lineNumber = + runtimeError.stackTrace && runtimeError.stackTrace[0] ? + runtimeError.stackTrace[0].lineNumber : 0; - this.selectedStackFrame_ = error.stackTrace && error.stackTrace[0] ? - error.stackTrace[0] : + this.selectedStackFrame_ = + runtimeError.stackTrace && runtimeError.stackTrace[0] ? + runtimeError.stackTrace[0] : null; break; } this.delegate.requestFileSource(args).then(code => this.code_ = code); } - /** - * @return {boolean} - * @private - */ - computeIsRuntimeError_(item) { + private computeIsRuntimeError_(item: ManifestError|RuntimeError): boolean { return item.type === chrome.developerPrivate.ErrorType.RUNTIME; } @@ -289,11 +255,9 @@ * The description is a human-readable summation of the frame, in the * form "<relative_url>:<line_number> (function)", e.g. * "myfile.js:25 (myFunction)". - * @param {!chrome.developerPrivate.StackFrame} frame - * @return {string} - * @private */ - getStackTraceLabel_(frame) { + private getStackTraceLabel_(frame: chrome.developerPrivate.StackFrame): + string { let description = getRelativeUrl(frame.url, this.getSelectedError()) + ':' + frame.lineNumber; @@ -307,41 +271,26 @@ return description; } - /** - * @param {chrome.developerPrivate.StackFrame} frame - * @return {string} - * @private - */ - getStackFrameClass_(frame) { + private getStackFrameClass_(frame: chrome.developerPrivate.StackFrame): + string { return frame === this.selectedStackFrame_ ? 'selected' : ''; } - /** - * @param {!chrome.developerPrivate.StackFrame} frame - * @return {number} - * @private - */ - getStackFrameTabIndex_(frame) { + private getStackFrameTabIndex_(frame: chrome.developerPrivate.StackFrame): + number { return frame === this.selectedStackFrame_ ? 0 : -1; } /** * This function is used to determine whether or not we want to show a * stack frame. We don't want to show code from internal scripts. - * @param {string} url - * @return {boolean} - * @private */ - shouldDisplayFrame_(url) { + private shouldDisplayFrame_(url: string): boolean { // All our internal scripts are in the 'extensions::' namespace. return !/^extensions::/.test(url); } - /** - * @param {!chrome.developerPrivate.StackFrame} frame - * @private - */ - updateSelected_(frame) { + private updateSelected_(frame: chrome.developerPrivate.StackFrame) { this.selectedStackFrame_ = assert(frame); const selectedError = this.getSelectedError(); @@ -355,20 +304,13 @@ .then(code => this.code_ = code); } - /** - * @param {!Event} e - * @private - */ - onStackFrameTap_(e) { - const frame = /** @type {!{model:Object}} */ (e).model.item; + private onStackFrameTap_( + e: RepeaterEvent<chrome.developerPrivate.StackFrame>) { + const frame = e.model.item; this.updateSelected_(frame); } - /** - * @param {!Event} e - * @private - */ - onStackKeydown_(e) { + private onStackKeydown_(e: KeyboardEvent) { let direction = 0; if (e.key === 'ArrowDown') { @@ -381,12 +323,13 @@ e.preventDefault(); - const list = e.target.parentElement.querySelectorAll('li'); + const list = + (e.target as HTMLElement).parentElement!.querySelectorAll('li'); for (let i = 0; i < list.length; ++i) { if (list[i].classList.contains('selected')) { - const polymerEvent = /** @type {!{model: !Object}} */ (e); - const frame = polymerEvent.model.item.stackTrace[i + direction]; + const repeaterEvent = e as unknown as RepeaterEvent<RuntimeError>; + const frame = repeaterEvent.model.item.stackTrace[i + direction]; if (frame) { this.updateSelected_(frame); list[i + direction].focus(); // Preserve focus. @@ -399,45 +342,32 @@ /** * Computes the class name for the error item depending on whether its * the currently selected error. - * @param {number} index - * @return {string} - * @private */ - computeErrorClass_(index) { + private computeErrorClass_(index: number): string { return index === this.selectedEntry_ ? 'selected' : ''; } - /** @private */ - iconName_(index) { + private iconName_(index: number): string { return index === this.selectedEntry_ ? 'icon-expand-less' : 'icon-expand-more'; } /** * Determine if the iron-collapse should be opened (expanded). - * @param {number} index - * @return {boolean} - * @private */ - isOpened_(index) { + private isOpened_(index: number): boolean { return index === this.selectedEntry_; } /** - * @param {number} index - * @return {string} The aria-expanded value as a string. - * @private + * @return The aria-expanded value as a string. */ - isAriaExpanded_(index) { + private isAriaExpanded_(index: number): string { return this.isOpened_(index).toString(); } - /** - * @param {!{type: string, code: string, model: !{index: number}}} e - * @private - */ - onErrorItemAction_(e) { + private onErrorItemAction_(e: KeyboardEvent) { if (e.type === 'keydown' && !((e.code === 'Space' || e.code === 'Enter'))) { return; } @@ -445,8 +375,15 @@ // Call preventDefault() to avoid the browser scrolling when the space key // is pressed. e.preventDefault(); - this.selectedEntry_ = - this.selectedEntry_ === e.model.index ? -1 : e.model.index; + const repeaterEvent = + e as unknown as RepeaterEvent<ManifestError|RuntimeError>; + this.selectedEntry_ = this.selectedEntry_ === repeaterEvent.model.index ? + -1 : + repeaterEvent.model.index; + } + + static get template() { + return html`{__html_template__}`; } }
diff --git a/chrome/browser/resources/extensions/host_permissions_toggle_list.js b/chrome/browser/resources/extensions/host_permissions_toggle_list.ts similarity index 78% rename from chrome/browser/resources/extensions/host_permissions_toggle_list.js rename to chrome/browser/resources/extensions/host_permissions_toggle_list.ts index a88c5c3..4514d4c 100644 --- a/chrome/browser/resources/extensions/host_permissions_toggle_list.js +++ b/chrome/browser/resources/extensions/host_permissions_toggle_list.ts
@@ -14,8 +14,8 @@ import {ItemDelegate} from './item.js'; import {UserAction} from './item_util.js'; +import {ExtensionsToggleRowElement} from './toggle_row.js'; -/** @polymer */ class ExtensionsHostPermissionsToggleListElement extends PolymerElement { static get is() { return 'extensions-host-permissions-toggle-list'; @@ -29,35 +29,33 @@ return { /** * The underlying permissions data. - * @type {chrome.developerPrivate.RuntimeHostPermissions} */ permissions: Object, - /** @private */ itemId: String, - /** @type {!ItemDelegate} */ delegate: Object, }; } + permissions: chrome.developerPrivate.RuntimeHostPermissions; + private itemId: string; + delegate: ItemDelegate; + /** - * @return {boolean} Whether the item is allowed to execute on all of its - * requested sites. - * @private + * @return Whether the item is allowed to execute on all of its requested + * sites. */ - allowedOnAllHosts_() { + private allowedOnAllHosts_(): boolean { return this.permissions.hostAccess === chrome.developerPrivate.HostAccess.ON_ALL_SITES; } /** - * Returns a lexicographically-sorted list of the hosts associated with this - * item. - * @return {!Array<!chrome.developerPrivate.SiteControl>} - * @private + * @return A lexicographically-sorted list of the hosts associated with this + * item. */ - getSortedHosts_() { + private getSortedHosts_(): Array<chrome.developerPrivate.SiteControl> { return this.permissions.hosts.sort((a, b) => { if (a.host < b.host) { return -1; @@ -69,11 +67,7 @@ }); } - /** - * @param {!CustomEvent<boolean>} e - * @private - */ - onAllHostsToggleChanged_(e) { + private onAllHostsToggleChanged_(e: CustomEvent<boolean>) { // TODO(devlin): In the case of going from all sites to specific sites, // we'll withhold all sites (i.e., all specific site toggles will move to // unchecked, and the user can check them individually). This is slightly @@ -94,13 +88,9 @@ } } - /** - * @param {!CustomEvent<boolean>} e - * @private - */ - onHostAccessChanged_(e) { - const host = e.target.host; - const checked = e.target.checked; + private onHostAccessChanged_(e: CustomEvent<boolean>) { + const host = (e.target as unknown as {host: string}).host; + const checked = (e.target as ExtensionsToggleRowElement).checked; if (checked) { this.delegate.addRuntimeHostPermission(this.itemId, host); @@ -111,8 +101,7 @@ } } - /** @private */ - onLearnMoreClick_() { + private onLearnMoreClick_() { this.delegate.recordUserAction(UserAction.LEARN_MORE); } }
diff --git a/chrome/browser/resources/extensions/item.js b/chrome/browser/resources/extensions/item.ts similarity index 63% rename from chrome/browser/resources/extensions/item.js rename to chrome/browser/resources/extensions/item.ts index dceb845..b11a2923 100644 --- a/chrome/browser/resources/extensions/item.js +++ b/chrome/browser/resources/extensions/item.ts
@@ -21,111 +21,51 @@ import 'chrome://resources/polymer/v3_0/paper-tooltip/paper-tooltip.js'; import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js'; +import {CrToggleElement} from 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js'; import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; +import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {flush, html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ItemMixin} from './item_mixin.js'; import {computeInspectableViewLabel, EnableControl, getEnableControl, getItemSource, getItemSourceString, isEnabled, SourceType, userCanChangeEnablement} from './item_util.js'; import {navigation, Page} from './navigation_helper.js'; -/** @interface */ -export class ItemDelegate { - /** @param {string} id */ - deleteItem(id) {} - - /** - * @param {string} id - * @param {boolean} isEnabled - */ - setItemEnabled(id, isEnabled) {} - - /** - * @param {string} id - * @param {boolean} isAllowedIncognito - */ - setItemAllowedIncognito(id, isAllowedIncognito) {} - - /** - * @param {string} id - * @param {boolean} isAllowedOnFileUrls - */ - setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {} - - /** - * @param {string} id - * @param {!chrome.developerPrivate.HostAccess} hostAccess - */ - setItemHostAccess(id, hostAccess) {} - - /** - * @param {string} id - * @param {boolean} collectsErrors - */ - setItemCollectsErrors(id, collectsErrors) {} - - /** - * @param {string} id - * @param {chrome.developerPrivate.ExtensionView} view - */ - inspectItemView(id, view) {} - - /** - * @param {string} url - */ - openUrl(url) {} - - /** - * @param {string} id - * @return {!Promise} - */ - reloadItem(id) {} - - /** @param {string} id */ - repairItem(id) {} - - /** @param {!chrome.developerPrivate.ExtensionInfo} extension */ - showItemOptionsPage(extension) {} - - /** @param {string} id */ - showInFolder(id) {} - - /** - * @param {string} id - * @return {!Promise<string>} - */ - getExtensionSize(id) {} - - /** - * @param {string} id - * @param {string} host - * @return {!Promise<void>} - */ - addRuntimeHostPermission(id, host) {} - - /** - * @param {string} id - * @param {string} host - * @return {!Promise<void>} - */ - removeRuntimeHostPermission(id, host) {} +export interface ItemDelegate { + deleteItem(id: string): void; + setItemEnabled(id: string, isEnabled: boolean): void; + setItemAllowedIncognito(id: string, isAllowedIncognito: boolean): void; + setItemAllowedOnFileUrls(id: string, isAllowedOnFileUrls: boolean): void; + setItemHostAccess(id: string, hostAccess: chrome.developerPrivate.HostAccess): + void; + setItemCollectsErrors(id: string, collectsErrors: boolean): void; + inspectItemView(id: string, view: chrome.developerPrivate.ExtensionView): + void; + openUrl(url: string): void; + reloadItem(id: string): Promise<void>; + repairItem(id: string): void; + showItemOptionsPage(extension: chrome.developerPrivate.ExtensionInfo): void; + showInFolder(id: string): void; + getExtensionSize(id: string): Promise<string>; + addRuntimeHostPermission(id: string, host: string): Promise<void>; + removeRuntimeHostPermission(id: string, host: string): Promise<void>; // TODO(tjudkins): This function is not specific to items, so should be pulled // out to a more generic place when we need to access it from elsewhere. - /** @param {string} metricName */ - recordUserAction(metricName) {} + recordUserAction(metricName: string): void; } -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const ExtensionsItemElementBase = - mixinBehaviors([I18nBehavior], ItemMixin(PolymerElement)); +export interface ExtensionsItemElement { + $: { + detailsButton: HTMLElement, + enableToggle: CrToggleElement, + }; +} -/** @polymer */ -class ExtensionsItemElement extends ExtensionsItemElementBase { +const ExtensionsItemElementBase = + mixinBehaviors([I18nBehavior], ItemMixin(PolymerElement)) as + {new (): PolymerElement & I18nBehavior}; + +export class ExtensionsItemElement extends ExtensionsItemElementBase { static get is() { return 'extensions-item'; } @@ -137,9 +77,7 @@ static get properties() { return { // The item's delegate, or null. - delegate: { - type: Object, - }, + delegate: Object, // Whether or not dev mode is enabled. inDevMode: { @@ -149,13 +87,9 @@ // The underlying ExtensionInfo itself. Public for use in declarative // bindings. - /** @type {chrome.developerPrivate.ExtensionInfo} */ - data: { - type: Object, - }, + data: Object, // Whether or not the expanded view of the item is shown. - /** @private */ showingDetails_: { type: Boolean, value: false, @@ -167,49 +101,37 @@ return ['observeIdVisibility_(inDevMode, showingDetails_, data.id)']; } - constructor() { - super(); + delegate: ItemDelegate; + inDevMode: boolean; + data: chrome.developerPrivate.ExtensionInfo; + private showingDetails_: boolean; + /** Prevents reloading the same item while it's already being reloaded. */ + private isReloading_: boolean = false; - /** Prevents reloading the same item while it's already being reloaded. */ - this.isReloading_ = false; - } - - /** - * @param {string} eventName - * @param {*=} detail - * @private - */ - fire_(eventName, detail) { + private fire_(eventName: string, detail?: any) { this.dispatchEvent( new CustomEvent(eventName, {bubbles: true, composed: true, detail})); } - /** @return {!HTMLElement} The "Details" button. */ getDetailsButton() { - return /** @type {!HTMLElement} */ (this.$.detailsButton); + return this.$.detailsButton; } - /** @return {?HTMLElement} The "Errors" button, if it exists. */ - getErrorsButton() { - return /** @type {?HTMLElement} */ ( - this.shadowRoot.querySelector('#errors-button')); + /** @return The "Errors" button, if it exists. */ + getErrorsButton(): HTMLElement|null { + return this.shadowRoot!.querySelector('#errors-button'); } - /** @private */ - observeIdVisibility_(inDevMode, showingDetails, id) { + private observeIdVisibility_() { flush(); - const idElement = this.shadowRoot.querySelector('#extension-id'); + const idElement = this.shadowRoot!.querySelector('#extension-id'); if (idElement) { assert(this.data); idElement.innerHTML = this.i18n('itemId', this.data.id); } } - /** - * @return {boolean} - * @private - */ - shouldShowErrorsButton_() { + private shouldShowErrorsButton_(): boolean { // When the error console is disabled (happens when // --disable-error-console command line flag is used or when in the // Stable/Beta channel), |installWarnings| is populated. @@ -223,19 +145,16 @@ this.data.runtimeErrors.length > 0; } - /** @private */ - onRemoveTap_() { + private onRemoveTap_() { this.delegate.deleteItem(this.data.id); } - /** @private */ - onEnableToggleChange_() { + private onEnableToggleChange_() { this.delegate.setItemEnabled(this.data.id, this.$.enableToggle.checked); this.$.enableToggle.checked = this.isEnabled_(); } - /** @private */ - onErrorsTap_() { + private onErrorsTap_() { if (this.data.installWarnings && this.data.installWarnings.length > 0) { this.fire_('show-install-warnings', this.data.installWarnings); return; @@ -244,26 +163,19 @@ navigation.navigateTo({page: Page.ERRORS, extensionId: this.data.id}); } - /** @private */ - onDetailsTap_() { + private onDetailsTap_() { navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id}); } - /** - * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e - * @private - */ - onInspectTap_(e) { + private onInspectTap_() { this.delegate.inspectItemView(this.data.id, this.data.views[0]); } - /** @private */ - onExtraInspectTap_() { + private onExtraInspectTap_() { navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id}); } - /** @private */ - onReloadTap_() { + private onReloadTap_() { // Don't reload if in the middle of an update. if (this.isReloading_) { return; @@ -290,60 +202,35 @@ }); } - /** @private */ - onRepairTap_() { + private onRepairTap_() { this.delegate.repairItem(this.data.id); } - /** - * @return {boolean} - * @private - */ - isEnabled_() { + private isEnabled_(): boolean { return isEnabled(this.data.state); } - /** - * @return {boolean} - * @private - */ - isEnableToggleEnabled_() { + private isEnableToggleEnabled_(): boolean { return userCanChangeEnablement(this.data); } - /** - * Returns true if the reload button should be shown. - * @return {boolean} - * @private - */ - showReloadButton_() { + /** @return Whether the reload button should be shown. */ + private showReloadButton_(): boolean { return getEnableControl(this.data) === EnableControl.RELOAD; } - /** - * Returns true if the repair button should be shown. - * @return {boolean} - * @private - */ - showRepairButton_() { + /** @return Whether the repair button should be shown. */ + private showRepairButton_(): boolean { return getEnableControl(this.data) === EnableControl.REPAIR; } - /** - * Returns true if the enable toggle should be shown. - * @return {boolean} - * @private - */ - showEnableToggle_() { + /** @return Whether the enable toggle should be shown. */ + private showEnableToggle_(): boolean { return getEnableControl(this.data) === EnableControl.ENABLE_TOGGLE; } - /** - * return {string} - * @private - */ - computeClasses_() { + private computeClasses_(): string { let classes = this.isEnabled_() ? 'enabled' : 'disabled'; if (this.inDevMode) { classes += ' dev-mode'; @@ -351,11 +238,7 @@ return classes; } - /** - * @return {string} - * @private - */ - computeSourceIndicatorIcon_() { + private computeSourceIndicatorIcon_(): string { switch (getItemSource(this.data)) { case SourceType.POLICY: return 'extensions-icons:business'; @@ -372,11 +255,7 @@ assertNotReached(); } - /** - * @return {string} - * @private - */ - computeSourceIndicatorText_() { + private computeSourceIndicatorText_(): string { if (this.data.locationText) { return this.data.locationText; } @@ -386,19 +265,11 @@ getItemSourceString(sourceType); } - /** - * @return {boolean} - * @private - */ - computeInspectViewsHidden_() { + private computeInspectViewsHidden_(): boolean { return !this.data.views || this.data.views.length === 0; } - /** - * @return {string} - * @private - */ - computeFirstInspectTitle_() { + private computeFirstInspectTitle_(): string { // Note: theoretically, this wouldn't be called without any inspectable // views (because it's in a dom-if="!computeInspectViewsHidden_()"). // However, due to the recycling behavior of iron list, it seems that @@ -409,28 +280,16 @@ ''; } - /** - * @return {string} - * @private - */ - computeFirstInspectLabel_() { + private computeFirstInspectLabel_(): string { const label = this.computeFirstInspectTitle_(); return label && this.data.views.length > 1 ? label + ',' : label; } - /** - * @return {boolean} - * @private - */ - computeExtraViewsHidden_() { + private computeExtraViewsHidden_(): boolean { return this.data.views.length <= 1; } - /** - * @return {boolean} - * @private - */ - computeDevReloadButtonHidden_() { + private computeDevReloadButtonHidden_(): boolean { // Only display the reload spinner if the extension is unpacked and // enabled or disabled for reload. If an extension fails to reload (due to // e.g. a parsing error), it will @@ -447,39 +306,23 @@ return !showIcon; } - /** - * @return {string} - * @private - */ - computeExtraInspectLabel_() { + private computeExtraInspectLabel_(): string { return this.i18n( 'itemInspectViewsExtra', (this.data.views.length - 1).toString()); } - /** - * @return {boolean} - * @private - */ - hasSevereWarnings_() { + private hasSevereWarnings_(): boolean { return this.data.disableReasons.corruptInstall || this.data.disableReasons.suspiciousInstall || this.data.runtimeWarnings.length > 0 || !!this.data.blacklistText; } - /** - * @return {boolean} - * @private - */ - showDescription_() { + private showDescription_(): boolean { return !this.hasSevereWarnings_() && !this.data.showSafeBrowsingAllowlistWarning; } - /** - * @return {boolean} - * @private - */ - showAllowlistWarning_() { + private showAllowlistWarning_(): boolean { // Only show the allowlist warning if there are no other warnings. The item // card has a fixed height and the content might get cropped if too many // warnings are displayed. This should be a rare edge case and the allowlist
diff --git a/chrome/browser/resources/extensions/item_list.js b/chrome/browser/resources/extensions/item_list.ts similarity index 72% rename from chrome/browser/resources/extensions/item_list.js rename to chrome/browser/resources/extensions/item_list.ts index 5d6a4644..28e38e6 100644 --- a/chrome/browser/resources/extensions/item_list.js +++ b/chrome/browser/resources/extensions/item_list.ts
@@ -8,22 +8,19 @@ import './shared_style.js'; import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; +import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js'; import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {ItemDelegate} from './item.js'; +import {ExtensionsItemElement, ItemDelegate} from './item.js'; -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ +type Filter = (info: chrome.developerPrivate.ExtensionInfo) => boolean; + const ExtensionsItemListElementBase = - mixinBehaviors([CrContainerShadowBehavior, I18nBehavior], PolymerElement); + mixinBehaviors([CrContainerShadowBehavior, I18nBehavior], PolymerElement) as + {new (): PolymerElement & I18nBehavior}; -/** @polymer */ class ExtensionsItemListElement extends ExtensionsItemListElementBase { static get is() { return 'extensions-item-list'; @@ -35,13 +32,8 @@ static get properties() { return { - /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ apps: Array, - - /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ extensions: Array, - - /** @type {ItemDelegate} */ delegate: Object, inDevMode: { @@ -53,32 +45,27 @@ type: String, }, - /** @private */ computedFilter_: { type: String, computed: 'computeFilter_(filter)', observer: 'announceSearchResults_', }, - /** @private */ maxColumns_: { type: Number, value: () => loadTimeData.getBoolean('showCheckup') ? 2 : 3, }, - /** @private */ showCheckup_: { type: Boolean, value: () => loadTimeData.getBoolean('showCheckup'), }, - /** @private */ shownAppsCount_: { type: Number, value: 0, }, - /** @private */ shownExtensionsCount_: { type: Number, value: 0, @@ -86,21 +73,26 @@ }; } - /** - * @param {string} id - * @return {?Element} - */ - getDetailsButton(id) { - const item = this.shadowRoot.querySelector(`#${id}`); + apps: Array<chrome.developerPrivate.ExtensionInfo>; + extensions: Array<chrome.developerPrivate.ExtensionInfo>; + delegate: ItemDelegate; + inDevMode: boolean; + filter: string; + private computedFilter_: string; + private maxColumns_: number; + private showCheckup_: boolean; + private shownAppsCount_: number; + private shownExtensionsCount_: number; + + getDetailsButton(id: string): HTMLElement|null { + const item = + this.shadowRoot!.querySelector<ExtensionsItemElement>(`#${id}`); return item && item.getDetailsButton(); } - /** - * @param {string} id - * @return {?Element} - */ - getErrorsButton(id) { - const item = this.shadowRoot.querySelector(`#${id}`); + getErrorsButton(id: string): HTMLElement|null { + const item = + this.shadowRoot!.querySelector<ExtensionsItemElement>(`#${id}`); return item && item.getErrorsButton(); } @@ -109,9 +101,8 @@ * should be shown. A |null| value indicates that everything should be * shown. * return {?Function} - * @private */ - computeFilter_() { + private computeFilter_(): Filter|null { const formattedFilter = this.filter.trim().toLowerCase(); if (!formattedFilter) { return null; @@ -121,8 +112,7 @@ s => s.toLowerCase().includes(formattedFilter)); } - /** @private */ - shouldShowEmptyItemsMessage_() { + private shouldShowEmptyItemsMessage_() { if (!this.apps || !this.extensions) { return; } @@ -130,21 +120,18 @@ return this.apps.length === 0 && this.extensions.length === 0; } - /** @private */ - shouldShowEmptySearchMessage_() { + private shouldShowEmptySearchMessage_() { return !this.shouldShowEmptyItemsMessage_() && this.shownAppsCount_ === 0 && this.shownExtensionsCount_ === 0; } - /** @private */ - onNoExtensionsTap_(e) { - if (e.target.tagName === 'A') { + private onNoExtensionsTap_(e: Event) { + if ((e.target as HTMLElement).tagName === 'A') { chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions'); } } - /** @private */ - announceSearchResults_() { + private announceSearchResults_() { if (this.computedFilter_) { IronA11yAnnouncer.requestAvailability(); setTimeout(() => { // Async to allow list to update. @@ -166,4 +153,10 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'extensions-item-list': ExtensionsItemListElement; + } +} + customElements.define(ExtensionsItemListElement.is, ExtensionsItemListElement);
diff --git a/chrome/browser/resources/extensions/keyboard_shortcuts.ts b/chrome/browser/resources/extensions/keyboard_shortcuts.ts index 5dc87d2..d72dd1b 100644 --- a/chrome/browser/resources/extensions/keyboard_shortcuts.ts +++ b/chrome/browser/resources/extensions/keyboard_shortcuts.ts
@@ -56,7 +56,6 @@ delegate: KeyboardShortcutDelegate; items: Array<chrome.developerPrivate.ExtensionInfo>; - /** @override */ ready() { super.ready(); this.addEventListener('view-enter-start', this.onViewEnter_);
diff --git a/chrome/browser/resources/extensions/kiosk_dialog.ts b/chrome/browser/resources/extensions/kiosk_dialog.ts index 1f13f306..bd0b829 100644 --- a/chrome/browser/resources/extensions/kiosk_dialog.ts +++ b/chrome/browser/resources/extensions/kiosk_dialog.ts
@@ -13,7 +13,7 @@ import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {assert} from 'chrome://resources/js/assert.m.js'; -import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js'; +import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js'; import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {KioskApp, KioskAppSettings, KioskBrowserProxy, KioskBrowserProxyImpl} from './kiosk_browser_proxy.js';
diff --git a/chrome/browser/resources/extensions/load_error.js b/chrome/browser/resources/extensions/load_error.ts similarity index 73% rename from chrome/browser/resources/extensions/load_error.js rename to chrome/browser/resources/extensions/load_error.ts index 47f59872..f6523d8 100644 --- a/chrome/browser/resources/extensions/load_error.js +++ b/chrome/browser/resources/extensions/load_error.ts
@@ -9,20 +9,26 @@ import './code_section.js'; import './strings.m.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -/** @interface */ -export class LoadErrorDelegate { +import {ExtensionsCodeSectionElement} from './code_section.js'; + +export interface LoadErrorDelegate { /** * Attempts to load the previously-attempted unpacked extension. - * @param {string} retryId - * @return {!Promise} */ - retryLoadUnpacked(retryId) {} + retryLoadUnpacked(retryGuid: string): Promise<boolean>; } -/** @polymer */ +interface ExtensionsLoadErrorElement { + $: { + code: ExtensionsCodeSectionElement, + dialog: CrDialogElement, + }; +} + class ExtensionsLoadErrorElement extends PolymerElement { static get is() { return 'extensions-load-error'; @@ -34,13 +40,8 @@ static get properties() { return { - /** @type {LoadErrorDelegate} */ delegate: Object, - - /** @type {chrome.developerPrivate.LoadError} */ loadError: Object, - - /** @private */ retrying_: Boolean, }; } @@ -51,16 +52,19 @@ ]; } + delegate: LoadErrorDelegate; + loadError: chrome.developerPrivate.LoadError; + private retrying_: boolean; + show() { - /** @type {!CrDialogElement} */ (this.$.dialog).showModal(); + this.$.dialog.showModal(); } close() { - /** @type {!CrDialogElement} */ (this.$.dialog).close(); + this.$.dialog.close(); } - /** @private */ - onRetryTap_() { + private onRetryTap_() { this.retrying_ = true; this.delegate.retryLoadUnpacked(this.loadError.retryGuid) .then( @@ -68,20 +72,17 @@ this.close(); }, loadError => { - this.loadError = - /** @type {chrome.developerPrivate.LoadError} */ (loadError); + this.loadError = loadError; this.retrying_ = false; }); } - /** @private */ - observeLoadErrorChanges_() { + private observeLoadErrorChanges_() { assert(this.loadError); const source = this.loadError.source; // CodeSection expects a RequestFileSourceResponse, rather than an // ErrorFileSource. Massage into place. // TODO(devlin): Make RequestFileSourceResponse use ErrorFileSource. - /** @type {!chrome.developerPrivate.RequestFileSourceResponse} */ const codeSectionProperties = { beforeHighlight: source ? source.beforeHighlight : '', highlight: source ? source.highlight : '', @@ -94,5 +95,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'extensions-load-error': ExtensionsLoadErrorElement; + } +} + customElements.define( ExtensionsLoadErrorElement.is, ExtensionsLoadErrorElement);
diff --git a/chrome/browser/resources/extensions/manager.js b/chrome/browser/resources/extensions/manager.ts similarity index 71% rename from chrome/browser/resources/extensions/manager.js rename to chrome/browser/resources/extensions/manager.ts index 969b3e93..e107d64 100644 --- a/chrome/browser/resources/extensions/manager.js +++ b/chrome/browser/resources/extensions/manager.ts
@@ -28,8 +28,10 @@ import {assert, assertNotReached} from 'chrome://resources/js/assert.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'; +import {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js'; import {ActivityLogExtensionPlaceholder} from './activity_log/activity_log.js'; +import {ExtensionsDetailViewElement} from './detail_view.js'; // <if expr="chromeos"> import {KioskBrowserProxyImpl} from './kiosk_browser_proxy.js'; // </if> @@ -38,15 +40,16 @@ /** * Compares two extensions to determine which should come first in the list. - * @param {chrome.developerPrivate.ExtensionInfo} a - * @param {chrome.developerPrivate.ExtensionInfo} b - * @return {number} */ -const compareExtensions = function(a, b) { - function compare(x, y) { +function compareExtensions( + a: chrome.developerPrivate.ExtensionInfo, + b: chrome.developerPrivate.ExtensionInfo): number { + function compare(x: string, y: string): number { return x < y ? -1 : (x > y ? 1 : 0); } - function compareLocation(x, y) { + function compareLocation( + x: chrome.developerPrivate.ExtensionInfo, + y: chrome.developerPrivate.ExtensionInfo): number { if (x.location === y.location) { return 0; } @@ -61,18 +64,25 @@ return compareLocation(a, b) || compare(a.name.toLowerCase(), b.name.toLowerCase()) || compare(a.id, b.id); -}; +} -/** @polymer */ +declare global { + interface HTMLElementEventMap { + 'load-error': CustomEvent<chrome.developerPrivate.LoadError>; + } +} + +interface ExtensionsManagerElement { + $: { + viewManager: CrViewManagerElement, + }; +} + class ExtensionsManagerElement extends PolymerElement { static get is() { return 'extensions-manager'; } - static get template() { - return html`{__html_template__}`; - } - static get properties() { return { canLoadUnpacked: { @@ -80,7 +90,6 @@ value: false, }, - /** @type {!Service} */ delegate: { type: Object, value() { @@ -103,7 +112,6 @@ value: false, }, - /** @private */ isSupervised_: { type: Boolean, value: false, @@ -125,70 +133,55 @@ * so that hidden subpages don't update when an item updates. That is, we * don't want the details view subpage to update when the item shown in * the errors page updates, and vice versa. - * @private {!chrome.developerPrivate.ExtensionInfo|undefined} */ errorPageItem_: Object, /** * The item currently displayed in the details view subpage. See also * errorPageItem_. - * @private {!chrome.developerPrivate.ExtensionInfo|undefined} */ detailViewItem_: Object, /** * The item that provides some information about the current extension * for the activity log view subpage. See also errorPageItem_. - * @private {!chrome.developerPrivate.ExtensionInfo|undefined| - * !ActivityLogExtensionPlaceholder} */ activityLogItem_: Object, - /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */ extensions_: Array, - /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */ apps_: Array, /** * Prevents page content from showing before data is first loaded. - * @private */ didInitPage_: { type: Boolean, value: false, }, - /** @private */ showDrawer_: Boolean, - /** @private */ showLoadErrorDialog_: Boolean, - /** @private */ showInstallWarningsDialog_: Boolean, - /** @private {?Array<string>} */ installWarnings_: Array, - /** @private */ showOptionsDialog_: Boolean, /** * Whether the last page the user navigated from was the activity log * page. - * @private */ fromActivityLog_: Boolean, // <if expr="chromeos"> - /** @private */ kioskEnabled_: { type: Boolean, value: false, }, - /** @private */ showKioskDialog_: { type: Boolean, value: false, @@ -197,47 +190,71 @@ }; } + canLoadUnpacked: boolean; + delegate: Service; + inDevMode: boolean; + showActivityLog: boolean; + devModeControlledByPolicy: boolean; + private isSupervised_: boolean; + private incognitoAvailable_: boolean; + filter: string; + private errorPageItem_?: chrome.developerPrivate.ExtensionInfo; + private detailViewItem_?: chrome.developerPrivate.ExtensionInfo; + private activityLogItem_?: chrome.developerPrivate.ExtensionInfo| + ActivityLogExtensionPlaceholder; + private extensions_: Array<chrome.developerPrivate.ExtensionInfo>; + private apps_: Array<chrome.developerPrivate.ExtensionInfo>; + private didInitPage_: boolean; + private showDrawer_: boolean; + private showLoadErrorDialog_: boolean; + private showInstallWarningsDialog_: boolean; + private installWarnings_: string[]|null; + private showOptionsDialog_: boolean; + private fromActivityLog_: boolean; + + // <if expr="chromeos"> + private kioskEnabled_: boolean; + private showKioskDialog_: boolean; + // </if> + + private currentPage_: PageState|null; + private navigationListener_: number|null = null; + constructor() { super(); /** * The current page being shown. Default to null, and initPage_ will figure * out the initial page based on url. - * @private {?PageState} */ this.currentPage_ = null; /** * The ID of the listener on |navigation|. Stored so that the * listener can be removed when this element is detached (happens in tests). - * @private {?number} */ this.navigationListener_ = null; } - /** @override */ ready() { super.ready(); - this.addEventListener( - 'load-error', - e => this.onLoadError_( - /** @type {!CustomEvent<!chrome.developerPrivate.LoadError>} */ ( - e))); + this.addEventListener('load-error', this.onLoadError_); this.addEventListener('view-enter-start', this.onViewEnterStart_); this.addEventListener('view-exit-start', this.onViewExitStart_); this.addEventListener('view-exit-finish', this.onViewExitFinish_); const service = Service.getInstance(); - const onProfileStateChanged = profileInfo => { - this.isSupervised_ = profileInfo.isSupervised; - this.incognitoAvailable_ = profileInfo.isIncognitoAvailable; - this.devModeControlledByPolicy = - profileInfo.isDeveloperModeControlledByPolicy; - this.inDevMode = profileInfo.inDeveloperMode; - this.canLoadUnpacked = profileInfo.canLoadUnpacked; - }; + const onProfileStateChanged = + (profileInfo: chrome.developerPrivate.ProfileInfo) => { + this.isSupervised_ = profileInfo.isSupervised; + this.incognitoAvailable_ = profileInfo.isIncognitoAvailable; + this.devModeControlledByPolicy = + profileInfo.isDeveloperModeControlledByPolicy; + this.inDevMode = profileInfo.inDeveloperMode; + this.canLoadUnpacked = profileInfo.canLoadUnpacked; + }; service.getProfileStateChangedTarget().addListener(onProfileStateChanged); service.getProfileConfiguration().then(onProfileStateChanged); @@ -257,41 +274,34 @@ // </if> } - /** @override */ connectedCallback() { super.connectedCallback(); document.documentElement.classList.remove('loading'); - document.fonts.load('bold 12px Roboto'); + // https://github.com/microsoft/TypeScript/issues/13569 + (document as any).fonts.load('bold 12px Roboto'); this.navigationListener_ = navigation.addListener(newPage => { this.changePage_(newPage); }); } - /** @override */ disconnectedCallback() { super.disconnectedCallback(); - assert(navigation.removeListener( - /** @type {number} */ (this.navigationListener_))); + assert(navigation.removeListener(this.navigationListener_!)); this.navigationListener_ = null; } /** * Initializes the page to reflect what's specified in the url so that if * the user visits chrome://extensions/?id=..., we land on the proper page. - * @private */ - initPage_() { + private initPage_() { this.didInitPage_ = true; this.changePage_(navigation.getCurrentPage()); } - /** - * @param {!chrome.developerPrivate.EventData} eventData - * @private - */ - onItemStateChanged_(eventData) { + private onItemStateChanged_(eventData: chrome.developerPrivate.EventData) { const EventType = chrome.developerPrivate.EventType; switch (eventData.event_type) { case EventType.VIEW_REGISTERED: @@ -322,7 +332,8 @@ const listId = this.getListId_(eventData.extensionInfo); const currentIndex = this.get(listId).findIndex( - item => item.id === eventData.extensionInfo.id); + (item: chrome.developerPrivate.ExtensionInfo) => + item.id === eventData.extensionInfo!.id); if (currentIndex >= 0) { this.updateItem_(listId, currentIndex, eventData.extensionInfo); @@ -338,31 +349,24 @@ } } - /** - * @param {!CustomEvent<string>} event - * @private - */ - onFilterChanged_(event) { - if (this.currentPage_.page !== Page.LIST) { + private onFilterChanged_(event: CustomEvent<string>) { + if (this.currentPage_!.page !== Page.LIST) { navigation.navigateTo({page: Page.LIST}); } this.filter = event.detail; } - /** @private */ - onMenuButtonTap_() { + private onMenuButtonTap_() { this.showDrawer_ = true; setTimeout(() => { - this.shadowRoot.querySelector('#drawer').openDrawer(); + this.shadowRoot!.querySelector('cr-drawer')!.openDrawer(); }, 0); } /** - * @param {!chrome.developerPrivate.ExtensionInfo} item - * @return {string} The ID of the list that the item belongs in. - * @private + * @return The ID of the list that the item belongs in. */ - getListId_(item) { + private getListId_(item: chrome.developerPrivate.ExtensionInfo): string { const ExtensionType = chrome.developerPrivate.ExtensionType; switch (item.type) { case ExtensionType.HOSTED_APP: @@ -377,25 +381,23 @@ break; } assertNotReached(); + return ''; } /** - * @param {string} listId The list to look for the item in. - * @param {string} itemId The id of the item to look for. - * @return {number} The index of the item in the list, or -1 if not found. - * @private + * @param listId The list to look for the item in. + * @param itemId The id of the item to look for. + * @return The index of the item in the list, or -1 if not found. */ - getIndexInList_(listId, itemId) { - return this.get(listId).findIndex(function(item) { + private getIndexInList_(listId: string, itemId: string): number { + return this.get(listId).findIndex(function( + item: chrome.developerPrivate.ExtensionInfo) { return item.id === itemId; }); } - /** - * @return {?chrome.developerPrivate.ExtensionInfo} - * @private - */ - getData_(id) { + private getData_(id: string): chrome.developerPrivate.ExtensionInfo + |undefined { return this.extensions_[this.getIndexInList_('extensions_', id)] || this.apps_[this.getIndexInList_('apps_', id)]; } @@ -403,13 +405,12 @@ /** * Categorizes |extensionsAndApps| to apps and extensions and initializes * those lists. - * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensionsAndApps - * @private */ - initExtensionsAndApps_(extensionsAndApps) { + private initExtensionsAndApps_( + extensionsAndApps: Array<chrome.developerPrivate.ExtensionInfo>) { extensionsAndApps.sort(compareExtensions); - const apps = []; - const extensions = []; + const apps: chrome.developerPrivate.ExtensionInfo[] = []; + const extensions: chrome.developerPrivate.ExtensionInfo[] = []; for (const i of extensionsAndApps) { const list = this.getListId_(i) === 'apps_' ? apps : extensions; list.push(i); @@ -422,14 +423,14 @@ /** * Creates and adds a new extensions-item element to the list, inserting it * into its sorted position in the relevant section. - * @param {!chrome.developerPrivate.ExtensionInfo} item The extension - * the new element is representing. - * @private + * @param item The extension the new element is representing. */ - addItem_(listId, item) { + private addItem_( + listId: string, item: chrome.developerPrivate.ExtensionInfo) { // We should never try and add an existing item. assert(this.getIndexInList_(listId, item.id) === -1); - let insertBeforeChild = this.get(listId).findIndex(function(listEl) { + let insertBeforeChild = this.get(listId).findIndex(function( + listEl: chrome.developerPrivate.ExtensionInfo) { return compareExtensions(listEl, item) > 0; }); if (insertBeforeChild === -1) { @@ -439,11 +440,11 @@ } /** - * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the - * item to update. - * @private + * @param item The data for the item to update. */ - updateItem_(listId, index, item) { + private updateItem_( + listId: string, index: number, + item: chrome.developerPrivate.ExtensionInfo) { // We should never try and update a non-existent item. assert(index >= 0); this.set([listId, index], item); @@ -454,24 +455,23 @@ // that the DOM will have stale data, but there's no point in causing the // extra work. if (this.detailViewItem_ && this.detailViewItem_.id === item.id && - this.currentPage_.page === Page.DETAILS) { + this.currentPage_!.page === Page.DETAILS) { this.detailViewItem_ = item; } else if ( this.errorPageItem_ && this.errorPageItem_.id === item.id && - this.currentPage_.page === Page.ERRORS) { + this.currentPage_!.page === Page.ERRORS) { this.errorPageItem_ = item; } else if ( this.activityLogItem_ && this.activityLogItem_.id === item.id && - this.currentPage_.page === Page.ACTIVITY_LOG) { + this.currentPage_!.page === Page.ACTIVITY_LOG) { this.activityLogItem_ = item; } } /** - * @param {string} itemId The id of item to remove. - * @private + * @param itemId The id of item to remove. */ - removeItem_(itemId) { + private removeItem_(itemId: string) { // Search for the item to be deleted in |extensions_|. let listId = 'extensions_'; let index = this.getIndexInList_(listId, itemId); @@ -484,23 +484,19 @@ // We should never try and remove a non-existent item. assert(index >= 0); this.splice(listId, index, 1); - if ((this.currentPage_.page === Page.ACTIVITY_LOG || - this.currentPage_.page === Page.DETAILS || - this.currentPage_.page === Page.ERRORS) && - this.currentPage_.extensionId === itemId) { + if ((this.currentPage_!.page === Page.ACTIVITY_LOG || + this.currentPage_!.page === Page.DETAILS || + this.currentPage_!.page === Page.ERRORS) && + this.currentPage_!.extensionId === itemId) { // Leave the details page (the 'list' page is a fine choice). navigation.replaceWith({page: Page.LIST}); } } - /** - * @param {!CustomEvent<!chrome.developerPrivate.LoadError>} e - * @private - */ - onLoadError_(e) { + private onLoadError_(e: CustomEvent<chrome.developerPrivate.LoadError>) { this.showLoadErrorDialog_ = true; setTimeout(() => { - const dialog = this.shadowRoot.querySelector('#load-error'); + const dialog = this.shadowRoot!.querySelector('extensions-load-error')!; dialog.loadError = e.detail; dialog.show(); }, 0); @@ -508,20 +504,19 @@ /** * Changes the active page selection. - * @param {PageState} newPage - * @private */ - changePage_(newPage) { + private changePage_(newPage: PageState) { this.onCloseDrawer_(); - const optionsDialog = this.shadowRoot.querySelector('#options-dialog'); + const optionsDialog = + this.shadowRoot!.querySelector('extensions-options-dialog'); if (optionsDialog && optionsDialog.open) { this.showOptionsDialog_ = false; } const fromPage = this.currentPage_ ? this.currentPage_.page : null; const toPage = newPage.page; - let data; + let data: chrome.developerPrivate.ExtensionInfo|undefined; let activityLogPlaceholder; if (newPage.extensionId) { data = this.getData_(newPage.extensionId); @@ -560,8 +555,7 @@ } if (fromPage !== toPage) { - /** @type {CrViewManagerElement} */ (this.$.viewManager) - .switchView(/** @type {string} */ (toPage)); + this.$.viewManager.switchView(toPage); } if (newPage.subpage) { @@ -569,12 +563,13 @@ assert(newPage.extensionId); this.showOptionsDialog_ = true; setTimeout(() => { - this.shadowRoot.querySelector('#options-dialog').show(data); + this.shadowRoot!.querySelector('extensions-options-dialog')!.show(data! + ); }, 0); } document.title = toPage === Page.DETAILS ? - `${loadTimeData.getString('title')} - ${this.detailViewItem_.name}` : + `${loadTimeData.getString('title')} - ${this.detailViewItem_!.name}` : loadTimeData.getString('title'); this.currentPage_ = newPage; } @@ -582,63 +577,51 @@ /** * This method detaches the drawer dialog completely. Should only be * triggered by the dialog's 'close' event. - * @private */ - onDrawerClose_() { + private onDrawerClose_() { this.showDrawer_ = false; } /** * This method animates the closing of the drawer. - * @private */ - onCloseDrawer_() { - const drawer = this.shadowRoot.querySelector('#drawer'); + private onCloseDrawer_() { + const drawer = this.shadowRoot!.querySelector('cr-drawer'); if (drawer && drawer.open) { drawer.close(); } } - /** @private */ - onLoadErrorDialogClose_() { + private onLoadErrorDialogClose_() { this.showLoadErrorDialog_ = false; } - /** @private */ - onOptionsDialogClose_() { + private onOptionsDialogClose_() { this.showOptionsDialog_ = false; - this.shadowRoot.querySelector('extensions-detail-view') - .focusOptionsButton(); + this.shadowRoot!.querySelector( + 'extensions-detail-view')!.focusOptionsButton(); } - /** @private */ - onViewEnterStart_() { + private onViewEnterStart_() { this.fromActivityLog_ = false; } - /** - * @param {!Event} e - * @private - */ - onViewExitStart_(e) { - const viewType = e.composedPath()[0].tagName; + private onViewExitStart_(e: Event) { + const viewType = (e.composedPath()[0] as HTMLElement).tagName; this.fromActivityLog_ = viewType === 'EXTENSIONS-ACTIVITY-LOG'; } - /** - * @param {!Event} e - * @private - */ - onViewExitFinish_(e) { - const viewType = e.composedPath()[0].tagName; + private onViewExitFinish_(e: Event) { + const viewType = (e.composedPath()[0] as HTMLElement).tagName; if (viewType === 'EXTENSIONS-ITEM-LIST' || viewType === 'EXTENSIONS-KEYBOARD-SHORTCUTS' || viewType === 'EXTENSIONS-ACTIVITY-LOG') { return; } - const extensionId = e.composedPath()[0].data.id; - const list = this.shadowRoot.querySelector('extensions-item-list'); + const extensionId = + (e.composedPath()[0] as ExtensionsDetailViewElement).data.id; + const list = this.shadowRoot!.querySelector('extensions-item-list')!; const button = viewType === 'EXTENSIONS-DETAIL-VIEW' ? list.getDetailsButton(extensionId) : list.getErrorsButton(extensionId); @@ -650,11 +633,7 @@ } } - /** - * @param {!CustomEvent<!Array<string>>} e - * @private - */ - onShowInstallWarnings_(e) { + private onShowInstallWarnings_(e: CustomEvent<Array<string>>) { // Leverage Polymer data bindings instead of just assigning the // installWarnings on the dialog since the dialog hasn't been stamped // in the DOM yet. @@ -662,22 +641,24 @@ this.showInstallWarningsDialog_ = true; } - /** @private */ - onInstallWarningsDialogClose_() { + private onInstallWarningsDialogClose_() { this.installWarnings_ = null; this.showInstallWarningsDialog_ = false; } // <if expr="chromeos"> - /** @private */ - onKioskTap_() { + private onKioskTap_() { this.showKioskDialog_ = true; } - onKioskDialogClose_() { + private onKioskDialogClose_() { this.showKioskDialog_ = false; } // </if> + + static get template() { + return html`{__html_template__}`; + } } customElements.define(ExtensionsManagerElement.is, ExtensionsManagerElement);
diff --git a/chrome/browser/resources/extensions/options_dialog.ts b/chrome/browser/resources/extensions/options_dialog.ts index 3d08a8e..97506fc 100644 --- a/chrome/browser/resources/extensions/options_dialog.ts +++ b/chrome/browser/resources/extensions/options_dialog.ts
@@ -42,7 +42,6 @@ }; } -/** @polymer */ class ExtensionsOptionsDialogElement extends PolymerElement { static get is() { return 'extensions-options-dialog'; @@ -110,7 +109,7 @@ // Add a 'resize' such that the dialog is resized when window size // changes. this.eventTracker_.add(window, 'resize', boundUpdateDialogSize); - this.$.body.appendChild(/** @type {Node} */ (this.extensionOptions_)); + this.$.body.appendChild(this.extensionOptions_); }); } @@ -133,5 +132,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'extensions-options-dialog': ExtensionsOptionsDialogElement; + } +} + customElements.define( ExtensionsOptionsDialogElement.is, ExtensionsOptionsDialogElement);
diff --git a/chrome/browser/resources/extensions/pack_dialog.ts b/chrome/browser/resources/extensions/pack_dialog.ts index 8f547a8e..1f34840 100644 --- a/chrome/browser/resources/extensions/pack_dialog.ts +++ b/chrome/browser/resources/extensions/pack_dialog.ts
@@ -68,7 +68,6 @@ private keyFile_: string; private lastResponse_: chrome.developerPrivate.PackDirectoryResponse|null; - /** @override */ connectedCallback() { super.connectedCallback(); this.$.dialog.showModal();
diff --git a/chrome/browser/resources/extensions/pack_dialog_alert.ts b/chrome/browser/resources/extensions/pack_dialog_alert.ts index 50e17f7..8cddb02 100644 --- a/chrome/browser/resources/extensions/pack_dialog_alert.ts +++ b/chrome/browser/resources/extensions/pack_dialog_alert.ts
@@ -47,7 +47,6 @@ return this.$.dialog.getNative().returnValue; } - /** @override */ ready() { super.ready(); @@ -75,7 +74,6 @@ } } - /** @override */ connectedCallback() { super.connectedCallback(); this.$.dialog.showModal();
diff --git a/chrome/browser/resources/extensions/runtime_host_permissions.js b/chrome/browser/resources/extensions/runtime_host_permissions.ts similarity index 77% rename from chrome/browser/resources/extensions/runtime_host_permissions.js rename to chrome/browser/resources/extensions/runtime_host_permissions.ts index e440c40..f955e30 100644 --- a/chrome/browser/resources/extensions/runtime_host_permissions.js +++ b/chrome/browser/resources/extensions/runtime_host_permissions.ts
@@ -17,13 +17,28 @@ import './shared_style.js'; import './strings.m.js'; +import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.m.js'; +import {CrRadioGroupElement} from 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ItemDelegate} from './item.js'; -/** @polymer */ +/** Event interface for dom-repeat. */ +interface RepeaterEvent extends CustomEvent { + model: { + item: string, + }; +} + +interface ExtensionsRuntimeHostPermissionsElement { + $: { + hostActionMenu: CrActionMenuElement, + 'host-access': CrRadioGroupElement, + }; +} + class ExtensionsRuntimeHostPermissionsElement extends PolymerElement { static get is() { return 'extensions-runtime-host-permissions'; @@ -37,27 +52,21 @@ return { /** * The underlying permissions data. - * @type {chrome.developerPrivate.RuntimeHostPermissions} */ permissions: Object, - /** @private */ itemId: String, - /** @type {!ItemDelegate} */ delegate: Object, /** * Whether the dialog to add a new host permission is shown. - * @private */ showHostDialog_: Boolean, /** * The current site of the entry that the host dialog is editing, if the * dialog is open for editing. - * @type {?string} - * @private */ hostDialogModel_: { type: String, @@ -66,8 +75,6 @@ /** * The element to return focus to once the host dialog closes. - * @type {?HTMLElement} - * @private */ hostDialogAnchorElement_: { type: Object, @@ -77,8 +84,6 @@ /** * If the action menu is open, the site of the entry it is open for. * Otherwise null. - * @type {?string} - * @private */ actionMenuModel_: { type: String, @@ -88,8 +93,6 @@ /** * The element that triggered the action menu, so that the page will * return focus once the action menu (or dialog) closes. - * @type {?HTMLElement} - * @private */ actionMenuAnchorElement_: { type: Object, @@ -99,8 +102,6 @@ /** * The old host access setting; used when we don't immediately commit the * change to host access so that we can reset it if the user cancels. - * @type {?string} - * @private */ oldHostAccess_: { type: String, @@ -111,7 +112,6 @@ * Indicator to track if an onHostAccessChange_ event is coming from the * setting being automatically reverted to the previous value, after a * change to a new value was canceled. - * @private */ revertingHostAccess_: { type: Boolean, @@ -120,7 +120,6 @@ /** * Proxying the enum to be used easily by the html template. - * @private */ HostAccess_: { type: Object, @@ -129,13 +128,20 @@ }; } - /** - * @param {!Event} event - * @private - */ - onHostAccessChange_(event) { - const group = /** @type {!HTMLElement} */ (this.$['host-access']); - const access = group.selected; + permissions: chrome.developerPrivate.RuntimeHostPermissions; + itemId: string; + delegate: ItemDelegate; + private showHostDialog_: boolean; + private hostDialogModel_: string|null; + private hostDialogAnchorElement_: HTMLElement|null; + private actionMenuModel_: string|null; + private actionMenuAnchorElement_: HTMLElement|null; + private oldHostAccess_: string|null; + private revertingHostAccess_: boolean; + + private onHostAccessChange_() { + const group = this.$['host-access']; + const access = group.selected as chrome.developerPrivate.HostAccess; // Log a user action when the host access selection is changed by the user, // but not when reverting from a canceled change to another setting. @@ -174,21 +180,15 @@ } } - /** - * @return {boolean} - * @private - */ - showSpecificSites_() { + private showSpecificSites_(): boolean { return this.permissions.hostAccess === chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES; } /** - * Returns the granted host permissions as a sorted set of strings. - * @return {!Array<string>} - * @private + * @return The granted host permissions as a sorted set of strings. */ - getRuntimeHosts_() { + private getRuntimeHosts_(): string[] { if (!this.permissions.hosts) { return []; } @@ -201,41 +201,33 @@ .sort(); } - /** - * @param {Event} e - * @private - */ - onAddHostClick_(e) { + private onAddHostClick_(e: Event) { chrome.metricsPrivate.recordUserAction( 'Extensions.Settings.Hosts.AddHostActivated'); - const target = /** @type {!HTMLElement} */ (e.target); - this.doShowHostDialog_(target, null); + this.doShowHostDialog_(e.target as HTMLElement, null); } /** - * @param {!HTMLElement} anchorElement The element to return focus to once - * the dialog closes. - * @param {?string} currentSite The site entry currently being - * edited, or null if this is to add a new entry. - * @private + * @param anchorElement The element to return focus to once the dialog closes. + * @param currentSite The site entry currently being edited, or null if this + * is to add a new entry. */ - doShowHostDialog_(anchorElement, currentSite) { + private doShowHostDialog_( + anchorElement: HTMLElement, currentSite: string|null) { this.hostDialogAnchorElement_ = anchorElement; this.hostDialogModel_ = currentSite; this.showHostDialog_ = true; } - /** @private */ - onHostDialogClose_() { + private onHostDialogClose_() { this.hostDialogModel_ = null; this.showHostDialog_ = false; - focusWithoutInk(assert(this.hostDialogAnchorElement_, 'Host Anchor')); + focusWithoutInk(assert(this.hostDialogAnchorElement_!, 'Host Anchor')); this.hostDialogAnchorElement_ = null; this.oldHostAccess_ = null; } - /** @private */ - onHostDialogCancel_() { + private onHostDialogCancel_() { // The user canceled the dialog. Set host-access back to the old value, // if the dialog was shown when just transitioning to a new state. chrome.metricsPrivate.recordUserAction( @@ -249,33 +241,19 @@ } } - /** - * @return {boolean} - * @private - */ - dialogShouldUpdateHostAccess_() { + private dialogShouldUpdateHostAccess_(): boolean { return !!this.oldHostAccess_; } - /** - * @param {!{ - * model: !{item: string}, - * target: !HTMLElement, - * }} e - * @private - */ - onEditHostClick_(e) { + private onEditHostClick_(e: RepeaterEvent) { chrome.metricsPrivate.recordUserAction( 'Extensions.Settings.Hosts.ActionMenuOpened'); this.actionMenuModel_ = e.model.item; - this.actionMenuAnchorElement_ = e.target; - const actionMenu = - /** @type {CrActionMenuElement} */ (this.$.hostActionMenu); - actionMenu.showAt(e.target); + this.actionMenuAnchorElement_ = e.target as HTMLElement; + this.$.hostActionMenu.showAt(e.target as HTMLElement); } - /** @private */ - onActionMenuEditClick_() { + private onActionMenuEditClick_() { chrome.metricsPrivate.recordUserAction( 'Extensions.Settings.Hosts.ActionMenuEditActivated'); // Cache the site before closing the action menu, since it's cleared. @@ -285,36 +263,27 @@ // to the action menu's trigger (since the dialog will be shown next). // Instead, curry the element to the dialog, so once it closes, focus // will be returned. - const anchorElement = assert(this.actionMenuAnchorElement_, 'Menu Anchor'); + const anchorElement = assert(this.actionMenuAnchorElement_!, 'Menu Anchor'); this.actionMenuAnchorElement_ = null; this.closeActionMenu_(); this.doShowHostDialog_(anchorElement, site); } - /** @private */ - onActionMenuRemoveClick_() { + private onActionMenuRemoveClick_() { chrome.metricsPrivate.recordUserAction( 'Extensions.Settings.Hosts.ActionMenuRemoveActivated'); this.delegate.removeRuntimeHostPermission( - this.itemId, assert(this.actionMenuModel_, 'Action Menu Model')); + this.itemId, assert(this.actionMenuModel_!, 'Action Menu Model')); this.closeActionMenu_(); } - /** @private */ - closeActionMenu_() { + private closeActionMenu_() { const menu = this.$.hostActionMenu; assert(menu.open); menu.close(); } - /** @private */ - onActionMenuClose_() { - this.actionMenuModel_ = null; - this.actionMenuAnchorElement_ = null; - } - - /** @private */ - onLearnMoreClick_() { + private onLearnMoreClick_() { chrome.metricsPrivate.recordUserAction( 'Extensions.Settings.Hosts.LearnMoreActivated'); }
diff --git a/chrome/browser/resources/extensions/runtime_hosts_dialog.ts b/chrome/browser/resources/extensions/runtime_hosts_dialog.ts index 611441f..2dc5f6ad 100644 --- a/chrome/browser/resources/extensions/runtime_hosts_dialog.ts +++ b/chrome/browser/resources/extensions/runtime_hosts_dialog.ts
@@ -105,7 +105,6 @@ private site_: string; private inputInvalid_: boolean; - /** @override */ connectedCallback() { super.connectedCallback();
diff --git a/chrome/browser/resources/extensions/service.ts b/chrome/browser/resources/extensions/service.ts index 3db2c6d..27dd6dc 100644 --- a/chrome/browser/resources/extensions/service.ts +++ b/chrome/browser/resources/extensions/service.ts
@@ -15,19 +15,14 @@ import {ToolbarDelegate} from './toolbar.js'; -/** - * @implements {ActivityLogDelegate} - * @implements {ActivityLogEventDelegate} - * @implements {ErrorPageDelegate} - * @implements {ItemDelegate} - * @implements {LoadErrorDelegate} - * @implements {ToolbarDelegate} - */ -export class Service implements KeyboardShortcutDelegate, PackDialogDelegate { +export class Service implements ActivityLogDelegate, ActivityLogEventDelegate, + ErrorPageDelegate, ItemDelegate, + KeyboardShortcutDelegate, LoadErrorDelegate, + PackDialogDelegate, ToolbarDelegate { private isDeleting_: boolean = false; private eventsToIgnoreOnce_: Set<string> = new Set(); - getProfileConfiguration() { + getProfileConfiguration(): Promise<chrome.developerPrivate.ProfileInfo> { return new Promise(function(resolve) { chrome.developerPrivate.getProfileConfiguration(resolve); }); @@ -52,21 +47,19 @@ return chrome.developerPrivate.onProfileStateChanged; } - getExtensionsInfo() { + getExtensionsInfo(): Promise<Array<chrome.developerPrivate.ExtensionInfo>> { return new Promise(function(resolve) { chrome.developerPrivate.getExtensionsInfo( {includeDisabled: true, includeTerminated: true}, resolve); }); } - /** @override */ getExtensionSize(id: string): Promise<string> { return new Promise(function(resolve) { chrome.developerPrivate.getExtensionSize(id, resolve); }); } - /** @override */ addRuntimeHostPermission(id: string, host: string): Promise<void> { return new Promise((resolve, reject) => { chrome.developerPrivate.addHostPermission(id, host, () => { @@ -79,7 +72,6 @@ }); } - /** @override */ removeRuntimeHostPermission(id: string, host: string): Promise<void> { return new Promise((resolve, reject) => { chrome.developerPrivate.removeHostPermission(id, host, () => { @@ -92,7 +84,6 @@ }); } - /** @override */ recordUserAction(metricName: string): void { chrome.metricsPrivate.recordUserAction(metricName); } @@ -117,7 +108,6 @@ }); } - /** @override */ updateExtensionCommandKeybinding( extensionId: string, commandName: string, keybinding: string) { chrome.developerPrivate.updateExtensionCommand({ @@ -127,7 +117,6 @@ }); } - /** @override */ updateExtensionCommandScope( extensionId: string, commandName: string, scope: chrome.developerPrivate.CommandScope): void { @@ -144,7 +133,6 @@ } - /** @override */ setShortcutHandlingSuspended(isCapturing: boolean) { chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing); } @@ -180,7 +168,6 @@ }); } - /** @override */ deleteItem(id: string) { if (this.isDeleting_) { return; @@ -196,7 +183,6 @@ }); } - /** @override */ setItemEnabled(id: string, isEnabled: boolean) { chrome.metricsPrivate.recordUserAction( isEnabled ? 'Extensions.ExtensionEnabled' : @@ -204,7 +190,6 @@ chrome.management.setEnabled(id, isEnabled); } - /** @override */ setItemAllowedIncognito(id: string, isAllowedIncognito: boolean) { chrome.developerPrivate.updateExtensionConfiguration({ extensionId: id, @@ -212,7 +197,6 @@ }); } - /** @override */ setItemAllowedOnFileUrls(id: string, isAllowedOnFileUrls: boolean) { chrome.developerPrivate.updateExtensionConfiguration({ extensionId: id, @@ -220,7 +204,6 @@ }); } - /** @override */ setItemHostAccess(id: string, hostAccess: chrome.developerPrivate.HostAccess): void { chrome.developerPrivate.updateExtensionConfiguration({ @@ -229,7 +212,6 @@ }); } - /** @override */ setItemCollectsErrors(id: string, collectsErrors: boolean): void { chrome.developerPrivate.updateExtensionConfiguration({ extensionId: id, @@ -237,7 +219,6 @@ }); } - /** @override */ inspectItemView(id: string, view: chrome.developerPrivate.ExtensionView): void { chrome.developerPrivate.openDevTools({ @@ -253,7 +234,6 @@ window.open(url); } - /** @override */ reloadItem(id: string): Promise<void> { return new Promise(function(resolve, reject) { chrome.developerPrivate.reload( @@ -269,12 +249,10 @@ }); } - /** @override */ repairItem(id: string): void { chrome.developerPrivate.repairExtension(id); } - /** @override */ showItemOptionsPage(extension: chrome.developerPrivate.ExtensionInfo): void { assert(extension && extension.optionsPage); if (extension.optionsPage!.openInTab) { @@ -288,39 +266,33 @@ } } - /** @override */ setProfileInDevMode(inDevMode: boolean) { chrome.developerPrivate.updateProfileConfiguration( {inDeveloperMode: inDevMode}); } - /** @override */ loadUnpacked(): Promise<boolean> { return this.loadUnpackedHelper_(); } - /** @override */ retryLoadUnpacked(retryGuid: string): Promise<boolean> { // Attempt to load an unpacked extension, optionally as another attempt at // a previously-specified load. return this.loadUnpackedHelper_({retryGuid: retryGuid}); } - /** @override */ choosePackRootDirectory(): Promise<string> { return this.chooseFilePath_( chrome.developerPrivate.SelectType.FOLDER, chrome.developerPrivate.FileType.LOAD); } - /** @override */ choosePrivateKeyPath(): Promise<string> { return this.chooseFilePath_( chrome.developerPrivate.SelectType.FILE, chrome.developerPrivate.FileType.PEM); } - /** @override */ packExtension( rootPath: string, keyPath: string, flag?: number, callback?: @@ -329,7 +301,6 @@ chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback); } - /** @override */ updateAllExtensions(extensions: chrome.developerPrivate.ExtensionInfo[]): Promise<string> { /** @@ -361,7 +332,6 @@ }); } - /** @override */ deleteErrors( extensionId: string, errorIds?: number[], type?: chrome.developerPrivate.ErrorType) { @@ -372,7 +342,6 @@ }); } - /** @override */ requestFileSource(args: chrome.developerPrivate.RequestFileSourceProperties): Promise<chrome.developerPrivate.RequestFileSourceResponse> { return new Promise(function(resolve) { @@ -380,13 +349,12 @@ }); } - /** @override */ showInFolder(id: string) { chrome.developerPrivate.showPath(id); } - /** @override */ - getExtensionActivityLog(extensionId: string) { + getExtensionActivityLog(extensionId: string): + Promise<chrome.activityLogPrivate.ActivityResultSet> { return new Promise(function(resolve) { chrome.activityLogPrivate.getExtensionActivities( { @@ -397,7 +365,6 @@ }); } - /** @override */ getFilteredExtensionActivityLog(extensionId: string, searchTerm: string) { const anyType = chrome.activityLogPrivate.ExtensionActivityFilter.ANY; @@ -445,14 +412,12 @@ }); } - /** @override */ deleteActivitiesById(activityIds: string[]): Promise<void> { return new Promise(function(resolve) { chrome.activityLogPrivate.deleteActivities(activityIds, resolve); }); } - /** @override */ deleteActivitiesFromExtension(extensionId: string): Promise<void> { return new Promise(function(resolve) { chrome.activityLogPrivate.deleteActivitiesByExtension( @@ -460,12 +425,10 @@ }); } - /** @override */ - getOnExtensionActivity() { + getOnExtensionActivity(): any { return chrome.activityLogPrivate.onExtensionActivity; } - /** @override */ downloadActivities(rawActivityData: string, fileName: string) { const blob = new Blob([rawActivityData], {type: 'application/json'}); const url = URL.createObjectURL(blob);
diff --git a/chrome/browser/resources/extensions/shortcut_input.js b/chrome/browser/resources/extensions/shortcut_input.ts similarity index 79% rename from chrome/browser/resources/extensions/shortcut_input.js rename to chrome/browser/resources/extensions/shortcut_input.ts index f099b7c6..d24e3ea 100644 --- a/chrome/browser/resources/extensions/shortcut_input.js +++ b/chrome/browser/resources/extensions/shortcut_input.ts
@@ -9,32 +9,33 @@ import 'chrome://resources/polymer/v3_0/paper-styles/color.js'; import {assert} from 'chrome://resources/js/assert.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; +import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js'; import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {KeyboardShortcutDelegate} from './keyboard_shortcut_delegate.js'; import {hasValidModifiers, isValidKeyCode, Key, keystrokeToString} from './shortcut_util.js'; -/** @enum {number} */ -const ShortcutError = { - NO_ERROR: 0, - INCLUDE_START_MODIFIER: 1, - TOO_MANY_MODIFIERS: 2, - NEED_CHARACTER: 3, -}; +enum ShortcutError { + NO_ERROR = 0, + INCLUDE_START_MODIFIER = 1, + TOO_MANY_MODIFIERS = 2, + NEED_CHARACTER = 3, +} // The UI to display and manage keyboard shortcuts set for extension commands. -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const ExtensionsShortcutInputElementBase = - mixinBehaviors([I18nBehavior], PolymerElement); +interface ExtensionsShortcutInputElement { + $: { + input: HTMLElement, + edit: HTMLElement, + }; +} -/** @polymer */ +const ExtensionsShortcutInputElementBase = + mixinBehaviors([I18nBehavior], PolymerElement) as + {new (): PolymerElement & I18nBehavior}; + class ExtensionsShortcutInputElement extends ExtensionsShortcutInputElementBase { static get is() { @@ -47,7 +48,6 @@ static get properties() { return { - /** @type {!KeyboardShortcutDelegate} */ delegate: Object, item: { @@ -65,27 +65,23 @@ value: '', }, - /** @private */ capturing_: { type: Boolean, value: false, }, - /** @private {!ShortcutError} */ error_: { type: Number, value: ShortcutError.NO_ERROR, }, - /** @private */ readonly_: { type: Boolean, value: true, reflectToAttribute: true, }, - /** @private */ pendingShortcut_: { type: String, value: '', @@ -93,7 +89,15 @@ }; } - /** @override */ + delegate: KeyboardShortcutDelegate; + item: string; + commandName: string; + shortcut: string; + private capturing_: boolean; + private error_: ShortcutError; + private readonly_: boolean; + private pendingShortcut_: string; + ready() { super.ready(); @@ -105,8 +109,7 @@ node.addEventListener('keyup', this.onKeyUp_.bind(this)); } - /** @private */ - startCapture_() { + private startCapture_() { if (this.capturing_ || this.readonly_) { return; } @@ -114,8 +117,7 @@ this.delegate.setShortcutHandlingSuspended(true); } - /** @private */ - endCapture_() { + private endCapture_() { if (!this.capturing_) { return; } @@ -127,8 +129,7 @@ this.readonly_ = true; } - /** @private */ - clearShortcut_() { + private clearShortcut_() { this.pendingShortcut_ = ''; this.shortcut = ''; // We commit the empty shortcut in order to clear the current shortcut @@ -137,11 +138,7 @@ this.endCapture_(); } - /** - * @param {!Event} e - * @private - */ - onKeyDown_(e) { + private onKeyDown_(e: KeyboardEvent) { if (this.readonly_) { return; } @@ -170,14 +167,10 @@ this.startCapture_(); } - this.handleKey_(/** @type {!KeyboardEvent} */ (e)); + this.handleKey_(e); } - /** - * @param {!Event} e - * @private - */ - onKeyUp_(e) { + private onKeyUp_(e: KeyboardEvent) { // Ignores pressing 'Space' or 'Enter' on the edit button. In 'Enter's // case, the edit button disappears before key-up, so 'Enter's key-up // target becomes the input field, not the edit button, and needs to @@ -194,19 +187,12 @@ return; } - this.handleKey_(/** @type {!KeyboardEvent} */ (e)); + this.handleKey_(e); } - /** - * @param {!ShortcutError} error - * @param {string} includeStartModifier - * @param {string} tooManyModifiers - * @param {string} needCharacter - * @return {string} UI string. - * @private - */ - getErrorString_( - error, includeStartModifier, tooManyModifiers, needCharacter) { + private getErrorString_( + _error: ShortcutError, includeStartModifier: string, + tooManyModifiers: string, needCharacter: string): string { switch (this.error_) { case ShortcutError.INCLUDE_START_MODIFIER: return includeStartModifier; @@ -220,11 +206,7 @@ } } - /** - * @param {!KeyboardEvent} e - * @private - */ - handleKey_(e) { + private handleKey_(e: KeyboardEvent) { // While capturing, we prevent all events from bubbling, to prevent // shortcuts lacking the right modifier (F3 for example) from activating // and ending capture prematurely. @@ -264,18 +246,13 @@ this.endCapture_(); } - /** @private */ - commitPending_() { + private commitPending_() { this.shortcut = this.pendingShortcut_; this.delegate.updateExtensionCommandKeybinding( this.item, this.commandName, this.shortcut); } - /** - * @return {string} The placeholder text. - * @private - */ - computePlaceholder_() { + private computePlaceholder_(): string { if (this.readonly_) { return this.shortcut ? this.i18n('shortcutSet', this.computeText_()) : this.i18n('shortcutNotSet'); @@ -284,25 +261,19 @@ } /** - * @return {string} The text to be displayed in the shortcut field. - * @private + * @return The text to be displayed in the shortcut field. */ - computeText_() { + private computeText_(): string { const shortcutString = this.capturing_ ? this.pendingShortcut_ : this.shortcut; return shortcutString.split('+').join(' + '); } - /** - * @return {boolean} - * @private - */ - getIsInvalid_() { + private getIsInvalid_(): boolean { return this.error_ !== ShortcutError.NO_ERROR; } - /** @private */ - onEditClick_() { + private onEditClick_() { // TODO(ghazale): The clearing functionality should be improved. // Instead of clicking the edit button, and then clicking elsewhere to // commit the "empty" shortcut, we want to introduce a separate clear
diff --git a/chrome/browser/resources/extensions/toggle_row.ts b/chrome/browser/resources/extensions/toggle_row.ts index c44f000..3b84cc34 100644 --- a/chrome/browser/resources/extensions/toggle_row.ts +++ b/chrome/browser/resources/extensions/toggle_row.ts
@@ -15,7 +15,7 @@ * a hidden native <input type="checkbox"> to achieve this. */ -interface ExtensionsToggleRowElement { +export interface ExtensionsToggleRowElement { $: { crToggle: CrToggleElement, label: HTMLLabelElement, @@ -23,7 +23,7 @@ }; } -class ExtensionsToggleRowElement extends PolymerElement { +export class ExtensionsToggleRowElement extends PolymerElement { static get is() { return 'extensions-toggle-row'; }
diff --git a/chrome/browser/resources/extensions/toolbar.js b/chrome/browser/resources/extensions/toolbar.ts similarity index 72% rename from chrome/browser/resources/extensions/toolbar.js rename to chrome/browser/resources/extensions/toolbar.ts index 182a092..f8dd45f 100644 --- a/chrome/browser/resources/extensions/toolbar.js +++ b/chrome/browser/resources/extensions/toolbar.ts
@@ -12,42 +12,36 @@ import './pack_dialog.js'; import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; +import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {listenOnce} from 'chrome://resources/js/util.m.js'; import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js'; import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -/** @interface */ -export class ToolbarDelegate { +export interface ToolbarDelegate { /** * Toggles whether or not the profile is in developer mode. - * @param {boolean} inDevMode */ - setProfileInDevMode(inDevMode) {} + setProfileInDevMode(inDevMode: boolean): void; - /** - * Opens the dialog to load unpacked extensions. - * @return {!Promise} - */ - loadUnpacked() {} + /** Opens the dialog to load unpacked extensions. */ + loadUnpacked(): Promise<boolean>; - /** - * Updates all extensions. - * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensions - * @return {!Promise} - */ - updateAllExtensions(extensions) {} + /** Updates all extensions. */ + updateAllExtensions(extensions: chrome.developerPrivate.ExtensionInfo[]): + Promise<string>; } -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const ExtensionsToolbarElementBase = - mixinBehaviors([I18nBehavior], PolymerElement); +interface ExtensionsToolbarElement { + $: { + devDrawer: HTMLElement, + packExtensions: HTMLElement, + }; +} -/** @polymer */ +const ExtensionsToolbarElementBase = + mixinBehaviors([I18nBehavior], PolymerElement) as + {new (): PolymerElement & I18nBehavior}; + class ExtensionsToolbarElement extends ExtensionsToolbarElementBase { static get is() { return 'extensions-toolbar'; @@ -59,10 +53,7 @@ static get properties() { return { - /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ extensions: Array, - - /** @type {ToolbarDelegate} */ delegate: Object, inDevMode: { @@ -73,7 +64,6 @@ }, devModeControlledByPolicy: Boolean, - isSupervised: Boolean, // <if expr="chromeos"> @@ -82,85 +72,71 @@ canLoadUnpacked: Boolean, - /** @private */ expanded_: Boolean, - - /** @private */ showPackDialog_: Boolean, /** * Prevents initiating update while update is in progress. - * @private */ - isUpdating_: {type: Boolean, value: false} + isUpdating_: {type: Boolean, value: false}, }; } - /** @override */ + extensions: Array<chrome.developerPrivate.ExtensionInfo>; + delegate: ToolbarDelegate; + inDevMode: boolean; + devModeControlledByPolicy: boolean; + isSupervised: boolean; + + // <if expr="chromeos"> + kioskEnabled: boolean; + // </if> + + canLoadUnpacked: boolean; + + private expanded_: boolean; + private showPackDialog_: boolean; + private isUpdating_: boolean; + + ready() { super.ready(); this.setAttribute('role', 'banner'); } - /** - * @param {string} eventName - * @param {*=} detail - * @private - */ - fire_(eventName, detail) { + private fire_(eventName: string, detail?: any) { this.dispatchEvent( new CustomEvent(eventName, {bubbles: true, composed: true, detail})); } - /** - * @return {boolean} - * @private - */ - shouldDisableDevMode_() { + private shouldDisableDevMode_(): boolean { return this.devModeControlledByPolicy || this.isSupervised; } - /** - * @return {string} - * @private - */ - getTooltipText_() { + private getTooltipText_(): string { return this.i18n( this.isSupervised ? 'controlledSettingChildRestriction' : 'controlledSettingPolicy'); } - /** - * @return {string} - * @private - */ - getIcon_() { + private getIcon_(): string { return this.isSupervised ? 'cr20:kite' : 'cr20:domain'; } - /** - * @param {!CustomEvent<boolean>} e - * @private - */ - onDevModeToggleChange_(e) { + private onDevModeToggleChange_(e: CustomEvent<boolean>) { this.delegate.setProfileInDevMode(e.detail); chrome.metricsPrivate.recordUserAction( 'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled')); } - /** - * @param {boolean} current - * @param {boolean} previous - * @private - */ - onInDevModeChanged_(current, previous) { + private onInDevModeChanged_(_current: boolean, previous: boolean) { const drawer = this.$.devDrawer; if (this.inDevMode) { if (drawer.hidden) { drawer.hidden = false; // Requesting the offsetTop will cause a reflow (to account for // hidden). - /** @suppress {suspiciousCode} */ drawer.offsetTop; + drawer.offsetTop; } } else { if (previous === undefined) { @@ -168,7 +144,7 @@ return; } - listenOnce(drawer, 'transitionend', e => { + listenOnce(drawer, 'transitionend', () => { if (!this.inDevMode) { drawer.hidden = true; } @@ -177,8 +153,7 @@ this.expanded_ = !this.expanded_; } - /** @private */ - onLoadUnpackedTap_() { + private onLoadUnpackedTap_() { this.delegate.loadUnpacked() .then((success) => { if (success) { @@ -193,27 +168,23 @@ chrome.metricsPrivate.recordUserAction('Options_LoadUnpackedExtension'); } - /** @private */ - onPackTap_() { + private onPackTap_() { chrome.metricsPrivate.recordUserAction('Options_PackExtension'); this.showPackDialog_ = true; } - /** @private */ - onPackDialogClose_() { + private onPackDialogClose_() { this.showPackDialog_ = false; this.$.packExtensions.focus(); } // <if expr="chromeos"> - /** @private */ - onKioskTap_() { + private onKioskTap_() { this.fire_('kiosk-tap'); } // </if> - /** @private */ - onUpdateNowTap_() { + private onUpdateNowTap_() { // If already updating, do not initiate another update. if (this.isUpdating_) { return;
diff --git a/chrome/browser/resources/extensions/tsconfig_base.json b/chrome/browser/resources/extensions/tsconfig_base.json index 3e71f763..afa07315 100644 --- a/chrome/browser/resources/extensions/tsconfig_base.json +++ b/chrome/browser/resources/extensions/tsconfig_base.json
@@ -1,7 +1,6 @@ { "extends": "../../../../tools/typescript/tsconfig_base.json", "compilerOptions": { - "allowJs": true, "noUncheckedIndexedAccess": false, "noUnusedLocals": false, "strictPropertyInitialization": false
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox_match.html b/chrome/browser/resources/new_tab_page/realbox/realbox_match.html index 65e2d091..4114116 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox_match.html +++ b/chrome/browser/resources/new_tab_page/realbox/realbox_match.html
@@ -30,20 +30,20 @@ white-space: pre; } - :host([has-image]) #container { + :host([is-rich-suggestion]) #container { align-items: flex-start; flex-direction: column; } - :host([has-image]) #separator { + :host([is-rich-suggestion]) #separator { display: none; } - :host([has-image]) #contents { + :host([is-rich-suggestion]) #contents { width: 100%; } - :host([has-image]) #description { + :host([is-rich-suggestion]) #description { font-size: .875em; width: 100%; } @@ -52,12 +52,12 @@ font-weight: 500; } - :host([has-image]) #description, + :host([is-rich-suggestion]) #description, .dim { color: var(--search-box-results-dim, var(--google-grey-refresh-700)); } - :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)):host([has-image]) #description, + :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)):host([is-rich-suggestion]) #description, :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)) .dim { color: var(--search-box-results-dim-selected, var(--google-grey-refresh-700)); }
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox_match.js b/chrome/browser/resources/new_tab_page/realbox/realbox_match.js index db9d02f..5ad196f 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox_match.js +++ b/chrome/browser/resources/new_tab_page/realbox/realbox_match.js
@@ -27,6 +27,8 @@ }; // clang-format on +const SEARCH_CALCULATOR_ANSWER_TYPE = 'search-calculator-answer'; + // Displays an autocomplete match similar to those in the Omnibox. class RealboxMatchElement extends PolymerElement { static get is() { @@ -64,6 +66,17 @@ }, /** + * Whether the match is a rich suggestion. Rich suggestions are displayed + * in two lines and may contain image. + * @type {boolean} + */ + isRichSuggestion: { + type: Boolean, + computed: `computeIsRichSuggestion_(match, hasImage)`, + reflectToAttribute: true, + }, + + /** * @type {!realbox.mojom.AutocompleteMatch} */ match: { @@ -302,6 +315,15 @@ * @return {boolean} * @private */ + computeIsRichSuggestion_() { + return this.hasImage || + (this.match && this.match.type === SEARCH_CALCULATOR_ANSWER_TYPE); + } + + /** + * @return {boolean} + * @private + */ computeRemoveButtonIsVisible_() { return this.match && this.match.supportsDeletion; }
diff --git a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.html b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.html index 140bcc6..67c2c61 100644 --- a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.html +++ b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.html
@@ -2,12 +2,33 @@ :host { --avatar-size: 100px; --banner-height: 244px; + --banner-size: auto; --footer-margin: 40px; + --content-container-margin-bottom: calc(48px + var(--footer-margin)); + --content-container-margin-top: 104px; + --info-box-margin-inline: auto; + --info-box-margin-top: 32px; + --info-box-width: 514px; --text-font-size: 1.16em; color: var(--cr-primary-text-color); display: block; } + :host([is-modal-dialog_]) { + --avatar-size: 76px; + --banner-height: 128px; + --banner-size: 90% 90%; + --content-container-margin-bottom: 0; + --content-container-margin-top: 96px; + --info-box-margin-inline: 32px; + --info-box-margin-top: 28px; + --info-box-width: auto; + --footer-margin: 16px; + min-height: 468px; + position: relative; + width: 512px; + } + .secondary { color: var(--cr-secondary-text-color); } @@ -30,6 +51,7 @@ background-image: url(images/enterprise_profile_welcome_illustration.svg); background-position: center; background-repeat: no-repeat; + background-size: var(--banner-size); height: 100%; position: absolute; top: 0; @@ -79,9 +101,9 @@ } #contentContainer { - margin-bottom: calc(48px + var(--footer-margin)); + margin-bottom: var(--content-container-margin-bottom); margin-inline: auto; - margin-top: 104px; + margin-top: var(--content-container-margin-top); text-align: center; } @@ -98,11 +120,11 @@ color: var(--google-grey-refresh-700); display: flex; flex-direction: row; - margin-inline: auto; - margin-top: 32px; + margin-inline: var(--info-box-margin-inline); + margin-top: var(--info-box-margin-top); padding-block: 12px; padding-inline-end: 18px; - width: 514px; + width: var(--info-box-width); } .info-box > p { @@ -128,10 +150,6 @@ width: var(--icon-size); } - #buttonsContainer { - --action-container-padding: var(--footer-margin); - } - #buttonsContainer cr-button { font-size: var(--text-font-size); min-width: 111px;
diff --git a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.js b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.js index 8d3550e2..9322f5f 100644 --- a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.js +++ b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_app.js
@@ -16,6 +16,20 @@ import {EnterpriseProfileInfo, EnterpriseProfileWelcomeBrowserProxy, EnterpriseProfileWelcomeBrowserProxyImpl} from './enterprise_profile_welcome_browser_proxy.js'; +document.addEventListener('DOMContentLoaded', () => { + const enterpriseProfileWelcomeBrowserProxyImpl = + EnterpriseProfileWelcomeBrowserProxyImpl.getInstance(); + // Prefer using |document.body.offsetHeight| instead of + // |document.body.scrollHeight| as it returns the correct height of the + // page even when the page zoom in Chrome is different than 100%. + enterpriseProfileWelcomeBrowserProxyImpl.initializedWithSize( + document.body.offsetHeight); + // The web dialog size has been initialized, so reset the body width to + // auto. This makes sure that the body only takes up the viewable width, + // e.g. when there is a scrollbar. + document.body.style.width = 'auto'; +}); + Polymer({ is: 'enterprise-profile-welcome-app', @@ -47,6 +61,15 @@ type: String, }, + /** @private */ + isModalDialog_: { + type: Boolean, + reflectToAttribute: true, + value() { + return loadTimeData.getBoolean('isModalDialog'); + } + }, + /** The label for the button to proceed with the flow */ proceedLabel_: { type: String,
diff --git a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_browser_proxy.js b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_browser_proxy.js index 4fb6b1a..dade626 100644 --- a/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_browser_proxy.js +++ b/chrome/browser/resources/signin/enterprise_profile_welcome/enterprise_profile_welcome_browser_proxy.js
@@ -30,6 +30,9 @@ */ initialized() {} + /** @param {number} height */ + initializedWithSize(height) {} + /** * Called when the user clicks the proceed button. */ @@ -49,6 +52,11 @@ } /** @override */ + initializedWithSize(height) { + chrome.send('initializedWithSize', [height]); + } + + /** @override */ proceed() { chrome.send('proceed'); }
diff --git a/chrome/browser/resources/signin/profile_picker/profile_card.html b/chrome/browser/resources/signin/profile_picker/profile_card.html index c73a824..51ac8a4 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_card.html +++ b/chrome/browser/resources/signin/profile_picker/profile_card.html
@@ -36,19 +36,14 @@ box-shadow: 0 0 2px rgba(60, 64, 67, 0.12), 0 0 6px rgba(60, 64, 67, 0.15); display: flex; height: var(--domain-icon-size); + inset-inline-end: -6px; justify-content: center; position: absolute; - right: -6px; top: calc(var(--profile-card-avatar-icon-size) - var(--domain-icon-size) - var(--domain-icon-border-size)); width: var(--domain-icon-size); } - :host-context([dir='rtl']) #iconContainer { - left: -6px; - right: initial; - } - iron-icon { --iron-icon-fill-color: var(--google-grey-refresh-700); }
diff --git a/chrome/browser/resources/signin/profile_picker/profile_switch.html b/chrome/browser/resources/signin/profile_picker/profile_switch.html index 3a159315..c7210857 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_switch.html +++ b/chrome/browser/resources/signin/profile_picker/profile_switch.html
@@ -32,6 +32,31 @@ bottom: 0; } + #iconContainer { + --iron-icon-height: 16px; + --iron-icon-width: 16px; + --domain-icon-size: 24px; + --domain-icon-border-size: 2px; + align-items: center; + background-color: white; + border: + var(--domain-icon-border-size) solid var(--profile-card-hover-color); + border-radius: 50%; + box-shadow: 0 0 2px rgba(60, 64, 67, 0.12), 0 0 6px rgba(60, 64, 67, 0.15); + display: flex; + height: var(--domain-icon-size); + inset-inline-end: -6px; + justify-content: center; + position: absolute; + top: calc(var(--profile-card-avatar-icon-size) - var(--domain-icon-size) + - var(--domain-icon-border-size)); + width: var(--domain-icon-size); + } + + iron-icon { + --iron-icon-fill-color: var(--google-grey-refresh-700); + } + #titleContainer { text-align: center; } @@ -48,12 +73,25 @@ margin-inline-start: 8px; min-width: 111px; } + + @media (prefers-color-scheme: dark) { + #iconContainer { + background-color: var(--md-background-color); + } + + iron-icon { + --iron-icon-fill-color: var(--google-grey-500); + } + } </style> <div id="outerContainer"> <div id="profileCardContainer"> <div id="avatarContainer"> <img class="profile-avatar" alt="" src="[[profileState_.avatarIcon]]"> + <div id="iconContainer" hidden="[[!profileState_.isManaged]]"> + <iron-icon icon="cr:domain"></iron-icon> + </div> </div> <div id="profileName" class="profile-card-info prominent-text"> [[profileState_.localProfileName]]
diff --git a/chrome/browser/resources/signin/profile_picker/profile_switch.js b/chrome/browser/resources/signin/profile_picker/profile_switch.js index 0d535705..7df15ee1 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_switch.js +++ b/chrome/browser/resources/signin/profile_picker/profile_switch.js
@@ -3,6 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; +import 'chrome://resources/cr_elements/icons.m.js'; import './profile_picker_shared_css.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.html b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.html index 2f5b6b6..f461249 100644 --- a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.html +++ b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.html
@@ -2,6 +2,10 @@ :host { --avatar-size: 100px; --banner-height: 244px; + --banner-size: auto; + --confirmation-description-margin-inline: auto; + --content-container-margin-bottom: calc(48px + var(--footer-margin)); + --content-container-margin-top: 104px; --footer-margin: 40px; --text-font-size: 1.16em; color: var(--cr-primary-text-color); @@ -92,6 +96,20 @@ } /* New design */ + :host([is-new-design-modal-dialog_]) { + --avatar-size: 76px; + --banner-height: 128px; + --banner-size: 90% 90%; + --content-container-margin-bottom: 0; + --content-container-margin-top: 96px; + --confirmation-description-margin-inline: 32px; + --footer-margin: 16px; + --text-font-size: unset; + min-height: 468px; + position: relative; + width: 512px; + } + #headerContainer { background-color: var(--theme-frame-color); height: var(--banner-height); @@ -103,6 +121,7 @@ background-image: url(images/sync_confirmation_refreshed_illustration.svg); background-position: center; background-repeat: no-repeat; + background-size: var(--banner-size); height: 100%; position: absolute; top: 0; @@ -140,6 +159,11 @@ width: var(--badge-width); } + :host([is-new-design-modal-dialog_]) .work-badge { + --badge-width: 26px; + --badge-offset: -8px; + } + .work-badge > iron-icon { --work-icon-size: 20px; background-color: var(--md-background-color); @@ -152,8 +176,8 @@ } #contentContainer { - margin-bottom: calc(48px + var(--footer-margin)); - margin-top: 104px; + margin-bottom: var(--content-container-margin-bottom); + margin-top: var(--content-container-margin-top); text-align: center; } @@ -164,7 +188,7 @@ #confirmationDescription { font-size: var(--text-font-size); - margin-inline: auto; + margin-inline: var(--confirmation-description-margin-inline); margin-top: 16px; max-width: 516px; } @@ -212,7 +236,7 @@ which user clicks to indicate consent. --> -<template is="dom-if" if="[[!isProfileCreationFlow_]]"> +<template is="dom-if" if="[[!isNewDesign_]]"> <div id="illustration-container"> <div id="grey-banner"></div> <div id="illustration"></div> @@ -255,7 +279,7 @@ </div> </template> -<template is="dom-if" if="[[isProfileCreationFlow_]]"> +<template is="dom-if" if="[[isNewDesign_]]"> <div id="headerContainer" style$="--theme-frame-color:[[highlightColor_]]"> <div id="syncPromoBanner"></div> <div id="avatarContainer">
diff --git a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.js b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.js index 13d403a..85e8683 100644 --- a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.js +++ b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation_app.js
@@ -36,10 +36,20 @@ }, /** @private */ - isProfileCreationFlow_: { + isNewDesignModalDialog_: { + type: Boolean, + reflectToAttribute: true, + value() { + return loadTimeData.getBoolean('isModalDialog') && + loadTimeData.getBoolean('isNewDesign'); + } + }, + + /** @private */ + isNewDesign_: { type: Boolean, value() { - return loadTimeData.getBoolean('isProfileCreationFlow'); + return loadTimeData.getBoolean('isNewDesign'); } },
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index f62c4c8..d62f140 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -155,10 +155,12 @@ "//components/safe_browsing/content/browser:client_side_detection", "//components/safe_browsing/content/browser:client_side_model_loader", "//components/safe_browsing/content/password_protection", + "//components/safe_browsing/content/triggers", "//components/safe_browsing/content/triggers:ad_popup_trigger", "//components/safe_browsing/content/triggers:ad_redirect_trigger", "//components/safe_browsing/content/triggers:ad_sampler_trigger", "//components/safe_browsing/content/triggers:suspicious_site_trigger", + "//components/safe_browsing/content/triggers:trigger_throttler", "//components/safe_browsing/core:csd_proto", "//components/safe_browsing/core:file_type_policies", "//components/safe_browsing/core:public", @@ -173,8 +175,6 @@ "//components/safe_browsing/core/db:metadata_proto", "//components/safe_browsing/core/realtime:policy_engine", "//components/safe_browsing/core/realtime:url_lookup_service", - "//components/safe_browsing/core/triggers", - "//components/safe_browsing/core/triggers:trigger_throttler", "//components/signin/public/identity_manager", "//components/site_engagement/core/mojom:mojo_bindings", "//components/sync_user_events",
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h index f645691..b0b9e7e 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h +++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h
@@ -10,7 +10,7 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_scanner_results_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/sw_reporter_invocation_win.h" #include "components/prefs/pref_registry_simple.h"
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc index 9cf039c1..ee0a315f 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -52,6 +52,7 @@ #include "components/prefs/scoped_user_pref_update.h" #include "components/safe_browsing/content/password_protection/password_protection_navigation_throttle.h" #include "components/safe_browsing/content/password_protection/password_protection_request_content.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "components/safe_browsing/content/web_ui/safe_browsing_ui.h" #include "components/safe_browsing/core/browser/sync/safe_browsing_primary_account_token_fetcher.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" @@ -60,7 +61,6 @@ #include "components/safe_browsing/core/db/database_manager.h" #include "components/safe_browsing/core/features.h" #include "components/safe_browsing/core/proto/csd.pb.h" -#include "components/safe_browsing/core/triggers/trigger_throttler.h" #include "components/safe_browsing/core/verdict_cache_manager.h" #include "components/security_interstitials/content/unsafe_resource_util.h" #include "components/security_interstitials/core/unsafe_resource.h" @@ -377,13 +377,6 @@ base::FeatureList::IsEnabled(safe_browsing::kDelayedWarnings)); experiment.set_delayed_warnings_mouse_clicks_enabled( safe_browsing::kDelayedWarningsEnableMouseClicks.Get()); - // Actual URL display experiments: - experiment.set_reveal_on_hover(base::FeatureList::IsEnabled( - omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover)); - experiment.set_hide_on_interaction(base::FeatureList::IsEnabled( - omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction)); - experiment.set_elide_to_registrable_domain( - base::FeatureList::IsEnabled(omnibox::kMaybeElideToRegistrableDomain)); return experiment; }
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.h b/chrome/browser/safe_browsing/chrome_password_protection_service.h index 678746f..9758faa 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service.h +++ b/chrome/browser/safe_browsing/chrome_password_protection_service.h
@@ -23,7 +23,7 @@ #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/safe_browsing/buildflags.h" #include "components/safe_browsing/content/password_protection/password_protection_service.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" #include "components/sessions/core/session_id.h" #include "components/sync/protocol/gaia_password_reuse.pb.h" #include "components/sync/protocol/user_event_specifics.pb.h"
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc index dfd5bf5..441f6cd 100644 --- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc +++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -18,6 +18,7 @@ #include "base/synchronization/waitable_event.h" #include "base/test/gmock_move_support.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_command_line.h" #include "base/test/simple_test_tick_clock.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/safe_browsing/ui_manager.h" @@ -1224,4 +1225,58 @@ EXPECT_TRUE(request.has_screenshot_digest()); } +class ClientSideDetectionHostDebugFeaturesTest + : public ClientSideDetectionHostTest { + public: + ClientSideDetectionHostDebugFeaturesTest() = default; + + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + command_line_.GetProcessCommandLine()->AppendSwitchPath( + "--csd-debug-feature-directory", temp_dir_.GetPath()); + + ClientSideDetectionHostTest::SetUp(); + } + + private: + base::ScopedTempDir temp_dir_; + base::test::ScopedCommandLine command_line_; +}; + +TEST_F(ClientSideDetectionHostDebugFeaturesTest, + SkipsAllowlistWhenDumpingFeatures) { + EXPECT_CALL(*csd_service_, GetModelStr()).WillRepeatedly(Return("model_str")); + GURL url("http://host.com/"); + ExpectPreClassificationChecks(url, &kFalse, nullptr, nullptr, nullptr, + nullptr); + EXPECT_CALL(*database_manager_.get(), CheckCsdAllowlistUrl(url, _)).Times(0); + NavigateAndKeepLoading(web_contents(), url); + WaitAndCheckPreClassificationChecks(); + fake_phishing_detector_.CheckMessage(&url); +} + +TEST_F(ClientSideDetectionHostDebugFeaturesTest, + SkipsCacheWhenDumpingFeatures) { + EXPECT_CALL(*csd_service_, GetModelStr()).WillRepeatedly(Return("model_str")); + GURL url("http://host.com/"); + ExpectPreClassificationChecks(url, &kFalse, nullptr, nullptr, nullptr, + nullptr); + EXPECT_CALL(*csd_service_, GetValidCachedResult(url, NotNull())).Times(0); + NavigateAndKeepLoading(web_contents(), url); + WaitAndCheckPreClassificationChecks(); + fake_phishing_detector_.CheckMessage(&url); +} + +TEST_F(ClientSideDetectionHostDebugFeaturesTest, + SkipsReportLimitWhenDumpingFeatures) { + EXPECT_CALL(*csd_service_, GetModelStr()).WillRepeatedly(Return("model_str")); + GURL url("http://host.com/"); + ExpectPreClassificationChecks(url, &kFalse, nullptr, nullptr, nullptr, + nullptr); + EXPECT_CALL(*csd_service_, OverPhishingReportLimit()).Times(0); + NavigateAndKeepLoading(web_contents(), url); + WaitAndCheckPreClassificationChecks(); + fake_phishing_detector_.CheckMessage(&url); +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc index c8d8970b..a8ea979 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -24,10 +24,10 @@ #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/content/browser/threat_details.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/safe_browsing/core/common/utils.h" #include "components/safe_browsing/core/features.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" #include "components/security_interstitials/content/content_metrics_helper.h" #include "components/security_interstitials/content/security_interstitial_controller_client.h" #include "components/security_interstitials/content/settings_page_helper.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc index 593fd3d..9c5e3e6 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -41,6 +41,7 @@ #include "components/prefs/pref_service.h" #include "components/safe_browsing/buildflags.h" #include "components/safe_browsing/content/browser/client_side_phishing_model.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" #include "components/safe_browsing/content/web_ui/safe_browsing_ui.h" #include "components/safe_browsing/core/browser/safe_browsing_network_context.h" #include "components/safe_browsing/core/common/safebrowsing_constants.h" @@ -49,7 +50,6 @@ #include "components/safe_browsing/core/file_type_policies.h" #include "components/safe_browsing/core/ping_manager.h" #include "components/safe_browsing/core/realtime/policy_engine.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h index 96847ec..4b0bc4a0 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.h +++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -17,7 +17,6 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/observer_list.h" #include "base/scoped_multi_source_observation.h" #include "base/sequenced_task_runner_helpers.h" #include "chrome/browser/net/proxy_config_monitor.h"
diff --git a/chrome/browser/safe_browsing/trigger_creator.cc b/chrome/browser/safe_browsing/trigger_creator.cc index 5e54789..45886f5 100644 --- a/chrome/browser/safe_browsing/trigger_creator.cc +++ b/chrome/browser/safe_browsing/trigger_creator.cc
@@ -13,9 +13,9 @@ #include "components/safe_browsing/content/triggers/ad_redirect_trigger.h" #include "components/safe_browsing/content/triggers/ad_sampler_trigger.h" #include "components/safe_browsing/content/triggers/suspicious_site_trigger.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "components/safe_browsing/core/features.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" -#include "components/safe_browsing/core/triggers/trigger_throttler.h" #include "components/security_interstitials/core/base_safe_browsing_error_ui.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc b/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc index fd9dfe6..d0b58ec6 100644 --- a/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc +++ b/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc
@@ -15,6 +15,7 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/search/one_google_bar/one_google_bar_data.h" #include "components/signin/core/browser/signin_header_helper.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/test/browser_task_environment.h" #include "net/http/http_request_headers.h" #include "net/http/http_status_code.h" @@ -114,6 +115,9 @@ // variations::AppendVariationHeaders requires browser threads. content::BrowserTaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; + // Supports JSON decoding in the loader implementation. data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
diff --git a/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc b/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc index f8e2822..28976ee 100644 --- a/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc +++ b/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc
@@ -12,6 +12,7 @@ #include "base/test/test_simple_task_runner.h" #include "base/time/time.h" #include "chrome/browser/search/search_suggest/search_suggest_data.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/test/browser_task_environment.h" #include "net/http/http_request_headers.h" #include "net/http/http_status_code.h" @@ -99,6 +100,9 @@ // variations::AppendVariationHeaders requires browser threads. content::BrowserTaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; + // Supports JSON parsing in the loader impl. data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
diff --git a/chrome/browser/search/task_module/task_module_service_unittest.cc b/chrome/browser/search/task_module/task_module_service_unittest.cc index 2a0a36c..fae58d4 100644 --- a/chrome/browser/search/task_module/task_module_service_unittest.cc +++ b/chrome/browser/search/task_module/task_module_service_unittest.cc
@@ -11,6 +11,7 @@ #include "base/test/mock_callback.h" #include "chrome/browser/search/task_module/task_module_service.h" #include "chrome/test/base/testing_profile.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/test/browser_task_environment.h" #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -41,6 +42,8 @@ protected: // Required to run tests from UI thread. content::BrowserTaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; TestingProfile profile_; network::TestURLLoaderFactory test_url_loader_factory_; data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc index cd764fd..49f795f 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -18,6 +18,7 @@ #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" +#include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h" @@ -41,9 +42,16 @@ #include "chrome/common/themes/autogenerated_theme_util.h" #include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/common/password_manager_ui.h" +#include "components/policy/core/browser/browser_policy_connector.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_namespace.h" +#include "components/policy/core/common/policy_service.h" +#include "components/policy/policy_constants.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" +#include "components/signin/public/base/signin_pref_names.h" +#include "components/signin/public/identity_manager/accounts_mutator.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "google_apis/gaia/gaia_auth_util.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -173,6 +181,16 @@ // interception is missed. return SigninInterceptionHeuristicOutcome::kAbortSyncSignin; } + + // If the email is an not an customer email and enterprise profile separation + // is mandatory, return `absl::nullopt` so that more information on the + // account is fetched. + if (!policy::BrowserPolicyConnector::IsNonEnterpriseUser(email) && + profile_->GetPrefs()->HasPrefPath( + prefs::kManagedAccountsSigninRestriction)) { + return absl::nullopt; + } + if (!is_new_account) { // Do not intercept reauth. return SigninInterceptionHeuristicOutcome::kAbortAccountNotNew; @@ -268,6 +286,7 @@ &entry); account_id_ = account_id; is_interception_in_progress_ = true; + new_account_interception_ = is_new_account; Observe(web_contents); if (heuristic_outcome) { @@ -312,9 +331,13 @@ CoreAccountId account_id, content::WebContents* intercepted_contents, std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> bubble_handle, + bool managed_account_interception, bool is_new_profile) { DCHECK(!session_startup_helper_); - DCHECK(bubble_handle); + DCHECK(bubble_handle || managed_account_interception); + DCHECK_EQ(managed_account_interception, !bubble_handle) + << "There should be no handle for managed accout interception"; + managed_account_interception_ = managed_account_interception; interception_bubble_handle_ = std::move(bubble_handle); session_startup_helper_ = std::make_unique<DiceInterceptedSessionStartupHelper>( @@ -338,6 +361,9 @@ on_account_info_update_timeout_.Cancel(); is_interception_in_progress_ = false; account_id_ = CoreAccountId(); + new_account_interception_ = false; + managed_account_interception_ = false; + intercepted_account_management_accepted_ = false; dice_signed_in_profile_creator_.reset(); was_interception_ui_displayed_ = false; account_info_fetch_start_time_ = base::TimeTicks(); @@ -363,6 +389,34 @@ return nullptr; } +bool DiceWebSigninInterceptor::ShouldEnforceEnterpriseProfileSeparation( + const AccountInfo& intercepted_account_info) const { + DCHECK(intercepted_account_info.IsValid()); + + CoreAccountInfo primary_core_account_info = + identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin); + // In case of re-auth, do not show the enterprise separation dialog if the + // user already consented to enterprise management. + if (!new_account_interception_ && primary_core_account_info.account_id == + intercepted_account_info.account_id) { + return base::FeatureList::IsEnabled(kAccountPoliciesLoadedWithoutSync) && + !profile_->GetPrefs()->GetBoolean( + prefs::kUserAcceptedAccountManagement); + } + + std::string account_restriction = + profile_->GetPrefs()->GetString(prefs::kManagedAccountsSigninRestriction); + if ((!account_restriction.empty() && + profile_->GetPrefs()->GetBoolean( + prefs::kManagedAccountsSigninRestrictionScopeMachine)) || + account_restriction == "primary_account_strict") { + return intercepted_account_info.IsManaged(); + } + + // TODO(crbug/1163117) Look for the policy value for the intercepted account. + return false; +} + bool DiceWebSigninInterceptor::ShouldShowEnterpriseBubble( const AccountInfo& intercepted_account_info) const { DCHECK(intercepted_account_info.IsValid()); @@ -418,6 +472,47 @@ absl::optional<SigninInterceptionType> interception_type; + ProfileAttributesEntry* entry = + g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetProfileAttributesWithPath(profile_->GetPath()); + SkColor profile_color = GenerateNewProfileColor(entry).color; + + if (ShouldEnforceEnterpriseProfileSeparation(info)) { + // TODO (crbug/1163117): Create a new SigninInterceptionType and use + // interception_bubble_handle_. + DCHECK(base::FeatureList::IsEnabled(kAccountPoliciesLoadedWithoutSync) || + !profile_->GetPrefs() + ->GetString(prefs::kManagedAccountsSigninRestriction) + .empty()); + managed_account_interception_ = true; + // Immediately switch to an already existing profile. + const ProfileAttributesEntry* switch_to_entry = + ShouldShowProfileSwitchBubble(info.email, + &g_browser_process->profile_manager() + ->GetProfileAttributesStorage()); + if (switch_to_entry) { + // TODO (crbug/1163117): There should be a UI notifying the user of the + // profile switch. + RecordSigninInterceptionHeuristicOutcome( + SigninInterceptionHeuristicOutcome:: + kInterceptEnterpriseForcedProfileSwitch); + OnProfileSwitchChoice(info.email, switch_to_entry->GetPath(), + SigninInterceptionResult::kAccepted); + } else { + RecordSigninInterceptionHeuristicOutcome( + SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); + Browser* browser = chrome::FindBrowserWithProfile(profile_); + DCHECK(browser); + delegate_->ShowEnterpriseProfileInterceptionDialog( + info.email, + base::BindOnce( + &DiceWebSigninInterceptor::OnEnterpriseProfileCreationResult, + base::Unretained(this), info, profile_color), + browser); + } + return; + } if (ShouldShowEnterpriseBubble(info)) interception_type = SigninInterceptionType::kEnterprise; else if (ShouldShowMultiUserBubble(info)) @@ -431,11 +526,6 @@ return; } - ProfileAttributesEntry* entry = - g_browser_process->profile_manager() - ->GetProfileAttributesStorage() - .GetProfileAttributesWithPath(profile_->GetPath()); - SkColor profile_color = GenerateNewProfileColor(entry).color; auto guest_option_availability = GetGuestOptionAvailablity(); Delegate::BubbleParameters bubble_parameters{ *interception_type, info, GetPrimaryAccountInfo(identity_manager_), @@ -472,7 +562,7 @@ return; } - DCHECK(interception_bubble_handle_); + DCHECK(interception_bubble_handle_ || managed_account_interception_); profile_creation_start_time_ = base::TimeTicks::Now(); std::u16string profile_name; profile_name = profiles::GetDefaultNameForNewSignedInProfile(account_info); @@ -499,7 +589,7 @@ return; } - DCHECK(interception_bubble_handle_); + DCHECK(interception_bubble_handle_ || managed_account_interception_); DCHECK(!dice_signed_in_profile_creator_); profile_creation_start_time_ = base::TimeTicks::Now(); // Unretained is fine because the profile creator is owned by this. @@ -543,17 +633,49 @@ base::TimeTicks::Now() - profile_creation_start_time_); } + new_profile->GetPrefs()->SetBoolean(prefs::kUserAcceptedAccountManagement, + intercepted_account_management_accepted_); + // Work is done in this profile, the flow continues in the // DiceWebSigninInterceptor that is attached to the new profile. DiceWebSigninInterceptorFactory::GetForProfile(new_profile) ->CreateBrowserAfterSigninInterception( account_id_, web_contents(), std::move(interception_bubble_handle_), - is_new_profile); + managed_account_interception_, is_new_profile); Reset(); } +void DiceWebSigninInterceptor::OnEnterpriseProfileCreationResult( + const AccountInfo& account_info, + SkColor profile_color, + bool create) { + intercepted_account_management_accepted_ = create; + if (create) { + // In case of a reauth if there was no consent for management, do not create + // a new profile. + if (!new_account_interception_ && + GetPrimaryAccountInfo(identity_manager_).account_id == + account_info.account_id) { + profile_->GetPrefs()->SetBoolean( + prefs::kUserAcceptedAccountManagement, + intercepted_account_management_accepted_); + } else { + OnProfileCreationChoice(account_info, profile_color, + SigninInterceptionResult::kAccepted); + } + } else { + OnProfileCreationChoice(account_info, profile_color, + SigninInterceptionResult::kDeclined); + auto* accounts_mutator = identity_manager_->GetAccountsMutator(); + accounts_mutator->RemoveAccount( + account_info.account_id, + signin_metrics::SourceForRefreshTokenOperation:: + kDiceTurnOnSyncHelper_Abort); + } +} + void DiceWebSigninInterceptor::OnNewBrowserCreated(bool is_new_profile) { - DCHECK(interception_bubble_handle_); + DCHECK(interception_bubble_handle_ || managed_account_interception_); interception_bubble_handle_.reset(); // Close the bubble now. session_startup_helper_.reset();
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.h b/chrome/browser/signin/dice_web_signin_interceptor.h index 22978f7..4749f80 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.h +++ b/chrome/browser/signin/dice_web_signin_interceptor.h
@@ -13,6 +13,7 @@ #include "base/gtest_prod_util.h" #include "base/scoped_observation.h" #include "base/time/time.h" +#include "chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h" #include "components/keyed_service/core/keyed_service.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "content/public/browser/web_contents_observer.h" @@ -81,7 +82,11 @@ // Signin interception is disabled by the SigninInterceptionEnabled policy. kAbortInterceptionDisabled = 15, - kMaxValue = kAbortInterceptionDisabled, + // Interception succeeded when enteprise account separation is mandatory. + kInterceptEnterpriseForced = 16, + kInterceptEnterpriseForcedProfileSwitch = 17, + + kMaxValue = kInterceptEnterpriseForcedProfileSwitch, }; // User selection in the interception bubble. @@ -172,6 +177,14 @@ const BubbleParameters& bubble_parameters, base::OnceCallback<void(SigninInterceptionResult)> callback) = 0; + // Shows the enterprise profile confirmation dialog to notify the user that + // a managed profile will be created or that their account needs a new + // profile to be created. + virtual void ShowEnterpriseProfileInterceptionDialog( + const std::string& email, + base::OnceCallback<void(bool)> callback, + Browser* browser) = 0; + // Shows the profile customization bubble. virtual void ShowProfileCustomizationBubble(Browser* browser) = 0; }; @@ -211,6 +224,7 @@ content::WebContents* intercepted_contents, std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> bubble_handle, + bool managed_account_interception, bool is_new_profile); // Returns the outcome of the interception heuristic. @@ -244,7 +258,17 @@ ShouldShowEnterpriseBubbleWithoutUPA); FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, ShouldShowMultiUserBubble); + FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, + ShouldEnforceEnterpriseProfileSeparation); + FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, + ShouldEnforceEnterpriseProfileSeparationWithoutUPA); + FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, + ShouldEnforceEnterpriseProfileSeparationReauth); FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, PersistentHash); + FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, + EnforceManagedAccountAsPrimary); + FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorReauthTest, + ShouldEnforceEnterpriseProfileSeparationReauth); // Cancels any current signin interception and resets the interceptor to its // initial state. @@ -254,6 +278,8 @@ const ProfileAttributesEntry* ShouldShowProfileSwitchBubble( const std::string& intercepted_email, ProfileAttributesStorage* profile_attribute_storage) const; + bool ShouldEnforceEnterpriseProfileSeparation( + const AccountInfo& intercepted_account_info) const; bool ShouldShowEnterpriseBubble( const AccountInfo& intercepted_account_info) const; bool ShouldShowMultiUserBubble( @@ -281,6 +307,13 @@ void OnNewSignedInProfileCreated(absl::optional<SkColor> profile_color, Profile* new_profile); + // Called after the user choses whether the session should continue in a new + // work profile or not. If the user choses not to continue in a work profile, + // the account is signed out. + void OnEnterpriseProfileCreationResult(const AccountInfo& account_info, + SkColor profile_color, + bool create); + // Called when the new browser is created after interception. Passed as // callback to `session_startup_helper_`. void OnNewBrowserCreated(bool is_new_profile); @@ -315,6 +348,9 @@ // Members below are related to the interception in progress. bool is_interception_in_progress_ = false; CoreAccountId account_id_; + bool new_account_interception_ = false; + bool managed_account_interception_ = false; + bool intercepted_account_management_accepted_ = false; base::ScopedObservation<signin::IdentityManager, signin::IdentityManager::Observer> account_info_update_observation_{this};
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc index feefd78a..df5525fe 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
@@ -32,11 +32,13 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/common/chrome_features.h" +#include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/profile_waiter.h" #include "chrome/test/base/ui_test_utils.h" #include "components/account_id/account_id.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/prefs/pref_service.h" #include "components/signin/public/identity_manager/accounts_mutator.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_test_environment.h" @@ -98,6 +100,13 @@ return bubble_handle; } + void ShowEnterpriseProfileInterceptionDialog( + const std::string& email, + base::OnceCallback<void(bool)> callback, + Browser* browser) override { + std::move(callback).Run(expected_enteprise_confirmation_result_); + } + void ShowProfileCustomizationBubble(Browser* browser) override { EXPECT_FALSE(customized_browser_) << "Customization must be shown only once."; @@ -115,6 +124,10 @@ expected_interception_result_ = result; } + void set_expected_enteprise_confirmation_result(bool result) { + expected_enteprise_confirmation_result_ = result; + } + bool intercept_bubble_shown() const { return weak_bubble_handle_.get(); } bool intercept_bubble_destroyed() const { @@ -127,6 +140,7 @@ DiceWebSigninInterceptor::SigninInterceptionType::kMultiUser; SigninInterceptionResult expected_interception_result_ = SigninInterceptionResult::kAccepted; + bool expected_enteprise_confirmation_result_ = false; base::WeakPtr<FakeBubbleHandle> weak_bubble_handle_; }; @@ -172,15 +186,22 @@ SigninInterceptionHeuristicOutcome outcome, bool intercept_to_guest = false) { int profile_switch_count = - outcome == SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch + outcome == SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch || + outcome == SigninInterceptionHeuristicOutcome:: + kInterceptEnterpriseForcedProfileSwitch ? 1 : 0; int profile_creation_count = 1 - profile_switch_count; + int fetched_account_count = + outcome == SigninInterceptionHeuristicOutcome:: + kInterceptEnterpriseForcedProfileSwitch + ? 1 + : profile_creation_count; histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", outcome, 1); histogram_tester.ExpectTotalCount("Signin.Intercept.AccountInfoFetchDuration", - profile_creation_count); + fetched_account_count); histogram_tester.ExpectTotalCount("Signin.Intercept.ProfileCreationDuration", profile_creation_count); histogram_tester.ExpectTotalCount("Signin.Intercept.ProfileSwitchDuration", @@ -240,6 +261,9 @@ return interceptor_delegate; } + protected: + base::test::ScopedFeatureList feature_list_; + private: // InProcessBrowserTest: void SetUpOnMainThread() override { @@ -287,7 +311,6 @@ Profile::FromBrowserContext(context), std::move(fake_delegate)); } - base::test::ScopedFeatureList feature_list_; network::TestURLLoaderFactory test_url_loader_factory_; std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> identity_test_env_profile_adaptor_; @@ -385,6 +408,100 @@ EXPECT_EQ(source_interceptor_delegate->customized_browser(), nullptr); } +// Tests the complete interception flow including profile and browser creation. +IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, + ForcedEnterpriseInterceptionTest) { + base::HistogramTester histogram_tester; + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable("alice@example.com"); + // Fill the account info, in particular for the hosted_domain field. + account_info.full_name = "fullname"; + account_info.given_name = "givenname"; + account_info.hosted_domain = "example.com"; + account_info.locale = "en"; + account_info.picture_url = "https://example.com"; + account_info.is_child_account = false; + DCHECK(account_info.IsValid()); + identity_test_env()->UpdateAccountInfoForAccount(account_info); + + // Enforce enterprise profile sepatation. + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account_strict"); + + // Instantly return from Gaia calls, to avoid timing out when injecting the + // account in the new profile. + network::TestURLLoaderFactory* loader_factory = test_url_loader_factory(); + loader_factory->SetInterceptor(base::BindLambdaForTesting( + [loader_factory](const network::ResourceRequest& request) { + std::string path = request.url.path(); + if (path == "/ListAccounts" || path == "/GetCheckConnectionInfo") { + loader_factory->AddResponse(request.url.spec(), std::string()); + return; + } + if (path == "/oauth/multilogin") { + loader_factory->AddResponse(request.url.spec(), + kMultiloginSuccessResponse); + return; + } + })); + + // Add a tab. + GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse"); + content::WebContents* web_contents = AddTab(intercepted_url); + int original_tab_count = browser()->tab_strip_model()->count(); + + // Do the signin interception. + EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); + FakeDiceWebSigninInterceptorDelegate* source_interceptor_delegate = + GetInterceptorDelegate(profile()); + source_interceptor_delegate->set_expected_enteprise_confirmation_result(true); + Profile* new_profile = + InterceptAndWaitProfileCreation(web_contents, account_info.account_id); + EXPECT_TRUE(new_profile->GetPrefs()->GetBoolean( + prefs::kUserAcceptedAccountManagement)); + ASSERT_TRUE(new_profile); + EXPECT_FALSE(source_interceptor_delegate->intercept_bubble_shown()); + signin::IdentityManager* new_identity_manager = + IdentityManagerFactory::GetForProfile(new_profile); + EXPECT_TRUE(new_identity_manager->HasAccountWithRefreshToken( + account_info.account_id)); + + IdentityTestEnvironmentProfileAdaptor adaptor(new_profile); + adaptor.identity_test_env()->SetAutomaticIssueOfAccessTokens(true); + + // Check the profile name. + ProfileAttributesStorage& storage = + g_browser_process->profile_manager()->GetProfileAttributesStorage(); + ProfileAttributesEntry* entry = + storage.GetProfileAttributesWithPath(new_profile->GetPath()); + ASSERT_TRUE(entry); + EXPECT_EQ("example.com", base::UTF16ToUTF8(entry->GetLocalProfileName())); + // Check the profile color. + EXPECT_TRUE(ThemeServiceFactory::GetForProfile(new_profile) + ->UsingAutogeneratedTheme()); + + // A browser has been created for the new profile and the tab was moved there. + Browser* added_browser = ui_test_utils::WaitForBrowserToOpen(); + ASSERT_TRUE(added_browser); + ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); + EXPECT_EQ(added_browser->profile(), new_profile); + EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1); + EXPECT_EQ(added_browser->tab_strip_model()->GetActiveWebContents()->GetURL(), + intercepted_url); + + CheckHistograms( + histogram_tester, + SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); + // Interception bubble is destroyed in the source profile, and was not shown + // in the new profile. + FakeDiceWebSigninInterceptorDelegate* new_interceptor_delegate = + GetInterceptorDelegate(new_profile); + + // Profile customization UI was shown exactly once in the new profile. + EXPECT_EQ(new_interceptor_delegate->customized_browser(), added_browser); + EXPECT_EQ(source_interceptor_delegate->customized_browser(), nullptr); +} + // Tests the complete profile switch flow when the profile is not loaded. IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, SwitchAndLoad) { base::HistogramTester histogram_tester; @@ -656,3 +773,180 @@ SigninInterceptionHeuristicOutcome::kInterceptMultiUser, /*intercept_to_guest =*/true); } + +class DiceWebSigninInterceptorEnterpriseSwitchBrowserTest + : public DiceWebSigninInterceptorBrowserTest { + public: + DiceWebSigninInterceptorEnterpriseSwitchBrowserTest() { + enterprise_feature_list_.InitAndEnableFeature( + kAccountPoliciesLoadedWithoutSync); + } + + private: + base::test::ScopedFeatureList enterprise_feature_list_; +}; + +// Tests the complete profile switch flow when the profile is not loaded. +IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorEnterpriseSwitchBrowserTest, + EnterpriseSwitchAndLoad) { + base::HistogramTester histogram_tester; + // Enforce enterprise profile sepatation. + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account_strict"); + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable("alice@example.com"); + // Fill the account info, in particular for the hosted_domain field. + account_info.full_name = "fullname"; + account_info.given_name = "givenname"; + account_info.hosted_domain = "example.com"; + account_info.locale = "en"; + account_info.picture_url = "https://example.com"; + account_info.is_child_account = false; + DCHECK(account_info.IsValid()); + identity_test_env()->UpdateAccountInfoForAccount(account_info); + + // Add a profile in the cache (simulate the profile on disk). + ProfileManager* profile_manager = g_browser_process->profile_manager(); + ProfileAttributesStorage* profile_storage = + &profile_manager->GetProfileAttributesStorage(); + const base::FilePath profile_path = + profile_manager->GenerateNextProfileDirectoryPath(); + ProfileAttributesInitParams params; + params.profile_path = profile_path; + params.profile_name = u"TestProfileName"; + params.gaia_id = account_info.gaia; + params.user_name = base::UTF8ToUTF16(account_info.email); + profile_storage->AddProfile(std::move(params)); + ProfileAttributesEntry* entry = + profile_storage->GetProfileAttributesWithPath(profile_path); + ASSERT_TRUE(entry); + ASSERT_EQ(entry->GetGAIAId(), account_info.gaia); + + // Add a tab. + GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse"); + content::WebContents* web_contents = AddTab(intercepted_url); + int original_tab_count = browser()->tab_strip_model()->count(); + + // Do the signin interception. + FakeDiceWebSigninInterceptorDelegate* source_interceptor_delegate = + GetInterceptorDelegate(profile()); + source_interceptor_delegate->set_expected_interception_type( + DiceWebSigninInterceptor::SigninInterceptionType::kProfileSwitch); + Profile* new_profile = + InterceptAndWaitProfileCreation(web_contents, account_info.account_id); + ASSERT_TRUE(new_profile); + EXPECT_FALSE(source_interceptor_delegate->intercept_bubble_shown()); + signin::IdentityManager* new_identity_manager = + IdentityManagerFactory::GetForProfile(new_profile); + EXPECT_TRUE(new_identity_manager->HasAccountWithRefreshToken( + account_info.account_id)); + + // Check that the right profile was opened. + EXPECT_EQ(new_profile->GetPath(), profile_path); + + // Add the account to the cookies (simulates the account reconcilor). + EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); + signin::SetCookieAccounts(new_identity_manager, test_url_loader_factory(), + {{account_info.email, account_info.gaia}}); + + // A browser has been created for the new profile and the tab was moved there. + ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); + Browser* added_browser = BrowserList::GetInstance()->get(1); + ASSERT_TRUE(added_browser); + EXPECT_EQ(added_browser->profile(), new_profile); + EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1); + EXPECT_EQ(added_browser->tab_strip_model()->GetActiveWebContents()->GetURL(), + intercepted_url); + + CheckHistograms(histogram_tester, + SigninInterceptionHeuristicOutcome:: + kInterceptEnterpriseForcedProfileSwitch); + + // Profile customization was not shown. + EXPECT_EQ(GetInterceptorDelegate(new_profile)->customized_browser(), nullptr); + EXPECT_EQ(source_interceptor_delegate->customized_browser(), nullptr); +} + +// Tests the complete profile switch flow when the profile is already loaded. +IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorEnterpriseSwitchBrowserTest, + EnterpriseSwitchAlreadyOpen) { + base::HistogramTester histogram_tester; + // Enforce enterprise profile sepatation. + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account_strict"); + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable("alice@example.com"); + // Fill the account info, in particular for the hosted_domain field. + account_info.full_name = "fullname"; + account_info.given_name = "givenname"; + account_info.hosted_domain = "example.com"; + account_info.locale = "en"; + account_info.picture_url = "https://example.com"; + account_info.is_child_account = false; + DCHECK(account_info.IsValid()); + identity_test_env()->UpdateAccountInfoForAccount(account_info); + // Create another profile with a browser window. + ProfileManager* profile_manager = g_browser_process->profile_manager(); + const base::FilePath profile_path = + profile_manager->GenerateNextProfileDirectoryPath(); + base::RunLoop loop; + Profile* other_profile = nullptr; + ProfileManager::CreateCallback callback = base::BindLambdaForTesting( + [&other_profile, &loop](Profile* profile, Profile::CreateStatus status) { + DCHECK_EQ(status, Profile::CREATE_STATUS_INITIALIZED); + other_profile = profile; + loop.Quit(); + }); + profiles::SwitchToProfile(profile_path, /*always_create=*/true, + std::move(callback)); + loop.Run(); + ASSERT_TRUE(other_profile); + ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); + Browser* other_browser = BrowserList::GetInstance()->get(1); + ASSERT_TRUE(other_browser); + ASSERT_EQ(other_browser->profile(), other_profile); + // Add the account to the other profile. + signin::IdentityManager* other_identity_manager = + IdentityManagerFactory::GetForProfile(other_profile); + other_identity_manager->GetAccountsMutator()->AddOrUpdateAccount( + account_info.gaia, account_info.email, "dummy_refresh_token", + /*is_under_advanced_protection=*/false, + signin_metrics::SourceForRefreshTokenOperation::kUnknown); + other_identity_manager->GetPrimaryAccountMutator()->SetPrimaryAccount( + account_info.account_id, signin::ConsentLevel::kSync); + + // Add a tab. + GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse"); + content::WebContents* web_contents = AddTab(intercepted_url); + int original_tab_count = browser()->tab_strip_model()->count(); + int other_original_tab_count = other_browser->tab_strip_model()->count(); + + // Start the interception. + GetInterceptorDelegate(profile())->set_expected_interception_type( + DiceWebSigninInterceptor::SigninInterceptionType::kProfileSwitch); + DiceWebSigninInterceptor* interceptor = + DiceWebSigninInterceptorFactory::GetForProfile(profile()); + interceptor->MaybeInterceptWebSignin(web_contents, account_info.account_id, + /*is_new_account=*/true, + /*is_sync_signin=*/false); + + // Add the account to the cookies (simulates the account reconcilor). + signin::SetCookieAccounts(other_identity_manager, test_url_loader_factory(), + {{account_info.email, account_info.gaia}}); + + // The tab was moved to the new browser. + ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); + EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1); + EXPECT_EQ(other_browser->tab_strip_model()->count(), + other_original_tab_count + 1); + EXPECT_EQ(other_browser->tab_strip_model()->GetActiveWebContents()->GetURL(), + intercepted_url); + + CheckHistograms(histogram_tester, + SigninInterceptionHeuristicOutcome:: + kInterceptEnterpriseForcedProfileSwitch); + // Profile customization was not shown. + EXPECT_EQ(GetInterceptorDelegate(other_profile)->customized_browser(), + nullptr); + EXPECT_EQ(GetInterceptorDelegate(profile())->customized_browser(), nullptr); +}
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc index 5e5efbeb..3a0ab37 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc
@@ -26,11 +26,13 @@ #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" #include "components/prefs/pref_service.h" +#include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" namespace { @@ -44,6 +46,12 @@ const BubbleParameters& bubble_parameters, base::OnceCallback<void(SigninInterceptionResult)> callback), (override)); + MOCK_METHOD(void, + ShowEnterpriseProfileInterceptionDialog, + (const std::string& email, + base::OnceCallback<void(bool)> callback, + Browser* browser), + (override)); void ShowProfileCustomizationBubble(Browser* browser) override {} }; @@ -144,10 +152,43 @@ SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); } + // Calls MaybeInterceptWebSignin and verifies the heuristic outcome and the + // histograms. + // This function only works if the interception decision cannot be made + // synchronously (GetHeuristicOutcome() returns no value). + void TestAsynchronousInterception( + AccountInfo account_info, + bool is_new_account, + bool is_sync_signin, + SigninInterceptionHeuristicOutcome expected_outcome) { + ASSERT_EQ(interceptor()->GetHeuristicOutcome(is_new_account, is_sync_signin, + account_info.email, + /*entry=*/nullptr), + absl::nullopt); + base::HistogramTester histogram_tester; + interceptor()->MaybeInterceptWebSignin(web_contents(), + account_info.account_id, + is_new_account, is_sync_signin); + testing::Mock::VerifyAndClearExpectations(mock_delegate()); + histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", + expected_outcome, 1); + EXPECT_TRUE(interceptor()->is_interception_in_progress()); + } + + protected: + virtual void InitFeatures() { + InitWithEnabledFeatures({kDiceWebSigninInterceptionFeature}); + } + + void InitWithEnabledFeatures( + const std::vector<base::Feature>& enabled_features) { + feature_list_.InitWithFeatures(enabled_features, {}); + } + private: // testing::Test: void SetUp() override { - feature_list_.InitAndEnableFeature(kDiceWebSigninInterceptionFeature); + InitFeatures(); BrowserWithTestWindowTest::SetUp(); identity_test_env_profile_adaptor_ = @@ -287,6 +328,165 @@ EXPECT_TRUE(interceptor()->ShouldShowEnterpriseBubble(account_info)); } +TEST_F(DiceWebSigninInterceptorTest, ShouldEnforceEnterpriseProfileSeparation) { + profile()->GetPrefs()->SetBoolean( + prefs::kManagedAccountsSigninRestrictionScopeMachine, true); + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account_strict"); + + // Setup 3 accounts in the profile: + // - primary account + // - other enterprise account that is not primary (should be ignored) + // - intercepted account. + AccountInfo primary_account_info = + identity_test_env()->MakePrimaryAccountAvailable( + "alice@gmail.com", signin::ConsentLevel::kSignin); + + AccountInfo other_account_info = + identity_test_env()->MakeAccountAvailable("dummy@example.com"); + MakeValidAccountInfo(&other_account_info); + other_account_info.hosted_domain = "example.com"; + identity_test_env()->UpdateAccountInfoForAccount(other_account_info); + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable("bob@example.com"); + MakeValidAccountInfo(&account_info); + identity_test_env()->UpdateAccountInfoForAccount(account_info); + ASSERT_EQ(identity_test_env()->identity_manager()->GetPrimaryAccountId( + signin::ConsentLevel::kSignin), + primary_account_info.account_id); + // Consumer account not intercepted. + EXPECT_FALSE( + interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info)); + account_info.hosted_domain = "example.com"; + identity_test_env()->UpdateAccountInfoForAccount(account_info); + // Managed account intercepted. + EXPECT_TRUE( + interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info)); +} + +TEST_F(DiceWebSigninInterceptorTest, + ShouldEnforceEnterpriseProfileSeparationWithoutUPA) { + profile()->GetPrefs()->SetBoolean( + prefs::kManagedAccountsSigninRestrictionScopeMachine, true); + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account_strict"); + AccountInfo account_info_1 = + identity_test_env()->MakeAccountAvailable("bob@example.com"); + MakeValidAccountInfo(&account_info_1); + account_info_1.hosted_domain = "example.com"; + identity_test_env()->UpdateAccountInfoForAccount(account_info_1); + + // Primary account is not set. + ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( + signin::ConsentLevel::kSignin)); + EXPECT_TRUE( + interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info_1)); +} + +class DiceWebSigninInterceptorReauthTest : public DiceWebSigninInterceptorTest { + protected: + void InitFeatures() override { + InitWithEnabledFeatures( + {kDiceWebSigninInterceptionFeature, kAccountPoliciesLoadedWithoutSync}); + } +}; + +TEST_F(DiceWebSigninInterceptorReauthTest, + ShouldEnforceEnterpriseProfileSeparationReauth) { + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account_strict"); + AccountInfo primary_account_info = + identity_test_env()->MakePrimaryAccountAvailable( + "alice@example.com", signin::ConsentLevel::kSignin); + MakeValidAccountInfo(&primary_account_info); + primary_account_info.hosted_domain = "example.com"; + identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); + + // Primary account is set. + ASSERT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount( + signin::ConsentLevel::kSignin)); + EXPECT_TRUE(interceptor()->ShouldEnforceEnterpriseProfileSeparation( + primary_account_info)); + + profile()->GetPrefs()->SetBoolean(prefs::kUserAcceptedAccountManagement, + true); + EXPECT_FALSE(interceptor()->ShouldEnforceEnterpriseProfileSeparation( + primary_account_info)); +} + +TEST_F(DiceWebSigninInterceptorReauthTest, + EnforceManagedAccountAsPrimaryReauth) { + profile()->GetPrefs()->SetBoolean( + prefs::kManagedAccountsSigninRestrictionScopeMachine, true); + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account"); + + // Reauth intercepted if enterprise confirmation not shown yet for forced + // managed separation. + AccountInfo account_info = identity_test_env()->MakePrimaryAccountAvailable( + "alice@example.com", signin::ConsentLevel::kSignin); + MakeValidAccountInfo(&account_info); + account_info.hosted_domain = "example.com"; + identity_test_env()->UpdateAccountInfoForAccount(account_info); + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account"); + EXPECT_CALL(*mock_delegate(), ShowEnterpriseProfileInterceptionDialog( + testing::_, testing::_, testing::_)) + .WillOnce(testing::Invoke( + [](const std::string& email, base::OnceCallback<void(bool)> callback, + Browser* browser) { std::move(callback).Run(true); })); + TestAsynchronousInterception( + account_info, /*is_new_account=*/false, /*is_sync_signin=*/false, + SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); +} + +TEST_F(DiceWebSigninInterceptorTest, EnforceManagedAccountAsPrimaryManaged) { + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable("alice@example.com"); + MakeValidAccountInfo(&account_info); + account_info.hosted_domain = "example.com"; + identity_test_env()->UpdateAccountInfoForAccount(account_info); + + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account_strict"); + + EXPECT_CALL(*mock_delegate(), ShowEnterpriseProfileInterceptionDialog( + testing::_, testing::_, testing::_)) + .WillOnce(testing::Invoke( + [](const std::string& email, base::OnceCallback<void(bool)> callback, + Browser* browser) { std::move(callback).Run(true); })); + TestAsynchronousInterception( + account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, + SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); +} + +TEST_F(DiceWebSigninInterceptorTest, + EnforceManagedAccountAsPrimaryProfileSwitch) { + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable("alice@example.com"); + MakeValidAccountInfo(&account_info); + account_info.hosted_domain = "example.com"; + identity_test_env()->UpdateAccountInfoForAccount(account_info); + + profile()->GetPrefs()->SetBoolean( + prefs::kManagedAccountsSigninRestrictionScopeMachine, true); + profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, + "primary_account_strict"); + + // Setup for profile switch interception. + Profile* profile_2 = CreateTestingProfile("Profile 2"); + ProfileAttributesEntry* entry = + profile_attributes_storage()->GetProfileAttributesWithPath( + profile_2->GetPath()); + ASSERT_NE(entry, nullptr); + entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(account_info.email), + /*is_consented_primary_account=*/false); + TestAsynchronousInterception(account_info, /*is_new_account=*/true, + /*is_sync_signin=*/false, + SigninInterceptionHeuristicOutcome:: + kInterceptEnterpriseForcedProfileSwitch); +} + TEST_F(DiceWebSigninInterceptorTest, ShouldShowEnterpriseBubbleWithoutUPA) { AccountInfo account_info_1 = identity_test_env()->MakeAccountAvailable("bob@example.com");
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc index d362eba8..47fbdd15 100644 --- a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc +++ b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
@@ -50,6 +50,14 @@ std::move(callback).Run(SigninInterceptionResult::kDeclined); return nullptr; } + + void ShowEnterpriseProfileInterceptionDialog( + const std::string& email, + base::OnceCallback<void(bool)> callback, + Browser* browser) override { + std::move(callback).Run(false); + } + void ShowProfileCustomizationBubble(Browser* browser) override {} };
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SyncConsentActivityLauncher.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SyncConsentActivityLauncher.java index 925f642..8c648419 100644 --- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SyncConsentActivityLauncher.java +++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SyncConsentActivityLauncher.java
@@ -22,7 +22,8 @@ @interface AccessPoint {} /** - * Launches the SigninActivity with default sign-in flow from personalized sign-in promo. + * Launches the {@link SyncConsentActivity} with default sign-in flow from personalized sign-in + * promo. * @param accessPoint {@link SigninAccessPoint} for starting sign-in flow. * @param accountName The account to preselect or null to preselect the default account. */ @@ -30,7 +31,7 @@ Context context, @SigninAccessPoint int accessPoint, String accountName); /** - * Launches the SigninActivity with "Choose account" sign-in flow from personalized + * Launches the {@link SyncConsentActivity} with "Choose account" sign-in flow from personalized * sign-in promo. * @param accessPoint {@link SigninAccessPoint} for starting sign-in flow. * @param accountName The account to preselect or null to preselect the default account. @@ -39,17 +40,17 @@ Context context, @SigninAccessPoint int accessPoint, String accountName); /** - * Launches the SigninActivity with "New account" sign-in flow from personalized sign-in - * promo. + * Launches the {@link SyncConsentActivity} with "New account" sign-in flow from personalized + * sign-in promo. * @param accessPoint {@link SigninAccessPoint} for starting sign-in flow. */ void launchActivityForPromoAddAccountFlow(Context context, @SigninAccessPoint int accessPoint); /** - * Launches the {@link SigninActivity} if signin is allowed. + * Launches the {@link SyncConsentActivity} if signin is allowed. * @param context A {@link Context} object. * @param accessPoint {@link SigninAccessPoint} for starting sign-in flow. - * @return a boolean indicating if the {@link SigninActivity} is launched. + * @return a boolean indicating if the {@link SyncConsentActivity} is launched. */ boolean launchActivityIfAllowed(Context context, @SigninAccessPoint int accessPoint); }
diff --git a/chrome/browser/speech/cros_speech_recognition_service_factory.cc b/chrome/browser/speech/cros_speech_recognition_service_factory.cc index ba9ff96b..e0df14a 100644 --- a/chrome/browser/speech/cros_speech_recognition_service_factory.cc +++ b/chrome/browser/speech/cros_speech_recognition_service_factory.cc
@@ -20,6 +20,12 @@ // static CrosSpeechRecognitionServiceFactory* +CrosSpeechRecognitionServiceFactory::GetInstanceForTest() { + return GetInstance(); +} + +// static +CrosSpeechRecognitionServiceFactory* CrosSpeechRecognitionServiceFactory::GetInstance() { static base::NoDestructor<CrosSpeechRecognitionServiceFactory> instance; return instance.get();
diff --git a/chrome/browser/speech/cros_speech_recognition_service_factory.h b/chrome/browser/speech/cros_speech_recognition_service_factory.h index fa33171..5c58caf5 100644 --- a/chrome/browser/speech/cros_speech_recognition_service_factory.h +++ b/chrome/browser/speech/cros_speech_recognition_service_factory.h
@@ -9,10 +9,6 @@ class Profile; -namespace ash { -class DictationTest; -} - namespace base { template <class T> class NoDestructor; @@ -28,11 +24,10 @@ : public BrowserContextKeyedServiceFactory { public: static speech::SpeechRecognitionService* GetForProfile(Profile* profile); + static CrosSpeechRecognitionServiceFactory* GetInstanceForTest(); private: friend class base::NoDestructor<CrosSpeechRecognitionServiceFactory>; - friend class OnDeviceSpeechRecognizerTest; - friend class ::ash::DictationTest; static CrosSpeechRecognitionServiceFactory* GetInstance(); CrosSpeechRecognitionServiceFactory();
diff --git a/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc b/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc index 3f5de01..9d4b2c2e 100644 --- a/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc +++ b/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc
@@ -100,17 +100,18 @@ void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); // Replaces normal CrosSpeechRecognitionService with a fake one. - CrosSpeechRecognitionServiceFactory::GetInstance()->SetTestingFactoryAndUse( - browser()->profile(), - base::BindRepeating( - &OnDeviceSpeechRecognizerTest::CreateTestSpeechRecognitionService, - base::Unretained(this))); + CrosSpeechRecognitionServiceFactory::GetInstanceForTest() + ->SetTestingFactoryAndUse( + browser()->profile(), + base::BindRepeating(&OnDeviceSpeechRecognizerTest:: + CreateTestSpeechRecognitionService, + base::Unretained(this))); mock_speech_delegate_ = std::make_unique<testing::StrictMock<MockSpeechRecognizerDelegate>>(); // Fake that SODA is installed. static_cast<speech::SodaInstallerImplChromeOS*>( speech::SodaInstaller::GetInstance()) - ->soda_installed_for_test_ = true; + ->set_soda_installed_for_test(true); } void TearDownOnMainThread() override {
diff --git a/chrome/browser/ssl/sct_reporting_service.h b/chrome/browser/ssl/sct_reporting_service.h index f1c8b37..bd24b1b7 100644 --- a/chrome/browser/ssl/sct_reporting_service.h +++ b/chrome/browser/ssl/sct_reporting_service.h
@@ -7,7 +7,6 @@ #include "base/callback_list.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "components/keyed_service/core/keyed_service.h" #include "url/gurl.h"
diff --git a/chrome/browser/ssl/typed_navigation_upgrade_throttle.cc b/chrome/browser/ssl/typed_navigation_upgrade_throttle.cc index bacd912..0343974 100644 --- a/chrome/browser/ssl/typed_navigation_upgrade_throttle.cc +++ b/chrome/browser/ssl/typed_navigation_upgrade_throttle.cc
@@ -56,7 +56,7 @@ bool is_using_https_as_default_scheme = static_cast<ChromeNavigationUIData*>(ui_data) ->is_using_https_as_default_scheme(); - return is_using_https_as_default_scheme && handle->IsInMainFrame() && + return is_using_https_as_default_scheme && handle->IsInPrimaryMainFrame() && !handle->IsSameDocument() && handle->GetURL().SchemeIs(url::kHttpsScheme) && !handle->GetWebContents()->IsPortal();
diff --git a/chrome/browser/subresource_redirect/origin_robots_rules_unittest.cc b/chrome/browser/subresource_redirect/origin_robots_rules_unittest.cc index b803b09d..d812e45 100644 --- a/chrome/browser/subresource_redirect/origin_robots_rules_unittest.cc +++ b/chrome/browser/subresource_redirect/origin_robots_rules_unittest.cc
@@ -12,6 +12,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/time/time.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/base/escape.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -127,6 +128,9 @@ base::HistogramTester histogram_tester_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; + std::unique_ptr<OriginRobotsRules> origin_robots_rules_; std::unique_ptr<RobotsRulesFetcherState> rules_fetcher_state_;
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index 6fee0df..24f111e 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -92,7 +92,7 @@ #include "chrome/browser/sync/test/integration/sync_arc_package_helper.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h" #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) #if defined(OS_ANDROID) @@ -188,35 +188,6 @@ return it != profile_to_fcm_network_handler_map->end() ? it->second : nullptr; } -// Helper class to ensure a profile is registered before the manager is -// notified of creation. -class SyncProfileDelegate : public Profile::Delegate { - public: - explicit SyncProfileDelegate( - base::OnceCallback<void(Profile*)> on_profile_created_callback) - : on_profile_created_callback_(std::move(on_profile_created_callback)) {} - ~SyncProfileDelegate() override = default; - - void OnProfileCreated(Profile* profile, - bool success, - bool is_new_profile) override { - g_browser_process->profile_manager()->RegisterTestingProfile( - base::WrapUnique(profile), true); - - // Perform any custom work needed before the profile is initialized. - if (!on_profile_created_callback_.is_null()) - std::move(on_profile_created_callback_).Run(profile); - - g_browser_process->profile_manager()->OnProfileCreated(profile, success, - is_new_profile); - } - - private: - base::OnceCallback<void(Profile*)> on_profile_created_callback_; - - DISALLOW_COPY_AND_ASSIGN(SyncProfileDelegate); -}; - instance_id::InstanceIDDriver* GetOrCreateInstanceIDDriver( Profile* profile, std::map<const Profile*, std::unique_ptr<instance_id::InstanceIDDriver>>* @@ -467,12 +438,9 @@ InitializeProfile(index, profile); #else // Without need of real GAIA authentication, we create new test profiles. - // For test profiles, a custom delegate needs to be used to do the - // initialization work before the profile is registered. - profile_delegates_[index] = - std::make_unique<SyncProfileDelegate>(base::BindOnce( - &SyncTest::InitializeProfile, base::Unretained(this), index)); - Profile* profile = MakeTestProfile(profile_path, index); + Profile* profile = + g_browser_process->profile_manager()->GetProfile(profile_path); + InitializeProfile(index, profile); #endif SetupMockGaiaResponsesForProfile(profile); @@ -513,13 +481,6 @@ return profile_manager->GetProfileByPath(profile_path); } -Profile* SyncTest::MakeTestProfile(base::FilePath profile_path, int index) { - std::unique_ptr<Profile> profile = - Profile::CreateProfile(profile_path, profile_delegates_[index].get(), - Profile::CREATE_MODE_SYNCHRONOUS); - return profile.release(); -} - Profile* SyncTest::GetProfile(int index) { DCHECK(!profiles_.empty()) << "SetupClients() has not yet been called."; DCHECK(index >= 0 && index < static_cast<int>(profiles_.size())) @@ -634,7 +595,6 @@ // Create the required number of sync profiles, browsers and clients. profiles_.resize(num_clients_); - profile_delegates_.resize(num_clients_ + 1); // + 1 for the verifier. clients_.resize(num_clients_); fake_server_invalidation_observers_.resize(num_clients_); @@ -682,10 +642,8 @@ if (UseVerifier()) { base::FilePath user_data_dir; base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); - profile_delegates_[num_clients_] = - std::make_unique<SyncProfileDelegate>(base::DoNothing()); - verifier_ = MakeTestProfile( - user_data_dir.Append(FILE_PATH_LITERAL("Verifier")), num_clients_); + verifier_ = g_browser_process->profile_manager()->GetProfile( + user_data_dir.Append(FILE_PATH_LITERAL("Verifier"))); WaitForDataModels(verifier()); } @@ -939,7 +897,6 @@ void SyncTest::ClearProfiles() { profiles_.clear(); - profile_delegates_.clear(); scoped_temp_dirs_.clear(); #if !defined(OS_ANDROID) browsers_.clear();
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h index 3fdbffc..2fa0284 100644 --- a/chrome/browser/sync/test/integration/sync_test.h +++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -402,10 +402,6 @@ void OnBrowserRemoved(Browser* browser); #endif - // Helper to Profile::CreateProfile that handles path creation. It creates - // a profile then registers it as a testing profile. - Profile* MakeTestProfile(base::FilePath profile_path, int index); - // Helper to block the current thread while the data models sync depends on // finish loading. void WaitForDataModels(Profile* profile); @@ -481,11 +477,6 @@ // directory. Profiles are owned by the ProfileManager. std::vector<Profile*> profiles_; - // Collection of profile delegates. Only used for test profiles, which - // require a custom profile delegate to ensure initialization happens at the - // right time. - std::vector<std::unique_ptr<Profile::Delegate>> profile_delegates_; - // List of temporary directories that need to be deleted when the test is // completed, used for two-client tests with external server. std::vector<std::unique_ptr<base::ScopedTempDir>> scoped_temp_dirs_;
diff --git a/chrome/browser/sync/trusted_vault_client_android.cc b/chrome/browser/sync/trusted_vault_client_android.cc index 3e3f62a2..8d518d3 100644 --- a/chrome/browser/sync/trusted_vault_client_android.cc +++ b/chrome/browser/sync/trusted_vault_client_android.cc
@@ -139,10 +139,6 @@ NOTREACHED(); } -void TrustedVaultClientAndroid::RemoveAllStoredKeys() { - // StoreKeys() not supported on Android, nothing to remove. -} - void TrustedVaultClientAndroid::MarkKeysAsStale( const CoreAccountInfo& account_info, base::OnceCallback<void(bool)> cb) {
diff --git a/chrome/browser/sync/trusted_vault_client_android.h b/chrome/browser/sync/trusted_vault_client_android.h index e2158d0..1d5fe62 100644 --- a/chrome/browser/sync/trusted_vault_client_android.h +++ b/chrome/browser/sync/trusted_vault_client_android.h
@@ -65,7 +65,6 @@ void StoreKeys(const std::string& gaia_id, const std::vector<std::vector<uint8_t>>& keys, int last_key_version) override; - void RemoveAllStoredKeys() override; void MarkKeysAsStale(const CoreAccountInfo& account_info, base::OnceCallback<void(bool)> cb) override; void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java index 7bad7cdf..dae3b706 100644 --- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java +++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -295,12 +295,6 @@ public boolean getHideFutureNavigations(); /** - * If true, new notification requests are blocked. - */ - public void setShouldBlockNewNotificationRequests(boolean value); - public boolean getShouldBlockNewNotificationRequests(); - - /** * Set whether {@link Tab} metadata (specifically all {@link PersistedTabData}) * will be saved. Not all Tabs need to be persisted across restarts. * The default value when a Tab is initialized is false.
diff --git a/chrome/browser/tab_provider/BUILD.gn b/chrome/browser/tab_provider/BUILD.gn new file mode 100644 index 0000000..d378721 --- /dev/null +++ b/chrome/browser/tab_provider/BUILD.gn
@@ -0,0 +1,17 @@ +# Copyright 2021 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("//build/config/android/rules.gni") + +android_library("java") { + sources = [ "android/java/src/org/chromium/chrome/browser/tab_provider/ActivityTabProvider.java" ] + + deps = [ + "//base:base_java", + "//chrome/browser/tab:java", + "//chrome/browser/tabmodel:java", + "//chrome/browser/ui/android/layouts:java", + "//third_party/androidx:androidx_annotation_annotation_java", + ] +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabProvider.java b/chrome/browser/tab_provider/android/java/src/org/chromium/chrome/browser/tab_provider/ActivityTabProvider.java similarity index 98% rename from chrome/android/java/src/org/chromium/chrome/browser/ActivityTabProvider.java rename to chrome/browser/tab_provider/android/java/src/org/chromium/chrome/browser/tab_provider/ActivityTabProvider.java index 6dd4b3a..ca12b7b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabProvider.java +++ b/chrome/browser/tab_provider/android/java/src/org/chromium/chrome/browser/tab_provider/ActivityTabProvider.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser; +package org.chromium.chrome.browser.tab_provider; import androidx.annotation.CallSuper; import androidx.annotation.VisibleForTesting;
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc index de014ea2..2586f53 100644 --- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc +++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -50,6 +50,7 @@ #include "components/translate/core/browser/translate_script.h" #include "components/translate/core/browser/translate_ui_delegate.h" #include "components/translate/core/common/language_detection_details.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_details.h" @@ -448,6 +449,9 @@ network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; + // The infobars that have been removed. // WARNING: the pointers point to deleted objects, use only for comparison. std::set<infobars::InfoBarDelegate*> removed_infobars_;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_test.cc b/chrome/browser/ui/app_list/arc/arc_app_test.cc index 1c6d2db..bca9a51 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_test.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_test.cc
@@ -27,6 +27,7 @@ #include "components/arc/intent_helper/arc_intent_helper_bridge.h" #include "components/arc/session/arc_bridge_service.h" #include "components/arc/session/arc_session_runner.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "components/arc/test/fake_arc_session.h"
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc index 5d6c3eb..0323667ab 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -76,6 +76,7 @@ #include "components/arc/metrics/arc_metrics_constants.h" #include "components/arc/mojom/app.mojom.h" #include "components/arc/mojom/compatibility_mode.mojom.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_app_instance.h" #include "components/arc/test/fake_intent_helper_instance.h" #include "components/services/app_service/public/cpp/app_registry_cache.h"
diff --git a/chrome/browser/ui/app_list/arc/arc_usb_host_permission_browsertest.cc b/chrome/browser/ui/app_list/arc/arc_usb_host_permission_browsertest.cc index b031f19..d522b6e 100644 --- a/chrome/browser/ui/app_list/arc/arc_usb_host_permission_browsertest.cc +++ b/chrome/browser/ui/app_list/arc/arc_usb_host_permission_browsertest.cc
@@ -20,6 +20,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "components/arc/arc_util.h" #include "components/arc/mojom/app.mojom.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "components/user_manager/scoped_user_manager.h"
diff --git a/chrome/browser/ui/app_list/arc/arc_usb_host_permission_manager.h b/chrome/browser/ui/app_list/arc/arc_usb_host_permission_manager.h index 1e0e064..c2188a57 100644 --- a/chrome/browser/ui/app_list/arc/arc_usb_host_permission_manager.h +++ b/chrome/browser/ui/app_list/arc/arc_usb_host_permission_manager.h
@@ -12,7 +12,6 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" #include "components/arc/usb/usb_host_ui_delegate.h" #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.h b/chrome/browser/ui/ash/chrome_screenshot_grabber.h index deea728..d8406232 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber.h +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.h
@@ -11,7 +11,6 @@ #include "ash/screenshot_delegate.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "build/build_config.h" #include "chrome/browser/ui/ash/screenshot_area.h" #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/ui/ash/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard_history_browsertest.cc index 6856214..3ed3587 100644 --- a/chrome/browser/ui/ash/clipboard_history_browsertest.cc +++ b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
@@ -505,13 +505,10 @@ // Verify that the first menu item's delete button shows. In addition, the // delete button's inkdrop highlight should fade in or be visible. - const ash::ClipboardHistoryDeleteButton* delete_button = - static_cast<const ash::ClipboardHistoryDeleteButton*>( - first_history_item_view->GetViewByID( - ash::ClipboardHistoryUtil::kDeleteButtonViewID)); + const views::View* const delete_button = first_history_item_view->GetViewByID( + ash::ClipboardHistoryUtil::kDeleteButtonViewID); ASSERT_TRUE(delete_button->GetVisible()); - EXPECT_TRUE(const_cast<ash::ClipboardHistoryDeleteButton*>(delete_button) - ->ink_drop() + EXPECT_TRUE(views::InkDrop::Get(const_cast<views::View*>(delete_button)) ->GetInkDrop() ->IsHighlightFadingInOrVisible());
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc index 156ac88e..271c4c3 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
@@ -1435,6 +1435,109 @@ in_progress_download_id)); } +// Verifies that canceling holding space items via primary action is WAI. +IN_PROC_BROWSER_TEST_F(HoldingSpaceUiInProgressDownloadsBrowserTest, + CancelItemViaPrimaryAction) { + ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode( + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); + + // Create an in-progress download. + auto in_progress_download = + CreateMockDownloadItem(download::DownloadItem::IN_PROGRESS, CreateFile(), + /*percent_complete=*/0); + in_progress_download->NotifyObserversDownloadUpdated(); + + // Create a completed download. + // NOTE: In production, the download manager will create COMPLETE download + // items from previous sessions during initialization, so we ignore them. To + // match production behavior, create an IN_PROGRESS download item and only + // then update it to COMPLETE state. + auto completed_download = + CreateMockDownloadItem(download::DownloadItem::IN_PROGRESS, CreateFile(), + /*percent_complete=*/0); + ON_CALL(*completed_download, GetState()) + .WillByDefault(testing::Return(download::DownloadItem::COMPLETE)); + ON_CALL(*completed_download, PercentComplete()) + .WillByDefault(testing::Return(100)); + completed_download->NotifyObserversDownloadUpdated(); + + // Show holding space UI. + test_api().Show(); + ASSERT_TRUE(test_api().IsShowing()); + + // Expect two download chips, one for each created download item. + std::vector<views::View*> download_chips = test_api().GetDownloadChips(); + ASSERT_EQ(download_chips.size(), 2u); + + // Cache download chips. NOTE: Chips are displayed in reverse order of their + // underlying holding space item creation. + views::View* const completed_download_chip = download_chips.at(0); + views::View* const in_progress_download_chip = download_chips.at(1); + + // Hover over the `completed_download_chip`. Because the underlying download + // is completed, the chip should contain a visible primary action for "Pin". + MoveMouseTo(completed_download_chip, /*count=*/10); + auto* primary_action_container = completed_download_chip->GetViewByID( + kHoldingSpaceItemPrimaryActionContainerId); + auto* primary_action_cancel = + primary_action_container->GetViewByID(kHoldingSpaceItemCancelButtonId); + auto* primary_action_pin = + primary_action_container->GetViewByID(kHoldingSpaceItemPinButtonId); + ViewDrawnWaiter().Wait(primary_action_container); + EXPECT_FALSE(primary_action_cancel->GetVisible()); + EXPECT_TRUE(primary_action_pin->GetVisible()); + + // Hover over the `in_progress_download_chip`. Because the underlying download + // is in-progress, the chip should contain a visible primary action for + // "Cancel". + MoveMouseTo(in_progress_download_chip, /*count=*/10); + primary_action_container = in_progress_download_chip->GetViewByID( + kHoldingSpaceItemPrimaryActionContainerId); + primary_action_cancel = + primary_action_container->GetViewByID(kHoldingSpaceItemCancelButtonId); + primary_action_pin = + primary_action_container->GetViewByID(kHoldingSpaceItemPinButtonId); + ViewDrawnWaiter().Wait(primary_action_container); + EXPECT_TRUE(primary_action_cancel->GetVisible()); + EXPECT_FALSE(primary_action_pin->GetVisible()); + + // Cache the holding space item IDs associated with the two download chips. + const std::string completed_download_id = + test_api().GetHoldingSpaceItemId(completed_download_chip); + const std::string in_progress_download_id = + test_api().GetHoldingSpaceItemId(in_progress_download_chip); + + // Bind an observer to watch for updates to the holding space model. + testing::NiceMock<MockHoldingSpaceModelObserver> mock; + base::ScopedObservation<HoldingSpaceModel, HoldingSpaceModelObserver> + observer{&mock}; + observer.Observe(HoldingSpaceController::Get()->model()); + + // Press the `primary_action_container` to execute "Cancel", expecting and + // waiting for the in-progress download item to be removed from the holding + // space model. + base::RunLoop run_loop; + EXPECT_CALL(mock, OnHoldingSpaceItemsRemoved) + .WillOnce([&](const std::vector<const HoldingSpaceItem*>& items) { + ASSERT_EQ(items.size(), 1u); + ASSERT_EQ(items[0]->id(), in_progress_download_id); + run_loop.Quit(); + }); + Click(primary_action_container); + run_loop.Run(); + + // Verify that there is now only a single download chip. + download_chips = test_api().GetDownloadChips(); + EXPECT_EQ(download_chips.size(), 1u); + + // Because the in-progress download was canceled, only the completed download + // chip should still be present in the UI. + EXPECT_TRUE(test_api().GetHoldingSpaceItemView(download_chips, + completed_download_id)); + EXPECT_FALSE(test_api().GetHoldingSpaceItemView(download_chips, + in_progress_download_id)); +} + // Base class for tests of the pause or resume commands, parameterized by which // command to use. This will either be `kPauseItem` or `kResumeItem`. class HoldingSpaceUiPauseOrResumeBrowserTest
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.cc b/chrome/browser/ui/ash/projector/projector_client_impl.cc index b3bbebb..2ccd777c 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl.cc +++ b/chrome/browser/ui/ash/projector/projector_client_impl.cc
@@ -21,21 +21,23 @@ } // namespace -ProjectorClientImpl::ProjectorClientImpl() { - ash::ProjectorController::Get()->SetClient(this); - +ProjectorClientImpl::ProjectorClientImpl(ash::ProjectorController* controller) + : controller_(controller) { + controller_->SetClient(this); bool recognition_available = OnDeviceSpeechRecognizer::IsOnDeviceSpeechRecognizerAvailable( kEnglishLanguageCode) || ShouldUseWebSpeechFallback(); - ash::ProjectorController::Get()->OnSpeechRecognitionAvailable( - recognition_available); + controller_->OnSpeechRecognitionAvailable(recognition_available); if (!recognition_available) { observed_soda_installer_.Observe(speech::SodaInstaller::GetInstance()); } } +ProjectorClientImpl::ProjectorClientImpl() + : ProjectorClientImpl(ash::ProjectorController::Get()) {} + ProjectorClientImpl::~ProjectorClientImpl() = default; void ProjectorClientImpl::StartSpeechRecognition() { @@ -75,7 +77,7 @@ bool is_final, const absl::optional<media::SpeechRecognitionResult>& full_result) { DCHECK(full_result.has_value()); - ash::ProjectorController::Get()->OnTranscription(full_result.value()); + controller_->OnTranscription(full_result.value()); } void ProjectorClientImpl::OnSpeechRecognitionStateChanged( @@ -83,7 +85,7 @@ if (new_state == SPEECH_RECOGNIZER_ERROR) { speech_recognizer_.reset(); recognizer_status_ = SPEECH_RECOGNIZER_OFF; - ash::ProjectorController::Get()->OnTranscriptionError(); + controller_->OnTranscriptionError(); } else if (new_state == SPEECH_RECOGNIZER_READY) { if (recognizer_status_ == SPEECH_RECOGNIZER_OFF && speech_recognizer_) { // The SpeechRecognizer was initialized after being created, and @@ -99,5 +101,5 @@ // OnDevice has been installed! Notify ProjectorController in ash. DCHECK(OnDeviceSpeechRecognizer::IsOnDeviceSpeechRecognizerAvailable( kEnglishLanguageCode)); - ash::ProjectorController::Get()->OnSpeechRecognitionAvailable(true); + controller_->OnSpeechRecognitionAvailable(true); }
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.h b/chrome/browser/ui/ash/projector/projector_client_impl.h index 26b26987..914d7e75 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl.h +++ b/chrome/browser/ui/ash/projector/projector_client_impl.h
@@ -8,6 +8,7 @@ #include <memory> #include "ash/public/cpp/projector/projector_client.h" +#include "ash/public/cpp/projector/projector_controller.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "chrome/browser/speech/speech_recognizer_delegate.h" @@ -23,6 +24,9 @@ public SpeechRecognizerDelegate, public speech::SodaInstaller::Observer { public: + // Used by unittests and browsertests to set projector controller. + explicit ProjectorClientImpl(ash::ProjectorController* controller); + ProjectorClientImpl(); ProjectorClientImpl(const ProjectorClientImpl&) = delete; ProjectorClientImpl& operator=(const ProjectorClientImpl&) = delete; @@ -58,6 +62,8 @@ } private: + ash::ProjectorController* const controller_; + SpeechRecognizerStatus recognizer_status_ = SpeechRecognizerStatus::SPEECH_RECOGNIZER_OFF; base::ScopedObservation<speech::SodaInstaller,
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc b/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc index fc9fcf08..237da74e 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc +++ b/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc
@@ -8,12 +8,43 @@ #include "ash/constants/ash_features.h" #include "ash/public/cpp/projector/projector_client.h" +#include "ash/public/cpp/projector/projector_controller.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/speech/cros_speech_recognition_service_factory.h" +#include "chrome/browser/speech/fake_speech_recognition_service.h" +#include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" +#include "components/soda/soda_installer_impl_chromeos.h" #include "content/public/test/browser_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" namespace ash { +namespace { + +const char kFirstSpeechResult[] = "the brown fox"; +const char kSecondSpeechResult[] = "the brown fox jumped over the lazy dog"; + +} // namespace + +class ASH_PUBLIC_EXPORT MockProjectorController : public ProjectorController { + public: + MockProjectorController() = default; + + MockProjectorController(const MockProjectorController&) = delete; + MockProjectorController& operator=(const MockProjectorController&) = delete; + ~MockProjectorController() override = default; + + // ProjectorController: + MOCK_METHOD1(SetClient, void(ProjectorClient* client)); + MOCK_METHOD1(OnSpeechRecognitionAvailable, void(bool available)); + MOCK_METHOD1(OnTranscription, + void(const media::SpeechRecognitionResult& result)); + MOCK_METHOD0(OnTranscriptionError, void()); +}; + class ProjectorClientTest : public InProcessBrowserTest { public: ProjectorClientTest() { @@ -27,11 +58,51 @@ // InProcessBrowserTest: void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); - client_ = std::make_unique<ProjectorClientImpl>(); + static_cast<speech::SodaInstallerImplChromeOS*>( + speech::SodaInstaller::GetInstance()) + ->set_soda_installed_for_test(true); + + scoped_resetter_ = + std::make_unique<ProjectorController::ScopedInstanceResetterForTest>(); + controller_ = std::make_unique<MockProjectorController>(); + client_ = std::make_unique<ProjectorClientImpl>(controller_.get()); + + CrosSpeechRecognitionServiceFactory::GetInstanceForTest() + ->SetTestingFactoryAndUse( + browser()->profile(), + base::BindRepeating( + &ProjectorClientTest::CreateTestSpeechRecognitionService, + base::Unretained(this))); + } + + void TearDownOnMainThread() override { + client_.reset(); + controller_.reset(); + scoped_resetter_.reset(); + } + + std::unique_ptr<KeyedService> CreateTestSpeechRecognitionService( + content::BrowserContext* context) { + std::unique_ptr<speech::FakeSpeechRecognitionService> fake_service = + std::make_unique<speech::FakeSpeechRecognitionService>(); + fake_service_ = fake_service.get(); + return std::move(fake_service); + } + + void SendSpeechResult(const char* result, bool is_final) { + EXPECT_TRUE(fake_service_->is_capturing_audio()); + base::RunLoop loop; + fake_service_->SendSpeechRecognitionResult( + media::SpeechRecognitionResult(result, is_final)); + loop.RunUntilIdle(); } protected: + std::unique_ptr<ProjectorController::ScopedInstanceResetterForTest> + scoped_resetter_; + std::unique_ptr<MockProjectorController> controller_; std::unique_ptr<ProjectorClient> client_; + speech::FakeSpeechRecognitionService* fake_service_; private: base::test::ScopedFeatureList scoped_feature_list_; @@ -48,4 +119,20 @@ // TODO(crbug/1199396): Add a test to verify the selfie cam turns off when the // device goes inactive. +IN_PROC_BROWSER_TEST_F(ProjectorClientTest, SpeechRecognitionResults) { + client_->StartSpeechRecognition(); + fake_service_->WaitForRecognitionStarted(); + base::RunLoop().RunUntilIdle(); + + EXPECT_CALL(*controller_, OnTranscription(media::SpeechRecognitionResult( + kFirstSpeechResult, false))); + SendSpeechResult(kFirstSpeechResult, false /* is_final */); + base::RunLoop().RunUntilIdle(); + + EXPECT_CALL(*controller_, OnTranscription(media::SpeechRecognitionResult( + kSecondSpeechResult, false))); + SendSpeechResult(kSecondSpeechResult, false /* is_final */); + base::RunLoop().RunUntilIdle(); +} + } // namespace ash
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc index c9023b4..4a29dd8 100644 --- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc +++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/ui/ash/shelf/arc_app_window_info.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" #include "chrome/common/chrome_features.h" +#include "components/full_restore/full_restore_utils.h" #include "extensions/common/constants.h" #include "ui/aura/client/aura_constants.h" #include "ui/gfx/image/image_skia.h" @@ -101,15 +102,17 @@ void AppServiceAppWindowArcTracker::HandleWindowDestroying( aura::Window* window) { app_service_controller_->UnregisterWindow(window); + // Replace the pointers to the window by nullptr to prevent from using it // before OnTaskDestroyed() is called to remove the entry from // |task_id_to_arc_app_window_info_|; - auto task_id = arc::GetWindowTaskId(window); - if (!task_id.has_value()) - return; - auto it = task_id_to_arc_app_window_info_.find(*task_id); - if (it != task_id_to_arc_app_window_info_.end()) - it->second->set_window(nullptr); + ArcAppWindowInfo* info = GetArcAppWindowInfo(window); + if (info) + info->set_window(nullptr); + + auto session_id = arc::GetWindowSessionId(window); + if (session_id.has_value()) + session_id_to_arc_app_window_info_.erase(*session_id); } void AppServiceAppWindowArcTracker::OnAppStatesChanged( @@ -371,15 +374,15 @@ } } -ash::ShelfID AppServiceAppWindowArcTracker::GetShelfId(int task_id) const { +ash::ShelfID AppServiceAppWindowArcTracker::GetShelfId(aura::Window* window) { if (observed_profile_ != app_service_controller_->owner()->profile()) return ash::ShelfID(); - const auto it = task_id_to_arc_app_window_info_.find(task_id); - if (it == task_id_to_arc_app_window_info_.end()) + ArcAppWindowInfo* info = GetArcAppWindowInfo(window); + if (!info) return ash::ShelfID(); - return it->second->shelf_id(); + return info->shelf_id(); } void AppServiceAppWindowArcTracker::CheckAndAttachControllers() { @@ -509,3 +512,35 @@ gfx::ImageSkia image = icon; SetDescription(task_id, title, image); } + +ArcAppWindowInfo* AppServiceAppWindowArcTracker::GetArcAppWindowInfo( + aura::Window* window) { + const auto task_id = arc::GetWindowTaskId(window); + if (task_id.has_value()) { + auto it = task_id_to_arc_app_window_info_.find(*task_id); + if (it != task_id_to_arc_app_window_info_.end()) + return it->second.get(); + } + + const auto session_id = arc::GetWindowSessionId(window); + if (!session_id.has_value()) + return nullptr; + + const std::string* arc_app_id = window->GetProperty(full_restore::kAppIdKey); + if (!arc_app_id || arc_app_id->empty()) + return nullptr; + + auto session_id_it = session_id_to_arc_app_window_info_.find(*session_id); + if (session_id_it != session_id_to_arc_app_window_info_.end()) + return session_id_it->second.get(); + + const arc::ArcAppShelfId arc_app_shelf_id = + arc::ArcAppShelfId::FromIntentAndAppId(/*intent=*/std::string(), + *arc_app_id); + session_id_to_arc_app_window_info_[*session_id] = + std::make_unique<ArcAppWindowInfo>(arc_app_shelf_id, + /*intent=*/std::string(), + /*package_name=*/std::string()); + + return session_id_to_arc_app_window_info_[*session_id].get(); +}
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.h b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.h index 9f082b00..cc0bfe8 100644 --- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.h +++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.h
@@ -92,7 +92,7 @@ void OnItemDelegateDiscarded(const ash::ShelfID& shelf_id, ash::ShelfItemDelegate* delegate); - ash::ShelfID GetShelfId(int task_id) const; + ash::ShelfID GetShelfId(aura::Window* window); int active_task_id() const { return active_task_id_; } @@ -100,6 +100,9 @@ using TaskIdToArcAppWindowInfo = std::map<int, std::unique_ptr<ArcAppWindowInfo>>; + using SessionIdToArcAppWindowInfo = + std::map<int, std::unique_ptr<ArcAppWindowInfo>>; + // Maps shelf group id to controller. Shelf group id is optional parameter for // the Android task. If it is not set, app id is used instead. using ShelfGroupToAppControllerMap = @@ -136,10 +139,13 @@ const std::string& title, gfx::ImageSkia icon); + ArcAppWindowInfo* GetArcAppWindowInfo(aura::Window* window); + Profile* const observed_profile_; AppServiceAppWindowShelfController* const app_service_controller_; TaskIdToArcAppWindowInfo task_id_to_arc_app_window_info_; + SessionIdToArcAppWindowInfo session_id_to_arc_app_window_info_; ShelfGroupToAppControllerMap app_shelf_group_to_controller_map_; // ARC app task id could be created after the window initialized.
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc index 0e051b7c..f3f1d2c0 100644 --- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc +++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc
@@ -34,8 +34,8 @@ #include "chrome/browser/web_applications/components/web_application_info.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_app_instance.h" #include "components/exo/shell_surface_util.h" #include "components/services/app_service/public/cpp/instance.h"
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_shelf_controller.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_shelf_controller.cc index eb3cb9a7..b5d7472 100644 --- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_shelf_controller.cc +++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_shelf_controller.cc
@@ -646,10 +646,8 @@ return ash::ShelfID(plugin_vm::kPluginVmShelfAppId); ash::ShelfID shelf_id; - if (arc_tracker_) { - shelf_id = arc_tracker_->GetShelfId( - arc::GetWindowTaskId(window).value_or(arc::kNoTaskId)); - } + if (arc_tracker_) + shelf_id = arc_tracker_->GetShelfId(window); if (!shelf_id.IsNull()) return shelf_id;
diff --git a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc index 5387185..156bf43 100644 --- a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc +++ b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
@@ -63,6 +63,9 @@ if (task_id.has_value()) { restore_window_id = full_restore::GetArcRestoreWindowIdForTaskId(*task_id); } else { + DCHECK(session_id.has_value()); + out_properties_container.SetProperty(full_restore::kGhostWindowSessionIdKey, + *session_id); restore_window_id = full_restore::GetArcRestoreWindowIdForSessionId(*session_id); }
diff --git a/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc b/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc index 801c0f2a..5e9bc50 100644 --- a/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc +++ b/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc
@@ -35,9 +35,9 @@ #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller_test_util.h" #include "chrome/browser/ui/ash/shelf/shelf_spinner_controller.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/metrics/arc_metrics_constants.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_app_instance.h" #include "components/exo/shell_surface.h" #include "components/exo/shell_surface_util.h"
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc index 21160b67..9fe7da2 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -109,10 +109,10 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "components/account_id/account_id.h" #include "components/arc/arc_prefs.h" -#include "components/arc/arc_util.h" #include "components/arc/metrics/arc_metrics_constants.h" #include "components/arc/mojom/app.mojom.h" #include "components/arc/mojom/compatibility_mode.mojom.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/fake_app_instance.h" #include "components/exo/shell_surface_util.h" #include "components/keep_alive_registry/scoped_keep_alive.h"
diff --git a/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller.h b/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller.h index 6f201b2..98e0bc4 100644 --- a/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller.h +++ b/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller.h
@@ -53,6 +53,9 @@ // Returns the descriptive label of the expiration date field. virtual std::u16string GetExpirationDateFieldLabel() const = 0; + // Returns the descriptive label of the cardholder name field. + virtual std::u16string GetCardholderNameFieldLabel() const = 0; + // Returns the descriptive label of the CVC field. virtual std::u16string GetCvcFieldLabel() const = 0;
diff --git a/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.cc index 6ed07a9f..1da5ef0 100644 --- a/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.cc +++ b/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.cc
@@ -91,6 +91,13 @@ IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EXP_DATE_LABEL); } +std::u16string +VirtualCardManualFallbackBubbleControllerImpl::GetCardholderNameFieldLabel() + const { + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_CARDHOLDER_NAME_LABEL); +} + std::u16string VirtualCardManualFallbackBubbleControllerImpl::GetCvcFieldLabel() const { return l10n_util::GetStringUTF16(
diff --git a/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.h b/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.h index b7a99eb..63b3e01b 100644 --- a/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.h +++ b/chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.h
@@ -45,6 +45,7 @@ std::u16string GetBubbleTitle() const override; std::u16string GetVirtualCardNumberFieldLabel() const override; std::u16string GetExpirationDateFieldLabel() const override; + std::u16string GetCardholderNameFieldLabel() const override; std::u16string GetCvcFieldLabel() const override; std::u16string GetCvc() const override; const CreditCard* GetVirtualCard() const override;
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm index 99fccbc..08ad7c2f 100644 --- a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm +++ b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
@@ -19,6 +19,7 @@ #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/sessions/chrome_tab_restore_service_client.h" #include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" +#include "chrome/common/chrome_features.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_profile.h" #include "components/favicon_base/favicon_types.h" @@ -169,6 +170,10 @@ bridge_->CancelFaviconRequest(item); } + bool ShouldMenuItemBeVisible(NSMenuItem* item) { + return bridge_->ShouldMenuItemBeVisible(item); + } + const std::map<NSMenuItem*, std::unique_ptr<HistoryMenuBridge::HistoryItem>>& menu_item_map() { return bridge_->menu_item_map_; @@ -178,6 +183,45 @@ std::unique_ptr<MockBridge> bridge_; }; +void CheckMenuItemVisibility(HistoryMenuBridgeTest* test, bool is_incognito) { + // Make sure the items belong to both original and incognito mode are visible. + NSInteger always_visible_items[] = {IDC_HOME, IDC_BACK, IDC_FORWARD}; + for (size_t i = 0; i < base::size(always_visible_items); i++) { + // Create a fake item with tag. + base::scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc] init]); + item.get().tag = always_visible_items[i]; + EXPECT_TRUE(test->ShouldMenuItemBeVisible(item)); + } + + // Check visibilty of items belong to regular mode. They should be visible for + // regular mode, not for incognito mode. + NSInteger regular_visible_items[] = { + HistoryMenuBridge::kRecentlyClosedSeparator, + HistoryMenuBridge::kRecentlyClosedTitle, + HistoryMenuBridge::kVisitedSeparator, + HistoryMenuBridge::kVisitedTitle, + HistoryMenuBridge::kShowFullSeparator, + IDC_SHOW_HISTORY}; + for (size_t i = 0; i < base::size(regular_visible_items); i++) { + // Create a fake item with tag. + base::scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc] init]); + item.get().tag = regular_visible_items[i]; + EXPECT_EQ(!is_incognito, test->ShouldMenuItemBeVisible(item)); + } + + // Check visibilty of items belong to incognito mode. They should be visible + // for incognito mode, not for regular mode. + NSInteger incognito_visible_items[] = { + HistoryMenuBridge::kIncognitoDisclaimerSeparator, + HistoryMenuBridge::kIncognitoDisclaimerLabel}; + for (size_t i = 0; i < base::size(incognito_visible_items); i++) { + // Create a fake item with tag. + base::scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc] init]); + item.get().tag = incognito_visible_items[i]; + EXPECT_EQ(is_incognito, test->ShouldMenuItemBeVisible(item)); + } +} + // Edge case test for clearing until the end of a menu. TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuUntilEnd) { NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease]; @@ -495,4 +539,16 @@ EXPECT_TRUE([item.menu_item image]); } +TEST_F(HistoryMenuBridgeTest, MenuItemVisibilityForRegularMode) { + CheckMenuItemVisibility(this, false); +} + +TEST_F(HistoryMenuBridgeTest, MenuItemVisibilityForIncognitoMode) { + base::test::ScopedFeatureList scoped_feature_list( + features::kUpdateHistoryEntryPointsInIncognito); + bridge_ = std::make_unique<MockBridge>( + profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true)); + CheckMenuItemVisibility(this, true); +} + } // namespace
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc index bf618dd9..c67ac08 100644 --- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc +++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -36,6 +36,7 @@ #include "extensions/common/extension.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/image/image_skia.h" #include "url/gurl.h" @@ -68,7 +69,7 @@ return false; } -gfx::ImageSkia HostedAppBrowserController::GetWindowAppIcon() const { +ui::ImageModel HostedAppBrowserController::GetWindowAppIcon() const { // TODO(calamity): Use the app name to retrieve the app icon without using the // extensions tab helper to make icon load more immediate. #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -76,7 +77,7 @@ apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile( browser()->profile())) { if (!app_icon_.isNull()) - return app_icon_; + return ui::ImageModel::FromImageSkia(app_icon_); const Extension* extension = GetExtension(); if (extension && @@ -104,14 +105,15 @@ if (!icon_bitmap) return GetFallbackAppIcon(); - return gfx::ImageSkia::CreateFrom1xBitmap(*icon_bitmap); + return ui::ImageModel::FromImageSkia( + gfx::ImageSkia::CreateFrom1xBitmap(*icon_bitmap)); } -gfx::ImageSkia HostedAppBrowserController::GetWindowIcon() const { +ui::ImageModel HostedAppBrowserController::GetWindowIcon() const { if (IsWebApp(browser())) return GetWindowAppIcon(); - return browser()->GetCurrentPageIcon().AsImageSkia(); + return ui::ImageModel::FromImage(browser()->GetCurrentPageIcon()); } absl::optional<SkColor> HostedAppBrowserController::GetThemeColor() const {
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.h b/chrome/browser/ui/extensions/hosted_app_browser_controller.h index 0c4976e5e..c9e2415 100644 --- a/chrome/browser/ui/extensions/hosted_app_browser_controller.h +++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
@@ -36,8 +36,8 @@ // web_app::AppBrowserController: bool HasMinimalUiButtons() const override; - gfx::ImageSkia GetWindowAppIcon() const override; - gfx::ImageSkia GetWindowIcon() const override; + ui::ImageModel GetWindowAppIcon() const override; + ui::ImageModel GetWindowIcon() const override; absl::optional<SkColor> GetThemeColor() const override; std::u16string GetTitle() const override; std::u16string GetAppShortName() const override;
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc index e8f466b3..85f8099 100644 --- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc +++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -88,6 +88,7 @@ #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" #include "third_party/blink/public/common/switches.h" #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" +#include "ui/views/image_model_utils.h" using content::RenderFrameHost; using content::WebContents; @@ -481,7 +482,8 @@ app_service_test().LoadAppIconBlocking( apps::mojom::AppType::kExtension, app_id_, extension_misc::EXTENSION_ICON_SMALL), - app_browser_->app_controller()->GetWindowAppIcon())); + views::GetImageSkiaFromImageModel( + app_browser_->app_controller()->GetWindowAppIcon(), nullptr))); } #endif
diff --git a/chrome/browser/ui/manifest_web_app_browser_controller.cc b/chrome/browser/ui/manifest_web_app_browser_controller.cc index cc94834..f87fc5455 100644 --- a/chrome/browser/ui/manifest_web_app_browser_controller.cc +++ b/chrome/browser/ui/manifest_web_app_browser_controller.cc
@@ -13,6 +13,7 @@ #include "extensions/common/constants.h" #include "services/network/public/cpp/is_potentially_trustworthy.h" #include "third_party/blink/public/common/manifest/manifest.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/favicon_size.h" #include "ui/gfx/image/image_skia.h" #include "url/gurl.h" @@ -53,21 +54,22 @@ return false; } -gfx::ImageSkia ManifestWebAppBrowserController::GetWindowAppIcon() const { - gfx::ImageSkia page_icon = browser()->GetCurrentPageIcon().AsImageSkia(); - if (!page_icon.isNull()) - return page_icon; +ui::ImageModel ManifestWebAppBrowserController::GetWindowAppIcon() const { + gfx::Image page_icon = browser()->GetCurrentPageIcon(); + if (!page_icon.IsEmpty()) + return ui::ImageModel::FromImage(page_icon); // The extension icon may be loading still. Return a transparent icon rather // than using a placeholder to avoid flickering. SkBitmap bitmap; bitmap.allocN32Pixels(gfx::kFaviconSize, gfx::kFaviconSize); bitmap.eraseColor(SK_ColorTRANSPARENT); - return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + return ui::ImageModel::FromImageSkia( + gfx::ImageSkia::CreateFrom1xBitmap(bitmap)); } -gfx::ImageSkia ManifestWebAppBrowserController::GetWindowIcon() const { - return browser()->GetCurrentPageIcon().AsImageSkia(); +ui::ImageModel ManifestWebAppBrowserController::GetWindowIcon() const { + return ui::ImageModel::FromImage(browser()->GetCurrentPageIcon()); } std::u16string ManifestWebAppBrowserController::GetAppShortName() const {
diff --git a/chrome/browser/ui/manifest_web_app_browser_controller.h b/chrome/browser/ui/manifest_web_app_browser_controller.h index 8cc0471..4bf9edc 100644 --- a/chrome/browser/ui/manifest_web_app_browser_controller.h +++ b/chrome/browser/ui/manifest_web_app_browser_controller.h
@@ -22,10 +22,6 @@ struct Manifest; } -namespace gfx { -class ImageSkia; -} - // Class to encapsulate logic to control the browser UI for manifest based web // apps or focus mode. class ManifestWebAppBrowserController : public web_app::AppBrowserController { @@ -36,8 +32,8 @@ // web_app::AppBrowserController: bool HasMinimalUiButtons() const override; bool ShouldShowCustomTabBar() const override; - gfx::ImageSkia GetWindowAppIcon() const override; - gfx::ImageSkia GetWindowIcon() const override; + ui::ImageModel GetWindowAppIcon() const override; + ui::ImageModel GetWindowIcon() const override; std::u16string GetAppShortName() const override; std::u16string GetFormattedUrlOrigin() const override; GURL GetAppStartUrl() const override;
diff --git a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc index 2a30ffc..ce8f4c0 100644 --- a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc +++ b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc
@@ -8,6 +8,7 @@ #include "base/callback.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h" DiceWebSigninInterceptorDelegate::DiceWebSigninInterceptorDelegate() = default; @@ -31,3 +32,24 @@ Browser* browser) { ShowProfileCustomizationBubbleInternal(browser); } + +void DiceWebSigninInterceptorDelegate::ShowEnterpriseProfileInterceptionDialog( + const std::string& email, + base::OnceCallback<void(bool)> callback, + Browser* browser) { + // TODO (crbug/1163117): Replace this temporary solution with the spaces + // enterprise welcome screen inside a dialog. + DiceTurnSyncOnHelper::Delegate::ShowEnterpriseAccountConfirmationForBrowser( + email, true, + base::BindOnce( + [](base::OnceCallback<void(bool)> callback, + DiceTurnSyncOnHelper::SigninChoice choice) { + std::move(callback).Run( + choice == DiceTurnSyncOnHelper::SigninChoice:: + SIGNIN_CHOICE_CONTINUE || + choice == DiceTurnSyncOnHelper::SigninChoice:: + SIGNIN_CHOICE_NEW_PROFILE); + }, + std::move(callback)), + browser); +}
diff --git a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h index b796032..1b0be3bd 100644 --- a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h +++ b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h
@@ -29,6 +29,11 @@ base::OnceCallback<void(SigninInterceptionResult)> callback) override; void ShowProfileCustomizationBubble(Browser* browser) override; + void ShowEnterpriseProfileInterceptionDialog( + const std::string& email, + base::OnceCallback<void(bool)> callback, + Browser* browser) override; + private: // Implemented in dice_web_signin_interception_bubble_view.cc std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle>
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc index 585d0a5..9506246 100644 --- a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc +++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
@@ -33,6 +33,9 @@ namespace { +// The OAuth token consumer name. +const char kOAuthConsumerName[] = "credential_provider_signin_dialog"; + #if BUILDFLAG(CAN_TEST_GCPW_SIGNIN_STARTUP) bool g_enable_gcpw_signin_during_tests = false; #endif // BUILDFLAG(CAN_TEST_GCPW_SIGNIN_STARTUP) @@ -125,7 +128,7 @@ // Create the fetcher and pass it to the callback so that it can be // deleted once it is finished. auto fetcher = std::make_unique<CredentialProviderSigninInfoFetcher>( - refresh_token, url_loader_factory); + refresh_token, kOAuthConsumerName, url_loader_factory); auto* const fetcher_ptr = fetcher.get(); fetcher_ptr->SetCompletionCallbackAndStart( access_token, additional_mdm_oauth_scopes,
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc index 9dead78c..23facc80 100644 --- a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc +++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc
@@ -21,8 +21,10 @@ CredentialProviderSigninInfoFetcher::CredentialProviderSigninInfoFetcher( const std::string& refresh_token, + const std::string& consumer_name, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) - : scoped_access_token_fetcher_( + : consumer_name_(consumer_name), + scoped_access_token_fetcher_( GaiaAccessTokenFetcher:: CreateExchangeRefreshTokenForAccessTokenInstance( this, @@ -112,6 +114,10 @@ WriteResultsIfFinished(true); } +std::string CredentialProviderSigninInfoFetcher::GetConsumerName() const { + return consumer_name_; +} + void CredentialProviderSigninInfoFetcher::RequestUserInfoFromAccessToken( const std::string& access_token) { user_info_fetcher_->GetUserInfo(access_token, 0, this);
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h index e5ed5de..7fef058 100644 --- a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h +++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h
@@ -40,6 +40,7 @@ CredentialProviderSigninInfoFetcher( const std::string& refresh_token, + const std::string& consumer_name, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); CredentialProviderSigninInfoFetcher( const CredentialProviderSigninInfoFetcher&) = delete; @@ -63,6 +64,7 @@ // OAuth2AccessTokenConsumer: void OnGetTokenSuccess(const TokenResponse& token_response) override; void OnGetTokenFailure(const GoogleServiceAuthError& error) override; + std::string GetConsumerName() const override; protected: void RequestUserInfoFromAccessToken(const std::string& access_token); @@ -77,6 +79,7 @@ std::string picture_url_; std::string mdm_id_token_; std::string mdm_access_token_; + const std::string consumer_name_; std::unique_ptr<OAuth2AccessTokenFetcher> scoped_access_token_fetcher_; std::unique_ptr<gaia::GaiaOAuthClient> user_info_fetcher_;
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc index 2b3aaf6..532e7c8a 100644 --- a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc +++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc
@@ -134,8 +134,10 @@ base::BindOnce(&CredentialProviderFetcherTest::OnFetchComplete, base::Unretained(this), run_loop.QuitClosure()); - CredentialProviderSigninInfoFetcher fetcher(kRefreshTokenValue, - shared_factory()); + CredentialProviderSigninInfoFetcher fetcher( + kRefreshTokenValue, + /*consumer_name=*/"credential_provider_signin_info_fetcher_win_unittest", + shared_factory()); fetcher.SetCompletionCallbackAndStart( kAccessTokenValue, additional_oauth_scopes, std::move(fetcher_callback)); run_loop.Run();
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc index e5f8a590..acb00e7 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -108,6 +108,11 @@ #include "components/policy/core/common/policy_types.h" #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) +#include "chrome/browser/web_applications/components/app_registrar.h" +#include "chrome/browser/web_applications/components/app_registry_controller.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_registry_update.h" #include "ui/views/widget/any_widget_observer.h" #include "ui/views/widget/widget.h" #endif @@ -1923,6 +1928,11 @@ // Wait for app launch task to complete. content::RunAllTasksUntilIdle(); + // Check that we added this protocol to web app's approved_launch_protocols + // on accept. + web_app::AppRegistrar& registrar = provider()->registrar(); + EXPECT_TRUE(registrar.IsApprovedLaunchProtocol(app_id, "web+test")); + // Check for new app window. ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); Browser* app_browser; @@ -1968,6 +1978,67 @@ EXPECT_EQ(GURL(kStartUrl), web_contents->GetVisibleURL()); } +IN_PROC_BROWSER_TEST_F( + StartupBrowserWebAppProtocolHandlingTest, + WebAppLaunch_WebAppIsLaunchedWithApprovedProtocolUrlPref) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppProtocolHandlerIntentPickerView"); + // Register web app as a protocol handler that should handle the launch. + blink::Manifest::ProtocolHandler protocol_handler; + const std::string handler_url = std::string(kStartUrl) + "/testing=%s"; + protocol_handler.url = GURL(handler_url); + protocol_handler.protocol = u"web+test"; + web_app::AppId app_id = InstallWebAppWithProtocolHandlers({protocol_handler}); + + // Launch the browser via a command line with a handled protocol URL param. + SetUpCommandlineAndStart("web+test://parameterString", app_id); + + // The waiter will get the dialog when it shows up and accepts it. + waiter.WaitIfNeededAndGet()->CloseWithReason( + views::Widget::ClosedReason::kAcceptButtonClicked); + + // Wait for app launch task to complete and launches a new browser. + ui_test_utils::WaitForBrowserToOpen(); + + // Check that we added this protocol to web app's approved_launch_protocols + // on accept. + web_app::AppRegistrar& registrar = provider()->registrar(); + EXPECT_TRUE(registrar.IsApprovedLaunchProtocol(app_id, "web+test")); + + // Check the first app window is created. + ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); + Browser* app_browser1; + app_browser1 = FindOneOtherBrowser(browser()); + ASSERT_TRUE(app_browser1); + + // Launch the browser via a command line with an handled protocol URL + // param, but this time we expect the permission dialog to not show up. + SetUpCommandlineAndStart("web+test://parameterString", app_id); + + // Wait for app launch task to complete and launches a new browser. + ui_test_utils::WaitForBrowserToOpen(); + + // Check the second app window is launched directly this time. The dialog + // is skipped because we have the approved protocol scheme for the same + // app launch. + Browser* app_browser2; + // There should be 3 browser windows opened at the moment. + ASSERT_EQ(3u, chrome::GetBrowserCount(browser()->profile())); + for (auto* b : *BrowserList::GetInstance()) { + if (b != browser() && b != app_browser1) + app_browser2 = b; + } + ASSERT_TRUE(app_browser2); + EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser2, app_id)); + + // Check the app is launched with the correctly translated URL. + TabStripModel* tab_strip = app_browser2->tab_strip_model(); + ASSERT_EQ(1, tab_strip->count()); + content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); + EXPECT_EQ("https://test.com/testing=web%2Btest%3A%2F%2FparameterString", + web_contents->GetVisibleURL()); +} + #endif // defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) class StartupBrowserCreatorExtensionsCheckupExperimentTest
diff --git a/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc b/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc index e7c541e2..2d3a210 100644 --- a/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc +++ b/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc
@@ -24,9 +24,14 @@ #include "chrome/browser/profiles/scoped_profile_keep_alive.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/startup/startup_browser_creator.h" +#include "chrome/browser/web_applications/components/app_registrar.h" +#include "chrome/browser/web_applications/components/app_registry_controller.h" #include "chrome/browser/web_applications/components/os_integration_manager.h" #include "chrome/browser/web_applications/components/web_app_id.h" +#include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_registry_update.h" #include "chrome/common/chrome_switches.h" #include "components/keep_alive_registry/keep_alive_types.h" #include "components/keep_alive_registry/scoped_keep_alive.h" @@ -81,6 +86,18 @@ web_app::startup::FinalizeWebAppLaunchCallback callback, bool accepted) { if (accepted) { + web_app::WebAppProviderBase* provider = + web_app::WebAppProviderBase::GetProviderBase(profile); + { + web_app::ScopedRegistryUpdate update( + provider->registry_controller().AsWebAppSyncBridge()); + web_app::WebApp* app_to_update = update->UpdateApp(app_id); + std::vector<std::string> protocol_handlers( + app_to_update->approved_launch_protocols()); + protocol_handlers.push_back(protocol_url.scheme()); + app_to_update->SetApprovedLaunchProtocols( + std::move(protocol_handlers)); + } apps::AppServiceProxyFactory::GetForProfile(profile) ->BrowserAppLauncher() ->LaunchAppWithCallback(app_id, command_line, cur_dir, @@ -91,10 +108,16 @@ command_line, cur_dir, profile, protocol_url, app_id, std::move(finalize_callback)); - // ShowWebAppProtocolHandlerIntentPicker keeps the `profile` alive through - // running of `launch_callback`. - chrome::ShowWebAppProtocolHandlerIntentPicker(protocol_url, profile, app_id, - std::move(launch_callback)); + // Check if we have permission to launch the app directly. + web_app::AppRegistrar& registrar = provider->registrar(); + if (registrar.IsApprovedLaunchProtocol(app_id, protocol_url.scheme())) { + std::move(launch_callback).Run(true); + } else { + // ShowWebAppProtocolHandlerIntentPicker keeps the `profile` alive through + // running of `launch_callback`. + chrome::ShowWebAppProtocolHandlerIntentPicker(protocol_url, profile, app_id, + std::move(launch_callback)); + } } } // namespace
diff --git a/chrome/browser/ui/thumbnails/thumbnail_image.h b/chrome/browser/ui/thumbnails/thumbnail_image.h index 1246e70d..dfd37678 100644 --- a/chrome/browser/ui/thumbnails/thumbnail_image.h +++ b/chrome/browser/ui/thumbnails/thumbnail_image.h
@@ -13,7 +13,6 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/sequence_checker.h" #include "base/token.h" #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_dialog_view_browsertest.cc b/chrome/browser/ui/views/apps/app_dialog/app_dialog_view_browsertest.cc index ceccdfb30..931fa2b 100644 --- a/chrome/browser/ui/views/apps/app_dialog/app_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/apps/app_dialog/app_dialog_view_browsertest.cc
@@ -20,8 +20,8 @@ #include "chrome/browser/ui/views/apps/app_dialog/app_block_dialog_view.h" #include "chrome/browser/ui/views/apps/app_dialog/app_pause_dialog_view.h" #include "chrome/test/base/in_process_browser_test.h" -#include "components/arc/arc_util.h" #include "components/arc/mojom/app.mojom.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc index 22c6155..425d438 100644 --- a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc
@@ -25,7 +25,7 @@ #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/in_process_browser_test.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc index d0829fef..5ef8b44 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
@@ -25,6 +25,7 @@ #include "components/zoom/zoom_controller.h" #include "extensions/browser/app_window/app_delegate.h" #include "third_party/skia/include/core/SkRegion.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/skia_util.h" @@ -228,7 +229,7 @@ // views::WidgetDelegate implementation. -gfx::ImageSkia ChromeNativeAppWindowViews::GetWindowAppIcon() { +ui::ImageModel ChromeNativeAppWindowViews::GetWindowAppIcon() { // Resulting icon is cached in aura::client::kAppIconKey window property. const gfx::Image& custom_image = GetCustomImage(); if (app_window()->app_icon_url().is_valid() && @@ -246,30 +247,30 @@ gfx::ImageSkiaOperations::CreateResizedImage( base_image.AsImageSkia(), skia::ImageOperations::RESIZE_BEST, gfx::Size(large_icon_size, large_icon_size)); - return gfx::ImageSkiaOperations::CreateIconWithBadge( - resized_image, GetAppIconImage().AsImageSkia()); + return ui::ImageModel::FromImageSkia( + gfx::ImageSkiaOperations::CreateIconWithBadge( + resized_image, GetAppIconImage().AsImageSkia())); } - return gfx::ImageSkiaOperations::CreateIconWithBadge( - base_image.AsImageSkia(), GetAppIconImage().AsImageSkia()); + return ui::ImageModel::FromImageSkia( + gfx::ImageSkiaOperations::CreateIconWithBadge( + base_image.AsImageSkia(), GetAppIconImage().AsImageSkia())); } if (!custom_image.IsEmpty()) - return *custom_image.ToImageSkia(); + return ui::ImageModel::FromImage(custom_image); EnsureAppIconCreated(); - return GetAppIconImage().AsImageSkia(); + return ui::ImageModel::FromImage(GetAppIconImage()); } -gfx::ImageSkia ChromeNativeAppWindowViews::GetWindowIcon() { +ui::ImageModel ChromeNativeAppWindowViews::GetWindowIcon() { // Resulting icon is cached in aura::client::kWindowIconKey window property. content::WebContents* web_contents = app_window()->web_contents(); if (web_contents) { favicon::FaviconDriver* favicon_driver = favicon::ContentFaviconDriver::FromWebContents(web_contents); - gfx::Image app_icon = favicon_driver->GetFavicon(); - if (!app_icon.IsEmpty()) - return *app_icon.ToImageSkia(); + return ui::ImageModel::FromImage(favicon_driver->GetFavicon()); } - return gfx::ImageSkia(); + return ui::ImageModel(); } std::unique_ptr<views::NonClientFrameView>
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h index b2455be..782031f 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
@@ -11,10 +11,6 @@ #include "chrome/browser/extensions/chrome_app_icon_delegate.h" #include "extensions/components/native_app_window/native_app_window_views.h" -namespace gfx { -class ImageSkia; -} - class ExtensionKeybindingRegistryViews; class ChromeNativeAppWindowViews @@ -48,8 +44,8 @@ ui::ZOrderLevel GetZOrderLevel() const override; // WidgetDelegate implementation. - gfx::ImageSkia GetWindowAppIcon() override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowAppIcon() override; + ui::ImageModel GetWindowIcon() override; std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView( views::Widget* widget) override; bool WidgetHasHitTestMask() const override;
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc index 77500b0..6d8d7a46 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -39,6 +39,7 @@ #include "extensions/common/constants.h" #include "ui/aura/client/aura_constants.h" #include "ui/base/hit_test.h" +#include "ui/base/models/image_model.h" #include "ui/base/models/simple_menu_model.h" #include "ui/base/ui_base_types.h" #include "ui/display/screen.h" @@ -49,6 +50,7 @@ #include "ui/views/controls/menu/menu_model_adapter.h" #include "ui/views/controls/menu/menu_runner.h" #include "ui/views/controls/webview/webview.h" +#include "ui/views/image_model_utils.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/coordinate_conversion.h" @@ -173,14 +175,19 @@ return ChromeNativeAppWindowViewsAura::GetModalType(); } -gfx::ImageSkia ChromeNativeAppWindowViewsAuraAsh::GetWindowIcon() { +ui::ImageModel ChromeNativeAppWindowViewsAuraAsh::GetWindowIcon() { if (!base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) return ChromeNativeAppWindowViews::GetWindowIcon(); - const gfx::ImageSkia& image_skia = - ChromeNativeAppWindowViews::GetWindowIcon(); - return !image_skia.isNull() ? apps::CreateStandardIconImage(image_skia) - : gfx::ImageSkia(); + const ui::ImageModel& image = ChromeNativeAppWindowViews::GetWindowIcon(); + if (image.IsEmpty()) + return ui::ImageModel(); + + DCHECK(image.IsImage()); + const gfx::ImageSkia image_skia = + views::GetImageSkiaFromImageModel(image, nullptr); + return ui::ImageModel::FromImageSkia( + apps::CreateStandardIconImage(image_skia)); } bool ChromeNativeAppWindowViewsAuraAsh::ShouldRemoveStandardFrame() {
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h index 81fd017..b42711ee 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
@@ -83,7 +83,7 @@ std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView( views::Widget* widget) override; ui::ModalType GetModalType() const override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; // NativeAppWindow: void SetFullscreen(int fullscreen_types) override;
diff --git a/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc b/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc index 00c8ad94..71e09613 100644 --- a/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc
@@ -22,8 +22,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/test/base/in_process_browser_test.h" -#include "components/arc/arc_util.h" #include "components/arc/mojom/app.mojom.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.cc index ca57053..55e2680f 100644 --- a/chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.cc +++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.cc
@@ -18,6 +18,7 @@ #include "components/vector_icons/vector_icons.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" namespace autofill { @@ -122,7 +123,9 @@ // Fade out inkdrop but only if icon was actually highlighted. Calling // SetHighlighted() can result in a spurious fade-out animation and visual // glitches. - if (this->ink_drop()->GetHighlighted()) + // TODO(pbos): Fix this and remove check. Calling SetHighlighted(false) with + // !GetHighighted() should be a no-op. + if (views::InkDrop::Get(this)->GetHighlighted()) SetHighlighted(false); // Handle corner cases where users navigate away or close the tab. UnpauseAnimation();
diff --git a/chrome/browser/ui/views/autofill/payments/migratable_card_view.cc b/chrome/browser/ui/views/autofill/payments/migratable_card_view.cc index 20b93163..ff600edf 100644 --- a/chrome/browser/ui/views/autofill/payments/migratable_card_view.cc +++ b/chrome/browser/ui/views/autofill/payments/migratable_card_view.cc
@@ -19,6 +19,7 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/checkbox.h" #include "ui/views/controls/button/image_button.h" @@ -121,7 +122,8 @@ // TODO(crbug/867194): Currently the ink drop animation circle is // cropped by the border of scroll bar view. Find a way to adjust the // format. - checkbox_->ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(checkbox_)->SetMode( + views::InkDropHost::InkDropMode::OFF); checkbox_->SetAssociatedLabel(card_description.get()); } break;
diff --git a/chrome/browser/ui/views/autofill/payments/virtual_card_manual_fallback_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/virtual_card_manual_fallback_bubble_views.cc index 2d211bf8..b22892fd 100644 --- a/chrome/browser/ui/views/autofill/payments/virtual_card_manual_fallback_bubble_views.cc +++ b/chrome/browser/ui/views/autofill/payments/virtual_card_manual_fallback_bubble_views.cc
@@ -115,6 +115,16 @@ controller_->GetVirtualCard()->Expiration4DigitYearAsString())); layout->AddView(std::move(expiry_row)); + // Adds a row for the cardholder name. + layout->StartRowWithPadding(views::GridLayout::kFixedSize, 0, + views::GridLayout::kFixedSize, + ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_UNRELATED_CONTROL_VERTICAL)); + layout->AddView( + CreateRowItemLabel(controller_->GetCardholderNameFieldLabel())); + layout->AddView(CreateRowItemButton( + controller_->GetVirtualCard()->GetRawInfo(CREDIT_CARD_NAME_FULL))); + // Adds a row for CVC. layout->StartRowWithPadding(views::GridLayout::kFixedSize, 0, views::GridLayout::kFixedSize,
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index ddebb0b..52dd015 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -103,6 +103,7 @@ #include "ui/resources/grit/ui_resources.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" @@ -332,7 +333,8 @@ // TODO(bruthig): The ACTION_PENDING triggering logic should be in // MenuButton::OnPressed() however there is a bug with the pressed state // logic in MenuButton. See http://crbug.com/567252. - ink_drop()->AnimateToState(views::InkDropState::ACTION_PENDING, &event); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::ACTION_PENDING, &event); } return BookmarkMenuButtonBase::OnMousePressed(event); }
diff --git a/chrome/browser/ui/views/bubble_menu_item_factory.cc b/chrome/browser/ui/views/bubble_menu_item_factory.cc index 6352886..0f6f898c8 100644 --- a/chrome/browser/ui/views/bubble_menu_item_factory.cc +++ b/chrome/browser/ui/views/bubble_menu_item_factory.cc
@@ -32,7 +32,7 @@ void OnThemeChanged() override { LabelButton::OnThemeChanged(); - ink_drop()->SetBaseColor(HoverButton::GetInkDropColor(this)); + views::InkDrop::Get(this)->SetBaseColor(HoverButton::GetInkDropColor(this)); } }; @@ -44,9 +44,9 @@ void ConfigureBubbleMenuItem(views::Button* button, int button_id) { // Items within a menu should not show focus rings. button->SetInstallFocusRingOnFocus(false); - button->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - button->ink_drop()->GetInkDrop()->SetShowHighlightOnFocus(true); - button->ink_drop()->GetInkDrop()->SetHoverHighlightFadeDuration( + views::InkDrop::Get(button)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(button)->GetInkDrop()->SetShowHighlightOnFocus(true); + views::InkDrop::Get(button)->GetInkDrop()->SetHoverHighlightFadeDuration( base::TimeDelta()); views::InstallRectHighlightPathGenerator(button); button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc index 9eabb1f..7448798 100644 --- a/chrome/browser/ui/views/download/download_item_view.cc +++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -85,6 +85,7 @@ #include "ui/native_theme/native_theme_color_id.h" #include "ui/native_theme/themed_vector_icon.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_host_view.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -141,13 +142,13 @@ explicit TransparentButton(DownloadItemView* parent) : Button(Button::PressedCallback()) { views::InstallRectHighlightPathGenerator(this); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); set_context_menu_controller(parent); // Button subclasses need to provide this because the default color is // kPlaceholderColor. In theory we could statically compute it in the // constructor but then it won't be correct after dark mode changes, and to // deal with that this class would have to observe NativeTheme and so on. - ink_drop()->SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](views::View* host) { // This button will be used like a LabelButton, so use the same // foreground base color as a label button.
diff --git a/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view.cc index 7067f2c..c2ac187 100644 --- a/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view.cc +++ b/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view.cc
@@ -211,11 +211,10 @@ } // override -gfx::ImageSkia ExtensionInstallFrictionDialogView::GetWindowIcon() { - return gfx::CreateVectorIcon( - vector_icons::kGppMaybeIcon, kWarningIconSize, - GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_AlertSeverityMedium)); +ui::ImageModel ExtensionInstallFrictionDialogView::GetWindowIcon() { + return ui::ImageModel::FromVectorIcon( + vector_icons::kGppMaybeIcon, + ui::NativeTheme::kColorId_AlertSeverityMedium, kWarningIconSize); } void ExtensionInstallFrictionDialogView::OnLearnMoreLinkClicked() {
diff --git a/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view.h b/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view.h index b4c1a94..54496205 100644 --- a/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view.h +++ b/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view.h
@@ -37,7 +37,7 @@ ExtensionInstallFrictionDialogView& operator=( const ExtensionInstallFrictionDialogView&) = delete; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; // Returns the parent web contents for the dialog. Returns nullptr if the web // contents have been destroyed.
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc index ae1ccd9..8579117 100644 --- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc +++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
@@ -37,6 +37,7 @@ #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/link.h" +#include "ui/views/image_model_utils.h" #include "ui/views/layout/box_layout.h" #if BUILDFLAG(ENABLE_DICE_SUPPORT) @@ -221,7 +222,7 @@ // Indent by the size of the icon. layout->set_inside_border_insets(gfx::Insets( 0, - GetWindowIcon().width() + + views::GetImageSkiaFromImageModel(GetWindowIcon(), nullptr).width() + provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL), 0, 0)); layout->set_cross_axis_alignment(
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_button.cc b/chrome/browser/ui/views/extensions/extensions_menu_button.cc index 955c484..efa0c5b 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_button.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_button.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/ui/views/hover_button_controller.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/button.h" #include "ui/views/style/typography.h" @@ -32,9 +33,9 @@ allow_pinning_(allow_pinning) { controller_->SetDelegate(this); // TODO(pbos): This currently inherits HoverButton, is this not a no-op? - // Also see call in OnThemeChanged() to ink_drop()->SetBaseColor which - // tries to do the same thing. - ink_drop()->SetBaseColorCallback(base::BindRepeating( + // Also see call in OnThemeChanged() to + // views::InkDrop::Get(this)->SetBaseColor which tries to do the same thing. + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](views::View* host) { return HoverButton::GetInkDropColor(host); }, this)); } @@ -52,7 +53,7 @@ void ExtensionsMenuButton::OnThemeChanged() { HoverButton::OnThemeChanged(); - ink_drop()->SetBaseColor(HoverButton::GetInkDropColor(this)); + views::InkDrop::Get(this)->SetBaseColor(HoverButton::GetInkDropColor(this)); } // ToolbarActionViewDelegateViews:
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc index c9996961..1714ebc 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
@@ -23,6 +23,7 @@ #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_host_view.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/menu_button_controller.h" @@ -124,7 +125,7 @@ ui::NativeTheme::kColorId_MenuIconColor)); if (pin_button_) - pin_button_->ink_drop()->SetBaseColor(icon_color); + views::InkDrop::Get(pin_button_)->SetBaseColor(icon_color); SetButtonIconWithColor(context_menu_button_, kBrowserToolsIcon, icon_color);
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc index 024c1cc..f98bbc05 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -399,10 +399,9 @@ ExtensionsMenuButtonHighlight) { LoadTestExtension("extensions/uitest/window_open"); ClickExtensionsMenuButton(); - EXPECT_EQ(BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->GetExtensionsButton() - ->ink_drop() + EXPECT_EQ(views::InkDrop::Get(BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->GetExtensionsButton()) ->GetInkDrop() ->GetTargetInkDropState(), views::InkDropState::ACTIVATED);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc index 012b7c92..87368524 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -44,6 +44,7 @@ #include "ui/base/hit_test.h" #include "ui/base/layout.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/display/screen.h" #include "ui/events/gestures/gesture_recognizer.h" #include "ui/gfx/canvas.h" @@ -522,9 +523,9 @@ return current_tab && current_tab->IsLoading(); } -gfx::ImageSkia BrowserNonClientFrameViewChromeOS::GetFaviconForTabIconView() { +ui::ImageModel BrowserNonClientFrameViewChromeOS::GetFaviconForTabIconView() { views::WidgetDelegate* delegate = frame()->widget_delegate(); - return delegate ? delegate->GetWindowIcon() : gfx::ImageSkia(); + return delegate ? delegate->GetWindowIcon() : ui::ImageModel(); } void BrowserNonClientFrameViewChromeOS::OnWindowDestroying( @@ -586,15 +587,12 @@ } void BrowserNonClientFrameViewChromeOS::OnImmersiveRevealEnded() { - // Ensure the caption button container receives events before the browser view - // by placing it higher in the z-order. - // [0] - FrameAnimatorView - // [1] - BrowserView - // [2] - FrameCaptionButtonContainerView - const int kCaptionButtonContainerIndex = 2; - AddChildViewAt(caption_button_container_, kCaptionButtonContainerIndex); + // Ensure the WebAppFrameToolbarView and FrameCaptionButtonContainerView + // receive events before the BrowserView by appending instead of inserting + // the child views. if (web_app_frame_toolbar()) - AddChildViewAt(web_app_frame_toolbar(), 0); + AddChildView(web_app_frame_toolbar()); + AddChildView(caption_button_container_); Layout(); }
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h index c65f4f83..a01d28aa 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
@@ -96,7 +96,7 @@ // TabIconViewModel: bool ShouldTabIconViewAnimate() const override; - gfx::ImageSkia GetFaviconForTabIconView() override; + ui::ImageModel GetFaviconForTabIconView() override; // aura::WindowObserver: void OnWindowDestroying(aura::Window* window) override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac_browsertest.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac_browsertest.mm index 986fe8d..13420615 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac_browsertest.mm +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac_browsertest.mm
@@ -5,6 +5,7 @@ #include "base/files/file_util.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/bind.h" #include "build/build_config.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -207,6 +208,10 @@ " -webkit-app-region: drag;" " height: 100px;" " width: 100px;" + " padding-left: env(titlebar-area-x);" + " padding-right: env(titlebar-area-width);" + " padding-top: env(titlebar-area-y);" + " padding-bottom: env(titlebar-area-height);" " }" "</style>" "<div id=target></div>"; @@ -264,6 +269,75 @@ DCHECK(web_app_frame_toolbar_->GetVisible()); } + void RunCallbackAndWaitForGeometryChangeEvent( + base::OnceCallback<void()> callback) { + auto* web_contents = browser_view_->GetActiveWebContents(); + EXPECT_TRUE( + ExecJs(web_contents->GetMainFrame(), + "geometrychangeCount = 0;" + "document.title = 'beforegeometrychange';" + "navigator.windowControlsOverlay.ongeometrychange = (e) => {" + " geometrychangeCount++;" + " overlay_rect_from_event = e.boundingRect;" + " overlay_visible_from_event = e.visible;" + " document.title = 'ongeometrychange';" + "}")); + + std::move(callback).Run(); + content::TitleWatcher title_watcher(web_contents, u"ongeometrychange"); + ignore_result(title_watcher.WaitAndGetTitle()); + } + + void ToggleWindowControlsOverlayEnabledAndWait() { + RunCallbackAndWaitForGeometryChangeEvent(base::BindLambdaForTesting( + [this]() { browser_view_->ToggleWindowControlsOverlayEnabled(); })); + } + + void ResizeWindowBoundsAndWait(const gfx::Rect& new_bounds) { + // Changing the width of widget should trigger a "geometrychange" event. + EXPECT_NE(new_bounds.width(), browser_view_->GetLocalBounds().width()); + RunCallbackAndWaitForGeometryChangeEvent(base::BindLambdaForTesting( + [&]() { browser_view_->GetWidget()->SetBounds(new_bounds); })); + } + + gfx::Rect GetWindowControlOverlayBoundingClientRectFromEvent() { + auto* web_contents = browser_view_->GetActiveWebContents(); + return gfx::Rect( + EvalJs(web_contents, "overlay_rect_from_event.x").ExtractInt(), + EvalJs(web_contents, "overlay_rect_from_event.y").ExtractInt(), + EvalJs(web_contents, "overlay_rect_from_event.width").ExtractInt(), + EvalJs(web_contents, "overlay_rect_from_event.height").ExtractInt()); + } + + gfx::Rect GetWindowControlOverlayBoundingClientRect() { + auto* web_contents = browser_view_->GetActiveWebContents(); + return gfx::Rect( + EvalJs(web_contents, + "navigator.windowControlsOverlay.getBoundingClientRect().x") + .ExtractInt(), + EvalJs(web_contents, + "navigator.windowControlsOverlay.getBoundingClientRect().y") + .ExtractInt(), + EvalJs(web_contents, + "navigator.windowControlsOverlay.getBoundingClientRect().width") + .ExtractInt(), + EvalJs(web_contents, + "navigator.windowControlsOverlay.getBoundingClientRect().height") + .ExtractInt()); + } + + bool GetWindowControlOverlayVisibility() { + auto* web_contents = browser_view_->GetActiveWebContents(); + return EvalJs(web_contents, + "window.navigator.windowControlsOverlay.visible") + .ExtractBool(); + } + + bool GetWindowControlOverlayVisibilityFromEvent() { + auto* web_contents = browser_view_->GetActiveWebContents(); + return EvalJs(web_contents, "overlay_visible_from_event").ExtractBool(); + } + Browser* app_browser_ = nullptr; BrowserView* browser_view_ = nullptr; BrowserNonClientFrameViewMac* frame_view_ = nullptr; @@ -278,71 +352,95 @@ WindowControlsOverlay) { InstallAndLaunchWebAppWithWindowControlsOverlay(); - browser_view_->ToggleWindowControlsOverlayEnabled(); - static_cast<views::View*>(frame_view_)->Layout(); - auto* web_contents = frame_view_->browser_view()->GetActiveWebContents(); + // Toggle overlay on, and validate JS API reflects the expected + // values. + ToggleWindowControlsOverlayEnabledAndWait(); - // window controls overlay should be not be an empty rect and visible as this - // a web app. + gfx::Rect bounds = GetWindowControlOverlayBoundingClientRect(); + EXPECT_TRUE(GetWindowControlOverlayVisibility()); + EXPECT_NE(0, bounds.x()); + EXPECT_EQ(0, bounds.y()); + EXPECT_FALSE(bounds.IsEmpty()); - EXPECT_EQ(true, EvalJs(web_contents, - "window.navigator.windowControlsOverlay.visible")); - - EXPECT_NE( - 0, EvalJs(web_contents, - "navigator.windowControlsOverlay.getBoundingClientRect().x")); - EXPECT_EQ( - 0, EvalJs(web_contents, - "navigator.windowControlsOverlay.getBoundingClientRect().y")); - EXPECT_NE( - 0, - EvalJs(web_contents, - "navigator.windowControlsOverlay.getBoundingClientRect().width")); - EXPECT_NE( - 0, - EvalJs(web_contents, - "navigator.windowControlsOverlay.getBoundingClientRect().height")); + // Toggle overlay off, and validate JS API reflects the expected + // values. + ToggleWindowControlsOverlayEnabledAndWait(); + bounds = GetWindowControlOverlayBoundingClientRect(); + EXPECT_FALSE(GetWindowControlOverlayVisibility()); + EXPECT_EQ(gfx::Rect(), bounds); } IN_PROC_BROWSER_TEST_F(WebAppBrowserFrameViewMacWindowControlsOverlayTest, GeometryChangeEvent) { InstallAndLaunchWebAppWithWindowControlsOverlay(); + ToggleWindowControlsOverlayEnabledAndWait(); - browser_view_->ToggleWindowControlsOverlayEnabled(); - auto* web_contents = frame_view_->browser_view()->GetActiveWebContents(); + // Store the initial bounding client rect for comparison later. + const gfx::Rect initial_js_overlay_bounds = + GetWindowControlOverlayBoundingClientRect(); + gfx::Rect new_bounds = browser_view_->GetLocalBounds(); + new_bounds.set_width(new_bounds.width() - 1); + ResizeWindowBoundsAndWait(new_bounds); - EXPECT_TRUE(ExecuteScript( - web_contents->GetMainFrame(), - "geometrychangeCount = 0;" + // Validate both the event payload and JS bounding client rect reflect + // the new size. + const gfx::Rect resized_js_overlay_bounds = + GetWindowControlOverlayBoundingClientRect(); + const gfx::Rect resized_js_overlay_event_bounds = + GetWindowControlOverlayBoundingClientRectFromEvent(); + EXPECT_EQ( + 1, EvalJs(browser_view_->GetActiveWebContents(), "geometrychangeCount")); + EXPECT_TRUE(GetWindowControlOverlayVisibility()); + EXPECT_TRUE(GetWindowControlOverlayVisibilityFromEvent()); + EXPECT_EQ(resized_js_overlay_bounds, resized_js_overlay_event_bounds); + EXPECT_EQ(initial_js_overlay_bounds.origin(), + resized_js_overlay_bounds.origin()); + EXPECT_NE(initial_js_overlay_bounds.width(), + resized_js_overlay_bounds.width()); + EXPECT_EQ(initial_js_overlay_bounds.height(), + resized_js_overlay_bounds.height()); +} + +IN_PROC_BROWSER_TEST_F(WebAppBrowserFrameViewMacWindowControlsOverlayTest, + NoGeometryChangeEventIfOverlayIsOff) { + InstallAndLaunchWebAppWithWindowControlsOverlay(); + + const char kTestScript[] = + "document.title = 'beforeevent';" "navigator.windowControlsOverlay.ongeometrychange = (e) => {" - " geometrychangeCount++;" - " rect = e.boundingRect;" - " visible = e.visible;" - "}")); + " document.title = 'ongeometrychange';" + "};" + "window.onresize = (e) => {" + " document.title = 'onresize';" + "};"; - // Change size of widget to trigger a "geometrychange" event. - gfx::Rect bounds = browser_view_->GetLocalBounds(); - bounds.set_width(bounds.width() - 1); - browser_view_->GetWidget()->SetBounds(bounds); + // Window Control Overlay is off by default. + auto* web_contents = browser_view_->GetActiveWebContents(); + gfx::Rect new_bounds = browser_view_->GetLocalBounds(); + new_bounds.set_width(new_bounds.width() + 10); + EXPECT_TRUE(ExecJs(web_contents->GetMainFrame(), kTestScript)); + browser_view_->GetWidget()->SetBounds(new_bounds); + content::TitleWatcher title_watcher(web_contents, u"onresize"); + title_watcher.AlsoWaitForTitle(u"ongeometrychange"); + EXPECT_EQ(u"onresize", title_watcher.WaitAndGetTitle()); - // Window controls overlay should be not be an empty rect and visible as this - // is a web app. + // Toggle Window Control Ovleray on and then off. + ToggleWindowControlsOverlayEnabledAndWait(); + ToggleWindowControlsOverlayEnabledAndWait(); - // expect the "geometrychange" event to have fired. - EXPECT_NE(0, EvalJs(web_contents, "geometrychangeCount")); - - // Validate event payload. - EXPECT_EQ(true, EvalJs(web_contents, "visible")); - EXPECT_NE(0, EvalJs(web_contents, "rect.width")); - EXPECT_NE(0, EvalJs(web_contents, "rect.height")); + // Validate event is not fired. + new_bounds.set_width(new_bounds.width() - 10); + EXPECT_TRUE(ExecJs(web_contents->GetMainFrame(), kTestScript)); + browser_view_->GetWidget()->SetBounds(new_bounds); + content::TitleWatcher title_watcher2(web_contents, u"onresize"); + title_watcher2.AlsoWaitForTitle(u"ongeometrychange"); + EXPECT_EQ(u"onresize", title_watcher2.WaitAndGetTitle()); } IN_PROC_BROWSER_TEST_F(WebAppBrowserFrameViewMacWindowControlsOverlayTest, WindowControlsOverlayDraggableRegions) { InstallAndLaunchWebAppWithWindowControlsOverlay(); - - browser_view_->ToggleWindowControlsOverlayEnabled(); - static_cast<views::View*>(frame_view_)->Layout(); + ToggleWindowControlsOverlayEnabledAndWait(); constexpr gfx::Point kPoint(50, 50); EXPECT_EQ(frame_view_->NonClientHitTest(kPoint), HTCAPTION); @@ -351,6 +449,150 @@ } IN_PROC_BROWSER_TEST_F(WebAppBrowserFrameViewMacWindowControlsOverlayTest, + WindowControlsOverlayRTL) { + base::i18n::SetICUDefaultLocale("ar"); + ASSERT_TRUE(base::i18n::IsRTL()); + InstallAndLaunchWebAppWithWindowControlsOverlay(); + ToggleWindowControlsOverlayEnabledAndWait(); + + const gfx::Rect bounds = GetWindowControlOverlayBoundingClientRect(); + EXPECT_TRUE(GetWindowControlOverlayVisibility()); + EXPECT_NE(0, bounds.x()); + EXPECT_EQ(0, bounds.y()); + EXPECT_FALSE(bounds.IsEmpty()); +} + +IN_PROC_BROWSER_TEST_F(WebAppBrowserFrameViewMacWindowControlsOverlayTest, + CSSRectTestLTR) { + InstallAndLaunchWebAppWithWindowControlsOverlay(); + ToggleWindowControlsOverlayEnabledAndWait(); + + constexpr char kTestScript[] = + "var element = document.getElementById('target');" + "var titlebarAreaX = " + " getComputedStyle(element).getPropertyValue('padding-left');" + "var titlebarAreaXInt = parseInt(titlebarAreaX.split('px')[0]);" + "var titlebarAreaY = " + " getComputedStyle(element).getPropertyValue('padding-top');" + "var titlebarAreaYInt = parseInt(titlebarAreaY.split('px')[0]);" + "var titlebarAreaWidthRect = " + " getComputedStyle(element).getPropertyValue('padding-right');" + "var titlebarAreaWidthRectInt = " + " parseInt(titlebarAreaWidthRect.split('px')[0]);" + "var titlebarAreaHeightRect = " + " getComputedStyle(element).getPropertyValue('padding-bottom');" + "var titlebarAreaHeightRectInt = " + " parseInt(titlebarAreaHeightRect.split('px')[0]);"; + + auto* web_contents = browser_view_->GetActiveWebContents(); + EXPECT_TRUE(ExecuteScript(web_contents->GetMainFrame(), kTestScript)); + + const int initial_x_value = + EvalJs(web_contents, "titlebarAreaXInt").ExtractInt(); + const int initial_y_value = + EvalJs(web_contents, "titlebarAreaYInt").ExtractInt(); + const int initial_width_value = + EvalJs(web_contents, "titlebarAreaWidthRectInt").ExtractInt(); + const int initial_height_value = + EvalJs(web_contents, "titlebarAreaHeightRectInt").ExtractInt(); + + EXPECT_NE(0, initial_x_value); + EXPECT_EQ(0, initial_y_value); + EXPECT_NE(0, initial_width_value); + EXPECT_NE(0, initial_height_value); + + // Change bounds so new values get sent. + gfx::Rect new_bounds = browser_view_->GetLocalBounds(); + new_bounds.set_width(new_bounds.width() + 20); + new_bounds.set_height(new_bounds.height() + 20); + ResizeWindowBoundsAndWait(new_bounds); + + EXPECT_TRUE(ExecuteScript(web_contents->GetMainFrame(), kTestScript)); + + const int updated_x_value = + EvalJs(web_contents, "titlebarAreaXInt").ExtractInt(); + const int updated_y_value = + EvalJs(web_contents, "titlebarAreaYInt").ExtractInt(); + const int updated_width_value = + EvalJs(web_contents, "titlebarAreaWidthRectInt").ExtractInt(); + const int updated_height_value = + EvalJs(web_contents, "titlebarAreaHeightRectInt").ExtractInt(); + + // Changing the window dimensions should only change the overlay width. The + // overlay height should remain the same. + EXPECT_EQ(initial_x_value, updated_x_value); + EXPECT_EQ(initial_y_value, updated_y_value); + EXPECT_NE(initial_width_value, updated_width_value); + EXPECT_EQ(initial_height_value, updated_height_value); +} + +IN_PROC_BROWSER_TEST_F(WebAppBrowserFrameViewMacWindowControlsOverlayTest, + CSSRectTestRTL) { + base::i18n::SetICUDefaultLocale("ar"); + ASSERT_TRUE(base::i18n::IsRTL()); + InstallAndLaunchWebAppWithWindowControlsOverlay(); + ToggleWindowControlsOverlayEnabledAndWait(); + + constexpr char kTestScript[] = + "var element = document.getElementById('target');" + "var titlebarAreaX = " + " getComputedStyle(element).getPropertyValue('padding-left');" + "var titlebarAreaXInt = parseInt(titlebarAreaX.split('px')[0]);" + "var titlebarAreaY = " + " getComputedStyle(element).getPropertyValue('padding-top');" + "var titlebarAreaYInt = parseInt(titlebarAreaY.split('px')[0]);" + "var titlebarAreaWidthRect = " + " getComputedStyle(element).getPropertyValue('padding-right');" + "var titlebarAreaWidthRectInt = " + " parseInt(titlebarAreaWidthRect.split('px')[0]);" + "var titlebarAreaHeightRect = " + " getComputedStyle(element).getPropertyValue('padding-bottom');" + "var titlebarAreaHeightRectInt = " + " parseInt(titlebarAreaHeightRect.split('px')[0]);"; + + auto* web_contents = browser_view_->GetActiveWebContents(); + EXPECT_TRUE(ExecuteScript(web_contents->GetMainFrame(), kTestScript)); + + const int initial_x_value = + EvalJs(web_contents, "titlebarAreaXInt").ExtractInt(); + const int initial_y_value = + EvalJs(web_contents, "titlebarAreaYInt").ExtractInt(); + const int initial_width_value = + EvalJs(web_contents, "titlebarAreaWidthRectInt").ExtractInt(); + const int initial_height_value = + EvalJs(web_contents, "titlebarAreaHeightRectInt").ExtractInt(); + + EXPECT_NE(0, initial_x_value); + EXPECT_EQ(0, initial_y_value); + EXPECT_NE(0, initial_width_value); + EXPECT_NE(0, initial_height_value); + + // Change bounds so new values get sent. + gfx::Rect new_bounds = browser_view_->GetLocalBounds(); + new_bounds.set_width(new_bounds.width() + 15); + new_bounds.set_height(new_bounds.height() + 15); + ResizeWindowBoundsAndWait(new_bounds); + + EXPECT_TRUE(ExecuteScript(web_contents->GetMainFrame(), kTestScript)); + + const int updated_x_value = + EvalJs(web_contents, "titlebarAreaXInt").ExtractInt(); + const int updated_y_value = + EvalJs(web_contents, "titlebarAreaYInt").ExtractInt(); + const int updated_width_value = + EvalJs(web_contents, "titlebarAreaWidthRectInt").ExtractInt(); + const int updated_height_value = + EvalJs(web_contents, "titlebarAreaHeightRectInt").ExtractInt(); + + // Changing the window dimensions should only change the overlay width. The + // overlay height should remain the same. + EXPECT_EQ(initial_x_value, updated_x_value); + EXPECT_EQ(initial_y_value, updated_y_value); + EXPECT_NE(initial_width_value, updated_width_value); + EXPECT_EQ(initial_height_value, updated_height_value); +} + +IN_PROC_BROWSER_TEST_F(WebAppBrowserFrameViewMacWindowControlsOverlayTest, ToggleWindowControlsOverlay) { InstallAndLaunchWebAppWithWindowControlsOverlay(); @@ -367,7 +609,7 @@ ->app_controller() ->AppUsesWindowControlsOverlay()); - // Toggle WCO off, and verify that the app returns to 'standalone' mode + // Toggle WCO off, and verify that the app returns to 'standalone' mode. browser_view_->ToggleWindowControlsOverlayEnabled(); EXPECT_FALSE(browser_view_->IsWindowControlsOverlayEnabled()); EXPECT_TRUE(browser_view_->browser()
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index cad9e986..d6090ad 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -187,6 +187,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/theme_provider.h" #include "ui/base/window_open_disposition.h" @@ -2502,15 +2503,15 @@ return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR); } -gfx::ImageSkia BrowserView::GetWindowAppIcon() { +ui::ImageModel BrowserView::GetWindowAppIcon() { web_app::AppBrowserController* app_controller = browser()->app_controller(); return app_controller ? app_controller->GetWindowAppIcon() : GetWindowIcon(); } -gfx::ImageSkia BrowserView::GetWindowIcon() { +ui::ImageModel BrowserView::GetWindowIcon() { // Use the default icon for devtools. if (browser_->is_type_devtools()) - return gfx::ImageSkia(); + return ui::ImageModel(); // Hosted apps always show their app icon. web_app::AppBrowserController* app_controller = browser()->app_controller(); @@ -2519,20 +2520,20 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - if (browser_->is_type_normal()) { - return rb.GetImageNamed(IDR_CHROME_APP_ICON_192).AsImageSkia(); - } + if (browser_->is_type_normal()) + return ui::ImageModel::FromImage(rb.GetImageNamed(IDR_CHROME_APP_ICON_192)); auto* window = GetNativeWindow(); int override_window_icon_resource_id = window ? window->GetProperty(kOverrideWindowIconResourceIdKey) : -1; if (override_window_icon_resource_id >= 0) - return rb.GetImageNamed(override_window_icon_resource_id).AsImageSkia(); + return ui::ImageModel::FromImage( + rb.GetImageNamed(override_window_icon_resource_id)); #endif if (browser_->deprecated_is_app() || browser_->is_type_popup()) - return browser_->GetCurrentPageIcon().AsImageSkia(); + return ui::ImageModel::FromImage(browser_->GetCurrentPageIcon()); - return gfx::ImageSkia(); + return ui::ImageModel(); } bool BrowserView::ExecuteWindowsCommand(int command_id) {
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 17968cd..25b8b82 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -537,8 +537,8 @@ std::u16string GetAccessibleWindowTitle() const override; views::View* GetInitiallyFocusedView() override; bool ShouldShowWindowTitle() const override; - gfx::ImageSkia GetWindowAppIcon() override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowAppIcon() override; + ui::ImageModel GetWindowIcon() override; bool ExecuteWindowsCommand(int command_id) override; std::string GetWindowName() const override; void SaveWindowPlacement(const gfx::Rect& bounds,
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc index 77c4319..f71373af 100644 --- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -44,6 +44,7 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/scoped_canvas.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/image_model_utils.h" #include "ui/views/win/hwnd_util.h" #include "ui/views/window/client_view.h" @@ -382,7 +383,7 @@ return current_tab && current_tab->IsLoading(); } -gfx::ImageSkia GlassBrowserFrameView::GetFaviconForTabIconView() { +ui::ImageModel GlassBrowserFrameView::GetFaviconForTabIconView() { DCHECK(ShouldShowWindowIcon(TitlebarType::kCustom)); return frame()->widget_delegate()->GetWindowIcon(); } @@ -797,7 +798,9 @@ HICON small_icon = nullptr; HICON big_icon = nullptr; - gfx::ImageSkia icon = browser_view()->GetWindowIcon(); + gfx::ImageSkia icon = views::GetImageSkiaFromImageModel( + browser_view()->GetWindowIcon(), GetNativeTheme()); + if (!icon.isNull()) { // Keep previous icons alive as long as they are referenced by the HWND. previous_small_icon = std::move(small_window_icon_);
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h index cb13795..517470d 100644 --- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h +++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
@@ -60,7 +60,7 @@ // TabIconViewModel: bool ShouldTabIconViewAnimate() const override; - gfx::ImageSkia GetFaviconForTabIconView() override; + ui::ImageModel GetFaviconForTabIconView() override; bool IsMaximized() const; bool IsWebUITabStrip() const;
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_chromeos_browsertest.cc index ba40ce4..d18909b 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_chromeos_browsertest.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_chromeos_browsertest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/ui/views/frame/immersive_mode_controller_chromeos.h" + #include "ash/public/cpp/test/shell_test_api.h" #include "base/macros.h" #include "base/test/test_mock_time_task_runner.h" @@ -14,7 +16,6 @@ #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h" #include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/ui/views/frame/immersive_mode_controller_chromeos.h" #include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" @@ -32,6 +33,7 @@ #include "net/cert/mock_cert_verifier.h" #include "ui/aura/client/aura_constants.h" #include "ui/events/base_event_utils.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/test/button_test_api.h" #include "ui/views/window/frame_caption_button.h" @@ -125,7 +127,7 @@ WebAppFrameToolbarView* container = frame_view->web_app_frame_toolbar_for_testing(); views::test::InkDropHostTestApi ink_drop_api( - container->GetAppMenuButton()->ink_drop()); + views::InkDrop::Get(container->GetAppMenuButton())); EXPECT_TRUE(container->GetContentSettingContainerForTesting()->layer()); EXPECT_EQ(views::InkDropHost::InkDropMode::ON, ink_drop_api.ink_drop_mode());
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc index 92e7e28..9c27f4f3 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -35,6 +35,7 @@ #include "ui/base/hit_test.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/base/theme_provider.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_list.h" @@ -378,11 +379,11 @@ return current_tab ? current_tab->IsLoading() : false; } -gfx::ImageSkia OpaqueBrowserFrameView::GetFaviconForTabIconView() { +ui::ImageModel OpaqueBrowserFrameView::GetFaviconForTabIconView() { views::WidgetDelegate* delegate = frame()->widget_delegate(); if (!delegate) { LOG(WARNING) << "delegate is null, returning safe default."; - return gfx::ImageSkia(); + return ui::ImageModel(); } return delegate->GetWindowIcon(); }
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h index e37eb5f..1db9c5d 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
@@ -83,7 +83,7 @@ // TabIconViewModel: bool ShouldTabIconViewAnimate() const override; - gfx::ImageSkia GetFaviconForTabIconView() override; + ui::ImageModel GetFaviconForTabIconView() override; // OpaqueBrowserFrameViewLayoutDelegate: bool ShouldShowWindowIcon() const override;
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc index 8772a0ad..5aecba9 100644 --- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc +++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -23,7 +23,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" -#include "ui/gfx/color_utils.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/image_button_factory.h" #include "ui/views/controls/highlight_path_generator.h" @@ -58,7 +58,8 @@ scroll_button->SetImageHorizontalAlignment( views::ImageButton::HorizontalAlignment::ALIGN_CENTER); scroll_button->SetHasInkDropActionOnClick(true); - scroll_button->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(scroll_button.get()) + ->SetMode(views::InkDropHost::InkDropMode::ON); scroll_button->SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY); scroll_button->SetPreferredSize(gfx::Size(28, 28)); views::HighlightPathGenerator::Install(
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.cc b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.cc index dec7eb6..12fd183b 100644 --- a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.cc +++ b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.cc
@@ -31,6 +31,7 @@ #include "ui/compositor/canvas_painter.h" #include "ui/compositor/layer.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/slide_out_controller.h" #include "ui/views/background.h" #include "ui/views/controls/button/image_button.h" @@ -397,7 +398,7 @@ UpdateDismissButtonIcon(); if (stop_cast_button_) { stop_cast_button_->SetEnabledTextColors(foreground_color_); - stop_cast_button_->ink_drop()->SetBaseColor(foreground_color_); + views::InkDrop::Get(stop_cast_button_)->SetBaseColor(foreground_color_); } } @@ -519,9 +520,10 @@ views::InstallRoundRectHighlightPathGenerator( stop_cast_button_, gfx::Insets(), kStopCastButtonStripSize.height() / 2); - stop_cast_button_->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(stop_cast_button_) + ->SetMode(views::InkDropHost::InkDropMode::ON); stop_cast_button_->SetHasInkDropActionOnClick(true); - stop_cast_button_->ink_drop()->SetBaseColor(foreground_color_); + views::InkDrop::Get(stop_cast_button_)->SetBaseColor(foreground_color_); stop_cast_button_->SetEnabledTextColors(foreground_color_); stop_cast_button_->SetFocusBehavior(FocusBehavior::ALWAYS); stop_cast_button_->SetBorder(views::CreatePaddedBorder(
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_device_entry_ui.cc b/chrome/browser/ui/views/global_media_controls/media_notification_device_entry_ui.cc index 3d0587bf..58fb7039 100644 --- a/chrome/browser/ui/views/global_media_controls/media_notification_device_entry_ui.cc +++ b/chrome/browser/ui/views/global_media_controls/media_notification_device_entry_ui.cc
@@ -77,10 +77,10 @@ subtitle(), icon_, foreground_color, background_color); SetFocusBehavior(views::View::FocusBehavior::ALWAYS); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - ink_drop()->SetBaseColor(foreground_color); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetBaseColor(foreground_color); // Bypass color-callback setup in HoverButton. - ink_drop()->SetBaseColorCallback({}); + views::InkDrop::Get(this)->SetBaseColorCallback({}); SetHasInkDropActionOnClick(true); SetPreferredSize(kDeviceEntryViewSize); } @@ -91,12 +91,12 @@ } is_highlighted_ = highlighted; if (highlighted) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); SetHasInkDropActionOnClick(false); - SetBackground(views::CreateSolidBackground( - SkColorSetA(ink_drop()->GetBaseColor(), kEntryHighlightOpacity))); + SetBackground(views::CreateSolidBackground(SkColorSetA( + views::InkDrop::Get(this)->GetBaseColor(), kEntryHighlightOpacity))); } else { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); SetBackground(nullptr); } @@ -109,7 +109,7 @@ void AudioDeviceEntryView::OnColorsChanged(SkColor foreground_color, SkColor background_color) { - ink_drop()->SetBaseColor(foreground_color); + views::InkDrop::Get(this)->SetBaseColor(foreground_color); ChangeEntryColor(static_cast<views::ImageView*>(icon_view()), title(), subtitle(), icon_, foreground_color, background_color); @@ -136,17 +136,17 @@ ChangeCastEntryColor(sink, foreground_color, background_color); SetFocusBehavior(views::View::FocusBehavior::ALWAYS); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - ink_drop()->SetBaseColor(foreground_color); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetBaseColor(foreground_color); SetHasInkDropActionOnClick(true); // Bypass color-callback setup in HoverButton. - ink_drop()->SetBaseColorCallback({}); + views::InkDrop::Get(this)->SetBaseColorCallback({}); SetPreferredSize(kDeviceEntryViewSize); } void CastDeviceEntryView::OnColorsChanged(SkColor foreground_color, SkColor background_color) { - ink_drop()->SetBaseColor(foreground_color); + views::InkDrop::Get(this)->SetBaseColor(foreground_color); ChangeCastEntryColor(sink(), foreground_color, background_color); }
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.cc b/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.cc index f376155d..64acead4 100644 --- a/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.cc +++ b/chrome/browser/ui/views/global_media_controls/media_notification_device_selector_view.cc
@@ -59,10 +59,10 @@ delegate_(delegate) { SetLabel(l10n_util::GetStringUTF16( IDS_GLOBAL_MEDIA_CONTROLS_DEVICES_BUTTON_LABEL)); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); SetFocusBehavior(FocusBehavior::ALWAYS); - ink_drop()->GetInkDrop()->SetShowHighlightOnHover(true); + views::InkDrop::Get(this)->GetInkDrop()->SetShowHighlightOnHover(true); SetBorder(views::CreateRoundedRectBorder( 1, kExpandButtonStripSize.height() / 2, gfx::Insets(),
diff --git a/chrome/browser/ui/views/hover_button.cc b/chrome/browser/ui/views/hover_button.cc index 647d324..cfd95b8 100644 --- a/chrome/browser/ui/views/hover_button.cc +++ b/chrome/browser/ui/views/hover_button.cc
@@ -17,6 +17,7 @@ #include "ui/base/models/image_model.h" #include "ui/compositor/layer.h" #include "ui/events/event_constants.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -96,11 +97,11 @@ 2; SetBorder(CreateBorderWithVerticalSpacing(vert_spacing)); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - views::InkDrop::UseInkDropForFloodFillRipple(ink_drop(), + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::UseInkDropForFloodFillRipple(views::InkDrop::Get(this), /*highlight_on_hover=*/false, /*highlight_on_focus=*/true); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](views::View* host) { return GetInkDropColor(host); }, this)); SetTriggerableEventFlags(ui::EF_LEFT_MOUSE_BUTTON |
diff --git a/chrome/browser/ui/views/hover_button_controller.cc b/chrome/browser/ui/views/hover_button_controller.cc index 3c3a1730..d3d515e 100644 --- a/chrome/browser/ui/views/hover_button_controller.cc +++ b/chrome/browser/ui/views/hover_button_controller.cc
@@ -34,11 +34,12 @@ if (button()->GetRequestFocusOnPress()) button()->RequestFocus(); if (callback_) { - button()->ink_drop()->AnimateToState(views::InkDropState::ACTION_TRIGGERED, - ui::LocatedEvent::FromIfValid(&event)); + views::InkDrop::Get(button())->AnimateToState( + views::InkDropState::ACTION_TRIGGERED, + ui::LocatedEvent::FromIfValid(&event)); } else { - button()->ink_drop()->AnimateToState(views::InkDropState::HIDDEN, - ui::LocatedEvent::FromIfValid(&event)); + views::InkDrop::Get(button())->AnimateToState( + views::InkDropState::HIDDEN, ui::LocatedEvent::FromIfValid(&event)); } return true; } @@ -51,7 +52,8 @@ if (callback_) callback_.Run(event); } else { - button()->ink_drop()->AnimateToState(views::InkDropState::HIDDEN, &event); + views::InkDrop::Get(button())->AnimateToState(views::InkDropState::HIDDEN, + &event); ButtonController::OnMouseReleased(event); } }
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc index 81b7eae..b9208a4 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -105,30 +105,30 @@ base::UTF8ToUTF16(base::StringPiece(display_name))) { SetHorizontalAlignment(gfx::ALIGN_LEFT); SetMinSize(gfx::Size(kMaxIntentPickerLabelButtonWidth, kRowHeight)); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); if (!icon_model.IsEmpty()) { SetImageModel(views::ImageButton::STATE_NORMAL, icon_model); } SetBorder(views::CreateEmptyBorder(8, 16, 8, 0)); - ink_drop()->SetBaseColor(SK_ColorGRAY); - ink_drop()->SetVisibleOpacity(kToolbarInkDropVisibleOpacity); + views::InkDrop::Get(this)->SetBaseColor(SK_ColorGRAY); + views::InkDrop::Get(this)->SetVisibleOpacity(kToolbarInkDropVisibleOpacity); } IntentPickerLabelButton(const IntentPickerLabelButton&) = delete; IntentPickerLabelButton& operator=(const IntentPickerLabelButton&) = delete; ~IntentPickerLabelButton() override = default; void MarkAsUnselected(const ui::Event* event) { - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, - ui::LocatedEvent::FromIfValid(event)); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::HIDDEN, ui::LocatedEvent::FromIfValid(event)); } void MarkAsSelected(const ui::Event* event) { - ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, - ui::LocatedEvent::FromIfValid(event)); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::ACTIVATED, ui::LocatedEvent::FromIfValid(event)); } views::InkDropState GetTargetInkDropState() { - return ink_drop()->GetInkDrop()->GetTargetInkDropState(); + return views::InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState(); } };
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc index 487ffc4..f8334a1 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
@@ -29,8 +29,8 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/arc/arc_service_manager.h" -#include "components/arc/arc_util.h" #include "components/arc/session/arc_bridge_service.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #include "components/arc/test/fake_intent_helper_instance.h"
diff --git a/chrome/browser/ui/views/location_bar/find_bar_icon.cc b/chrome/browser/ui/views/location_bar/find_bar_icon.cc index 4598649a..80d3b56 100644 --- a/chrome/browser/ui/views/location_bar/find_bar_icon.cc +++ b/chrome/browser/ui/views/location_bar/find_bar_icon.cc
@@ -28,17 +28,20 @@ FindBarIcon::~FindBarIcon() {} void FindBarIcon::SetActive(bool activate, bool should_animate) { - if (activate == (ink_drop()->GetInkDrop()->GetTargetInkDropState() == - views::InkDropState::ACTIVATED)) + if (activate == + (views::InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == + views::InkDropState::ACTIVATED)) return; if (activate) { if (should_animate) { - ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, nullptr); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTIVATED, + nullptr); } else { - ink_drop()->GetInkDrop()->SnapToActivated(); + views::InkDrop::Get(this)->GetInkDrop()->SnapToActivated(); } } else { - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, nullptr); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, + nullptr); } }
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc index f08cd04d..f069c0f6 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -24,6 +24,7 @@ #include "ui/views/accessibility/ax_virtual_view.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" @@ -93,7 +94,7 @@ return; } - views::InkDrop* ink_drop = owner_->ink_drop()->GetInkDrop(); + views::InkDrop* const ink_drop = views::InkDrop::Get(owner_)->GetInkDrop(); DCHECK(ink_drop); // If an inkdrop highlight or ripple is animating in or visible, the @@ -145,22 +146,22 @@ separator_view_->SetVisible(ShouldShowSeparator()); - ink_drop()->SetVisibleOpacity( + views::InkDrop::Get(this)->SetVisibleOpacity( GetOmniboxStateOpacity(OmniboxPartState::SELECTED)); - ink_drop()->SetHighlightOpacity( + views::InkDrop::Get(this)->SetHighlightOpacity( GetOmniboxStateOpacity(OmniboxPartState::HOVERED)); - ink_drop()->SetCreateInkDropCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](IconLabelBubbleView* host) { std::unique_ptr<views::InkDrop> ink_drop = views::InkDrop::CreateInkDropForFloodFillRipple( - host->ink_drop(), /*highlight_on_hover=*/true, + views::InkDrop::Get(host), /*highlight_on_hover=*/true, /*highlight_on_focus=*/!host->focus_ring()); ink_drop->AddObserver(host); return ink_drop; }, this)); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](IconLabelBubbleView* host) { return host->delegate_->GetIconLabelBubbleInkDropColor(); }, @@ -379,8 +380,9 @@ PreferredSizeChanged(); } - ink_drop()->GetInkDrop()->SetShowHighlightOnHover(true); - ink_drop()->GetInkDrop()->SetShowHighlightOnFocus(!focus_ring()); + views::InkDrop::Get(this)->GetInkDrop()->SetShowHighlightOnHover(true); + views::InkDrop::Get(this)->GetInkDrop()->SetShowHighlightOnFocus( + !focus_ring()); } void IconLabelBubbleView::AnimationProgressed(const gfx::Animation* animation) { @@ -454,7 +456,7 @@ } void IconLabelBubbleView::SetUpForAnimation() { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); label()->SetElideBehavior(gfx::NO_ELIDE); label()->SetVisible(false); @@ -549,14 +551,14 @@ void IconLabelBubbleView::ShowAnimation() { slide_animation_.Show(); - ink_drop()->GetInkDrop()->SetShowHighlightOnHover(false); - ink_drop()->GetInkDrop()->SetShowHighlightOnFocus(false); + views::InkDrop::Get(this)->GetInkDrop()->SetShowHighlightOnHover(false); + views::InkDrop::Get(this)->GetInkDrop()->SetShowHighlightOnFocus(false); } void IconLabelBubbleView::HideAnimation() { slide_animation_.Hide(); - ink_drop()->GetInkDrop()->SetShowHighlightOnHover(false); - ink_drop()->GetInkDrop()->SetShowHighlightOnFocus(false); + views::InkDrop::Get(this)->GetInkDrop()->SetShowHighlightOnHover(false); + views::InkDrop::Get(this)->GetInkDrop()->SetShowHighlightOnFocus(false); } SkPath IconLabelBubbleView::GetHighlightPath() const {
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc index f7511c1..4201e8e 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc
@@ -18,6 +18,7 @@ #include "ui/events/base_event_utils.h" #include "ui/events/gesture_detection/gesture_configuration.h" #include "ui/events/test/event_generator.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/animation/test/test_ink_drop.h" #include "ui/views/controls/image_view.h" @@ -79,8 +80,8 @@ } void HideBubble() { - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, - nullptr /* event */); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, + nullptr /* event */); is_bubble_showing_ = false; } @@ -115,8 +116,8 @@ bool IsShrinking() const override { return state() == SHRINKING; } bool ShowBubble(const ui::Event& event) override { - ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, - nullptr /* event */); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTIVATED, + nullptr /* event */); is_bubble_showing_ = true; return true; } @@ -187,7 +188,7 @@ void AttachInkDrop() { ink_drop_ = new TestInkDrop(); - InkDropHostTestApi(view_->ink_drop()) + InkDropHostTestApi(views::InkDrop::Get(view_)) .SetInkDrop(base::WrapUnique(ink_drop_)); }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc b/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc index e4a261a..1747ee38 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc
@@ -11,6 +11,8 @@ #include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/policy/policy_test_utils.h" #include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -22,11 +24,15 @@ #include "chrome/common/chrome_paths.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/network_session_configurator/common/network_switches.h" #include "components/omnibox/browser/location_bar_model_impl.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/common/omnibox_features.h" #include "components/permissions/permission_request_manager.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/policy_constants.h" #include "components/security_state/core/security_state.h" +#include "components/vector_icons/vector_icons.h" #include "components/zoom/zoom_controller.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_features.h" @@ -35,14 +41,18 @@ #include "net/dns/mock_host_resolver.h" #include "net/ssl/ssl_info.h" #include "net/test/cert_test_util.h" +#include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/test_data_directory.h" #include "services/device/public/cpp/test/scoped_geolocation_overrider.h" #include "services/network/public/cpp/features.h" #include "services/network/public/mojom/url_response_head.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/page/page_zoom.h" #include "ui/base/pointer/touch_ui_controller.h" +#include "ui/gfx/favicon_size.h" +#include "ui/gfx/paint_vector_icon.h" class LocationBarViewBrowserTest : public InProcessBrowserTest { public: @@ -352,3 +362,77 @@ // Geolocation icon should be off. EXPECT_FALSE(geolocation_icon.GetVisible()); } + +// Tests LockIconInAddressBarEnabled policy which controls whether the omnibox +// should show a lock icon for secure HTTPS URLs. +template <bool enable> +class LockIconPolicyTest : public policy::PolicyTest { + public: + void SetUp() override { + feature_list_.InitAndEnableFeature( + omnibox::kUpdatedConnectionSecurityIndicators); + InProcessBrowserTest::SetUp(); + } + + void SetUpOnMainThread() override { + host_resolver()->AddRule("*", "127.0.0.1"); + https_server_ = std::make_unique<net::EmbeddedTestServer>( + net::EmbeddedTestServer::TYPE_HTTPS); + https_server_->SetSSLConfig( + net::test_server::EmbeddedTestServer::CERT_TEST_NAMES); + https_server_->AddDefaultHandlers(GetChromeTestDataDir()); + ASSERT_TRUE(https_server_->Start()); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kIgnoreCertificateErrors); + } + + void SetUpInProcessBrowserTestFixture() override { + PolicyTest::SetUpInProcessBrowserTestFixture(); + policy::PolicyMap policies; + policies.Set(policy::key::kLockIconInAddressBarEnabled, + policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, + policy::POLICY_SOURCE_CLOUD, base::Value(enable), nullptr); + provider_.UpdateChromePolicy(policies); + } + + net::EmbeddedTestServer* https_server() { return https_server_.get(); } + + LocationBarView* GetLocationBarView() { + BrowserView* browser_view = + BrowserView::GetBrowserViewForBrowser(browser()); + return browser_view->GetLocationBarView(); + } + + void NavigateAndExpectIcon(const GURL& url, + const gfx::VectorIcon& expected_vector_icon) { + ui_test_utils::NavigateToURL(browser(), url); + gfx::ImageSkia expected_icon = gfx::CreateVectorIcon( + expected_vector_icon, gfx::kFaviconSize, gfx::kPlaceholderColor); + gfx::ImageSkia icon = + gfx::CreateVectorIcon(GetLocationBarView() + ->delegate() + ->GetLocationBarModel() + ->GetVectorIcon(), + gfx::kFaviconSize, gfx::kPlaceholderColor); + EXPECT_EQ(icon.bitmap(), expected_icon.bitmap()); + } + + private: + base::test::ScopedFeatureList feature_list_; + std::unique_ptr<net::EmbeddedTestServer> https_server_; +}; + +using LockIconEnabledPolicyTest = LockIconPolicyTest<true>; +using LockIconDisabledPolicyTest = LockIconPolicyTest<false>; + +IN_PROC_BROWSER_TEST_F(LockIconEnabledPolicyTest, LockIconPolicyEnabled) { + NavigateAndExpectIcon(https_server()->GetURL("a.test", "/title1.html"), + vector_icons::kHttpsValidIcon); +} + +IN_PROC_BROWSER_TEST_F(LockIconDisabledPolicyTest, LockIconPolicyDisabled) { + NavigateAndExpectIcon(https_server()->GetURL("a.test", "/title1.html"), + vector_icons::kHttpsValidArrowIcon); +}
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.cc b/chrome/browser/ui/views/location_bar/location_icon_view.cc index 29d0784..e9bcbf5 100644 --- a/chrome/browser/ui/views/location_bar/location_icon_view.cc +++ b/chrome/browser/ui/views/location_bar/location_icon_view.cc
@@ -31,6 +31,7 @@ #include "ui/base/clipboard/clipboard.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/label.h" using content::WebContents; @@ -154,7 +155,7 @@ } const views::InkDrop* LocationIconView::get_ink_drop_for_testing() { - return ink_drop()->GetInkDrop(); + return views::InkDrop::Get(this)->GetInkDrop(); } std::u16string LocationIconView::GetText() const { @@ -246,19 +247,19 @@ : l10n_util::GetStringUTF16(IDS_TOOLTIP_LOCATION_ICON)); // We should only enable/disable the InkDrop if the editing state has changed, - // as the drop gets recreated when ink_drop()->SetMode() is called. - // This can result in strange behaviour, like the the InkDrop disappearing mid - // animation. + // as the drop gets recreated when views::InkDrop::Get(this)->SetMode() is + // called. This can result in strange behaviour, like the the InkDrop + // disappearing mid animation. if (is_editing_or_empty != was_editing_or_empty_) { // If the omnibox is empty or editing, the user should not be able to left // click on the icon. As such, the icon should not show a highlight or be // focusable. Note: using the middle mouse to copy-and-paste should still // work on the icon. if (is_editing_or_empty) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); SetFocusBehavior(FocusBehavior::NEVER); } else { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); #if defined(OS_MAC) SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view_browsertest.cc b/chrome/browser/ui/views/location_bar/location_icon_view_browsertest.cc index 6eab9fe5..f71b9131 100644 --- a/chrome/browser/ui/views/location_bar/location_icon_view_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/location_icon_view_browsertest.cc
@@ -9,6 +9,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "components/omnibox/browser/omnibox_edit_model.h" #include "content/public/test/browser_test.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" // TODO (spqchan): Refine tests. See crbug.com/770873. @@ -46,14 +47,14 @@ model->SetInputInProgress(true); icon_view()->Update(/*suppress_animations=*/true); - EXPECT_EQ( - views::InkDropHost::InkDropMode::OFF, - views::test::InkDropHostTestApi(icon_view()->ink_drop()).ink_drop_mode()); + EXPECT_EQ(views::InkDropHost::InkDropMode::OFF, + views::test::InkDropHostTestApi(views::InkDrop::Get(icon_view())) + .ink_drop_mode()); model->SetInputInProgress(false); icon_view()->Update(/*suppress_animations=*/true); - EXPECT_EQ( - views::InkDropHost::InkDropMode::ON, - views::test::InkDropHostTestApi(icon_view()->ink_drop()).ink_drop_mode()); + EXPECT_EQ(views::InkDropHost::InkDropMode::ON, + views::test::InkDropHostTestApi(views::InkDrop::Get(icon_view())) + .ink_drop_mode()); }
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc index 4085c3a..c212d018 100644 --- a/chrome/browser/ui/views/location_bar/star_view.cc +++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -91,7 +91,7 @@ } else { next_state = views::InkDropState::DEACTIVATED; } - ink_drop()->GetInkDrop()->AnimateToState(next_state); + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState(next_state); } }
diff --git a/chrome/browser/ui/views/location_bar/star_view_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/star_view_interactive_uitest.cc index 55b5fe29..f8b6717 100644 --- a/chrome/browser/ui/views/location_bar/star_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/location_bar/star_view_interactive_uitest.cc
@@ -34,6 +34,7 @@ #include "content/public/test/test_utils.h" #include "ui/base/ui_base_switches.h" #include "ui/events/event_utils.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/controls/menu/menu_runner.h" #include "ui/views/test/button_test_api.h" @@ -125,7 +126,8 @@ IN_PROC_BROWSER_TEST_F(StarViewTest, InkDropHighlighted) { PageActionIconView* star_icon = GetStarIcon(); - views::test::InkDropHostTestApi ink_drop_test_api(star_icon->ink_drop()); + views::test::InkDropHostTestApi ink_drop_test_api( + views::InkDrop::Get(star_icon)); if (ink_drop_test_api.HasInkDrop()) { GURL url("http://test.com");
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.cc b/chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.cc index cd6b92b..fd7a8ce 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.cc
@@ -29,6 +29,7 @@ #include "ui/base/page_transition_types.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/image_button_factory.h" #include "ui/views/controls/image_view.h" @@ -85,7 +86,7 @@ icon->SetBorder(views::CreateEmptyBorder(media_router::kPrimaryIconBorder)); icon->SetAccessibleName( l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_NO_DEVICES_FOUND_BUTTON)); - icon->ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(icon)->SetMode(views::InkDropHost::InkDropMode::OFF); icon_ = icon; label_->SetText(
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc index 4f929c3..0f4af61 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
@@ -34,6 +34,7 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/controls/color_tracking_icon_view.h" #include "ui/views/controls/styled_label.h" @@ -155,8 +156,9 @@ void CastDialogSinkButton::OnEnabledChanged() { // Prevent a DCHECK failure seen at https://crbug.com/912687 by not having an // InkDrop if the button is disabled. - ink_drop()->SetMode(GetEnabled() ? views::InkDropHost::InkDropMode::ON - : views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode( + GetEnabled() ? views::InkDropHost::InkDropMode::ON + : views::InkDropHost::InkDropMode::OFF); // If the button has a state other than AVAILABLE (e.g. CONNECTED), there is // no need to change the status or the icon. if (sink_.state != UIMediaSinkState::AVAILABLE)
diff --git a/chrome/browser/ui/views/media_router/cast_toolbar_button.cc b/chrome/browser/ui/views/media_router/cast_toolbar_button.cc index a11f63a..af3108fa 100644 --- a/chrome/browser/ui/views/media_router/cast_toolbar_button.cc +++ b/chrome/browser/ui/views/media_router/cast_toolbar_button.cc
@@ -24,6 +24,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/vector_icon_types.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/button_controller.h" namespace media_router { @@ -93,11 +94,13 @@ } void CastToolbarButton::ActivateIcon() { - ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, nullptr); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTIVATED, + nullptr); } void CastToolbarButton::DeactivateIcon() { - ink_drop()->AnimateToState(views::InkDropState::DEACTIVATED, nullptr); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::DEACTIVATED, + nullptr); } void CastToolbarButton::OnIssue(const media_router::Issue& issue) {
diff --git a/chrome/browser/ui/views/media_router/media_router_dialog_controller_views.h b/chrome/browser/ui/views/media_router/media_router_dialog_controller_views.h index 40f19f28..f620c19 100644 --- a/chrome/browser/ui/views/media_router/media_router_dialog_controller_views.h +++ b/chrome/browser/ui/views/media_router/media_router_dialog_controller_views.h
@@ -8,7 +8,6 @@ #include <memory> #include "base/macros.h" -#include "base/observer_list.h" #include "base/scoped_multi_source_observation.h" #include "chrome/browser/ui/media_router/media_router_ui_service.h" #include "components/media_router/browser/media_router_dialog_controller.h"
diff --git a/chrome/browser/ui/views/omnibox/omnibox_row_view.cc b/chrome/browser/ui/views/omnibox/omnibox_row_view.cc index 1dec6fc..0703d92 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_row_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_row_view.cc
@@ -26,6 +26,7 @@ #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/image_button_factory.h" @@ -158,7 +159,7 @@ SkColor icon_color = GetOmniboxColor(GetThemeProvider(), OmniboxPart::RESULTS_ICON, part_state); - header_toggle_button_->ink_drop()->SetBaseColor(icon_color); + views::InkDrop::Get(header_toggle_button_)->SetBaseColor(icon_color); int dip_size = GetLayoutConstant(LOCATION_BAR_ICON_SIZE); const gfx::ImageSkia arrow_down =
diff --git a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc index 328bcb14..ada64b3 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc
@@ -25,6 +25,7 @@ #include "ui/gfx/color_utils.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/background.h" #include "ui/views/controls/button/label_button_border.h" @@ -55,9 +56,9 @@ SetCornerRadius(GetInsets().height() + GetLayoutConstant(LOCATION_BAR_ICON_SIZE)); - ink_drop()->SetHighlightOpacity( + views::InkDrop::Get(this)->SetHighlightOpacity( GetOmniboxStateOpacity(OmniboxPartState::HOVERED)); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](OmniboxSuggestionRowButton* host) { return color_utils::GetColorWithMaxContrast( host->omnibox_bg_color_.value());
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 1f127e1..5ec77a84 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -27,7 +27,6 @@ #include "chrome/browser/external_protocol/external_protocol_handler.h" #include "chrome/browser/history_clusters/history_clusters_tab_helper.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/reputation/url_elision_policy.h" #include "chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h" #include "chrome/browser/send_tab_to_self/send_tab_to_self_util.h" #include "chrome/browser/themes/theme_service.h" @@ -155,220 +154,8 @@ ->IsMarkedByOriginatorAsConfidential(); } -// Draws a rectangle of dimensions and position |rect| in |canvas|, colored -// with a gradient from |start_color| to |end_color|. -void DrawGradientRect(const gfx::Rect& rect, - SkColor start_color, - SkColor end_color, - gfx::Canvas* canvas) { - SkColor colors[2] = {start_color, end_color}; - SkPoint points[2]; - points[0].iset(rect.origin().x(), rect.origin().y()); - points[1].iset(rect.right(), rect.y()); - cc::PaintFlags flags; - flags.setShader(cc::PaintShader::MakeLinearGradient(points, colors, nullptr, - 2, SkTileMode::kClamp)); - canvas->DrawRect(rect, flags); -} - -// Returns true if the substring indicated by |range| overflows -// |omnibox_view|'s current local bounds. -bool TextRangeOverflowsView(OmniboxViewViews* omnibox_view, - gfx::RenderText* render_text, - const gfx::Range& range) { - // The RenderText must be in NO_ELIDE mode to attempt to retrieve the bounds - // of |range| (which could be outside its display area). - DCHECK_EQ(gfx::NO_ELIDE, render_text->elide_behavior()); - - gfx::Rect range_rect; - for (const auto& rect : render_text->GetSubstringBounds(range)) - range_rect.Union(rect); - return omnibox_view->GetLocalBounds().width() < range_rect.width(); -} - } // namespace -OmniboxViewViews::ElideAnimation::ElideAnimation(OmniboxViewViews* view, - gfx::RenderText* render_text) - : AnimationDelegateViews(view), view_(view), render_text_(render_text) { - DCHECK(view_); - DCHECK(render_text_); -} - -OmniboxViewViews::ElideAnimation::~ElideAnimation() = default; - -// TODO(estark): this code doesn't work for URLs with RTL components. Will need -// to figure out another animation or just skip the animation entirely on URLs -// with RTL components. -void OmniboxViewViews::ElideAnimation::Start( - const gfx::Range& elide_to_bounds, - uint32_t delay_ms, - const std::vector<gfx::Range>& ranges_surrounding_simplified_domain, - SkColor starting_color, - SkColor ending_color) { - DCHECK(ranges_surrounding_simplified_domain.size() == 1 || - ranges_surrounding_simplified_domain.size() == 2); - ranges_surrounding_simplified_domain_ = ranges_surrounding_simplified_domain; - starting_color_ = starting_color; - ending_color_ = ending_color; - - // simplified_domain_bounds_ will be set to a rectangle surrounding the part - // of the URL that is never elided, on its original position before any - // animation runs. If ranges_surrounding_simplified_domain_ only contains one - // range it means we are not eliding on the right side, so we use the right - // side of elide_to_bounds as the range as it will always be the right limit - // of the simplified section. - gfx::Range simplified_domain_range( - ranges_surrounding_simplified_domain_[0].end(), - ranges_surrounding_simplified_domain_.size() == 2 - ? ranges_surrounding_simplified_domain_[1].start() - : elide_to_bounds.end()); - for (auto rect : render_text_->GetSubstringBounds(simplified_domain_range)) { - simplified_domain_bounds_.Union(rect - render_text_->GetLineOffset(0)); - } - - // After computing |elide_to_rect_| below, |elide_to_bounds| aren't actually - // need anymore for the animation. However, the bounds provide a convenient - // way for the animation consumer to check if an animation is currently in - // progress to a specific range, so that the consumer can avoid starting a - // duplicate animation (to avoid flicker). So we save the bounds so that - // consumers can query them. - elide_to_bounds_ = elide_to_bounds; - - animation_ = - std::make_unique<gfx::MultiAnimation>(gfx::MultiAnimation::Parts({ - gfx::MultiAnimation::Part(base::TimeDelta::FromMilliseconds(delay_ms), - gfx::Tween::ZERO), - gfx::MultiAnimation::Part(base::TimeDelta::FromMilliseconds(300), - gfx::Tween::FAST_OUT_SLOW_IN), - })); - animation_->set_delegate(this); - animation_->set_continuous(false); - - elide_from_rect_ = render_text_->display_rect(); - elide_to_rect_ = gfx::Rect(); - for (const auto& rect : render_text_->GetSubstringBounds(elide_to_bounds)) - elide_to_rect_.Union(rect); - // The URL should never shift vertically while eliding to/from simplified - // domain. - elide_to_rect_.set_y(elide_from_rect_.y()); - elide_to_rect_.set_height(elide_from_rect_.height()); - - // There is nothing to animate in this case, so return without starting. - if (elide_from_rect_ == elide_to_rect_ && starting_color_ == ending_color_) - return; - - starting_display_offset_ = render_text_->GetUpdatedDisplayOffset().x(); - // Shift the text to where |elide_to_bounds| starts, relative to the current - // display rect. - if (base::i18n::IsRTL()) { - ending_display_offset_ = starting_display_offset_ + - elide_from_rect_.right() - elide_to_rect_.right(); - } else { - ending_display_offset_ = - starting_display_offset_ - (elide_to_rect_.x() - elide_from_rect_.x()); - } - - animation_->Start(); -} - -void OmniboxViewViews::ElideAnimation::Stop() { - // Reset the smoothing rectangles whenever the animation stops to prevent - // stale rectangles from showing at the start of the next animation. - view_->elide_animation_smoothing_rect_left_ = gfx::Rect(); - view_->elide_animation_smoothing_rect_right_ = gfx::Rect(); - if (animation_) - animation_->Stop(); -} - -bool OmniboxViewViews::ElideAnimation::IsAnimating() { - return animation_ && animation_->is_animating(); -} - -const gfx::Range& OmniboxViewViews::ElideAnimation::GetElideToBounds() const { - return elide_to_bounds_; -} - -SkColor OmniboxViewViews::ElideAnimation::GetCurrentColor() const { - return animation_ - ? gfx::Tween::ColorValueBetween(animation_->GetCurrentValue(), - starting_color_, ending_color_) - : gfx::kPlaceholderColor; -} - -gfx::MultiAnimation* -OmniboxViewViews::ElideAnimation::GetAnimationForTesting() { - return animation_.get(); -} - -void OmniboxViewViews::ElideAnimation::AnimationProgressed( - const gfx::Animation* animation) { - DCHECK(!view_->model()->user_input_in_progress()); - DCHECK_EQ(animation, animation_.get()); - - if (animation->GetCurrentValue() == 0) - return; - - // |bounds| contains the interpolated substring to show for this frame. Shift - // it to line up with the x position of the previous frame (|old_bounds|), - // because the animation should gradually bring the desired string into view - // at the leading edge. The y/height values shouldn't change because - // |elide_to_rect_| is set to have the same y and height values as - // |elide_to_rect_|. - gfx::Rect old_bounds = render_text_->display_rect(); - gfx::Rect bounds = gfx::Tween::RectValueBetween( - animation->GetCurrentValue(), elide_from_rect_, elide_to_rect_); - DCHECK_EQ(bounds.y(), old_bounds.y()); - DCHECK_EQ(bounds.height(), old_bounds.height()); - gfx::Rect shifted_bounds(base::i18n::IsRTL() - ? old_bounds.right() - bounds.width() - : old_bounds.x(), - old_bounds.y(), bounds.width(), old_bounds.height()); - render_text_->SetDisplayRect(shifted_bounds); - current_offset_ = gfx::Tween::IntValueBetween(animation->GetCurrentValue(), - starting_display_offset_, - ending_display_offset_); - render_text_->SetDisplayOffset(current_offset_); - - for (const auto& range : ranges_surrounding_simplified_domain_) { - view_->ApplyColor(GetCurrentColor(), range); - } - - // TODO(crbug.com/1101472): The smoothing gradient mask is not yet implemented - // correctly for RTL UI. - if (base::i18n::IsRTL()) { - view_->SchedulePaint(); - return; - } - - // The gradient mask should be a fixed width, except if that width would - // cause it to mask the unelided section. In that case we set it to the - // maximum width possible that won't cover the unelided section. - int unelided_left_bound = simplified_domain_bounds_.x() + current_offset_; - int unelided_right_bound = - unelided_left_bound + simplified_domain_bounds_.width(); - // GetSubstringBounds rounds up when calculating unelided_left_bound and - // unelided_right_bound, we subtract 1 pixel from the gradient widths to make - // sure they never overlap with the always visible part of the URL. - // gfx::Rect() switches negative values to 0, so this doesn't affect - // rectangles that were originally size 0. - int left_gradient_width = kSmoothingGradientMaxWidth < unelided_left_bound - ? kSmoothingGradientMaxWidth - 1 - : unelided_left_bound - 1; - int right_gradient_width = - shifted_bounds.right() - kSmoothingGradientMaxWidth > unelided_right_bound - ? kSmoothingGradientMaxWidth - 1 - : shifted_bounds.right() - unelided_right_bound - 1; - - view_->elide_animation_smoothing_rect_left_ = gfx::Rect( - old_bounds.x(), old_bounds.y(), left_gradient_width, old_bounds.height()); - view_->elide_animation_smoothing_rect_right_ = - gfx::Rect(shifted_bounds.right() - right_gradient_width, old_bounds.y(), - right_gradient_width, old_bounds.height()); - - view_->SchedulePaint(); -} - // OmniboxViewViews ----------------------------------------------------------- OmniboxViewViews::OmniboxViewViews(OmniboxEditController* controller, @@ -378,7 +165,6 @@ const gfx::FontList& font_list) : OmniboxView(controller, std::move(client)), popup_window_mode_(popup_window_mode), - clock_(base::DefaultClock::GetInstance()), location_bar_view_(location_bar), latency_histogram_state_(NOT_ACTIVE), friendly_suggestion_text_prefix_length_(0) { @@ -393,8 +179,7 @@ location_bar_view_->browser()->profile()->GetPrefs()); pref_change_registrar_.Add( omnibox::kPreventUrlElisionsInOmnibox, - base::BindRepeating(&OmniboxViewViews::OnShouldPreventElisionChanged, - base::Unretained(this))); + base::BindRepeating(&OmniboxViewViews::Update, base::Unretained(this))); } // Sometimes there are additional ignored views, such as a View representing @@ -431,10 +216,6 @@ // Initialize the popup view using the same font. popup_view_ = std::make_unique<OmniboxPopupContentsView>( this, model(), location_bar_view_); - if (OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() && - !model()->ShouldPreventElision()) { - Observe(location_bar_view_->GetWebContents()); - } // Set whether the text should be used to improve typing suggestions. SetShouldDoLearning(!location_bar_view_->profile()->IsOffTheRecord()); @@ -496,15 +277,6 @@ // TODO(msw|oshima): Consider saving/restoring edit history. ClearEditHistory(); - - // When the tab is changed, unelide the URL in case it had previously been - // elided to a simplified domain by a user interaction (when certain field - // trials are enabled). - ResetToHideOnInteraction(); - if (OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() && - !model()->ShouldPreventElision()) { - Observe(web_contents); - } } void OmniboxViewViews::ResetTabState(content::WebContents* web_contents) { @@ -528,12 +300,6 @@ } void OmniboxViewViews::EmphasizeURLComponents() { - // Cancel any existing simplified URL animations. - if (hover_elide_or_unelide_animation_) - hover_elide_or_unelide_animation_->Stop(); - if (elide_after_web_contents_interaction_animation_) - elide_after_web_contents_interaction_animation_->Stop(); - // If the current contents is a URL, turn on special URL rendering mode in // RenderText. bool text_is_url = model()->CurrentTextIsURL(); @@ -543,56 +309,6 @@ std::u16string text = GetText(); UpdateTextStyle(text, text_is_url, model()->client()->GetSchemeClassifier()); - - if (model()->ShouldPreventElision()) - return; - - // If the text isn't eligible to be elided to a simplified domain, and - // simplified domain field trials are enabled, then ensure that as much of the - // text as will fit is visible. - if (!GetURLEligibleForSimplifiedDomainEliding() && - (OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() || - OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover())) { - FitToLocalBounds(); - return; - } - - // In the simplified domain field trials, elide or unelide according to the - // current state and field trial configuration. These elisions are not - // animated because we often don't want this to be a user-visible - // transformation; for example, a navigation should just show the URL in the - // desired state without drawing additional attention from the user. - if (OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction()) { - // In the hide-on-interaction field trial, elide or unelide the URL to the - // simplified domain depending on whether the user has already interacted - // with the page or not. This is a best guess at the correct elision state, - // which we don't really know for sure until a navigation has committed - // (because the elision behavior depends on whether the navigation is - // same-document and if it changes the path). We elide here based on the - // current elision setting; we'll then update the elision state as we get - // more information about the navigation in DidStartNavigation and - // DidFinishNavigation. - if (elide_after_web_contents_interaction_animation_) { - // This can cause a slight quirk in browser-initiated navigations that - // occur after the user interacts with the previous page. In this case, - // the simplified domain will be shown briefly before we show the full URL - // in DidStartNavigation(). - ElideURL(); - } else { - // Note that here we are only adjusting the display of the URL, not - // resetting any state associated with the animations (in particular, we - // are not calling ResetToHideOnInteraction()). This is, as above, because - // we don't know exactly how to set state until we know what kind of - // navigation is happening. Thus here we are only adjusting the display so - // things look right mid-navigation, and the final state will be set - // appropriately in DidFinishNavigation(). - ShowFullURLWithoutSchemeAndTrivialSubdomain(); - } - } else if (OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()) { - // If reveal-on-hover is enabled and hide-on-interaction is disabled, elide - // to the simplified domain now. - ElideURL(); - } } void OmniboxViewViews::Update() { @@ -770,22 +486,6 @@ SCOPED_UMA_HISTOGRAM_TIMER("Omnibox.PaintTime"); Textfield::OnPaint(canvas); } - if ((hover_elide_or_unelide_animation_ && - hover_elide_or_unelide_animation_->IsAnimating()) || - (elide_after_web_contents_interaction_animation_ && - elide_after_web_contents_interaction_animation_->IsAnimating())) { - SkColor bg_color = GetBackgroundColor(); - // We can't use the SK_ColorTRANSPARENT constant here because for purposes - // of the gradient the R,G,B values of the transparent color do matter, and - // need to be identical to the background color (SK_ColorTRANSPARENT is a - // transparent black, and results in the gradient looking gray). - SkColor bg_transparent = SkColorSetARGB( - 0, SkColorGetR(bg_color), SkColorGetG(bg_color), SkColorGetB(bg_color)); - DrawGradientRect(elide_animation_smoothing_rect_left_, bg_color, - bg_transparent, canvas); - DrawGradientRect(elide_animation_smoothing_rect_right_, bg_transparent, - bg_color, canvas); - } } void OmniboxViewViews::ExecuteCommand(int command_id, int event_flags) { @@ -857,16 +557,6 @@ scoped_compositor_observation_.Reset(); } -OmniboxViewViews::ElideAnimation* -OmniboxViewViews::GetHoverElideOrUnelideAnimationForTesting() { - return hover_elide_or_unelide_animation_.get(); -} - -OmniboxViewViews::ElideAnimation* -OmniboxViewViews::GetElideAfterInteractionAnimationForTesting() { - return elide_after_web_contents_interaction_animation_.get(); -} - void OmniboxViewViews::OnThemeChanged() { views::Textfield::OnThemeChanged(); @@ -874,12 +564,6 @@ GetThemeProvider(), OmniboxPart::LOCATION_BAR_TEXT_DIMMED); set_placeholder_text_color(dimmed_text_color); - if (!model()->ShouldPreventElision() && - OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()) { - hover_elide_or_unelide_animation_ = - std::make_unique<ElideAnimation>(this, GetRenderText()); - } - EmphasizeURLComponents(); } @@ -1306,161 +990,11 @@ void OmniboxViewViews::OnMouseMoved(const ui::MouseEvent& event) { if (location_bar_view_) location_bar_view_->OnOmniboxHovered(true); - - if (model()->ShouldPreventElision()) - return; - - if (!GetURLEligibleForSimplifiedDomainEliding()) - return; - - if (hover_start_time_ == base::Time() && - GetURLEligibleForSimplifiedDomainEliding()) { - hover_start_time_ = clock_->Now(); - } - - if (!OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()) - return; - - if (elide_after_web_contents_interaction_animation_) - elide_after_web_contents_interaction_animation_->Stop(); - - // When the reveal-on-hover field trial is enabled, we elide the path and - // optionally subdomains of the URL. We bring back the URL when the user - // hovers over the omnibox, as is happening now. This is done via an animation - // that slides both ends of the URL into view while shifting the text so that - // the visible text is aligned with the leading edge of the display area. The - // reverse animation occurs when the mouse exits the omnibox area (in - // OnMouseExited()). - // - // The animation shouldn't begin immediately on hover to avoid the URL - // flickering in and out as the user passes over the omnibox on their way to - // e.g. the tab strip. Thus we pass a delay threshold (configurable via field - // trial) to ElideAnimation so that the unelision animation only begins after - // this delay. - if (hover_elide_or_unelide_animation_) { - // There might already be an unelide in progress. If it's animating to the - // same state as we're targeting, then we don't need to do anything. - gfx::Range unelide_bounds = gfx::Range(0, GetText().size()); - if (hover_elide_or_unelide_animation_->IsAnimating() && - hover_elide_or_unelide_animation_->GetElideToBounds() == - unelide_bounds) { - return; - } - - SkColor starting_color = - hover_elide_or_unelide_animation_->GetCurrentColor(); - if (starting_color == gfx::kPlaceholderColor) - starting_color = SK_ColorTRANSPARENT; - hover_elide_or_unelide_animation_->Stop(); - - // Figure out where we are uneliding from so that the hover animation can - // fade in the surrounding text (|ranges_to_fade_in|). If the user has - // already interacted with the page, then we elided to the simplified domain - // and that is what we are uneliding from now. Otherwise, only the scheme - // and possibly a trivial subdomain have been elided and those components - // now need to be faded in. - std::vector<gfx::Range> ranges_to_fade_in; - // |minimum_visible_range| will contain either the simplified domain or the - // full hostname, depending on which is currently supposed to be showing. If - // |minimum_visible_range| does not currently fit in the omnibox bounds, - // then we don't do any hover animation. This is for simplicity, because - // ElideAnimation doesn't know how to position the text so that the most - // important part of the hostname is showing if it doesn't all fit. - // Furthermore, it doesn't seem necessary to do hover animation when the - // hostname doesn't fit because nothing is being elided beyond what has to - // be to fit in the local bounds. - gfx::Range minimum_visible_range; - if (elide_after_web_contents_interaction_animation_ || - !OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction()) { - // The URL has been elided to the simplified domain. We want to fade in - // everything surrounding the simplified domain. - minimum_visible_range = GetSimplifiedDomainBounds(&ranges_to_fade_in); - } else { - // The full URL is showing, except for the scheme and trivial subdomain. - // We want to fade in the scheme and trivial subdomain. - url::Component host = GetHostComponentAfterTrivialSubdomain(); - ranges_to_fade_in.emplace_back(0, host.begin); - minimum_visible_range = gfx::Range(host.begin, host.end()); - } - - if (TextRangeOverflowsView(this, GetRenderText(), minimum_visible_range)) - return; - - hover_elide_or_unelide_animation_->Start( - unelide_bounds, OmniboxFieldTrial::UnelideURLOnHoverThresholdMs(), - ranges_to_fade_in, starting_color, - GetOmniboxColor(GetThemeProvider(), - OmniboxPart::LOCATION_BAR_TEXT_DIMMED)); - } } void OmniboxViewViews::OnMouseExited(const ui::MouseEvent& event) { if (location_bar_view_) location_bar_view_->OnOmniboxHovered(false); - - // A histogram records the duration that the user has hovered continuously - // over the omnibox without focusing it. - if (hover_start_time_ != base::Time() && !recorded_hover_on_focus_) { - UmaHistogramTimes("Omnibox.HoverTime", clock_->Now() - hover_start_time_); - } - hover_start_time_ = base::Time(); - recorded_hover_on_focus_ = false; - - if (!OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover() || - model()->ShouldPreventElision()) { - return; - } - if (!GetURLEligibleForSimplifiedDomainEliding()) - return; - - // When the reveal-on-hover field trial is enabled, we bring the URL into view - // when the user hovers over the omnibox and elide back to simplified domain - // when their mouse exits the omnibox area. The elision animation is the - // reverse of the unelision animation: we shrink the URL from both sides while - // shifting the text to the leading edge. - DCHECK(hover_elide_or_unelide_animation_); - SkColor starting_color = - hover_elide_or_unelide_animation_->IsAnimating() - ? hover_elide_or_unelide_animation_->GetCurrentColor() - : GetOmniboxColor(GetThemeProvider(), - OmniboxPart::LOCATION_BAR_TEXT_DIMMED); - hover_elide_or_unelide_animation_->Stop(); - // Elisions don't take display offset into account (see - // https://crbug.com/1099078), so the RenderText must be in NO_ELIDE mode to - // avoid over-eliding when some of the text is not visible due to display - // offset. - GetRenderText()->SetElideBehavior(gfx::NO_ELIDE); - - // Figure out where to elide to. If the user has already interacted with the - // page or reveal-on-interaction is disabled, then elide to the simplified - // domain; otherwise just hide the scheme and trivial subdomain (if any). - if (elide_after_web_contents_interaction_animation_ || - !OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction()) { - std::vector<gfx::Range> ranges_surrounding_simplified_domain; - gfx::Range simplified_domain = - GetSimplifiedDomainBounds(&ranges_surrounding_simplified_domain); - // If the simplified domain overflows the local bounds, then hover - // animations are disabled for simplicity. - if (TextRangeOverflowsView(this, GetRenderText(), simplified_domain)) - return; - hover_elide_or_unelide_animation_->Start( - simplified_domain, 0 /* delay_ms */, - ranges_surrounding_simplified_domain, starting_color, - SK_ColorTRANSPARENT); - } else { - std::u16string text = GetText(); - url::Component host = GetHostComponentAfterTrivialSubdomain(); - // If the hostname overflows the local bounds, then hover animations are - // disabled for simplicity. - if (TextRangeOverflowsView(this, GetRenderText(), - gfx::Range(host.begin, host.end()))) { - return; - } - hover_elide_or_unelide_animation_->Start( - gfx::Range(host.begin, text.size()), 0 /* delay_ms */, - std::vector<gfx::Range>{gfx::Range(0, host.begin)}, starting_color, - SK_ColorTRANSPARENT); - } } bool OmniboxViewViews::IsItemForCommandIdDynamic(int command_id) const { @@ -1785,57 +1319,9 @@ return Textfield::HandleAccessibleAction(action_data); } -void OmniboxViewViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { - Textfield::OnBoundsChanged(previous_bounds); - - if (!OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover() && - !OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction()) { - return; - } - - // When simplified domain display field trials are enabled, - // Textfield::OnBoundsChanged() may have undone the effect of any previous URL - // elisions, because it expands the Textfield's display rect to the local - // bounds, which may bring more of the URL into view than intended. Re-apply - // simplified domain elisions now. - - // Cancel any running animations. This could cause some abrupt transitions, - // but we can't adapt running animations to new bounds. - if (hover_elide_or_unelide_animation_) - hover_elide_or_unelide_animation_->Stop(); - if (elide_after_web_contents_interaction_animation_) - elide_after_web_contents_interaction_animation_->Stop(); - - // |elide_after_web_contents_interaction_animation_| is created when the user - // interacts with the page, if hide-on-interaction is enabled. If - // hide-on-interaction is disabled or the user has already interacted with the - // page, the simplified domain should have been showing before the bounds - // changed (or we would have been in the process of animating to the - // simplified domain). - if (!OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() || - elide_after_web_contents_interaction_animation_) { - if (GetURLEligibleForSimplifiedDomainEliding() && - !model()->ShouldPreventElision()) { - ElideURL(); - } - } else { - // The user hasn't interacted with the page yet. This resets animation state - // and shows the partially elided URL with scheme and trivial subdomains - // hidden. - ResetToHideOnInteraction(); - } -} - void OmniboxViewViews::OnFocus() { views::Textfield::OnFocus(); - // A histogram records the duration that the user has hovered continuously - // over the omnibox without focusing it. - if (hover_start_time_ != base::Time() && !recorded_hover_on_focus_) { - recorded_hover_on_focus_ = true; - UmaHistogramTimes("Omnibox.HoverTime", clock_->Now() - hover_start_time_); - } - // TODO(tommycli): This does not seem like it should be necessary. // Investigate why it's needed and see if we can remove it. model()->ResetDisplayTexts(); @@ -1850,7 +1336,6 @@ saved_selection_for_focus_change_.clear(); } - ShowFullURL(); GetRenderText()->SetElideBehavior(gfx::NO_ELIDE); // Focus changes can affect the visibility of any keyword hint. @@ -1943,37 +1428,6 @@ } ClearAccessibilityLabel(); - - // When the relevant field trial is enabled, reset state so that the URL will - // be elided/unelided on next user interaction or hover. - if (!model()->ShouldPreventElision()) { - if (OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover() && - !OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction()) { - // When reveal-on-hover is enabled but not hide-on-interaction, blur - // should unfocus the omnibox and return to the same state as on page - // load: the URL is elided to a simplified domain until the user hovers - // over the omnibox. There's no need to animate in this case because the - // omnibox's appearance already changes quite dramatically on blur - // (selection clearer, other URL transformations, etc.), so there's no - // need to make this change gradual. - hover_elide_or_unelide_animation_ = - std::make_unique<OmniboxViewViews::ElideAnimation>(this, - GetRenderText()); - if (GetURLEligibleForSimplifiedDomainEliding()) { - ElideURL(); - } else { - // If the text isn't eligible to be elided to a simplified domain, then - // ensure that as much of it is visible as will fit. - FitToLocalBounds(); - } - } else if (OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction()) { - // When hide-on-interaction is enabled, this method ensures that, once the - // omnibox is blurred, the URL is visible and that the animation state is - // set so that the URL will be animated to the simplified domain the - // next time the user interacts with the page. - ResetToHideOnInteraction(); - } - } } bool OmniboxViewViews::IsCommandIdEnabled(int command_id) const { @@ -1994,96 +1448,6 @@ location_bar_view_->command_updater()->IsCommandEnabled(command_id); } -void OmniboxViewViews::DidStartNavigation( - content::NavigationHandle* navigation) { - if (!OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() || - model()->ShouldPreventElision()) { - return; - } - - // If navigating to a different page in a browser-initiated navigation, the - // new URL should be shown unelided while the navigation is in progress. For - // renderer-initiated navigations, the URL isn't displayed until the - // navigation commits, so there's no need to elide/unelide it now. - if (navigation->IsInMainFrame() && !navigation->IsSameDocument() && - !navigation->IsRendererInitiated()) { - ResetToHideOnInteraction(); - } -} - -void OmniboxViewViews::DidFinishNavigation( - content::NavigationHandle* navigation) { - if (!OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() || - model()->ShouldPreventElision()) { - return; - } - - // Non-main-frame navigations don't change the visible URL, so no action is - // necessary for simplified domain elisions. - if (!navigation->IsInMainFrame()) - return; - - // If the navigation didn't commit, and it was renderer-initiated, then no - // action is needed, as the URL won't have been updated. But if it was - // browser-initiated, then the URL would have been updated to show the URL of - // the in-progress navigation; in this case, reset to show the full URL now - // that the navigation has finished without committing. - if (!navigation->HasCommitted()) { - if (navigation->IsRendererInitiated()) { - return; - } - ResetToHideOnInteraction(); - return; - } - - // Once a navigation finishes that changes the visible URL (besides just the - // ref), unelide and reset state so that we'll show the simplified domain on - // interaction. Same-document navigations that only change the ref are treated - // specially and don't cause the elision/unelision state to be altered. This - // is to avoid frequent eliding/uneliding within single-page apps that do - // frequent fragment navigations. - if (navigation->IsErrorPage() || !navigation->IsSameDocument() || - !navigation->GetPreviousMainFrameURL().EqualsIgnoringRef( - navigation->GetURL())) { - ResetToHideOnInteraction(); - } -} - -void OmniboxViewViews::DidGetUserInteraction( - const blink::WebInputEvent& event) { - // Exclude mouse clicks from triggering the simplified domain elision. Mouse - // clicks can be done idly and aren't a good signal of real intent to interact - // with the page. Plus, it can be jarring when the URL elides when the user - // clicks on a link only to immediately come back as the navigation occurs. - if (blink::WebInputEvent::IsMouseEventType(event.GetType())) - return; - - // Exclude modifier keys to prevent keyboard shortcuts (such as switching - // tabs) from eliding the URL. We don't want to count these shortcuts as - // interactions with the page content. - if (blink::WebInputEvent::IsKeyboardEventType(event.GetType()) && - event.GetModifiers() & blink::WebInputEvent::kKeyModifiers) { - return; - } - - MaybeElideURLWithAnimationFromInteraction(); -} - -void OmniboxViewViews::OnFocusChangedInPage( - content::FocusedNodeDetails* details) { - // Elide the URL to the simplified domain (the most security-critical - // information) when the user focuses a form text field, which is a key moment - // for making security decisions. Ignore the focus event if it didn't come - // from a mouse click/tap. Focus via keyboard will trigger elision from - // DidGetUserInteraction(), and we want to ignore focuses that aren't from an - // explicit user action (e.g., input fields that are autofocused on page - // load). - if (details->is_editable_node && - details->focus_type == blink::mojom::FocusType::kMouse) { - MaybeElideURLWithAnimationFromInteraction(); - } -} - std::u16string OmniboxViewViews::GetSelectionClipboardText() const { return SanitizeTextForPaste(Textfield::GetSelectionClipboardText()); } @@ -2545,373 +1909,10 @@ ExternalProtocolHandler::PermitLaunchUrl(); } -gfx::Range OmniboxViewViews::GetSimplifiedDomainBounds( - std::vector<gfx::Range>* ranges_surrounding_simplified_domain) { - DCHECK(ranges_surrounding_simplified_domain); - DCHECK(ranges_surrounding_simplified_domain->empty()); - - std::u16string text = GetText(); - url::Component host = GetHostComponentAfterTrivialSubdomain(); - - GURL url = url_formatter::FixupURL(base::UTF16ToUTF8(text), std::string()); - if (!OmniboxFieldTrial::ShouldMaybeElideToRegistrableDomain() || - !ShouldElideToRegistrableDomain(url)) { - ranges_surrounding_simplified_domain->emplace_back(0, host.begin); - ranges_surrounding_simplified_domain->emplace_back(host.end(), text.size()); - return gfx::Range(host.begin, host.end()); - } - - // TODO(estark): push this inside ParseForEmphasizeComponents()? - std::u16string simplified_domain = url_formatter::IDNToUnicode( - net::registry_controlled_domains::GetDomainAndRegistry( - url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)); - - if (simplified_domain.empty()) { - ranges_surrounding_simplified_domain->emplace_back(0, host.begin); - ranges_surrounding_simplified_domain->emplace_back(host.end(), text.size()); - return gfx::Range(host.begin, host.end()); - } - - size_t simplified_domain_pos = text.rfind(simplified_domain, host.end()); - DCHECK_NE(simplified_domain_pos, std::string::npos); - ranges_surrounding_simplified_domain->emplace_back(0, simplified_domain_pos); - ranges_surrounding_simplified_domain->emplace_back(host.end(), text.size()); - return gfx::Range(simplified_domain_pos, host.end()); -} - -bool OmniboxViewViews::GetURLEligibleForSimplifiedDomainEliding() const { - if (HasFocus() || model()->user_input_in_progress()) - return false; - if (!model()->CurrentTextIsURL()) - return false; - std::u16string text = GetText(); - url::Parsed parts; - std::u16string scheme_str; - // Call Parse() here instead of ParseForEmphasizeComponents() because the - // latter parses the inner URL for blob:, filesystem:, and view-source: URLs. - // For those schemes, we want the outer scheme so that we can disable elision - // for those schemes. - AutocompleteInput::Parse(text, std::string(), - model()->client()->GetSchemeClassifier(), &parts, - &scheme_str, nullptr); - - // TODO(crbug.com/1117631): Simplified domain elision can have bugs for some - // URLs with bidirectional hosts, disable elision for those URLs while the - // bugs are fixed. - const std::u16string url_host = text.substr(parts.host.begin, parts.host.len); - if (base::i18n::GetStringDirection(url_host) == - base::i18n::TextDirection::UNKNOWN_DIRECTION) { - return false; - } - - // Simplified domain display only makes sense for http/https schemes; for now - // we don't want to mess with the display of other URLs like data:, blob:, - // chrome:, etc. - return (scheme_str == base::UTF8ToUTF16(url::kHttpScheme) || - scheme_str == base::UTF8ToUTF16(url::kHttpsScheme)) && - !url_host.empty() && - !net::HostStringIsLocalhost( - base::UTF16ToUTF8(text.substr(parts.host.begin, parts.host.len))); -} - -void OmniboxViewViews::ResetToHideOnInteraction() { - if (!OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() || - model()->ShouldPreventElision()) { - return; - } - // Delete the interaction animation; it'll get recreated in - // DidGetUserInteraction(). Recreate the hover animation now because the user - // can hover over the URL before interacting with the page to reveal the - // scheme and trivial subdomain (if any). - elide_after_web_contents_interaction_animation_.reset(); - hover_elide_or_unelide_animation_ = - std::make_unique<OmniboxViewViews::ElideAnimation>(this, GetRenderText()); - if (GetURLEligibleForSimplifiedDomainEliding()) { - ShowFullURLWithoutSchemeAndTrivialSubdomain(); - } else { - if (!HasFocus() && !model()->user_input_in_progress()) - GetRenderText()->SetElideBehavior(gfx::ELIDE_TAIL); - FitToLocalBounds(); - } -} - -void OmniboxViewViews::OnShouldPreventElisionChanged() { - Update(); - if (!OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() && - !OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()) { - return; - } - if (model()->ShouldPreventElision()) { - hover_elide_or_unelide_animation_.reset(); - elide_after_web_contents_interaction_animation_.reset(); - if (GetURLEligibleForSimplifiedDomainEliding()) - ShowFullURL(); - return; - } - if (OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction()) { - if (location_bar_view_) - Observe(location_bar_view_->GetWebContents()); - ResetToHideOnInteraction(); - } else if (OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()) { - if (GetURLEligibleForSimplifiedDomainEliding()) { - ElideURL(); - } - hover_elide_or_unelide_animation_ = - std::make_unique<ElideAnimation>(this, GetRenderText()); - } -} - -void OmniboxViewViews::MaybeElideURLWithAnimationFromInteraction() { - if (!OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() || - model()->ShouldPreventElision()) { - return; - } - - // If there's already a hover animation running, just let it run as we will - // end up at the same place. - if (hover_elide_or_unelide_animation_->IsAnimating()) - return; - - // This method runs when the user interacts with the page, such as scrolling - // or typing. In the hide-on-interaction field trial, the URL is shown until - // user interaction, at which point it's animated to a simplified version of - // the domain (hiding the path and, optionally, subdomains). The animation is - // designed to draw the user's attention and suggest that they can return to - // the omnibox to uncover the full URL. - - // If we've already created and run the animation in an earlier call to this - // method, we don't need to do so again. - if (!GetURLEligibleForSimplifiedDomainEliding() || - elide_after_web_contents_interaction_animation_) { - return; - } - GetRenderText()->SetElideBehavior(gfx::NO_ELIDE); - elide_after_web_contents_interaction_animation_ = - std::make_unique<ElideAnimation>(this, GetRenderText()); - std::vector<gfx::Range> ranges_surrounding_simplified_domain; - gfx::Range simplified_domain = - GetSimplifiedDomainBounds(&ranges_surrounding_simplified_domain); - elide_after_web_contents_interaction_animation_->Start( - simplified_domain, 0 /* delay_ms */, ranges_surrounding_simplified_domain, - GetOmniboxColor(GetThemeProvider(), - OmniboxPart::LOCATION_BAR_TEXT_DIMMED), - SK_ColorTRANSPARENT); -} - -void OmniboxViewViews::ElideURL() { - DCHECK(OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() || - OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()); - DCHECK(GetURLEligibleForSimplifiedDomainEliding()); - - std::vector<gfx::Range> ranges_surrounding_simplified_domain; - gfx::Range simplified_domain_bounds = - GetSimplifiedDomainBounds(&ranges_surrounding_simplified_domain); - - // Setting the elision behavior to anything other than NO_ELIDE would result - // in the string getting cut off shorter the simplified domain, because - // display offset isn't taken into account when RenderText elides the string. - // See https://crbug.com/1099078. It's important to set to NO_ELIDE before - // starting to calculate simplified domain bounds with GetSubstringBounds(), - // because GetSubstringBounds() will fail if the simplified domain isn't - // visible due to RenderText elision. - GetRenderText()->SetElideBehavior(gfx::NO_ELIDE); - - // The simplified domain string must be a substring of the current display - // text in order to elide to it. - DCHECK_NE( - GetRenderText()->GetDisplayText().find(GetText().substr( - simplified_domain_bounds.start(), simplified_domain_bounds.end())), - std::string::npos); - - SetCursorEnabled(false); - - gfx::Rect simplified_domain_rect; - for (const auto& rect : - GetRenderText()->GetSubstringBounds(simplified_domain_bounds)) { - simplified_domain_rect.Union(rect); - } - - // |simplified_domain_rect| gives us the current bounds of the simplified - // domain substring. We shift it to the leftmost (rightmost if UI is RTL) edge - // of the omnibox (as determined by the x position of the current display - // rect), and then scroll to where the simplified domain begins, so that the - // simplified domain appears at the leftmost/rightmost edge. - gfx::Rect old_bounds = GetRenderText()->display_rect(); - int shifted_simplified_domain_x_pos; - // The x position of the elided domain will depend on whether the UI is LTR or - // RTL. - if (base::i18n::IsRTL()) { - shifted_simplified_domain_x_pos = - old_bounds.right() - simplified_domain_rect.width(); - } else { - shifted_simplified_domain_x_pos = old_bounds.x(); - } - // Use |old_bounds| for y and height values because the URL should never shift - // vertically while eliding to/from simplified domain. - gfx::Rect shifted_simplified_domain_rect( - shifted_simplified_domain_x_pos, old_bounds.y(), - simplified_domain_rect.width(), old_bounds.height()); - - // Now apply the display rect and offset so that exactly the simplified domain - // is visible. - - // First check if the simplified domain fits in the local bounds. If it - // doesn't, then we need to scroll so that the rightmost side is visible (e.g. - // "evil.com" instead of "victim.com" if the full hostname - // "victim.com.evil.com"). This check is only necessary for LTR mode because - // in RTL mode, we scroll to the rightmost side of the domain automatically. - if (shifted_simplified_domain_rect.width() > GetLocalBounds().width() && - !base::i18n::IsRTL()) { - FitToLocalBounds(); - GetRenderText()->SetDisplayOffset( - GetRenderText()->GetUpdatedDisplayOffset().x() - - (simplified_domain_rect.right() - - GetRenderText()->display_rect().width())); - } else { - // The simplified domain fits in the local bounds, so we proceed to set the - // display rect and offset to make the simplified domain visible. - GetRenderText()->SetDisplayRect(shifted_simplified_domain_rect); - // Scroll the text to where the simplified domain begins, relative to the - // leftmost (rightmost if UI is RTL) edge of the current display rect. - if (base::i18n::IsRTL()) { - GetRenderText()->SetDisplayOffset( - GetRenderText()->GetUpdatedDisplayOffset().x() + old_bounds.right() - - simplified_domain_rect.right()); - } else { - GetRenderText()->SetDisplayOffset( - GetRenderText()->GetUpdatedDisplayOffset().x() - - (simplified_domain_rect.x() - old_bounds.x())); - } - } - - // GetSubstringBounds() rounds outward internally, so there may be small - // portions of text still showing. Set the ranges surrounding the simplified - // domain to transparent so that these artifacts don't show. - for (const auto& range : ranges_surrounding_simplified_domain) - ApplyColor(SK_ColorTRANSPARENT, range); -} - -void OmniboxViewViews::ShowFullURL() { - if (!OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() && - !OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()) { - return; - } - - if (hover_elide_or_unelide_animation_) - hover_elide_or_unelide_animation_->Stop(); - if (elide_after_web_contents_interaction_animation_) - elide_after_web_contents_interaction_animation_->Stop(); - ApplyCaretVisibility(); - FitToLocalBounds(); - - // Previous animations or elisions might have faded the path and/or subdomains - // to transparent, so reset their color now that they should be visible. - ApplyColor(GetOmniboxColor(GetThemeProvider(), - OmniboxPart::LOCATION_BAR_TEXT_DIMMED), - gfx::Range(0, GetText().size())); - UpdateTextStyle(GetText(), model()->CurrentTextIsURL(), - model()->client()->GetSchemeClassifier()); - - GetRenderText()->SetElideBehavior(gfx::ELIDE_TAIL); -} - -void OmniboxViewViews::ShowFullURLWithoutSchemeAndTrivialSubdomain() { - DCHECK(GetURLEligibleForSimplifiedDomainEliding()); - DCHECK(OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() || - OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()); - DCHECK(!model()->ShouldPreventElision()); - - // First show the full URL, then figure out what to elide. - ShowFullURL(); - - if (!GetURLEligibleForSimplifiedDomainEliding() || - model()->ShouldPreventElision()) { - return; - } - - // TODO(https://crbug.com/1099078): currently, we cannot set the elide - // behavior to anything other than NO_ELIDE when the display offset is 0, i.e. - // when we are not hiding the scheme and trivial subdomain. This is because - // RenderText does not take display offset into account when eliding, so it - // will over-elide by however much text is scrolled out of the display area. - GetRenderText()->SetElideBehavior(gfx::NO_ELIDE); - - GetRenderText()->SetDisplayOffset(0); - const gfx::Rect& current_display_rect = GetRenderText()->display_rect(); - - // If the scheme and trivial subdomain should be elided, then we want to set - // the display offset to where the hostname after the trivial subdomain (if - // any) begins, relative to the current display rect. - std::u16string text = GetText(); - url::Component host = GetHostComponentAfterTrivialSubdomain(); - - // First check if the full hostname can fit in the local bounds. If not, then - // show the rightmost portion of the hostname. - gfx::Rect display_url_bounds; - gfx::Range host_range(host.begin, host.end()); - if (TextRangeOverflowsView(this, GetRenderText(), host_range)) { - gfx::Rect host_bounds; - for (const auto& rect : GetRenderText()->GetSubstringBounds(host_range)) - host_bounds.Union(rect); - // The full hostname won't fit, so show as much of it as possible starting - // from the right side. - display_url_bounds.set_x( - current_display_rect.x() + - (host_bounds.right() - current_display_rect.right())); - display_url_bounds.set_y(current_display_rect.y()); - display_url_bounds.set_width(current_display_rect.width()); - display_url_bounds.set_height(current_display_rect.height()); - } else { - for (const auto& rect : GetRenderText()->GetSubstringBounds( - gfx::Range(host.begin, text.size()))) { - display_url_bounds.Union(rect); - } - display_url_bounds.set_height(current_display_rect.height()); - display_url_bounds.set_y(current_display_rect.y()); - } - - // Set the scheme and trivial subdomain to transparent. This isn't necessary - // to hide this portion of the text because it will be scrolled out of - // visibility anyway when we set the display offset below. However, if the - // user subsequently hovers over the URL to bring back the scheme and trivial - // subdomain, the hover animation assumes that the hidden text starts from - // transparent and fades it back in. - ApplyColor(SK_ColorTRANSPARENT, gfx::Range(0, host.begin)); - - // Before setting the display offset, set the display rect to the portion of - // the URL that won't be elided, or leave it at the local bounds, whichever is - // smaller. The display offset is capped at 0 if the text doesn't overflow the - // display rect, so we must fit the display rect to the text so that we can - // then set the display offset to scroll the scheme and trivial subdomain out - // of visibility. - GetRenderText()->SetDisplayRect( - gfx::Rect(base::i18n::IsRTL() - ? current_display_rect.right() - display_url_bounds.width() - : current_display_rect.x(), - display_url_bounds.y(), display_url_bounds.width(), - display_url_bounds.height())); - - GetRenderText()->SetDisplayOffset( - -1 * (display_url_bounds.x() - current_display_rect.x())); -} - -url::Component OmniboxViewViews::GetHostComponentAfterTrivialSubdomain() const { - url::Component host; - url::Component unused_scheme; - std::u16string text = GetText(); - AutocompleteInput::ParseForEmphasizeComponents( - text, model()->client()->GetSchemeClassifier(), &unused_scheme, &host); - url_formatter::StripWWWFromHostComponent(base::UTF16ToUTF8(text), &host); - return host; -} - BEGIN_METADATA(OmniboxViewViews, views::Textfield) ADD_READONLY_PROPERTY_METADATA(bool, SelectionAtEnd) ADD_READONLY_PROPERTY_METADATA(int, TextWidth) ADD_READONLY_PROPERTY_METADATA(int, UnelidedTextWidth) ADD_READONLY_PROPERTY_METADATA(int, Width) ADD_READONLY_PROPERTY_METADATA(std::u16string, SelectedText) -ADD_READONLY_PROPERTY_METADATA(bool, URLEligibleForSimplifiedDomainEliding) -ADD_READONLY_PROPERTY_METADATA(url::Component, - HostComponentAfterTrivialSubdomain) END_METADATA
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h index 796e9e5..c178ede1 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -20,7 +20,6 @@ #include "components/prefs/pref_change_registrar.h" #include "components/search_engines/template_url_service.h" #include "components/search_engines/template_url_service_observer.h" -#include "content/public/browser/web_contents_observer.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/window_open_disposition.h" @@ -41,7 +40,6 @@ class OmniboxPopupContentsView; namespace content { -struct FocusedNodeDetails; class WebContents; } // namespace content @@ -62,8 +60,7 @@ #endif public views::TextfieldController, public ui::CompositorObserver, - public TemplateURLServiceObserver, - public content::WebContentsObserver { + public TemplateURLServiceObserver { public: METADATA_HEADER(OmniboxViewViews); @@ -153,118 +150,12 @@ std::u16string GetLabelForCommandId(int command_id) const override; bool IsCommandIdEnabled(int command_id) const override; - // content::WebContentsObserver: - void DidStartNavigation(content::NavigationHandle* navigation) override; - void DidFinishNavigation(content::NavigationHandle* navigation) override; - void DidGetUserInteraction(const blink::WebInputEvent& event) override; - void OnFocusChangedInPage(content::FocusedNodeDetails* details) override; - // For testing only. OmniboxPopupContentsView* GetPopupContentsViewForTesting() const { return popup_view_.get(); } protected: - // Animates the URL to a given range of text, which could be a substring or - // superstring of what's currently displayed. An elision animation hides the - // path (and optionally subdomains) by narrowing the bounds of each side of - // the URL while also shifting the text to remain aligned with the leading - // edge of the display area. While the bounds change, the text being elided - // can be simultaneously faded to transparent to make the transition smoother. - // An unelision animation is the reverse. - // - // Animation is used for elision when the elision is in response to a user - // interaction and we want to draw attention to where the URL is going and how - // it can be retrieved. Depending on field trial configurations, this could be - // after the user interacts with the page (where we want to hide the full URL - // but hint that it can be brought back by interacting with the omnibox), - // and/or when the user hovers over the omnibox. In contrast, - // ElideToSimplifiedDomain() and UnelideFromSimplifiedDomain() instantly - // elide/unelide and are used when we want to elide/unelide without drawing - // the user's attention (for example, on a same-document navigation where we - // want the URL to remain simplified if it was simplified before the - // navigation). - // - // This class is declared here for testing. - class ElideAnimation : public views::AnimationDelegateViews { - public: - ElideAnimation(OmniboxViewViews* view, gfx::RenderText* render_text); - ~ElideAnimation() override; - - // Begin the elision animation targeting |elide_to_bounds|, after a delay of - // |delay_ms|. |ranges_surrounding_simplified_domain| should contain 1 or 2 - // ranges surrounding the simplified domain part, they should be in order - // (i.e. the range on the left should be the first element). If only one - // element is set, it will be assumed we are only eliding from the left - // side. Those ranges will be faded from |starting_color| to - // |ending_color|. - void Start( - const gfx::Range& elide_to_bounds, - uint32_t delay_ms, - const std::vector<gfx::Range>& ranges_surrounding_simplified_domain, - SkColor starting_color, - SkColor ending_color); - - void Stop(); - - // Returns true if the animation is currently running. - bool IsAnimating(); - - // Returns the bounds to which the animation is eliding, as passed in to - // Start(). - const gfx::Range& GetElideToBounds() const; - - // Returns the current color applied to each of the ranges in - // |ranges_surrounding_simplified_domain| passed in to Start(), if the - // animation is running or has completed running. - // Returns gfx::kPlaceholderColor if the animation has not starting - // running yet. - SkColor GetCurrentColor() const; - - gfx::MultiAnimation* GetAnimationForTesting(); - - int GetCurrentOffsetForTesting() { return current_offset_; } - - // views::AnimationDelegateViews: - void AnimationProgressed(const gfx::Animation* animation) override; - - private: - // Non-owning pointers. |view_| and |render_text_| must always outlive this - // class. - OmniboxViewViews* view_; - gfx::RenderText* render_text_; - - // The target bounds passed in to Start(). - gfx::Range elide_to_bounds_; - // The desired end state: the display rect that we are eliding or uneliding - // to. - gfx::Rect elide_to_rect_; - // The starting display rect from which we are eliding or uneliding. - gfx::Rect elide_from_rect_; - // The display rect surrounding the simplified domain. - gfx::Rect simplified_domain_bounds_; - // The starting and ending display offsets for |render_text_|. - int starting_display_offset_ = 0; - int ending_display_offset_ = 0; - - // The current offset, exposed for testing. - int current_offset_; - - // Holds the ranges surrounding the simplified domain part. As the animation - // runs, each range fades from |starting_color_| to |ending_color_|. - std::vector<gfx::Range> ranges_surrounding_simplified_domain_; - SkColor starting_color_; - SkColor ending_color_; - - // The underlying animation. We use a MultiAnimation to implement the - // |delay_ms| delay passed into Start(). When this delay is nonzero, the - // first part of the animation is a zero tween of |delay_ms| length. - std::unique_ptr<gfx::MultiAnimation> animation_; - }; - - ElideAnimation* GetHoverElideOrUnelideAnimationForTesting(); - ElideAnimation* GetElideAfterInteractionAnimationForTesting(); - // views::Textfield: void OnThemeChanged() override; bool IsDropCursorForInsertion() const override; @@ -277,78 +168,7 @@ FRIEND_TEST_ALL_PREFIXES( OmniboxViewViewsTest, RendererInitiatedFocusPreservesCursorWhenStartingFocused); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, HoverAndExit); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, HoverAndExitIDN); FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, PrivateRegistry); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - BrowserInitiatedNavigation); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - UserInteractionAndHover); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - MouseClick); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - FocusingEditableNode); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - BoundsChanged); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, BoundsChanged); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, HoverHistogram); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, - CancellingAnimationDoesNotCrash); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - SchemeAndTrivialSubdomainElision); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, - SimplifiedDomainElisionWithNarrowOmnibox); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - SimplifiedDomainElisionWithNarrowOmnibox); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - HideOnInteractionAfterFocusAndBlur); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - URLPositionWithHideOnInteraction); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, AfterBlur); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - PathChangeDuringAnimation); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - VerticalAndHorizontalPosition); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - NoStaleGradientMask); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, ModifierKeys); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, - ErrorPageNavigation); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, - SameDocNavigations); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, - SameDocNavigationDuringAnimation); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, GradientMask); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, - GradientMaskResetAfterStop); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, - UserInteractionDuringAnimation); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, - SubframeNavigations); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, - AlwaysShowFullURLs); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsHideOnInteractionTest, - AlwaysShowFullURLs); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest, - UnsetAlwaysShowFullURLs); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsRevealOnHoverTest, - RegistrableDomainRepeated); - FRIEND_TEST_ALL_PREFIXES( - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - TabChangeWhenNotEligibleForEliding); FRIEND_TEST_ALL_PREFIXES(OmniboxPopupContentsViewTest, EmitAccessibilityEvents); // TODO(tommycli): Remove the rest of these friends after porting these @@ -356,8 +176,6 @@ FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, CloseOmniboxPopupOnTextDrag); FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, FriendlyAccessibleLabel); FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, DoNotNavigateOnDrop); - FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, - ElideAnimationDoesntStartIfNoVisibleChange); enum class UnelisionGesture { HOME_KEY_PRESSED, @@ -434,7 +252,6 @@ bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; bool HandleAccessibleAction(const ui::AXActionData& action_data) override; - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnFocus() override; void OnBlur() override; std::u16string GetSelectionClipboardText() const override; @@ -485,127 +302,12 @@ // always be considered "user gesture-triggered", lest it always return BLOCK. void PermitExternalProtocolHandler(); - // Returns the gfx::Range of the simplified domain of the current URL, if - // there is one. The simplified domain could be either the registrable domain - // (if OmniboxFieldTrial::ElideToRegistrableDomain() is enabled) or the full - // hostname. |ranges_surrounding_simplified_domain| is an optional output - // parameter; if non-null, it will be populated with the ranges that do not - // contain the simplified domain. - gfx::Range GetSimplifiedDomainBounds( - std::vector<gfx::Range>* ranges_surrounding_simplified_domain); - - // Returns true if the currently displayed URL is eligible for elision to a - // simplified domain. This takes into account the omnibox's current state - // (e.g. the URL shouldn't be elided if the user is currently editing it) as - // well as properties of the current text (e.g. extension URLs or non-URLs - // shouldn't be elided because they may not have simplified domains; localhost - // URLs shouldn't be elided because they are used in development workflows - // where the full URL is useful). - // - // This method does NOT take field trials into account or the "Always show - // full URLs" option. Calling code should check field trial state and - // model()->ShouldPreventElision() if applicable. - bool GetURLEligibleForSimplifiedDomainEliding() const; - - // When certain field trials are enabled, the URL is shown on page load - // and elided to a simplified domain when the user interacts with the page. - // This method resets back to the on-page-load state. That is, it unhides the - // URL (if currently hidden) and resets state so that the URL will show until - // user interaction. This is used on navigation and blur, when the URL should - // be shown but hidden on next user interaction. - void ResetToHideOnInteraction(); - - // Called when the "Always show full URLs" preference is toggled. Updates the - // state to elide to a simplified domain on user interaction and/or reveal the - // URL on hover, depending on field trial configuration. - // - // When the preference changes, we immediately elide/unelide instead of - // animating. Animating might look a little nicer, but this should be a - // relatively rare event so it's simpler to just immediately update the - // display. - void OnShouldPreventElisionChanged(); - - // Elides the URL to a simplified version of the domain with an animation. - // This should be called when a user interaction with the web contents - // triggers elision. Does nothing if the relevant field trial is disabled or - // the URL is not eligible for eliding. - void MaybeElideURLWithAnimationFromInteraction(); - - // The methods below elide to or unelide from a simplified version of the URL. - // Callers should ensure that the URL is valid before calling. - // - // These methods do not animate, but rather immediately elide/unelide. These - // methods are used when we don't want to draw the user's attention to the URL - // simplification -- for example, if the URL is already simplified and the - // user performs a same-document navigation, we want to keep the URL - // simplified without it appearing to be a change from the user's perspective. - - // Elides the URL to a simplified version of the domain. This will be the - // registrable domain if OmniboxFieldTrial::ShouldElideToRegistrableDomain() - // is true; otherwise it is the hostname with trivial subdomains ("www.") - // elided. The scheme, path, and other components of the URL are hidden. - void ElideURL(); - // Show the full URL, including scheme, all subdomains, and path. - void ShowFullURL(); - // Shows the full URL and then elides http/https schemes and the - // "www." subdomain (if present) by setting the display rect to the width of - // the remaining URL and then setting the display offset to scroll the scheme - // and trivial subdomain offscreen. - void ShowFullURLWithoutSchemeAndTrivialSubdomain(); - - // Parses GetText() as a URL, trims trivial subdomains from it (if any and if - // applicable), and returns the result. - url::Component GetHostComponentAfterTrivialSubdomain() const; - // When true, the location bar view is read only and also is has a slightly // different presentation (smaller font size). This is used for popups. bool popup_window_mode_; std::unique_ptr<OmniboxPopupContentsView> popup_view_; - // Animations are used to elide/unelide the path (and subdomains, if - // OmniboxFieldTrial::ShouldElideToRegistrableDomain() is true) under some - // field trial settings. These animations are created at different times - // depending on the field trial configuration, so don't assume they are - // non-null. - // - // These animations are used by different field trials as described below. - - // This animation is used to unelide or elide the URL - // when the mouse hovers or exits the omnibox. The URL will unelide to the - // full URL or a partially elided version (with scheme and trivial subdomains - // elided) depending on whether the user has interacted with the page yet - // (when reveal-on-interaction is enabled). - std::unique_ptr<ElideAnimation> hover_elide_or_unelide_animation_; - // When ShouldHidePathQueryRefOnInteraction() is enabled, when a - // navigation finishes, we unelide the URL if it was a full cross-document - // navigation. Once the user interacts with the page, we create and run - // |elide_after_web_contents_interaction_animation_| to elide the URL. After - // the first user interaction, - // |elide_after_web_contents_interaction_animation_| doesn't run again until - // it's re-created after the next navigation. There are 2 separate animations - // (one for after-interaction and one hovering) so that the state of the - // after-interaction animation can be queried to know when the user has or has - // not already interacted with the page. - std::unique_ptr<ElideAnimation> - elide_after_web_contents_interaction_animation_; - - // If set, rectangles will be drawn as gradient masks over the omnibox text. - // Used to smooth color transition when an ElideAnimation is animating. - gfx::Rect elide_animation_smoothing_rect_left_; - gfx::Rect elide_animation_smoothing_rect_right_; - - // The time that the mouse begins hovering over the omnibox, used for - // recording metrics related to simplified domain field trials. Set in - // OnMouseMoved() and cleared when the mouse exits the hover. - base::Time hover_start_time_; - // A histogram is recorded for each continuous hover over the omnibox, ended - // by either focusing or exiting the mouse. This is set to true if the - // histogram was recorded due to the omnibox being focused, so that it won't - // be recorded again for the same continuous hover when the mouse exits. - bool recorded_hover_on_focus_ = false; - base::Clock* clock_; - // Selection persisted across temporary text changes, like popup suggestions. std::vector<gfx::Range> saved_temporary_selection_;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc index 4d55b1e..fd7c844b 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
@@ -527,10 +527,7 @@ ui_test_utils::NavigateToURL(browser(), GURL("http://example.com/#%E2%98%83")); - EXPECT_EQ(view->GetText(), - OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover() - ? u"http://example.com/#\u2603" - : u"example.com/#\u2603"); + EXPECT_EQ(view->GetText(), u"example.com/#\u2603"); } // Ensure that when the user navigates between suggestions, that the accessible @@ -721,16 +718,7 @@ ui_test_utils::NavigateToURL(browser(), url); - // By default, the URL should be elided. Depending on field trial - // configuration, this will be implemented by pushing the scheme out of the - // display area or by eliding it from the actual text. - if (OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()) { - EXPECT_EQ(url_text, omnibox_view_views->GetText()); - EXPECT_GT( - 0, omnibox_view_views->GetRenderText()->GetUpdatedDisplayOffset().x()); - } else { - EXPECT_EQ(url_text, u"http://" + omnibox_view_views->GetText()); - } + EXPECT_EQ(url_text, u"http://" + omnibox_view_views->GetText()); // After toggling the setting, the full URL should be shown. chrome::ToggleShowFullURLs(browser()); @@ -740,13 +728,7 @@ // Toggling the setting again should go back to the elided URL. chrome::ToggleShowFullURLs(browser()); - if (OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover()) { - EXPECT_EQ(url_text, omnibox_view_views->GetText()); - EXPECT_GT( - 0, omnibox_view_views->GetRenderText()->GetUpdatedDisplayOffset().x()); - } else { - EXPECT_EQ(url_text, u"http://" + omnibox_view_views->GetText()); - } + EXPECT_EQ(url_text, u"http://" + omnibox_view_views->GetText()); } // The following set of tests require UIA accessibility support, which only
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc index 7f13620..b503424 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -70,16 +70,6 @@ class TestingOmniboxView; -void ExpectElidedToSimplifiedDomain(TestingOmniboxView* view, - base::StringPiece16 scheme, - base::StringPiece16 subdomain, - base::StringPiece16 hostname_and_scheme, - base::StringPiece16 path, - bool should_elide_to_registrable_domain); - -void ExpectUnelidedFromSimplifiedDomain(gfx::RenderText* render_text, - const gfx::Range& display_url); - // TestingOmniboxView --------------------------------------------------------- class TestingOmniboxView : public OmniboxViewViews { @@ -112,34 +102,6 @@ void GetAccessibleNodeData(ui::AXNodeData* node_data) override {} void OnThemeChanged() override; - // In the simplified domain field trials, these methods advance through - // elision/unelision animations (triggered by hovering over the omnibox and - // interacting with the web contents, respectively) by |step_ms|. - void StepSimplifiedDomainHoverAnimation(int64_t step_ms); - void StepSimplifiedDomainInteractionAnimation(int64_t step_ms); - - // Simulates a navigation and checks that the URL is elided to the simplified - // domain afterwards. This simulates a renderer-initiated navigation, in which - // the display URL is updated between DidStartNavigation() and - // DidFinishNavigation() calls. - void NavigateAndExpectElided(const GURL& url, - bool is_same_document, - const GURL& previous_url, - base::StringPiece16 scheme, - base::StringPiece16 subdomain, - base::StringPiece16 hostname_and_scheme, - base::StringPiece16 path, - bool should_elide_to_registrable_domain); - - // Simluates a navigation and checks that the URL is unelided from the - // simplified domain afterwards. This simulates a renderer-initiated - // navigation, in which the display URL is updated between - // DidStartNavigation() and DidFinishNavigation() calls. - void NavigateAndExpectUnelided(base::StringPiece16 url, - bool is_same_document, - const GURL& previous_url, - base::StringPiece16 scheme); - using OmniboxView::OnInlineAutocompleteTextMaybeChanged; private: @@ -166,8 +128,6 @@ // order. std::vector<std::pair<SkColor, gfx::Range>> range_colors_; - TestLocationBarModel* location_bar_model_; - // SetEmphasis() logs whether the base color of the text is emphasized. bool base_text_emphasis_; }; @@ -179,8 +139,7 @@ std::move(client), false, nullptr, - gfx::FontList()), - location_bar_model_(location_bar_model) {} + gfx::FontList()) {} void TestingOmniboxView::ResetEmphasisTestState() { base_text_emphasis_ = false; @@ -250,192 +209,6 @@ OmniboxViewViews::ApplyColor(color, range); } -void TestingOmniboxView::StepSimplifiedDomainHoverAnimation(int64_t step_ms) { - OmniboxViewViews::ElideAnimation* hover_animation = - GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(hover_animation); - EXPECT_TRUE(hover_animation->IsAnimating()); - gfx::AnimationContainerElement* hover_animation_as_element = - static_cast<gfx::AnimationContainerElement*>( - hover_animation->GetAnimationForTesting()); - hover_animation_as_element->SetStartTime(base::TimeTicks()); - hover_animation_as_element->Step(base::TimeTicks() + - base::TimeDelta::FromMilliseconds(step_ms)); -} - -void TestingOmniboxView::StepSimplifiedDomainInteractionAnimation( - int64_t step_ms) { - OmniboxViewViews::ElideAnimation* interaction_animation = - GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(interaction_animation); - EXPECT_TRUE(interaction_animation->IsAnimating()); - gfx::AnimationContainerElement* interaction_animation_as_element = - static_cast<gfx::AnimationContainerElement*>( - interaction_animation->GetAnimationForTesting()); - interaction_animation_as_element->SetStartTime(base::TimeTicks()); - interaction_animation_as_element->Step( - base::TimeTicks() + base::TimeDelta::FromMilliseconds(step_ms)); -} - -void TestingOmniboxView::NavigateAndExpectElided( - const GURL& url, - bool is_same_document, - const GURL& previous_url, - base::StringPiece16 scheme, - base::StringPiece16 subdomain, - base::StringPiece16 hostname_and_scheme, - base::StringPiece16 path, - bool should_elide_to_registrable_domain) { - content::MockNavigationHandle navigation; - navigation.set_is_same_document(is_same_document); - navigation.set_url(url); - navigation.set_previous_main_frame_url(previous_url); - DidStartNavigation(&navigation); - location_bar_model_->set_url(url); - location_bar_model_->set_url_for_display(base::ASCIIToUTF16(url.spec())); - model()->ResetDisplayTexts(); - RevertAll(); - navigation.set_has_committed(true); - DidFinishNavigation(&navigation); - ExpectElidedToSimplifiedDomain(this, scheme, subdomain, hostname_and_scheme, - path, should_elide_to_registrable_domain); -} - -void TestingOmniboxView::NavigateAndExpectUnelided(base::StringPiece16 url, - bool is_same_document, - const GURL& previous_url, - base::StringPiece16 scheme) { - content::MockNavigationHandle navigation; - navigation.set_is_same_document(is_same_document); - navigation.set_url(GURL(url)); - navigation.set_previous_main_frame_url(previous_url); - DidStartNavigation(&navigation); - location_bar_model_->set_url(GURL(url)); - location_bar_model_->set_url_for_display(std::u16string(url)); - model()->ResetDisplayTexts(); - RevertAll(); - navigation.set_has_committed(true); - DidFinishNavigation(&navigation); - ExpectUnelidedFromSimplifiedDomain(this->GetRenderText(), - gfx::Range(scheme.size(), url.size())); -} - -// TODO(crbug.com/1112536): With RTL UI, the URL is sometimes off by one pixel -// of the right edge. Investigate if this is expected, otherwise replace this -// with equality checks in tests that use it. Checks |a| is within 1 of |b|. -void CheckEqualsWithMarginOne(int a, int b) { - EXPECT_LE(std::abs(a - b), 1); -} - -// Checks that |view|'s current display rect and offset does not display -// |path|, and also does not display |subdomain_and_scheme| if -// |should_elide_to_registrable_domain| is true. -// -// |subdomain_and_scheme| is assumed to be a prefix of |hostname_and_scheme|. -// |subdomain_and_scheme| and |subdomain| should include a trailing ".", and -// |path| should include a leading "/". -void ExpectElidedToSimplifiedDomain(TestingOmniboxView* view, - base::StringPiece16 scheme, - base::StringPiece16 subdomain, - base::StringPiece16 hostname_and_scheme, - base::StringPiece16 path, - bool should_elide_to_registrable_domain) { - gfx::RenderText* render_text = view->GetRenderText(); - gfx::Rect subdomain_and_scheme_rect; - for (const auto& rect : render_text->GetSubstringBounds( - gfx::Range(0, scheme.size() + subdomain.size()))) { - subdomain_and_scheme_rect.Union(rect); - } - gfx::Rect path_rect; - for (const auto& rect : render_text->GetSubstringBounds( - gfx::Range(hostname_and_scheme.size(), - hostname_and_scheme.size() + path.size()))) { - path_rect.Union(rect); - } - EXPECT_FALSE(render_text->display_rect().Contains(path_rect)); - if (should_elide_to_registrable_domain) { - EXPECT_FALSE( - render_text->display_rect().Contains(subdomain_and_scheme_rect)); - gfx::Rect registrable_domain_rect; - for (const auto& rect : render_text->GetSubstringBounds(gfx::Range( - scheme.size() + subdomain.size(), hostname_and_scheme.size()))) { - registrable_domain_rect.Union(rect); - } - EXPECT_TRUE(render_text->display_rect().Contains(registrable_domain_rect)); - // The text should be scrolled to push the scheme and subdomain offscreen, - // so that the text starts at the registrable domain. Note that this code - // computes the expected offset by comparing x() values rather than - // comparing based on widths (for example, it wouldn't work to check that - // the display offset is equal to |subdomain_and_scheme_rect|'s width). This - // is because GetSubstringBounds() rounds outward, so the width of - // |subdomain_and_scheme_rect| could slightly overlap - // |registrable_domain_rect|. - // In the RTL UI case, the offset instead has to push the path offscreen to - // the right, so we check offset equals the width of the path rectangle. - if (base::i18n::IsRTL()) { - CheckEqualsWithMarginOne(path_rect.width(), - render_text->GetUpdatedDisplayOffset().x()); - } else { - EXPECT_EQ(registrable_domain_rect.x() - subdomain_and_scheme_rect.x(), - -1 * render_text->GetUpdatedDisplayOffset().x()); - } - // The scheme and subdomain should be transparent. - EXPECT_EQ(SK_ColorTRANSPARENT, view->GetLatestColorForRange(gfx::Range( - 0, scheme.size() + subdomain.size()))); - } else { - // When elision to registrable domain is disabled, the scheme should be - // hidden but the subdomain should not be. - EXPECT_FALSE( - render_text->display_rect().Contains(subdomain_and_scheme_rect)); - gfx::Rect hostname_rect; - for (const auto& rect : render_text->GetSubstringBounds( - gfx::Range(scheme.size(), hostname_and_scheme.size()))) { - hostname_rect.Union(rect); - } - // The text should be scrolled to push the scheme offscreen, so that the - // text starts at the subdomain. As above, it's important to compute the - // expected offset with x() values instead of width()s, since the width()s - // of different adjacent substring bounds could overlap. - // In the RTL UI case, the offset instead has to push the path offscreen to - // the right, so we check offset equals the width of the path rectangle. - if (base::i18n::IsRTL()) { - CheckEqualsWithMarginOne(path_rect.width(), - render_text->GetUpdatedDisplayOffset().x()); - } else { - EXPECT_EQ(hostname_rect.x() - subdomain_and_scheme_rect.x(), - -1 * render_text->GetUpdatedDisplayOffset().x()); - } - // The scheme should be transparent. - EXPECT_EQ(SK_ColorTRANSPARENT, - view->GetLatestColorForRange(gfx::Range(0, scheme.size()))); - } - // The path should be transparent. - EXPECT_EQ(SK_ColorTRANSPARENT, - view->GetLatestColorForRange( - gfx::Range(hostname_and_scheme.size(), - hostname_and_scheme.size() + path.size()))); -} - -// Checks that |render_text|'s current display rect and offset displays all of -// |display_url|, starting at the leading edge. -void ExpectUnelidedFromSimplifiedDomain(gfx::RenderText* render_text, - const gfx::Range& display_url) { - gfx::Rect unelided_rect; - for (const auto& rect : render_text->GetSubstringBounds(display_url)) { - unelided_rect.Union(rect); - } - EXPECT_TRUE(render_text->display_rect().Contains(unelided_rect)); - // |display_url| should be at the leading edge of |render_text|'s display - // rect for LTR UI, or at the rightmost side of the omnibox for RTL UI. - if (base::i18n::IsRTL()) { - CheckEqualsWithMarginOne( - unelided_rect.x(), - render_text->display_rect().right() - unelided_rect.width()); - } else { - EXPECT_EQ(unelided_rect.x(), render_text->display_rect().x()); - } -} - // TestingOmniboxEditController ----------------------------------------------- class TestingOmniboxEditController : public ChromeOmniboxEditController { @@ -489,19 +262,6 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -// The display URL used in simplified domain display tests. -static constexpr base::StringPiece16 kSimplifiedDomainDisplayUrl = - u"https://foo.example.test/bar"; -static constexpr base::StringPiece16 - kSimplifiedDomainDisplayUrlHostnameAndScheme = u"https://foo.example.test"; -static constexpr base::StringPiece16 - kSimplifiedDomainDisplayUrlSubdomainAndScheme = u"https://foo."; -static constexpr base::StringPiece16 kSimplifiedDomainDisplayUrlSubdomain = - u"foo."; -static constexpr base::StringPiece16 kSimplifiedDomainDisplayUrlPath = u"/bar"; -static constexpr base::StringPiece16 kSimplifiedDomainDisplayUrlScheme = - u"https://"; - class OmniboxViewViewsTest : public OmniboxViewViewsTestBase { public: OmniboxViewViewsTest(const std::vector<FeatureAndParams>& enabled_features, @@ -556,13 +316,6 @@ omnibox_view()->RevertAll(); } - // Sets up tests for the simplified domain field trials. - void SetUpSimplifiedDomainTest() { - UpdateDisplayURL(kSimplifiedDomainDisplayUrl); - // Call OnThemeChanged() to create the animations. - omnibox_view()->OnThemeChanged(); - } - // testing::Test: void SetUp() override; void TearDown() override; @@ -1092,30 +845,6 @@ EXPECT_FALSE(omnibox_view()->IsSelectAll()); } -TEST_F(OmniboxViewViewsTest, ElideAnimationDoesntStartIfNoVisibleChange) { - SetUpSimplifiedDomainTest(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - OmniboxViewViews::ElideAnimation elide_animation(omnibox_view(), render_text); - // Before any animation runs, the elide from rectangle is considered to be - // render_text's DisplayRect, so set it manually to be the current URL length. - gfx::Rect full_url_bounds; - for (auto rect : render_text->GetSubstringBounds( - gfx::Range(0, omnibox_view()->GetOmniboxTextLength()))) { - full_url_bounds.Union(rect); - } - render_text->SetDisplayRect(full_url_bounds); - // Start the animation, and have it animate to the current state. - elide_animation.Start( - gfx::Range(0, - omnibox_view()->GetOmniboxTextLength()), /* elide_to_bounds */ - 0, /* delay_ms */ - {gfx::Range(0, 0)}, /* ranges_surrounding_simplified_domain */ - SK_ColorBLACK, /* starting_color */ - SK_ColorBLACK); /* ending_color */ - // Animation shouldn't have been started. - EXPECT_FALSE(elide_animation.IsAnimating()); -} - class OmniboxViewViewsClipboardTest : public OmniboxViewViewsTest, public ::testing::WithParamInterface<ui::TextEditCommand> { @@ -1688,1880 +1417,3 @@ EXPECT_EQ(0U, end); ExpectFullUrlDisplayed(); } - -// Returns true if |render_text|'s current display rect and offset display at -// least part of |path_bounds|, but not the full |display_url|. This is useful -// for checking the displayed text partway through an animation. -bool IsPartlyThroughSimplifiedDomainElision(gfx::RenderText* render_text, - base::StringPiece16 display_url, - const gfx::Range& path_bounds) { - // First check if all of |display_url| is showing; if it is, we aren't partly - // elided. - gfx::Rect unelided_rect; - for (const auto& rect : - render_text->GetSubstringBounds(gfx::Range(0, display_url.size()))) { - unelided_rect.Union(rect); - } - if (render_text->display_rect().Contains(unelided_rect) && - render_text->GetUpdatedDisplayOffset().x() == 0) { - return false; - } - // Now check if at least some of |path| is visible. - gfx::Rect path_rect; - for (const auto& rect : render_text->GetSubstringBounds(path_bounds)) { - path_rect.Union(rect); - } - return render_text->display_rect().Intersects(path_rect); -} - -class OmniboxViewViewsNoSimplifiedDomainTest : public OmniboxViewViewsTest { - public: - OmniboxViewViewsNoSimplifiedDomainTest() - : OmniboxViewViewsTest( - {}, - {omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction, - omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover}) {} - - OmniboxViewViewsNoSimplifiedDomainTest( - const OmniboxViewViewsNoSimplifiedDomainTest&) = delete; - OmniboxViewViewsNoSimplifiedDomainTest& operator=( - const OmniboxViewViewsNoSimplifiedDomainTest&) = delete; -}; - -// Tests that when no simplified domain field trials are enabled, URL components -// are not hidden. Regression test for https://crbug.com/1093748. -TEST_F(OmniboxViewViewsNoSimplifiedDomainTest, UrlNotSimplifiedByDefault) { - SetUpSimplifiedDomainTest(); - omnibox_view()->EmphasizeURLComponents(); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(0, kSimplifiedDomainDisplayUrl.size()))); -} - -class OmniboxViewViewsRevealOnHoverTest - : public OmniboxViewViewsTest, - public ::testing::WithParamInterface<std::pair<bool, bool>> { - public: - OmniboxViewViewsRevealOnHoverTest() - : OmniboxViewViewsTest( - GetParam().first - ? std::vector<FeatureAndParams>( - {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover, - {}}, - {omnibox::kMaybeElideToRegistrableDomain, - // Ensure all domains are elidable by policy. - {{"max_unelided_host_length", "0"}}}}) - : std::vector<FeatureAndParams>( - {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover, - {}}}), - {}, - GetParam().second) { - // The lookalike allowlist is used by the registrable-domain-elision code. - reputation::InitializeBlankLookalikeAllowlistForTesting(); - } - - OmniboxViewViewsRevealOnHoverTest(const OmniboxViewViewsRevealOnHoverTest&) = - delete; - OmniboxViewViewsRevealOnHoverTest& operator=( - const OmniboxViewViewsRevealOnHoverTest&) = delete; - - protected: - bool ShouldElideToRegistrableDomain() { return GetParam().first; } -}; - -INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsRevealOnHoverTest, - OmniboxViewViewsRevealOnHoverTest, - ::testing::ValuesIn({std::make_pair(true, false), - std::make_pair(false, false), - std::make_pair(true, true), - std::make_pair(false, true)})); - -// Tests the field trial variation that shows a simplified domain by default and -// reveals the unsimplified URL on hover. -TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExit) { - SetUpSimplifiedDomainTest(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // As soon as the mouse hovers over the omnibox, the unelide animation should - // start running. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* hover_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(hover_animation); - EXPECT_TRUE(hover_animation->IsAnimating()); - - // Advance the clock through the animation. - ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation( - OmniboxFieldTrial::UnelideURLOnHoverThresholdMs())); - // After the extended hover threshold has elapsed, the display text shouldn't - // have changed yet. - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // Now advance through the unelision and check the display text. We assume - // that the animation takes less than 1 second. - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size()))); - EXPECT_FALSE(hover_animation->IsAnimating()); - // Check that the path and subdomain are not transparent. - EXPECT_NE(SK_ColorTRANSPARENT, - omnibox_view()->GetLatestColorForRange( - gfx::Range(kSimplifiedDomainDisplayUrlHostnameAndScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); - EXPECT_NE(SK_ColorTRANSPARENT, - omnibox_view()->GetLatestColorForRange(gfx::Range( - 0, kSimplifiedDomainDisplayUrlSubdomainAndScheme.size()))); - - // Now exit the mouse. At this point the elision animation should run. - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_EXITED, {0, 0})); - EXPECT_TRUE(hover_animation->IsAnimating()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); -} - -// Tests the field trial variation that shows a simplified domain by default and -// reveals the unsimplified URL on hover, using an IDN url. -TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExitIDN) { - // The display URL used in simplified domain display tests. - static constexpr base::StringPiece16 kSimplifiedDomainDisplayIDNUrl = - u"https://テスト.住所の例.test/bar"; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayIDNUrlHostnameAndScheme = - u"https://テスト.住所の例.test"; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayIDNUrlSubdomainAndScheme = u"https://テスト."; - static constexpr base::StringPiece16 kSimplifiedDomainDisplayIDNUrlSubdomain = - u"テスト."; - static constexpr base::StringPiece16 kSimplifiedDomainDisplayIDNUrlPath = - u"/bar"; - static constexpr base::StringPiece16 kSimplifiedDomainDisplayIDNUrlScheme = - u"https://"; - UpdateDisplayURL(kSimplifiedDomainDisplayIDNUrl); - // Call OnThemeChanged() to create the animations. - omnibox_view()->OnThemeChanged(); - - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme, - kSimplifiedDomainDisplayIDNUrlSubdomain, - kSimplifiedDomainDisplayIDNUrlHostnameAndScheme, - kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain())); - - // As soon as the mouse hovers over the omnibox, the unelide animation should - // start running. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - // Advance the clock through the animation. - ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation( - OmniboxFieldTrial::UnelideURLOnHoverThresholdMs())); - // After the extended hover threshold has elapsed, the display text shouldn't - // have changed yet. - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme, - kSimplifiedDomainDisplayIDNUrlSubdomain, - kSimplifiedDomainDisplayIDNUrlHostnameAndScheme, - kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain())); - - // Now advance through the unelision and check the display text. We assume - // that the animation takes less than 1 second. - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - render_text, gfx::Range(0, kSimplifiedDomainDisplayIDNUrl.size()))); - OmniboxViewViews::ElideAnimation* hover_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(hover_animation); - EXPECT_FALSE(hover_animation->IsAnimating()); - // Check that the path and subdomain are not transparent. - EXPECT_NE(SK_ColorTRANSPARENT, - omnibox_view()->GetLatestColorForRange(gfx::Range( - kSimplifiedDomainDisplayIDNUrlHostnameAndScheme.size(), - kSimplifiedDomainDisplayIDNUrl.size()))); - EXPECT_NE(SK_ColorTRANSPARENT, - omnibox_view()->GetLatestColorForRange(gfx::Range( - 0, kSimplifiedDomainDisplayIDNUrlSubdomainAndScheme.size()))); - - // Now exit the mouse. At this point the elision animation should run. - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_EXITED, {0, 0})); - EXPECT_TRUE(hover_animation->IsAnimating()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme, - kSimplifiedDomainDisplayIDNUrlSubdomain, - kSimplifiedDomainDisplayIDNUrlHostnameAndScheme, - kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain())); -} - -// Tests the field trial variation that shows a simplified domain by default -// using a private registry (https://publicsuffix.org/list/). Private registries -// should be ignored when computing the simplified domain, to avoid creating -// incentives for malicious sites to add themselves to the Public Suffix List. -TEST_P(OmniboxViewViewsRevealOnHoverTest, PrivateRegistry) { - // This test is only applicable when we elide to the registrable domain; - // otherwise private vs public registries are irrelevant. - if (!ShouldElideToRegistrableDomain()) - return; - - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayPrivateRegistryUrl = - u"https://foo.blogspot.com/bar"; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayPrivateRegistryUrlHostnameAndScheme = - u"https://foo.blogspot.com"; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayPrivateRegistryUrlSubdomain = u"foo."; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayPrivateRegistryUrlPath = u"/bar"; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayPrivateRegistryUrlScheme = u"https://"; - UpdateDisplayURL(kSimplifiedDomainDisplayPrivateRegistryUrl); - // Call OnThemeChanged() to create the animations. - omnibox_view()->OnThemeChanged(); - - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayPrivateRegistryUrlScheme, - kSimplifiedDomainDisplayPrivateRegistryUrlSubdomain, - kSimplifiedDomainDisplayPrivateRegistryUrlHostnameAndScheme, - kSimplifiedDomainDisplayPrivateRegistryUrlPath, - ShouldElideToRegistrableDomain())); -} - -// Tests the field trial variation that shows a simplified domain by default and -// reveals the unsimplified URL on hover, using a URL where the path contains -// the domain name. -TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExitDomainInPath) { - // The display URL used in simplified domain display tests. - static constexpr base::StringPiece16 kSimplifiedDomainDisplayRepeatedUrl = - u"https://ex.example.test/example.test"; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayRepeatedUrlHostnameAndScheme = - u"https://ex.example.test"; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayRepeatedUrlSubdomain = u"ex."; - static constexpr base::StringPiece16 kSimplifiedDomainDisplayRepeatedUrlPath = - u"/example.test"; - static constexpr base::StringPiece16 - kSimplifiedDomainDisplayRepeatedUrlScheme = u"https://"; - location_bar_model()->set_url(GURL(kSimplifiedDomainDisplayRepeatedUrl)); - location_bar_model()->set_url_for_display( - std::u16string(kSimplifiedDomainDisplayRepeatedUrl)); - omnibox_view()->model()->ResetDisplayTexts(); - omnibox_view()->RevertAll(); - // Call OnThemeChanged() to create the animations. - omnibox_view()->OnThemeChanged(); - - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayRepeatedUrlScheme, - kSimplifiedDomainDisplayRepeatedUrlSubdomain, - kSimplifiedDomainDisplayRepeatedUrlHostnameAndScheme, - kSimplifiedDomainDisplayRepeatedUrlPath, - ShouldElideToRegistrableDomain())); -} - -class OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest - : public OmniboxViewViewsTest, - public ::testing::WithParamInterface<std::pair<bool, bool>> { - public: - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest() - : OmniboxViewViewsTest( - GetParam().first - ? std::vector<FeatureAndParams>( - {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover, - {}}, - {omnibox:: - kHideSteadyStateUrlPathQueryAndRefOnInteraction, - {}}, - {omnibox::kMaybeElideToRegistrableDomain, - // Ensure all domains are elidable by policy. - {{"max_unelided_host_length", "0"}}}}) - : std::vector<FeatureAndParams>( - {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover, - {}}, - {omnibox:: - kHideSteadyStateUrlPathQueryAndRefOnInteraction, - {}}}), - {}, - GetParam().second) { - // The lookalike allowlist is used by the registrable-domain-elision code. - reputation::InitializeBlankLookalikeAllowlistForTesting(); - } - - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest( - const OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest&) = delete; - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest& operator=( - const OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest&) = delete; - - protected: - bool ShouldElideToRegistrableDomain() { return GetParam().first; } -}; - -INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - ::testing::ValuesIn({std::make_pair(true, false), - std::make_pair(false, false), - std::make_pair(true, true), - std::make_pair(false, true)})); - -// Tests the field trial variation that shows the simplified domain when the -// user interacts with the page and brings back the URL when the user hovers -// over the omnibox. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - UserInteractionAndHover) { - SetUpSimplifiedDomainTest(); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction and check that the fade-out animation runs. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - // Advance the clock through the fade-out animation; we assume that it takes - // less than 1s. - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // A second user interaction should not run the animation again. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - EXPECT_FALSE(omnibox_view() - ->GetElideAfterInteractionAnimationForTesting() - ->IsAnimating()); - - // The URL should come back on hover. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - // The hover should bring back the full URL, including scheme and trivial - // subdomains. - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(0, kSimplifiedDomainDisplayUrl.size()))); - // The path and scheme/subdomain should not be transparent. - EXPECT_NE(SK_ColorTRANSPARENT, - omnibox_view()->GetLatestColorForRange( - gfx::Range(kSimplifiedDomainDisplayUrlHostnameAndScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); - EXPECT_NE(SK_ColorTRANSPARENT, - omnibox_view()->GetLatestColorForRange(gfx::Range( - 0, kSimplifiedDomainDisplayUrlSubdomainAndScheme.size()))); -} - -// Tests that the hide-on-interaction simplified domain field trial handles -// intermediate states during a navigation properly. This test simulates a -// browser-initiated navigation in which the URL updates before the navigation -// commits. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - BrowserInitiatedNavigation) { - SetUpSimplifiedDomainTest(); - - ASSERT_NO_FATAL_FAILURE(omnibox_view()->NavigateAndExpectUnelided( - kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), kSimplifiedDomainDisplayUrlScheme)); - - // Before a user interaction triggers elision, a browser-initiated navigation - // should show the full URL (minus scheme and trivial subdomain) throughout - // the navigation. - - // Set a longer URL to ensure that the full URL stays visible even if it's - // longer than the previous URL. - static constexpr base::StringPiece16 kUrlSuffix = u"/foobar"; - UpdateDisplayURL(base::StrCat({kSimplifiedDomainDisplayUrl, kUrlSuffix})); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size()))); - - { - // In this test, we create MockNavigationHandles here instead of using the - // NavigateAndExpect* helpers because those helpers simulate - // renderer-initiated navigations, where the display URL isn't updated until - // just before DidFinishNavigation. - content::MockNavigationHandle navigation; - navigation.set_is_renderer_initiated(false); - - omnibox_view()->DidStartNavigation(&navigation); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size()))); - - omnibox_view()->DidFinishNavigation(&navigation); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size()))); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); - } - - // Simulate a user interaction and advance all the way through the animation - // until the URL is elided to the simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - base::StrCat({kSimplifiedDomainDisplayUrlPath, kUrlSuffix}), - ShouldElideToRegistrableDomain())); - - // Begin simulating a browser-initiated navigation, in which the URL is - // updated before DidStartNavigation() runs. - UpdateDisplayURL(base::StrCat({kSimplifiedDomainDisplayUrl, kUrlSuffix})); - // Ideally we would actually be unelided at this point, when a - // browser-initiated navigation has begun. But EmphasizeURLComponents() - // doesn't know which type of navigation is in progress, so this is the best - // we can do. - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - base::StrCat({kSimplifiedDomainDisplayUrlPath, kUrlSuffix}), - ShouldElideToRegistrableDomain())); - { - content::MockNavigationHandle navigation; - navigation.set_is_renderer_initiated(false); - - // Once the navigation starts and we know that it's a cross-document - // navigation, the URL should be unelided. - omnibox_view()->DidStartNavigation(&navigation); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size()))); - - omnibox_view()->DidFinishNavigation(&navigation); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size()))); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); - } -} - -// Tests that the hide-on-interaction simplified domain field trial handles -// non-committed navigations properly. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - NonCommittedNavigations) { - SetUpSimplifiedDomainTest(); - - ASSERT_NO_FATAL_FAILURE(omnibox_view()->NavigateAndExpectUnelided( - kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), kSimplifiedDomainDisplayUrlScheme)); - // Simulate a user interaction to elide the URL. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // When a renderer-initiated navigation finishes without committing, the URL - // should remain elided; we don't update the display URL until the navigation - // commits. - { - content::MockNavigationHandle navigation; - navigation.set_is_renderer_initiated(true); - navigation.set_has_committed(false); - omnibox_view()->DidStartNavigation(&navigation); - omnibox_view()->DidFinishNavigation(&navigation); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - } - - // When a browser-initiated navigation finishes without committing, the URL - // updates before commit, so we should reset back to the on-page-load state if - // the navigation doesn't eventually commit. - content::MockNavigationHandle navigation; - navigation.set_is_renderer_initiated(false); - navigation.set_has_committed(false); - omnibox_view()->DidStartNavigation(&navigation); - omnibox_view()->DidFinishNavigation(&navigation); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); -} - -// Tests that mouse clicks do not count as user interactions and do not elide -// the URL. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, MouseClick) { - SetUpSimplifiedDomainTest(); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a mouse click and check that the fade-out animation does not run. - blink::WebMouseEvent event; - event.SetType(blink::WebInputEvent::Type::kMouseDown); - omnibox_view()->DidGetUserInteraction(event); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); -} - -// Tests that focusing an editable node does count as a user interaction and -// elides the URL. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - FocusingEditableNode) { - SetUpSimplifiedDomainTest(); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Focusing a non-editable node should not run the fade-out animation. - content::FocusedNodeDetails details; - details.is_editable_node = false; - details.focus_type = blink::mojom::FocusType::kMouse; - omnibox_view()->OnFocusChangedInPage(&details); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); - - // Focusing via keypress should not run the fade-out animation. - details.is_editable_node = true; - details.focus_type = blink::mojom::FocusType::kForward; - omnibox_view()->OnFocusChangedInPage(&details); - elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); - - // Other ways that an element can be focused, such as element.focus() in - // JavaScript, have a focus type of kNone and should not run the fade-out - // animation. - details.is_editable_node = true; - details.focus_type = blink::mojom::FocusType::kNone; - omnibox_view()->OnFocusChangedInPage(&details); - elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); - - // Focusing an editable node should run the fade-out animation. - details.is_editable_node = true; - details.focus_type = blink::mojom::FocusType::kMouse; - omnibox_view()->OnFocusChangedInPage(&details); - elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_TRUE(elide_animation->IsAnimating()); -} - -// Tests that simplified domain elisions are re-applied when the omnibox's -// bounds change. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, BoundsChanged) { - SetUpSimplifiedDomainTest(); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // After the bounds change, the URL should remain unelided. - omnibox_view()->OnBoundsChanged(gfx::Rect()); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); - - // Hover over the omnibox and change the bounds during the animation. The - // animation should be cancelled and immediately transition back to the - // unelided URL. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* unelide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(unelide_animation); - EXPECT_TRUE(unelide_animation->IsAnimating()); - omnibox_view()->OnBoundsChanged(gfx::Rect()); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); - - // Simulate a user interaction and change the bounds during the animation. The - // animation should be cancelled and immediately transition to the animation's - // end state (simplified domain). - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_TRUE(elide_animation->IsAnimating()); - omnibox_view()->OnBoundsChanged(gfx::Rect()); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); -} - -// Tests that simplified domain elisions are re-applied when the omnibox's -// bounds change when only reveal-on-hover is enabled. -TEST_P(OmniboxViewViewsRevealOnHoverTest, BoundsChanged) { - SetUpSimplifiedDomainTest(); - - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // After the bounds change, the URL should remain elided. - omnibox_view()->OnBoundsChanged(gfx::Rect()); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // Hover over the omnibox and change the bounds during the animation. The - // animation should be cancelled and immediately transition back to the - // simplified domain. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* unelide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(unelide_animation); - EXPECT_TRUE(unelide_animation->IsAnimating()); - omnibox_view()->OnBoundsChanged(gfx::Rect()); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); -} - -// Tests that simplified domain hover duration histogram is recorded correctly. -TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverHistogram) { - base::SimpleTestClock clock; - constexpr int kHoverTimeMs = 1000; - SetUpSimplifiedDomainTest(); - clock.SetNow(base::Time::Now()); - omnibox_view()->clock_ = &clock; - - // Hover over the omnibox and then exit and check that the histogram is - // recorded correctly. - { - base::HistogramTester histograms; - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* unelide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(unelide_animation); - EXPECT_TRUE(unelide_animation->IsAnimating()); - clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs / 2)); - // Call OnMouseMoved() again halfway through the hover time to ensure that - // the histogram is only recorded once per continuous hover. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs / 2)); - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - auto samples = histograms.GetAllSamples("Omnibox.HoverTime"); - ASSERT_EQ(1u, samples.size()); - histograms.ExpectTimeBucketCount( - "Omnibox.HoverTime", base::TimeDelta::FromMilliseconds(kHoverTimeMs), - 1); - - // Focusing the omnibox while not hovering should not record another sample. - omnibox_view()->OnFocus(); - samples = histograms.GetAllSamples("Omnibox.HoverTime"); - ASSERT_EQ(1u, samples.size()); - } - - // Hover over the omnibox and then focus it, and check that the histogram is - // recorded correctly. - { - base::HistogramTester histograms; - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* unelide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(unelide_animation); - EXPECT_TRUE(unelide_animation->IsAnimating()); - clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs)); - omnibox_view()->OnFocus(); - auto samples = histograms.GetAllSamples("Omnibox.HoverTime"); - ASSERT_EQ(1u, samples.size()); - histograms.ExpectTimeBucketCount( - "Omnibox.HoverTime", base::TimeDelta::FromMilliseconds(kHoverTimeMs), - 1); - - // Moving the mouse, focusing again, and exiting from the omnibox after - // focusing it should not record any more samples. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - omnibox_view()->OnFocus(); - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - samples = histograms.GetAllSamples("Omnibox.HoverTime"); - ASSERT_EQ(1u, samples.size()); - - // Hovering and exiting again should record another sample. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - samples = histograms.GetAllSamples("Omnibox.HoverTime"); - ASSERT_EQ(2u, samples.size()); - } - - // Hovering over the omnibox while focused should not record a histogram, - // because no elide animation happens while focused. - { - base::HistogramTester histograms; - omnibox_view()->RequestFocus(); - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* unelide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(unelide_animation); - EXPECT_FALSE(unelide_animation->IsAnimating()); - clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs)); - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - auto samples = histograms.GetAllSamples("Omnibox.HoverTime"); - ASSERT_EQ(0u, samples.size()); - } -} - -// Tests that the simplified domain animation doesn't crash when it's cancelled. -// Regression test for https://crbug.com/1103738. -TEST_P(OmniboxViewViewsRevealOnHoverTest, CancellingAnimationDoesNotCrash) { - SetUpSimplifiedDomainTest(); - - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // Hover over the omnibox to begin the unelision animation, then change the - // URL such that the current animation would go out of bounds if it continued - // running. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - // Step through the animation partially so that it has a nonzero current - // value. (A zero current value causes an early return that circumvents the - // crash we are regression-testing.) - ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation( - OmniboxFieldTrial::UnelideURLOnHoverThresholdMs() + 1)); - - // Stopping the animation after changing the underlying display text should - // not crash. - UpdateDisplayURL(u"https://foo.test"); - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting()->Stop(); -} - -// Tests scheme and trivial subdomain elision when simplified domain field -// trials are enabled. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - SchemeAndTrivialSubdomainElision) { - // Use custom setup code instead of SetUpSimplifiedDomainTest() to use a URL - // with a "www." prefix (a trivial subdomain). - static constexpr base::StringPiece16 kFullUrl = - u"https://www.example.test/foo"; - constexpr size_t kSchemeAndSubdomainSize = 12; // "https://www." - UpdateDisplayURL(kFullUrl); - omnibox_view()->OnThemeChanged(); - - omnibox_view()->NavigateAndExpectUnelided(kFullUrl, - /*is_same_document=*/false, GURL(), - u"htpts://www."); - EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange( - gfx::Range(0, kSchemeAndSubdomainSize))); - - // Hovering before user interaction should bring back the scheme and trivial - // subdomain. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size()))); - EXPECT_NE(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange( - gfx::Range(0, kSchemeAndSubdomainSize))); - - // After mousing out, the scheme should fade out again. - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSchemeAndSubdomainSize, kSimplifiedDomainDisplayUrl.size()))); - EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange( - gfx::Range(0, kSchemeAndSubdomainSize))); - - // Simulate a user interaction and check that the URL gets elided to the - // simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - // Use should_elide_to_registrable_domain=true here regardless of how the - // field trial is set because the "www." should be elided as a trivial - // subdomain. - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), u"https://", u"www.", u"https://www.example.test", - u"/foo", - /* should_elide_to_registrable_domain=*/true)); - - // Do another hover and check that the URL gets unelided to the full URL. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size()))); - EXPECT_NE(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange( - gfx::Range(0, kSchemeAndSubdomainSize))); - - // And after another mouse exit, the URL should go back to the simplified - // domain. - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), u"https://", u"www.", u"https://www.example.test", - u"/foo", - /* should_elide_to_registrable_domain=*/true)); - EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange( - gfx::Range(0, kSchemeAndSubdomainSize))); -} - -class OmniboxViewViewsHideOnInteractionTest - : public OmniboxViewViewsTest, - public ::testing::WithParamInterface<std::pair<bool, bool>> { - public: - OmniboxViewViewsHideOnInteractionTest() - : OmniboxViewViewsTest( - GetParam().first - ? std::vector<FeatureAndParams>( - {{omnibox:: - kHideSteadyStateUrlPathQueryAndRefOnInteraction, - {}}, - {omnibox::kMaybeElideToRegistrableDomain, - // Ensure all domains are elidable by policy. - {{"max_unelided_host_length", "0"}}}}) - : std::vector<FeatureAndParams>( - {{omnibox:: - kHideSteadyStateUrlPathQueryAndRefOnInteraction, - {}}}), - {}, - GetParam().second) { - // The lookalike allowlist is used by the registrable-domain-elision code. - reputation::InitializeBlankLookalikeAllowlistForTesting(); - } - - OmniboxViewViewsHideOnInteractionTest( - const OmniboxViewViewsHideOnInteractionTest&) = delete; - OmniboxViewViewsHideOnInteractionTest& operator=( - const OmniboxViewViewsHideOnInteractionTest&) = delete; - - protected: - bool ShouldElideToRegistrableDomain() { return GetParam().first; } -}; - -INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsHideOnInteractionTest, - OmniboxViewViewsHideOnInteractionTest, - ::testing::ValuesIn({std::make_pair(true, false), - std::make_pair(false, false), - std::make_pair(true, true), - std::make_pair(false, true)})); - -// Tests the the "Always Show Full URLs" option works with the field trial -// variation that shows a simplified domain when the user interacts with the -// page. -TEST_P(OmniboxViewViewsHideOnInteractionTest, AlwaysShowFullURLs) { - // This test does setup itself and doesn't call SetUpSimplifiedDomainTest() - // because SetUpSimplifiedDomainTest() uses a URL with a foo.example.test - // hostname, and in this test we want to use a "www." subdomain to test that - // the URL is displayed properly when trivial subdomain elision is disabled. - static constexpr base::StringPiece16 kFullUrl = - u"https://www.example.test/foo"; - UpdateDisplayURL(kFullUrl); - omnibox_view()->OnThemeChanged(); - - // Enable the "Always show full URLs" setting. - location_bar_model()->set_should_prevent_elision(true); - omnibox_view()->OnShouldPreventElisionChanged(); - std::unique_ptr<content::WebContents> web_contents = - content::WebContentsTester::CreateTestWebContents(profile(), nullptr); - omnibox_view()->OnTabChanged(web_contents.get()); - EXPECT_EQ(kFullUrl, omnibox_view()->GetText()); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size()))); - - // When the Always Show Full URLs pref is enabled, the omnibox view won't - // observe user interactions and elide the URL. - EXPECT_FALSE(omnibox_view()->web_contents()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); -} - -// Tests the the "Always Show Full URLs" option works with the field trial -// variation that shows a simplified domain until the user hovers over the -// omnibox. -TEST_P(OmniboxViewViewsRevealOnHoverTest, AlwaysShowFullURLs) { - SetUpSimplifiedDomainTest(); - - // Enable the "Always show full URLs" setting. - location_bar_model()->set_should_prevent_elision(true); - omnibox_view()->OnShouldPreventElisionChanged(); - - // After a hover, there should be no animations running. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - EXPECT_FALSE(elide_animation); - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - elide_animation = omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - EXPECT_FALSE(elide_animation); -} - -// This test fixture enables the reveal-on-hover simplified domain field trial, -// and the hide-on-interaction variation when the parameter is true. -class OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest - : public OmniboxViewViewsTest, - public ::testing::WithParamInterface<std::pair<bool, bool>> { - public: - OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest() - : OmniboxViewViewsTest( - GetParam().first - ? std::vector<FeatureAndParams>( - {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover, - {}}, - {omnibox:: - kHideSteadyStateUrlPathQueryAndRefOnInteraction, - {}}}) - : std::vector<FeatureAndParams>( - {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover, - {}}}), - {omnibox::kMaybeElideToRegistrableDomain}, - GetParam().second) {} - - OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest( - const OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest&) = - delete; - OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest& operator=( - const OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest&) = - delete; - - protected: - bool IsHideOnInteractionEnabled() { return GetParam().first; } -}; - -INSTANTIATE_TEST_SUITE_P( - OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest, - OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest, - ::testing::ValuesIn({std::make_pair(true, false), - std::make_pair(false, false), - std::make_pair(true, true), - std::make_pair(false, true)})); - -// Tests that unsetting the "Always show full URLs" option begins showing/hiding -// the full URL appropriately when simplified domain field trials are enabled. -// This test has kMaybeElideToRegistrableDomain disabled so that we can check -// that www is elided when the option is unset but other subdomains are not. -TEST_P(OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest, - UnsetAlwaysShowFullURLs) { - // This test does setup itself and doesn't call SetUpSimplifiedDomainTest() - // because SetUpSimplifiedDomainTest() uses a URL with a foo.example.test - // hostname, and in this test we want to use a "www." subdomain to test that - // the URL is displayed properly when trivial subdomain elision is disabled. - static constexpr base::StringPiece16 kFullUrl = - u"https://www.example.test/foo"; - UpdateDisplayURL(kFullUrl); - omnibox_view()->OnThemeChanged(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - - // Enable the "Always show full URLs" setting. - location_bar_model()->set_should_prevent_elision(true); - omnibox_view()->OnShouldPreventElisionChanged(); - std::unique_ptr<content::WebContents> web_contents = - content::WebContentsTester::CreateTestWebContents(profile(), nullptr); - omnibox_view()->OnTabChanged(web_contents.get()); - EXPECT_EQ(u"https://www.example.test/foo", omnibox_view()->GetText()); - - // Now toggle the preference and check that the animations run as expected. - location_bar_model()->set_should_prevent_elision(false); - location_bar_model()->set_url_for_display(u"https://www.example.test/foo"); - omnibox_view()->OnShouldPreventElisionChanged(); - // When simplified domain field trials are enabled, LocationBarModelImpl - // doesn't do any elision, leaving it all up to OmniboxViewViews, so the text - // returned from LocationBarModelImpl is the same even though the preference - // has changed. - EXPECT_EQ(u"https://www.example.test/foo", omnibox_view()->GetText()); - if (IsHideOnInteractionEnabled()) { - ExpectUnelidedFromSimplifiedDomain( - render_text, - gfx::Range(std::string("https://www.").size(), kFullUrl.size())); - // Simulate a user interaction and check the fade-out animation. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_TRUE(elide_animation->IsAnimating()); - } else { - // Even though kMaybeElideToRegistrableDomain is disabled, we expect to be - // elided to the registrable domain because the www subdomain is considered - // trivial. - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), u"https://", u"www.", u"https://www.example.test", - u"/foo", true /* should elide to registrable domain */)); - } - // Simulate a hover event and check the elide/unelide animations. This - // should happen the same regardless of whether hide-on-interaction is - // enabled. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_TRUE(elide_animation->IsAnimating()); -} - -// Tests that in the hide-on-interaction field trial, the omnibox is reset to -// the local bounds on tab change when the new text is not eligible for -// simplified domain elision. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - TabChangeWhenNotEligibleForEliding) { - SetUpSimplifiedDomainTest(); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction and advance through the animation to elide the - // URL. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // Change the tab and set state such that the current text is not eligible for - // simplified domain eliding (specifically, use an ftp:// URL; only http/https - // URLs are eligible for eliding). The omnibox should take up the full local - // bounds and be reset to tail-eliding behavior, just as if the above - // simplified domain elision had not happened. - UpdateDisplayURL(u"ftp://foo.example.test"); - std::unique_ptr<content::WebContents> web_contents = - content::WebContentsTester::CreateTestWebContents(profile(), nullptr); - omnibox_view()->SaveStateToTab(web_contents.get()); - omnibox_view()->OnTabChanged(web_contents.get()); - - EXPECT_EQ(gfx::ELIDE_TAIL, omnibox_view()->GetRenderText()->elide_behavior()); - EXPECT_EQ(u"ftp://foo.example.test", - omnibox_view()->GetRenderText()->GetDisplayText()); - - // Change the tab and simulate user input in progress. In this case, the - // omnibox should take up the full local bounds but should not be reset to - // tail-eliding behavior, because it should always be in NO_ELIDE mode when - // editing. - UpdateDisplayURL(kSimplifiedDomainDisplayUrl); - omnibox_view()->Focus(); - omnibox_view()->model()->SetInputInProgress(true); - std::unique_ptr<content::WebContents> web_contents2 = - content::WebContentsTester::CreateTestWebContents(profile(), nullptr); - omnibox_view()->SaveStateToTab(web_contents2.get()); - omnibox_view()->OnTabChanged(web_contents2.get()); - - EXPECT_EQ(gfx::NO_ELIDE, omnibox_view()->GetRenderText()->elide_behavior()); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(0, kSimplifiedDomainDisplayUrl.size()))); -} - -// Tests that in the simplified domain field trials, non-http/https and -// localhost URLs are not elided. -TEST_P(OmniboxViewViewsRevealOnHoverTest, UrlsNotEligibleForEliding) { - static constexpr base::StringPiece16 kTestCases[] = { - // Various URLs that aren't eligible for simplified domain eliding. - u"ftp://foo.bar.test/baz", - u"javascript:alert(1)", - u"data:text/html,hello", - u"http://localhost:4000/foo", - u"blob:https://example.test/", - u"view-source:https://example.test/", - u"filesystem:https://example.test/a", - // A smoke test to check that the test code results in - // the URL being elided properly when eligible. - kSimplifiedDomainDisplayUrl, - }; - - for (const auto& test_case : kTestCases) { - UpdateDisplayURL(test_case); - omnibox_view()->OnThemeChanged(); - - if (test_case == kSimplifiedDomainDisplayUrl) { - // This case is the smoke test to check that the test setup does properly - // elide URLs that are eligible for eliding. - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - } else { - EXPECT_EQ(gfx::ELIDE_TAIL, - omnibox_view()->GetRenderText()->elide_behavior()); - EXPECT_EQ(test_case, omnibox_view()->GetRenderText()->GetDisplayText()); - EXPECT_EQ(0, - omnibox_view()->GetRenderText()->GetUpdatedDisplayOffset().x()); - } - } -} - -// Tests that in the hide-on-interaction field trial, when the path changes -// while being elided, the animation is stopped. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - PathChangeDuringAnimation) { - SetUpSimplifiedDomainTest(); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction and check that the fade-out animation runs. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_TRUE(elide_animation->IsAnimating()); - - // Change the path and check that the animation is cancelled. - UpdateDisplayURL(u"foo.example.test/bar#bar"); - omnibox_view()->model()->ResetDisplayTexts(); - omnibox_view()->RevertAll(); - EXPECT_FALSE(elide_animation->IsAnimating()); -} - -// Tests that vertical and horizontal positioning doesn't change when eliding -// to/from simplified domain. Regression test for https://crbug.com/1101674. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - VerticalAndHorizontalPosition) { - SetUpSimplifiedDomainTest(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - - const gfx::Rect& original_display_rect = render_text->display_rect(); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // After a navigation, the URL should not be elided to the simplified domain, - // and the display rect (including vertical and horizontal position) should be - // unchanged. - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); - EXPECT_EQ(original_display_rect, render_text->display_rect()); - - // Simulate a user interaction to elide to simplified domain and advance - // through the animation; the vertical position should still be unchanged, and - // the text should still start at the some position (the same x value). - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - const gfx::Rect& elided_display_rect = render_text->display_rect(); - EXPECT_EQ(original_display_rect.y(), elided_display_rect.y()); - EXPECT_EQ(original_display_rect.height(), elided_display_rect.height()); - EXPECT_EQ(original_display_rect.x(), elided_display_rect.x()); - - // Now hover over the omnibox to trigger an unelide and check that the display - // rect (including vertical and horizontal position) is back to what it was - // originally. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - const gfx::Rect& unelided_display_rect = render_text->display_rect(); - EXPECT_EQ(original_display_rect, unelided_display_rect); -} - -// Tests that modifier keys don't count as user interactions in the -// hide-on-interaction field trial. -TEST_P(OmniboxViewViewsHideOnInteractionTest, ModifierKeys) { - SetUpSimplifiedDomainTest(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction with a modifier key and check that the elide - // animation doesn't run. - blink::WebKeyboardEvent event( - blink::WebInputEvent::Type::kRawKeyDown, - blink::WebInputEvent::kControlKey, - blink::WebInputEvent::GetStaticTimeStampForTests()); - omnibox_view()->DidGetUserInteraction(event); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); -} - -// Tests that in the hide-on-interaction field trial, the URL is unelided when -// navigating to an error page. -TEST_P(OmniboxViewViewsHideOnInteractionTest, ErrorPageNavigation) { - SetUpSimplifiedDomainTest(); - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - // Simulate a user interaction to elide to the simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_TRUE(elide_animation->IsAnimating()); - - // Now simulate a navigation to an error page and check that the URL is - // unelided. - content::MockNavigationHandle navigation; - navigation.set_url(GURL(kSimplifiedDomainDisplayUrl)); - navigation.set_is_error_page(true); - omnibox_view()->DidStartNavigation(&navigation); - omnibox_view()->DidFinishNavigation(&navigation); - ExpectUnelidedFromSimplifiedDomain( - omnibox_view()->GetRenderText(), - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size())); -} - -// Tests that in the hide-on-interaction field trial, the URL is simplified on -// cross-document main-frame navigations, but not on same-document navigations. -TEST_P(OmniboxViewViewsHideOnInteractionTest, SameDocNavigations) { - SetUpSimplifiedDomainTest(); - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - static constexpr base::StringPiece16 kUrlSuffix = u"/foobar"; - - // On a same-document navigation before the URL has been simplified, the URL - // should remain unsimplified after the navigation finishes. - - { - // Set a longer URL to ensure that the full URL stays visible even if it's - // longer than the previous URL. - omnibox_view()->NavigateAndExpectUnelided( - base::StrCat({kSimplifiedDomainDisplayUrl, kUrlSuffix}), - /*is_same_document=*/true, GURL(), kSimplifiedDomainDisplayUrlScheme); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); - } - - // Simulate a user interaction to elide to the simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_TRUE(elide_animation->IsAnimating()); - - // On a cross-document main-frame navigation, the unsimplified URL should - // remain visible. - { - omnibox_view()->NavigateAndExpectUnelided( - kSimplifiedDomainDisplayUrl, /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); - } - - // Simulate another user interaction to elide to the simplified domain, and - // advance the clock all the way through the animation. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // On same-document main-frame fragment navigation, the URL should remain - // elided to the simplified domain. - { - omnibox_view()->NavigateAndExpectElided( - GURL(base::StrCat({kSimplifiedDomainDisplayUrl, u"#foobar"})), - /*is_same_document=*/true, GURL(kSimplifiedDomainDisplayUrl), - kSimplifiedDomainDisplayUrlScheme, kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - base::StrCat({kSimplifiedDomainDisplayUrlPath, u"#foobar"}), - ShouldElideToRegistrableDomain()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_FALSE(elide_animation->IsAnimating()); - } - - // On same-document main-frame non-fragment navigation, the URL shouldn't - // remain elided to the simplified domain. - { - omnibox_view()->NavigateAndExpectUnelided( - base::StrCat({kSimplifiedDomainDisplayUrl, kUrlSuffix}), - /*is_same_document=*/true, GURL(kSimplifiedDomainDisplayUrl), - kSimplifiedDomainDisplayUrlScheme); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_FALSE(elide_animation); - } -} - -// Tests that in the hide-on-interaction field trial, a same-document navigation -// cancels a currently-running animation and goes straight to the end state -// (elided to the simplified domain). -TEST_P(OmniboxViewViewsHideOnInteractionTest, - SameDocNavigationDuringAnimation) { - SetUpSimplifiedDomainTest(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - gfx::Range path_bounds( - kSimplifiedDomainDisplayUrl.find(kSimplifiedDomainDisplayUrlPath), - kSimplifiedDomainDisplayUrl.size()); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction to begin animating to the simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - - // Advance the clock by 1ms until the full URL is no longer showing, but we - // haven't finished eliding to the simplified domain yet. After a - // same-document navigation, we check that the URL has gone straight to the - // end state. In other words, a same-document navigation will cancel a - // currently-running animation but should end up where the animation was - // targeting. - bool is_midway_through_elision = false; - uint32_t step_ms = 1; - while (!is_midway_through_elision) { - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms)); - is_midway_through_elision = IsPartlyThroughSimplifiedDomainElision( - render_text, kSimplifiedDomainDisplayUrl, path_bounds); - } - - omnibox_view()->NavigateAndExpectElided( - GURL(kSimplifiedDomainDisplayUrl), - /*is_same_document=*/true, GURL(kSimplifiedDomainDisplayUrl), - kSimplifiedDomainDisplayUrlScheme, kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()); - - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_FALSE(elide_animation->IsAnimating()); -} - -// Tests that gradient mask is set correctly. -TEST_P(OmniboxViewViewsHideOnInteractionTest, GradientMask) { - if (base::i18n::IsRTL()) { - // TODO(crbug.com/1101472): Re-enable this test once gradient mask is - // implemented for RTL UI. - return; - } - SetUpSimplifiedDomainTest(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction to begin animating to the simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - // Advance the clock by 1ms until the full size gradient has been added. - uint32_t step_ms = 1; - int max_gradient_width = OmniboxViewViews::kSmoothingGradientMaxWidth - 1; - while (omnibox_view()->elide_animation_smoothing_rect_right_.width() < - max_gradient_width) { - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms)); - } - // If we are eliding from the left, the other side gradient should also be - // full size at this point, otherwise it should be 0. - if (ShouldElideToRegistrableDomain()) { - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), - max_gradient_width); - } else { - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0); - } - - // Get a bounding box for the unelided section of the URL. - std::vector<gfx::Range> ranges_surrounding_simplified_domain; - gfx::Range simplified_range = omnibox_view()->GetSimplifiedDomainBounds( - &ranges_surrounding_simplified_domain); - gfx::Rect simplified_rect; - for (auto rect : render_text->GetSubstringBounds(simplified_range)) { - simplified_rect.Union(rect - render_text->GetLineOffset(0)); - } - - // Advance the animation until both gradients start shrinking. - while (omnibox_view()->elide_animation_smoothing_rect_left_.width() == - max_gradient_width || - omnibox_view()->elide_animation_smoothing_rect_right_.width() == - max_gradient_width) { - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms)); - } - int offset = omnibox_view() - ->GetElideAfterInteractionAnimationForTesting() - ->GetCurrentOffsetForTesting(); - gfx::Rect display_rect = render_text->display_rect(); - // Check the expected size and positions for both gradients. - EXPECT_TRUE(omnibox_view()->elide_animation_smoothing_rect_left_.width() == - simplified_rect.x() + offset - 1 || - omnibox_view()->elide_animation_smoothing_rect_left_.width() == - 0); - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.x(), - display_rect.x()); - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(), - display_rect.right() - (simplified_rect.right() + offset) - 1); - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.x() - 1, - simplified_rect.right() + offset); -} - -// Tests that gradient mask is reset when animation is stopped. -TEST_P(OmniboxViewViewsHideOnInteractionTest, GradientMaskResetAfterStop) { - if (base::i18n::IsRTL()) { - // TODO(crbug.com/1101472): Re-enable this test once gradient mask is - // implemented for RTL UI. - return; - } - SetUpSimplifiedDomainTest(); - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction to begin animating to the simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - // Advance animation so it sets the gradient mask, then stop it. - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - omnibox_view()->GetElideAfterInteractionAnimationForTesting()->Stop(); - - // Both gradient mask rectangles should have a width of 0 once the animation - // has stopped. - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0); - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(), 0); -} - -// Tests that in the hide-on-interaction field trial, a second user interaction -// does not interfere with an animation that is currently running. This is -// similar to SameDocNavigationDuringAnimation except that this test checks that -// a second user interaction (rather than a same-doc navigation) lets the -// animation proceed undisturbed. -TEST_P(OmniboxViewViewsHideOnInteractionTest, UserInteractionDuringAnimation) { - SetUpSimplifiedDomainTest(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - gfx::Range path_bounds( - kSimplifiedDomainDisplayUrl.find(kSimplifiedDomainDisplayUrlPath), - kSimplifiedDomainDisplayUrl.size()); - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction to begin animating to the simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - - // Advance the clock by 1ms until the full URL is no longer showing, but we - // haven't finished eliding to the simplified domain yet. After a subsequent - // user interaction, we check that the URL is still in the same state (midway - // through elision) and that the animation is still running undisturbed. In - // other words, a second user interaction shouldn't change anything when an - // animation is in progress. - bool is_midway_through_elision = false; - uint32_t step_ms = 0; - while (!is_midway_through_elision) { - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms)); - is_midway_through_elision = IsPartlyThroughSimplifiedDomainElision( - render_text, kSimplifiedDomainDisplayUrl, path_bounds); - } - double animation_value = omnibox_view() - ->GetElideAfterInteractionAnimationForTesting() - ->GetAnimationForTesting() - ->GetCurrentValue(); - - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_TRUE(elide_animation->IsAnimating()); - EXPECT_EQ(animation_value, - elide_animation->GetAnimationForTesting()->GetCurrentValue()); - // The current display text should reflect that the animation in progress: the - // full display URL shouldn't be still visible, but we haven't necessarily - // reached the end state (just the simplified domain visible) yet. - EXPECT_TRUE(IsPartlyThroughSimplifiedDomainElision( - render_text, kSimplifiedDomainDisplayUrl, path_bounds)); -} - -// Tests that in the hide-on-interaction field trial, the path is not re-shown -// on subframe navigations. -TEST_P(OmniboxViewViewsHideOnInteractionTest, SubframeNavigations) { - SetUpSimplifiedDomainTest(); - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction to elide to the simplified domain, and advance - // the clock all the way through the animation. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // On a subframe navigation, the URL should remain elided to a simplified - // domain. - { - content::MockNavigationHandle navigation; - navigation.set_is_same_document(false); - std::unique_ptr<content::WebContents> web_contents = - content::WebContentsTester::CreateTestWebContents(profile(), nullptr); - content::RenderFrameHostTester::For(web_contents->GetMainFrame()) - ->InitializeRenderFrameIfNeeded(); - content::RenderFrameHost* subframe = - content::RenderFrameHostTester::For(web_contents->GetMainFrame()) - ->AppendChild("subframe"); - navigation.set_render_frame_host(subframe); - omnibox_view()->DidStartNavigation(&navigation); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - omnibox_view()->DidFinishNavigation(&navigation); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - } -} - -// Tests that in the reveal-on-hover field trial variation, domains are aligned -// to the right (truncated from the left) if the omnibox is too narrow to fit -// the whole domain. -TEST_P(OmniboxViewViewsRevealOnHoverTest, - SimplifiedDomainElisionWithNarrowOmnibox) { - const int kOmniboxWidth = 60; - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - gfx::Rect current_bounds = omnibox_view()->GetLocalBounds(); - gfx::Rect bounds(current_bounds.x(), current_bounds.y(), kOmniboxWidth, - current_bounds.height()); - omnibox_view()->SetBoundsRect(bounds); - SetUpSimplifiedDomainTest(); - - ASSERT_EQ(kSimplifiedDomainDisplayUrl, render_text->GetDisplayText()); - - // The omnibox should contain a substring of the domain, aligned to the right. - gfx::Rect hostname_bounds; - for (const auto& rect : render_text->GetSubstringBounds( - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrlHostnameAndScheme.size()))) { - hostname_bounds.Union(rect); - } - EXPECT_LT(hostname_bounds.x(), omnibox_view()->GetLocalBounds().x()); - EXPECT_FALSE(omnibox_view()->GetLocalBounds().Contains(hostname_bounds)); - - // No hover animations should run when the omnibox is too narrow to fit the - // simplified domain. - - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_FALSE(elide_animation->IsAnimating()); - - omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - elide_animation = omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_FALSE(elide_animation->IsAnimating()); -} - -// Tests that in the reveal-on-hover and hide-on-interaction field trial -// variation, domains are aligned to the right (truncated from the left) if the -// omnibox is too narrow to fit the whole domain. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - SimplifiedDomainElisionWithNarrowOmnibox) { - const int kOmniboxWidth = 60; - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - gfx::Rect current_bounds = omnibox_view()->GetLocalBounds(); - gfx::Rect bounds(current_bounds.x(), current_bounds.y(), kOmniboxWidth, - current_bounds.height()); - omnibox_view()->SetBoundsRect(bounds); - SetUpSimplifiedDomainTest(); - - content::MockNavigationHandle navigation; - navigation.set_is_same_document(false); - omnibox_view()->DidFinishNavigation(&navigation); - - ASSERT_EQ(kSimplifiedDomainDisplayUrl, render_text->GetDisplayText()); - - // The omnibox should contain a substring of the domain, aligned to the right. - gfx::Rect hostname_bounds; - for (const auto& rect : render_text->GetSubstringBounds( - gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrlHostnameAndScheme.size()))) { - hostname_bounds.Union(rect); - } - EXPECT_LT(hostname_bounds.x(), omnibox_view()->GetLocalBounds().x()); - EXPECT_FALSE(omnibox_view()->GetLocalBounds().Contains(hostname_bounds)); -} - -// Tests that in the hide-on-interaction field trial variation, the path is -// faded out after omnibox focus and blur. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - HideOnInteractionAfterFocusAndBlur) { - SetUpSimplifiedDomainTest(); - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - - // Simulate a user interaction to fade out the path. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // After focus, the URL should be fully unelided. - omnibox_view()->OnFocus(); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size()))); - EXPECT_NE(SK_ColorTRANSPARENT, - omnibox_view()->GetLatestColorForRange( - gfx::Range(0, omnibox_view()->GetText().size()))); - EXPECT_EQ(gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrlHostnameAndScheme.size()), - omnibox_view()->emphasis_range()); - - // After blur, the URL should return to the same state as page load: only - // scheme and trivial subdomains elided. - omnibox_view()->OnBlur(); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); - EXPECT_NE(SK_ColorTRANSPARENT, - omnibox_view()->GetLatestColorForRange( - gfx::Range(0, omnibox_view()->GetText().size()))); - EXPECT_EQ(gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrlHostnameAndScheme.size()), - omnibox_view()->emphasis_range()); - - // After a post-blur user interaction, the URL should animate to the - // simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetElideAfterInteractionAnimationForTesting(); - EXPECT_TRUE(elide_animation->IsAnimating()); -} - -// Tests that in the hide-on-interaction field trial variation, the URL is -// aligned as appropriate for LTR and RTL UIs during the different stages -// of elision. -// Regression test for crbug.com/1114332 -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - URLPositionWithHideOnInteraction) { - SetUpSimplifiedDomainTest(); - gfx::RenderText* render_text = omnibox_view()->GetRenderText(); - // Initially the display rect of the render text matches the omnibox bounds, - // store a copy of it. - gfx::Rect omnibox_bounds(render_text->display_rect()); - - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction to fade out the path. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - - // Check the URL is right aligned if the UI is RTL, or left aligned if it is - // LTR. - if (base::i18n::IsRTL()) { - EXPECT_EQ(render_text->display_rect().x(), - omnibox_bounds.right() - render_text->display_rect().width()); - } else { - EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x()); - } - - // Call OnFocus to trigger unelision. - omnibox_view()->OnFocus(); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size()))); - - // Check alignment again - if (base::i18n::IsRTL()) { - EXPECT_EQ(render_text->display_rect().x(), - omnibox_bounds.right() - render_text->display_rect().width()); - } else { - EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x()); - } - - // Call OnBlur to return to the state on page load. - omnibox_view()->OnBlur(); - ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain( - render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(), - kSimplifiedDomainDisplayUrl.size()))); - - // Check alignment again - if (base::i18n::IsRTL()) { - EXPECT_EQ(render_text->display_rect().x(), - omnibox_bounds.right() - render_text->display_rect().width()); - } else { - EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x()); - } -} - -// Tests that the last gradient mask from a previous animation is no longer -// visible when starting a new animation. -TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, - NoStaleGradientMask) { - if (base::i18n::IsRTL()) { - // TODO(crbug.com/1101472): Re-enable this test once gradient mask is - // implemented for RTL UI. - return; - } - SetUpSimplifiedDomainTest(); - omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl, - /*is_same_document=*/false, GURL(), - kSimplifiedDomainDisplayUrlScheme); - - // Simulate a user interaction to begin animating to the simplified domain. - omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent()); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainInteractionAnimation( - /*step_ms=*/1000)); - - // Hover over the omnibox to trigger unelide animation. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - ASSERT_NO_FATAL_FAILURE( - omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000)); - - // Both gradient mask rectangles will be full sized at this point - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), - OmniboxViewViews::kSmoothingGradientMaxWidth - 1); - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(), - OmniboxViewViews::kSmoothingGradientMaxWidth - 1); - - // Select the text in the omnibox, then click on the page, this will trigger - // an elision with no animation. - omnibox_view()->SelectAll(false); - blink::WebMouseEvent event; - event.SetType(blink::WebInputEvent::Type::kMouseDown); - omnibox_view()->DidGetUserInteraction(event); - - // Hover over the omnibox to trigger the unelide animation. - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - - // Even though the unelide animation hasn't advanced, the gradient mask - // rectangles should have been reset. - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0); - EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(), 0); -} - -// Tests that in the reveal-on-hover field trial variation (without -// hide-on-interaction), the path is faded back in after focus, then blur, then -// hover. -// TODO(crbug.com/1115551): Test is flaky. -TEST_P(OmniboxViewViewsRevealOnHoverTest, DISABLED_AfterBlur) { - SetUpSimplifiedDomainTest(); - - // Focus and blur the omnibox, then hover over it. The URL should unelide. - omnibox_view()->OnFocus(); - omnibox_view()->OnBlur(); - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), kSimplifiedDomainDisplayUrlScheme, - kSimplifiedDomainDisplayUrlSubdomain, - kSimplifiedDomainDisplayUrlHostnameAndScheme, - kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain())); - omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0})); - OmniboxViewViews::ElideAnimation* elide_animation = - omnibox_view()->GetHoverElideOrUnelideAnimationForTesting(); - ASSERT_TRUE(elide_animation); - EXPECT_TRUE(elide_animation->IsAnimating()); -} - -// Tests that registrable domain elision properly handles the case when the -// registrable domain appears as a subdomain, e.g. test.com.test.com. -TEST_P(OmniboxViewViewsRevealOnHoverTest, RegistrableDomainRepeated) { - // This test only applies when the URL is elided to the registrable domain. - if (!ShouldElideToRegistrableDomain()) - return; - - static constexpr base::StringPiece16 kRepeatedRegistrableDomainUrl = - u"https://example.com.example.com/foo"; - gfx::Range registrable_domain_and_path_range( - 20 /* "https://www.example.com." */, - kRepeatedRegistrableDomainUrl.size()); - - UpdateDisplayURL(kRepeatedRegistrableDomainUrl); - // Call OnThemeChanged() to create the animations. - omnibox_view()->OnThemeChanged(); - - ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain( - omnibox_view(), u"https://", u"example.com.", - u"https://example.com.example.com", u"/foo", - ShouldElideToRegistrableDomain())); - - // Check that the domain is elided up to the second instance of "example.com", - // not the first. - gfx::Rect registrable_domain_and_path; - for (const auto& rect : omnibox_view()->GetRenderText()->GetSubstringBounds( - registrable_domain_and_path_range)) { - registrable_domain_and_path.Union(rect); - } - EXPECT_EQ(omnibox_view()->GetRenderText()->display_rect().x(), - registrable_domain_and_path.x()); -}
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_controller.cc b/chrome/browser/ui/views/page_action/page_action_icon_controller.cc index 59936ed..6f9192a 100644 --- a/chrome/browser/ui/views/page_action/page_action_icon_controller.cc +++ b/chrome/browser/ui/views/page_action/page_action_icon_controller.cc
@@ -39,6 +39,7 @@ #include "chrome/browser/ui/views/translate/translate_icon_view.h" #include "chrome/browser/ui/views/webauthn/webauthn_icon_view.h" #include "content/public/common/content_features.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/layout/box_layout.h" PageActionIconController::PageActionIconController() = default; @@ -56,8 +57,9 @@ auto add_page_action_icon = [¶ms, this](PageActionIconType type, auto icon) { icon->SetVisible(false); - icon->ink_drop()->SetVisibleOpacity( - params.page_action_icon_delegate->GetPageActionInkDropVisibleOpacity()); + views::InkDrop::Get(icon.get()) + ->SetVisibleOpacity(params.page_action_icon_delegate + ->GetPageActionInkDropVisibleOpacity()); if (params.icon_color) icon->SetIconColor(*params.icon_color); if (params.font_list)
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_view.cc index 14542b17..4cf3b837 100644 --- a/chrome/browser/ui/views/page_action/page_action_icon_view.cc +++ b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
@@ -19,6 +19,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/native_theme/native_theme.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" @@ -63,7 +64,7 @@ DCHECK(delegate_); image()->SetFlipCanvasOnPaintForRTLUI(true); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); // Only shows bubble after mouse is released. button_controller()->set_notify_action(
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc index 97029c2a..ea33b67 100644 --- a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc +++ b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
@@ -51,7 +51,7 @@ #include "chrome/browser/ash/arc/arc_util.h" #include "chrome/browser/ash/arc/session/arc_session_manager.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" -#include "components/arc/arc_util.h" +#include "components/arc/test/arc_util_test_support.h" #include "components/arc/test/connection_holder_util.h" #include "components/arc/test/fake_app_instance.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.cc b/chrome/browser/ui/views/passwords/password_save_update_view.cc index fb878357..a9bd2cbe 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_view.cc +++ b/chrome/browser/ui/views/passwords/password_save_update_view.cc
@@ -31,6 +31,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/combobox_model.h" #include "ui/base/models/combobox_model_observer.h" +#include "ui/base/models/image_model.h" #include "ui/base/models/simple_combobox_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/color_utils.h" @@ -351,8 +352,8 @@ !controller_.pending_password().password_value.empty(); } -gfx::ImageSkia PasswordSaveUpdateView::GetWindowIcon() { - return gfx::ImageSkia(); +ui::ImageModel PasswordSaveUpdateView::GetWindowIcon() { + return ui::ImageModel(); } void PasswordSaveUpdateView::AddedToWidget() {
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.h b/chrome/browser/ui/views/passwords/password_save_update_view.h index 953b113..81102341 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_view.h +++ b/chrome/browser/ui/views/passwords/password_save_update_view.h
@@ -37,7 +37,7 @@ // PasswordBubbleViewBase: views::View* GetInitiallyFocusedView() override; bool IsDialogButtonEnabled(ui::DialogButton button) const override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; bool Accept() override; // View:
diff --git a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc index a6a0ea5..7bed4b3 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc +++ b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc
@@ -35,6 +35,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/combobox_model.h" #include "ui/base/models/combobox_model_observer.h" +#include "ui/base/models/image_model.h" #include "ui/base/models/simple_combobox_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/color_palette.h" @@ -523,8 +524,8 @@ !controller_.pending_password().password_value.empty(); } -gfx::ImageSkia PasswordSaveUpdateWithAccountStoreView::GetWindowIcon() { - return gfx::ImageSkia(); +ui::ImageModel PasswordSaveUpdateWithAccountStoreView::GetWindowIcon() { + return ui::ImageModel(); } void PasswordSaveUpdateWithAccountStoreView::AddedToWidget() {
diff --git a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h index c96167cb..eefb64ec 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h +++ b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h
@@ -62,7 +62,7 @@ // PasswordBubbleViewBase: views::View* GetInitiallyFocusedView() override; bool IsDialogButtonEnabled(ui::DialogButton button) const override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; // View: void AddedToWidget() override;
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h index a57a6af..6cfe449 100644 --- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h +++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
@@ -8,7 +8,6 @@ #include <string> #include "base/macros.h" -#include "base/observer_list.h" #include "chrome/browser/ui/autofill/payments/autofill_dialog_models.h" #include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h" #include "components/autofill/core/browser/payments/full_card_request.h"
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.cc b/chrome/browser/ui/views/payments/payment_request_item_list.cc index 3d60af3..05584d2 100644 --- a/chrome/browser/ui/views/payments/payment_request_item_list.cc +++ b/chrome/browser/ui/views/payments/payment_request_item_list.cc
@@ -18,6 +18,7 @@ #include "ui/gfx/color_utils.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/image_button_factory.h" @@ -116,7 +117,7 @@ edit_button->SetImage(views::Button::STATE_NORMAL, gfx::CreateVectorIcon(vector_icons::kEditIcon, kEditIconSize, icon_color)); - edit_button->ink_drop()->SetBaseColor(icon_color); + views::InkDrop::Get(edit_button.get())->SetBaseColor(icon_color); edit_button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS); edit_button->SetID(static_cast<int>(DialogViewID::EDIT_ITEM_BUTTON)); edit_button->SetAccessibleName(
diff --git a/chrome/browser/ui/views/profiles/profile_customization_bubble_sync_controller.cc b/chrome/browser/ui/views/profiles/profile_customization_bubble_sync_controller.cc index 999e6963..8d0b979 100644 --- a/chrome/browser/ui/views/profiles/profile_customization_bubble_sync_controller.cc +++ b/chrome/browser/ui/views/profiles/profile_customization_bubble_sync_controller.cc
@@ -20,6 +20,7 @@ bool CanSyncStart(syncer::SyncService* sync_service) { if (!sync_service || !sync_service->CanSyncFeatureStart()) return false; + CHECK(sync_service->GetUserSettings()); if (!sync_service->GetUserSettings()->GetSelectedTypes().Has( syncer::UserSelectableType::kThemes)) { return false; @@ -131,6 +132,7 @@ return; } + CHECK(theme_service_->GetThemeSyncableService()); theme_observation_.Observe(theme_service_->GetThemeSyncableService()); // Observe also the sync service to abort waiting for theme sync if the user
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc index 29432f0..e340cf8 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc +++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -44,6 +44,7 @@ #include "ui/native_theme/themed_vector_icon.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/button/md_text_button.h" #include "ui/views/controls/highlight_path_generator.h" @@ -190,7 +191,7 @@ background_profile_color_(background_profile_color), show_border_(show_border) { SetTooltipText(text); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); InstallCircleHighlightPathGenerator(this); } @@ -211,7 +212,7 @@ ImageForMenu(icon_, kShortcutIconToImageRatio, icon_color); SetImage(views::Button::STATE_NORMAL, SizeImage(image, kCircularImageButtonSize)); - ink_drop()->SetBaseColor(icon_color); + views::InkDrop::Get(this)->SetBaseColor(icon_color); if (show_border_) { const SkColor separator_color = GetNativeTheme()->GetSystemColor( @@ -554,8 +555,8 @@ SetPaintClientToLayer(true); set_margins(gfx::Insets(0)); DCHECK(anchor_button); - anchor_button->ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, - nullptr); + views::InkDrop::Get(anchor_button) + ->AnimateToState(views::InkDropState::ACTIVATED, nullptr); SetEnableArrowKeyTraversal(true); GetViewAccessibility().OverrideRole(ax::mojom::Role::kMenu); @@ -1015,9 +1016,10 @@ void ProfileMenuViewBase::OnWindowClosing() { DCHECK_EQ(g_profile_bubble_, this); - if (anchor_button()) - anchor_button()->ink_drop()->AnimateToState( - views::InkDropState::DEACTIVATED, nullptr); + if (anchor_button()) { + views::InkDrop::Get(anchor_button()) + ->AnimateToState(views::InkDropState::DEACTIVATED, nullptr); + } g_profile_bubble_ = nullptr; }
diff --git a/chrome/browser/ui/views/profiles/profile_picker_sign_in_flow_controller.cc b/chrome/browser/ui/views/profiles/profile_picker_sign_in_flow_controller.cc index 4d5bc9a..84041c0 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_sign_in_flow_controller.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_sign_in_flow_controller.cc
@@ -409,8 +409,9 @@ ->GetWebUI() ->GetController() ->GetAs<EnterpriseProfileWelcomeUI>(); - enterprise_profile_welcome_ui->Initialize( - type, GetUserDomain(), GetProfileColor(), std::move(proceed_callback)); + enterprise_profile_welcome_ui->Initialize(/*browser=*/nullptr, type, + GetUserDomain(), GetProfileColor(), + std::move(proceed_callback)); } void ProfilePickerSignInFlowController::FinishAndOpenBrowser(
diff --git a/chrome/browser/ui/views/profiles/profile_picker_turn_sync_on_delegate.cc b/chrome/browser/ui/views/profiles/profile_picker_turn_sync_on_delegate.cc index aaddd4a..656f018 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_turn_sync_on_delegate.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_turn_sync_on_delegate.cc
@@ -314,5 +314,9 @@ FinishSyncConfirmation( LoginUIService::SYNC_WITH_DEFAULT_SETTINGS, ProfileMetrics::ProfileAddSignInFlowOutcome::kEnterpriseSyncDisabled); + break; + case EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation: + NOTREACHED() << "The profile picker should not show an enterprise " + "welcome that prompts for profile creation"; } }
diff --git a/chrome/browser/ui/views/reader_mode/reader_mode_icon_view.cc b/chrome/browser/ui/views/reader_mode/reader_mode_icon_view.cc index 2b18e55..c3c3e398 100644 --- a/chrome/browser/ui/views/reader_mode/reader_mode_icon_view.cc +++ b/chrome/browser/ui/views/reader_mode/reader_mode_icon_view.cc
@@ -19,6 +19,7 @@ #include "services/metrics/public/cpp/ukm_recorder.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/views/animation/ink_drop.h" using dom_distiller::UMAHelper; using dom_distiller::url_utils::IsDistilledPage; @@ -62,7 +63,8 @@ void ReaderModeIconView::DidFinishNavigation( content::NavigationHandle* navigation_handle) { if (GetVisible()) - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, nullptr); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, + nullptr); } void ReaderModeIconView::ReadyToCommitNavigation(
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc index ce380c65..adea58dd 100644 --- a/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc +++ b/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc
@@ -24,10 +24,12 @@ #include "components/vector_icons/vector_icons.h" #include "ui/base/buildflags.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/text_constants.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/bubble/bubble_border.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_frame_view.h" @@ -83,12 +85,11 @@ return true; } -gfx::ImageSkia RelaunchRecommendedBubbleView::GetWindowIcon() { - return gfx::CreateVectorIcon( - gfx::IconDescription(vector_icons::kBusinessIcon, - ChromeLayoutProvider::Get()->GetDistanceMetric( - DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE), - gfx::kChromeIconGrey)); +ui::ImageModel RelaunchRecommendedBubbleView::GetWindowIcon() { + return ui::ImageModel::FromVectorIcon( + vector_icons::kBusinessIcon, gfx::kChromeIconGrey, + ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE)); } void RelaunchRecommendedBubbleView::Init() { @@ -120,8 +121,7 @@ void RelaunchRecommendedBubbleView::VisibilityChanged( views::View* starting_from, bool is_visible) { - views::Button::AsButton(GetAnchorView()) - ->ink_drop() + views::InkDrop::Get(GetAnchorView()) ->AnimateToState(is_visible ? views::InkDropState::ACTIVATED : views::InkDropState::DEACTIVATED, nullptr);
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.h b/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.h index 9cef812..bf2f4a0 100644 --- a/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.h +++ b/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.h
@@ -35,7 +35,7 @@ bool Accept() override; std::u16string GetWindowTitle() const override; bool ShouldShowCloseButton() const override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; protected: // LocationBarBubbleDelegateView:
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.cc index 31ed887..b6dab70 100644 --- a/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.cc +++ b/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.cc
@@ -19,6 +19,7 @@ #include "components/constrained_window/constrained_window_views.h" #include "components/vector_icons/vector_icons.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/point.h" @@ -62,12 +63,11 @@ return relaunch_required_timer_.GetWindowTitle(); } -gfx::ImageSkia RelaunchRequiredDialogView::GetWindowIcon() { - return gfx::CreateVectorIcon( - gfx::IconDescription(vector_icons::kBusinessIcon, - ChromeLayoutProvider::Get()->GetDistanceMetric( - DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE), - gfx::kChromeIconGrey)); +ui::ImageModel RelaunchRequiredDialogView::GetWindowIcon() { + return ui::ImageModel::FromVectorIcon( + vector_icons::kBusinessIcon, gfx::kChromeIconGrey, + ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE)); } // |relaunch_required_timer_| automatically starts for the next time the title
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.h b/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.h index ae6fb3d3..ee53925 100644 --- a/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.h +++ b/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.h
@@ -39,7 +39,7 @@ // views::DialogDelegateView: std::u16string GetWindowTitle() const override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; private: RelaunchRequiredDialogView(base::Time deadline,
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc index 1db2b04..72c6fecc 100644 --- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc +++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
@@ -21,6 +21,7 @@ #include "content/public/browser/web_contents.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/image/image.h" @@ -259,15 +260,14 @@ return false; } -gfx::ImageSkia PasswordReuseModalWarningDialog::GetWindowIcon() { +ui::ImageModel PasswordReuseModalWarningDialog::GetWindowIcon() { return password_type_.account_type() == ReusedPasswordAccountType::SAVED_PASSWORD - ? gfx::ImageSkia() - : gfx::CreateVectorIcon( - kSecurityIcon, + ? ui::ImageModel() + : ui::ImageModel::FromVectorIcon( + kSecurityIcon, gfx::kChromeIconGrey, ChromeLayoutProvider::Get()->GetDistanceMetric( - DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE), - gfx::kChromeIconGrey); + DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE)); } void PasswordReuseModalWarningDialog::OnGaiaPasswordChanged() {
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h index 04150f78..fc7ba239 100644 --- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h +++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
@@ -49,7 +49,7 @@ gfx::Size CalculatePreferredSize() const override; std::u16string GetWindowTitle() const override; bool ShouldShowCloseButton() const override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; // ChromePasswordProtectionService::Observer: void OnGaiaPasswordChanged() override;
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.h b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.h index 5f924a6..781c3c3 100644 --- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.h +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "chrome/browser/ui/media_router/cast_dialog_controller.h" #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
diff --git a/chrome/browser/ui/views/sharing/sharing_icon_view.cc b/chrome/browser/ui/views/sharing/sharing_icon_view.cc index 7d710c08..cf265ca 100644 --- a/chrome/browser/ui/views/sharing/sharing_icon_view.cc +++ b/chrome/browser/ui/views/sharing/sharing_icon_view.cc
@@ -137,8 +137,9 @@ void SharingIconView::UpdateInkDrop(bool activate) { auto target_state = activate ? views::InkDropState::ACTIVATED : views::InkDropState::HIDDEN; - if (ink_drop()->GetInkDrop()->GetTargetInkDropState() != target_state) - ink_drop()->AnimateToState(target_state, /*event=*/nullptr); + if (views::InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() != + target_state) + views::InkDrop::Get(this)->AnimateToState(target_state, /*event=*/nullptr); } bool SharingIconView::IsTriggerableEvent(const ui::Event& event) {
diff --git a/chrome/browser/ui/views/tab_icon_view.cc b/chrome/browser/ui/views/tab_icon_view.cc index 55ad8a8a..a6aae90 100644 --- a/chrome/browser/ui/views/tab_icon_view.cc +++ b/chrome/browser/ui/views/tab_icon_view.cc
@@ -24,6 +24,7 @@ #include "ui/gfx/favicon_size.h" #include "ui/gfx/paint_throbber.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/image_model_utils.h" #if defined(OS_WIN) #include "chrome/browser/win/app_icon.h" @@ -139,7 +140,8 @@ return; } - gfx::ImageSkia favicon = model_->GetFaviconForTabIconView(); + gfx::ImageSkia favicon = views::GetImageSkiaFromImageModel( + model_->GetFaviconForTabIconView(), GetNativeTheme()); if (!favicon.isNull()) { PaintFavicon(canvas, favicon); return;
diff --git a/chrome/browser/ui/views/tab_icon_view_model.h b/chrome/browser/ui/views/tab_icon_view_model.h index 2c0a30a..1890956fa 100644 --- a/chrome/browser/ui/views/tab_icon_view_model.h +++ b/chrome/browser/ui/views/tab_icon_view_model.h
@@ -5,9 +5,9 @@ #ifndef CHROME_BROWSER_UI_VIEWS_TAB_ICON_VIEW_MODEL_H_ #define CHROME_BROWSER_UI_VIEWS_TAB_ICON_VIEW_MODEL_H_ -namespace gfx { -class ImageSkia; -} +namespace ui { +class ImageModel; +} // namespace ui // Classes implement this interface to provide state for the TabIconView. class TabIconViewModel { @@ -16,7 +16,7 @@ virtual bool ShouldTabIconViewAnimate() const = 0; // Returns the favicon to display in the icon view - virtual gfx::ImageSkia GetFaviconForTabIconView() = 0; + virtual ui::ImageModel GetFaviconForTabIconView() = 0; protected: virtual ~TabIconViewModel() {}
diff --git a/chrome/browser/ui/views/tabs/color_picker_view.cc b/chrome/browser/ui/views/tabs/color_picker_view.cc index 7e58ec9..5a4b1040 100644 --- a/chrome/browser/ui/views/tabs/color_picker_view.cc +++ b/chrome/browser/ui/views/tabs/color_picker_view.cc
@@ -25,6 +25,7 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/favicon_size.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/border.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/highlight_path_generator.h" @@ -91,7 +92,7 @@ : gfx::Insets(padding); SetBorder(views::CreateEmptyBorder(insets)); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); SetAnimateOnStateChange(true); }
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc index 66288f9..dcf7c81 100644 --- a/chrome/browser/ui/views/tabs/new_tab_button.cc +++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -66,9 +66,9 @@ ink_drop_container_ = AddChildView(std::make_unique<views::InkDropContainerView>()); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - ink_drop()->SetHighlightOpacity(0.16f); - ink_drop()->SetVisibleOpacity(0.14f); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetHighlightOpacity(0.16f); + views::InkDrop::Get(this)->SetVisibleOpacity(0.14f); SetInstallFocusRingOnFocus(true); views::HighlightPathGenerator::Install( @@ -77,7 +77,12 @@ SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); } -NewTabButton::~NewTabButton() = default; +NewTabButton::~NewTabButton() { + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); +} void NewTabButton::FrameColorsChanged() { UpdateInkDropBaseColor(); @@ -85,7 +90,7 @@ } void NewTabButton::AnimateToStateForTesting(views::InkDropState state) { - ink_drop()->GetInkDrop()->AnimateToState(state); + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState(state); } void NewTabButton::AddLayerBeneathView(ui::Layer* new_layer) { @@ -137,7 +142,7 @@ void NewTabButton::NotifyClick(const ui::Event& event) { ImageButton::NotifyClick(event); - ink_drop()->GetInkDrop()->AnimateToState( + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState( views::InkDropState::ACTION_TRIGGERED); } @@ -264,7 +269,7 @@ } void NewTabButton::UpdateInkDropBaseColor() { - ink_drop()->SetBaseColor( + views::InkDrop::Get(this)->SetBaseColor( color_utils::GetColorWithMaxContrast(GetButtonFillColor())); }
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.cc b/chrome/browser/ui/views/tabs/tab_close_button.cc index 96584e5..ac7d0e6 100644 --- a/chrome/browser/ui/views/tabs/tab_close_button.cc +++ b/chrome/browser/ui/views/tabs/tab_close_button.cc
@@ -48,14 +48,15 @@ SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - ink_drop()->SetHighlightOpacity(0.16f); - ink_drop()->SetVisibleOpacity(0.14f); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetHighlightOpacity(0.16f); + views::InkDrop::Get(this)->SetVisibleOpacity(0.14f); // Disable animation so that the hover indicator shows up immediately to help // avoid mis-clicks. SetAnimationDuration(base::TimeDelta()); - ink_drop()->GetInkDrop()->SetHoverHighlightFadeDuration(base::TimeDelta()); + views::InkDrop::Get(this)->GetInkDrop()->SetHoverHighlightFadeDuration( + base::TimeDelta()); // The ink drop highlight path is the same as the focus ring highlight path, // but needs to be explicitly mirrored for RTL. @@ -97,7 +98,7 @@ if (colors == colors_) return; colors_ = std::move(colors); - ink_drop()->SetBaseColor( + views::InkDrop::Get(this)->SetBaseColor( color_utils::GetColorWithMaxContrast(colors_.background_color)); OnPropertyChanged(&colors_, views::kPropertyEffectsPaint); }
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc index 2e83921..c85ab8a 100644 --- a/chrome/browser/ui/views/task_manager_view.cc +++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -27,6 +27,7 @@ #include "components/prefs/pref_service.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/base/models/table_model_observer.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" @@ -179,13 +180,13 @@ return false; } -gfx::ImageSkia TaskManagerView::GetWindowIcon() { +ui::ImageModel TaskManagerView::GetWindowIcon() { #if BUILDFLAG(IS_CHROMEOS_ASH) // TODO(crbug.com/1162514): Move apps::CreateStandardIconImage to some // where lower in the stack. - return apps::CreateStandardIconImage( + return ui::ImageModel::FromImageSkia(apps::CreateStandardIconImage( *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - IDR_ASH_SHELF_ICON_TASK_MANAGER)); + IDR_ASH_SHELF_ICON_TASK_MANAGER))); #else return views::DialogDelegateView::GetWindowIcon(); #endif
diff --git a/chrome/browser/ui/views/task_manager_view.h b/chrome/browser/ui/views/task_manager_view.h index 861bfa3..1b39db0 100644 --- a/chrome/browser/ui/views/task_manager_view.h +++ b/chrome/browser/ui/views/task_manager_view.h
@@ -60,7 +60,7 @@ // views::DialogDelegateView: views::View* GetInitiallyFocusedView() override; bool ExecuteWindowsCommand(int command_id) override; - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; std::string GetWindowName() const override; bool Accept() override; bool IsDialogButtonEnabled(ui::DialogButton button) const override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc index ed87f2e..4e765bc 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -33,6 +33,7 @@ #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/image/image_skia_source.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/label_button_border.h" @@ -176,7 +177,8 @@ // TODO(bruthig): The ACTION_PENDING triggering logic should be in // MenuButton::OnPressed() however there is a bug with the pressed state // logic in MenuButton. See http://crbug.com/567252. - ink_drop()->AnimateToState(views::InkDropState::ACTION_PENDING, &event); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::ACTION_PENDING, &event); } }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc index 2432062..13e307f0 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_button.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -165,19 +165,19 @@ if (base::FeatureList::IsEnabled(views::kInstallableInkDropFeature)) { installable_ink_drop_ = std::make_unique<views::InstallableInkDrop>(this); installable_ink_drop_->SetConfig(GetToolbarInstallableInkDropConfig(this)); - ink_drop()->SetCreateInkDropCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](Button* host) -> std::unique_ptr<views::InkDrop> { // Ensure this doesn't get called when InstallableInkDrops are // enabled. DCHECK( !base::FeatureList::IsEnabled(views::kInstallableInkDropFeature)); return views::InkDrop::CreateInkDropForFloodFillRipple( - host->ink_drop()); + views::InkDrop::Get(host)); }, this)); } - ink_drop()->SetCreateMaskCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateMaskCallback(base::BindRepeating( [](ToolbarButton* host) -> std::unique_ptr<views::InkDropMask> { if (host->has_in_product_help_promo_) { // This gets the latest ink drop insets. |SetTrailingMargin()| is @@ -196,7 +196,7 @@ GetHighlightPath(host)); }, this)); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](ToolbarButton* host) { // Ensure this doesn't get called when InstallableInkDrops are enabled. DCHECK( @@ -592,7 +592,7 @@ // // TODO(collinbaker): Consider adding explicit way to recreate mask instead // of relying on HostSizeChanged() to do so. - ink_drop()->GetInkDrop()->HostSizeChanged(size()); + views::InkDrop::Get(this)->GetInkDrop()->HostSizeChanged(size()); views::InkDropState next_state; if (has_in_product_help_promo_ || GetVisible()) { @@ -608,7 +608,7 @@ // else should keep this ACTIVATED or in some other state. Consider adding // code to track the correct state and restore to that. } - ink_drop()->GetInkDrop()->AnimateToState(next_state); + views::InkDrop::Get(this)->GetInkDrop()->AnimateToState(next_state); UpdateIcon(); SchedulePaint(); @@ -688,8 +688,8 @@ menu_showing_ = true; - ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, - nullptr /* event */); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTIVATED, + nullptr /* event */); // Exit if the model is null. Although ToolbarButton::ShouldShowMenu() // performs the same check, its overrides may not. @@ -711,14 +711,14 @@ } void ToolbarButton::OnMenuClosed() { - ink_drop()->AnimateToState(views::InkDropState::DEACTIVATED, - nullptr /* event */); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::DEACTIVATED, + nullptr /* event */); menu_showing_ = false; // Set the state back to normal after the drop down menu is closed. if (GetState() != STATE_DISABLED) { - ink_drop()->GetInkDrop()->SetHovered(IsMouseHovered()); + views::InkDrop::Get(this)->GetInkDrop()->SetHovered(IsMouseHovered()); SetState(STATE_NORMAL); }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc index 338267b..5253acd8 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc
@@ -19,6 +19,7 @@ #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/canvas.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/background.h" #include "ui/views/layout/animating_layout_manager.h" #include "ui/views/layout/flex_layout.h" @@ -142,9 +143,10 @@ // We don't care about the main button being highlighted. if (button != main_button_) { subscriptions_.push_back( - button->ink_drop()->AddHighlightedChangedCallback(base::BindRepeating( - &ToolbarIconContainerView::OnButtonHighlightedChanged, - base::Unretained(this), base::Unretained(button)))); + views::InkDrop::Get(button)->AddHighlightedChangedCallback( + base::BindRepeating( + &ToolbarIconContainerView::OnButtonHighlightedChanged, + base::Unretained(this), base::Unretained(button)))); } subscriptions_.push_back(button->AddStateChangedCallback(base::BindRepeating( &ToolbarIconContainerView::UpdateHighlight, base::Unretained(this)))); @@ -275,7 +277,7 @@ void ToolbarIconContainerView::OnButtonHighlightedChanged( views::Button* button) { - if (button->ink_drop()->GetHighlighted()) + if (views::InkDrop::Get(button)->GetHighlighted()) highlighted_buttons_.insert(button); else highlighted_buttons_.erase(button);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.cc b/chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.cc index 376448e..6026bcc8 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.cc
@@ -15,6 +15,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/skia_util.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_host_view.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/installable_ink_drop_config.h" @@ -83,9 +84,10 @@ host->SetHasInkDropActionOnClick(true); views::HighlightPathGenerator::Install( host, std::make_unique<ToolbarButtonHighlightPathGenerator>()); - host->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - host->ink_drop()->SetVisibleOpacity(kToolbarInkDropVisibleOpacity); - host->ink_drop()->SetHighlightOpacity(kToolbarInkDropHighlightVisibleOpacity); - host->ink_drop()->SetBaseColorCallback( + views::InkDrop::Get(host)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(host)->SetVisibleOpacity(kToolbarInkDropVisibleOpacity); + views::InkDrop::Get(host)->SetHighlightOpacity( + kToolbarInkDropHighlightVisibleOpacity); + views::InkDrop::Get(host)->SetBaseColorCallback( base::BindRepeating(&GetToolbarInkDropBaseColor, host)); }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h index c232c1c..89ab036 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -8,7 +8,6 @@ #include <memory> #include <vector> -#include "base/observer_list.h" #include "base/scoped_observation.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/command_observer.h"
diff --git a/chrome/browser/ui/views/toolbar/webui_tab_counter_button.cc b/chrome/browser/ui/views/toolbar/webui_tab_counter_button.cc index c27608e5..e4f4597 100644 --- a/chrome/browser/ui/views/toolbar/webui_tab_counter_button.cc +++ b/chrome/browser/ui/views/toolbar/webui_tab_counter_button.cc
@@ -500,7 +500,12 @@ SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); } -WebUITabCounterButton::~WebUITabCounterButton() = default; +WebUITabCounterButton::~WebUITabCounterButton() { + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); +} void WebUITabCounterButton::UpdateTooltip(int num_tabs) { SetTooltipText(base::i18n::MessageFormatter::FormatWithNumberedArgs(
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc index 1ebed69..bf49c2107 100644 --- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc +++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
@@ -40,6 +40,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/size.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/label.h" #include "ui/views/view.h" #include "url/gurl.h" @@ -238,7 +239,7 @@ toolbar_button_provider->GetAppMenuButton(); const SkColor original_ink_drop_color = - app_menu_button->ink_drop()->GetBaseColor(); + views::InkDrop::Get(app_menu_button)->GetBaseColor(); { content::ThemeChangeWaiter theme_change_waiter(web_contents); @@ -247,7 +248,7 @@ "setAttribute('content', '#246')")); theme_change_waiter.Wait(); - EXPECT_NE(app_menu_button->ink_drop()->GetBaseColor(), + EXPECT_NE(views::InkDrop::Get(app_menu_button)->GetBaseColor(), original_ink_drop_color); } @@ -257,7 +258,7 @@ web_contents, "document.getElementById('theme-color').remove()")); theme_change_waiter.Wait(); - EXPECT_EQ(app_menu_button->ink_drop()->GetBaseColor(), + EXPECT_EQ(views::InkDrop::Get(app_menu_button)->GetBaseColor(), original_ink_drop_color); } #endif
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_menu_button.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_menu_button.cc index 86f2d48..feb6388 100644 --- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_menu_button.cc +++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_menu_button.cc
@@ -35,8 +35,8 @@ browser_view_(browser_view) { views::SetHitTestComponent(this, static_cast<int>(HTMENU)); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](WebAppMenuButton* host) { return host->GetColor(); }, this)); SetFocusBehavior(FocusBehavior::ALWAYS); @@ -75,10 +75,12 @@ } void WebAppMenuButton::StartHighlightAnimation() { - ink_drop()->GetInkDrop()->SetHoverHighlightFadeDuration( + views::InkDrop::Get(this)->GetInkDrop()->SetHoverHighlightFadeDuration( WebAppToolbarButtonContainer::kOriginFadeInDuration); - ink_drop()->GetInkDrop()->SetHovered(true); - ink_drop()->GetInkDrop()->UseDefaultHoverHighlightFadeDuration(); + views::InkDrop::Get(this)->GetInkDrop()->SetHovered(true); + views::InkDrop::Get(this) + ->GetInkDrop() + ->UseDefaultHoverHighlightFadeDuration(); highlight_off_timer_.Start( FROM_HERE, @@ -101,10 +103,12 @@ void WebAppMenuButton::FadeHighlightOff() { if (!ShouldEnterHoveredState()) { - ink_drop()->GetInkDrop()->SetHoverHighlightFadeDuration( + views::InkDrop::Get(this)->GetInkDrop()->SetHoverHighlightFadeDuration( WebAppToolbarButtonContainer::kOriginFadeOutDuration); - ink_drop()->GetInkDrop()->SetHovered(false); - ink_drop()->GetInkDrop()->UseDefaultHoverHighlightFadeDuration(); + views::InkDrop::Get(this)->GetInkDrop()->SetHovered(false); + views::InkDrop::Get(this) + ->GetInkDrop() + ->UseDefaultHoverHighlightFadeDuration(); } }
diff --git a/chrome/browser/ui/views/web_apps/web_app_hover_button.cc b/chrome/browser/ui/views/web_apps/web_app_hover_button.cc index 0ced78c..30d92c6 100644 --- a/chrome/browser/ui/views/web_apps/web_app_hover_button.cc +++ b/chrome/browser/ui/views/web_apps/web_app_hover_button.cc
@@ -25,6 +25,7 @@ #include "ui/base/models/image_model.h" #include "ui/events/event.h" #include "ui/gfx/image/image_skia.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/label.h" #include "url/gurl.h" @@ -72,13 +73,13 @@ WebAppHoverButton::~WebAppHoverButton() = default; void WebAppHoverButton::MarkAsUnselected(const ui::Event* event) { - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, - ui::LocatedEvent::FromIfValid(event)); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::HIDDEN, ui::LocatedEvent::FromIfValid(event)); } void WebAppHoverButton::MarkAsSelected(const ui::Event* event) { - ink_drop()->AnimateToState(views::InkDropState::ACTIVATED, - ui::LocatedEvent::FromIfValid(event)); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::ACTIVATED, ui::LocatedEvent::FromIfValid(event)); } void WebAppHoverButton::OnIconsRead(
diff --git a/chrome/browser/ui/views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc b/chrome/browser/ui/views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc index 25a71cb..8af6889 100644 --- a/chrome/browser/ui/views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc +++ b/chrome/browser/ui/views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc
@@ -199,8 +199,6 @@ Profile* profile, const web_app::AppId& app_id, WebAppProtocolHandlerAcceptanceCallback close_callback) { - // TODO(crbug.com/1105257)::Check if we have permission to - // launch the app directly. auto profile_keep_alive = std::make_unique<ScopedProfileKeepAlive>( profile, ProfileKeepAliveOrigin::kWebAppPermissionDialogWindow); auto keep_alive = std::make_unique<ScopedKeepAlive>(
diff --git a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.cc b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.cc index 0bef2dc..8336eef 100644 --- a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.cc +++ b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.cc
@@ -29,6 +29,7 @@ #include "extensions/browser/extension_dialog_auto_confirm.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/controls/button/checkbox.h" @@ -150,8 +151,8 @@ std::exchange(dialog_, nullptr)->UninstallCancelled(); } -gfx::ImageSkia WebAppUninstallDialogDelegateView::GetWindowIcon() { - return image_; +ui::ImageModel WebAppUninstallDialogDelegateView::GetWindowIcon() { + return ui::ImageModel::FromImageSkia(image_); } void WebAppUninstallDialogDelegateView::Uninstall() {
diff --git a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h index cf7d0fa..3014d07 100644 --- a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h +++ b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h
@@ -56,7 +56,7 @@ private: // views::DialogDelegateView: - gfx::ImageSkia GetWindowIcon() override; + ui::ImageModel GetWindowIcon() override; // Uninstalls the web app. void Uninstall();
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc index 5f6e376..6a04026 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -44,6 +44,7 @@ #include "net/base/escape.h" #include "third_party/blink/public/common/features.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/models/image_model.h" #include "ui/base/models/simple_menu_model.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -530,14 +531,16 @@ void AppBrowserController::OnTabRemoved(content::WebContents* contents) {} -gfx::ImageSkia AppBrowserController::GetFallbackAppIcon() const { +ui::ImageModel AppBrowserController::GetFallbackAppIcon() const { gfx::ImageSkia page_icon = browser()->GetCurrentPageIcon().AsImageSkia(); if (!page_icon.isNull()) { #if BUILDFLAG(IS_CHROMEOS_ASH) - if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) - return apps::CreateStandardIconImage(page_icon); + if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) { + return ui::ImageModel::FromImageSkia( + apps::CreateStandardIconImage(page_icon)); + } #endif - return page_icon; + return ui::ImageModel::FromImageSkia(page_icon); } // The icon may be loading still. Return a transparent icon rather @@ -545,7 +548,8 @@ SkBitmap bitmap; bitmap.allocN32Pixels(gfx::kFaviconSize, gfx::kFaviconSize); bitmap.eraseColor(SK_ColorTRANSPARENT); - return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + return ui::ImageModel::FromImageSkia( + gfx::ImageSkia::CreateFrom1xBitmap(bitmap)); } void AppBrowserController::UpdateDraggableRegion(const SkRegion& region) {
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.h b/chrome/browser/ui/web_applications/app_browser_controller.h index e3375d3..07c7cab8 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.h +++ b/chrome/browser/ui/web_applications/app_browser_controller.h
@@ -26,10 +26,13 @@ class TabMenuModelFactory; namespace gfx { -class ImageSkia; class Rect; } // namespace gfx +namespace ui { +class ImageModel; +} + namespace web_app { class WebAppBrowserController; @@ -102,10 +105,10 @@ virtual bool HasMinimalUiButtons() const = 0; // Returns the app icon for the window to use in the task list. - virtual gfx::ImageSkia GetWindowAppIcon() const = 0; + virtual ui::ImageModel GetWindowAppIcon() const = 0; // Returns the icon to be displayed in the window title bar. - virtual gfx::ImageSkia GetWindowIcon() const = 0; + virtual ui::ImageModel GetWindowIcon() const = 0; // Returns the color of the title bar. virtual absl::optional<SkColor> GetThemeColor() const; @@ -222,7 +225,7 @@ virtual void OnTabRemoved(content::WebContents* contents); // Gets the icon to use if the app icon is not available. - gfx::ImageSkia GetFallbackAppIcon() const; + ui::ImageModel GetFallbackAppIcon() const; private: // Sets the url that the app browser controller was created with.
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc index 3fb425d..eef285f 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -125,7 +125,7 @@ callback_for_testing_ = std::move(callback); } -gfx::ImageSkia WebAppBrowserController::GetWindowAppIcon() const { +ui::ImageModel WebAppBrowserController::GetWindowAppIcon() const { if (app_icon_) return *app_icon_; app_icon_ = GetFallbackAppIcon(); @@ -150,7 +150,7 @@ return *app_icon_; } -gfx::ImageSkia WebAppBrowserController::GetWindowIcon() const { +ui::ImageModel WebAppBrowserController::GetWindowIcon() const { return GetWindowAppIcon(); } @@ -270,7 +270,7 @@ if (icon_value->icon_type != apps::mojom::IconType::kStandard) return; - app_icon_ = icon_value->uncompressed; + app_icon_ = ui::ImageModel::FromImageSkia(icon_value->uncompressed); if (icon_value->is_placeholder_icon) LoadAppIcon(false /* allow_placeholder_icon */); @@ -287,7 +287,8 @@ return; } - app_icon_ = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + app_icon_ = + ui::ImageModel::FromImageSkia(gfx::ImageSkia::CreateFrom1xBitmap(bitmap)); if (auto* contents = web_contents()) contents->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); if (callback_for_testing_)
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.h b/chrome/browser/ui/web_applications/web_app_browser_controller.h index b80988c0a..c57c28c 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.h +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.h
@@ -19,7 +19,7 @@ #include "components/services/app_service/public/mojom/types.mojom-forward.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/image/image_skia.h" +#include "ui/base/models/image_model.h" #if BUILDFLAG(IS_CHROMEOS_ASH) #include "components/digital_asset_links/digital_asset_links_handler.h" // nogncheck @@ -53,8 +53,8 @@ // AppBrowserController: bool HasMinimalUiButtons() const override; - gfx::ImageSkia GetWindowAppIcon() const override; - gfx::ImageSkia GetWindowIcon() const override; + ui::ImageModel GetWindowAppIcon() const override; + ui::ImageModel GetWindowIcon() const override; absl::optional<SkColor> GetThemeColor() const override; absl::optional<SkColor> GetBackgroundColor() const override; std::u16string GetTitle() const override; @@ -104,7 +104,7 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) WebAppProvider& provider_; - mutable absl::optional<gfx::ImageSkia> app_icon_; + mutable absl::optional<ui::ImageModel> app_icon_; #if BUILDFLAG(IS_CHROMEOS_ASH) // The result of digital asset link verification of the web app.
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 8be0714..ea42de75 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -167,9 +167,9 @@ #include "chrome/browser/ash/scanning/scan_service.h" #include "chrome/browser/ash/scanning/scan_service_factory.h" #include "chrome/browser/ash/web_applications/chrome_camera_app_ui_delegate.h" -#include "chrome/browser/ash/web_applications/chrome_personalization_app_ui_delegate.h" #include "chrome/browser/ash/web_applications/help_app/help_app_ui_delegate.h" #include "chrome/browser/ash/web_applications/media_app/chrome_media_app_ui_delegate.h" +#include "chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_ui_delegate.h" #include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h" #include "chrome/browser/chromeos/eche_app/eche_app_manager_factory.h" #include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_service_factory.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/os_install_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/os_install_screen_handler.cc index 64fbde5..dff80a96 100644 --- a/chrome/browser/ui/webui/chromeos/login/os_install_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/os_install_screen_handler.cc
@@ -46,6 +46,10 @@ builder->Add("osInstallDialogInProgressTitle", IDS_OS_INSTALL_SCREEN_IN_PROGRESS_TITLE); + + builder->Add("osInstallDialogErrorTitle", IDS_OS_INSTALL_SCREEN_ERROR_TITLE); + builder->Add("osInstallDialogSuccessTitle", + IDS_OS_INSTALL_SCREEN_SUCCESS_TITLE); } void OsInstallScreenHandler::Initialize() {}
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_lacros.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_lacros.cc index 64569ccf..f56ef0fb9 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_lacros.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_lacros.cc
@@ -13,6 +13,7 @@ #include "base/callback.h" #include "base/logging.h" #include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" #include "base/metrics/histogram_functions.h" #include "base/stl_util.h" #include "base/values.h" @@ -31,6 +32,9 @@ namespace { +// We only support sending username for named users but just in case. +const char kUsernamePlaceholder[] = "chronos"; + base::Value PrinterToValue(const crosapi::mojom::LocalDestinationInfo& p) { base::Value value(base::Value::Type::DICTIONARY); value.SetStringKey(kSettingDeviceName, p.device_name); @@ -164,8 +168,31 @@ PrintCallback callback) { size_t size_in_kb = print_data->size() / 1024; base::UmaHistogramMemoryKB("Printing.CUPS.PrintDocumentSize", size_in_kb); - // TODO(crbug.com/1206495): add support for - // printing.send_username_and_filename_enabled flag. + if (!service_->IsAvailable<crosapi::mojom::LocalPrinter>()) { + LOG(ERROR) << "Local printer not available"; + OnProfileUsernameReady(std::move(settings), std::move(print_data), + std::move(callback), absl::nullopt); + return; + } + + service_->GetRemote<crosapi::mojom::LocalPrinter>() + ->IsSendUsernameFilenameEnabled( + base::BindOnce(&LocalPrinterHandlerLacros::OnProfileUsernameReady, + weak_ptr_factory_.GetWeakPtr(), std::move(settings), + std::move(print_data), std::move(callback))); +} + +void LocalPrinterHandlerLacros::OnProfileUsernameReady( + base::Value settings, + scoped_refptr<base::RefCountedMemory> print_data, + PrinterHandler::PrintCallback callback, + const absl::optional<std::string>& username) { + if (username.has_value()) { + settings.SetKey(kSettingUsername, + base::Value(username.value().empty() ? kUsernamePlaceholder + : username.value())); + settings.SetKey(kSettingSendUserInfo, base::Value(true)); + } StartLocalPrint(std::move(settings), std::move(print_data), preview_web_contents_, std::move(callback)); }
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_lacros.h b/chrome/browser/ui/webui/print_preview/local_printer_handler_lacros.h index cd3e0583..8558aa3 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_lacros.h +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_lacros.h
@@ -9,9 +9,11 @@ #include <string> #include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" #include "base/values.h" #include "chrome/browser/ui/webui/print_preview/printer_handler.h" #include "chromeos/lacros/lacros_chrome_service_impl.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { class WebContents; @@ -48,8 +50,16 @@ private: explicit LocalPrinterHandlerLacros( content::WebContents* preview_web_contents); + + void OnProfileUsernameReady(base::Value settings, + scoped_refptr<base::RefCountedMemory> print_data, + PrinterHandler::PrintCallback callback, + const absl::optional<std::string>& username); + content::WebContents* const preview_web_contents_; chromeos::LacrosChromeServiceImpl* const service_; + + base::WeakPtrFactory<LocalPrinterHandlerLacros> weak_ptr_factory_{this}; }; } // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc index 81bc6638..666701e 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc
@@ -158,6 +158,10 @@ std::move(callback).Run(); } void GetPolicies(GetPoliciesCallback callback) override { FAIL(); } + void IsSendUsernameFilenameEnabled( + IsSendUsernameFilenameEnabledCallback callback) override { + FAIL(); + } private: friend class PrintPreviewHandlerChromeOSTest;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc index cb82852..a493c74 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
@@ -340,6 +340,10 @@ std::move(callback).Run(policies_->Clone()); policies_.reset(); } + void IsSendUsernameFilenameEnabled( + IsSendUsernameFilenameEnabledCallback callback) override { + FAIL(); + } private: absl::optional<crosapi::mojom::Policies> policies_;
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.cc b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.cc index 7161697..b8c8bdab 100644 --- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.cc +++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.cc
@@ -14,8 +14,11 @@ #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/managed_ui.h" +#include "chrome/browser/ui/signin_view_controller.h" #include "chrome/browser/ui/webui/management/management_ui_handler.h" +#include "chrome/browser/ui/webui/signin/signin_utils.h" #include "chrome/common/themes/autogenerated_theme_util.h" #include "chrome/grit/generated_resources.h" #include "components/signin/public/identity_manager/account_info.h" @@ -63,18 +66,28 @@ } // namespace EnterpriseProfileWelcomeHandler::EnterpriseProfileWelcomeHandler( + Browser* browser, EnterpriseProfileWelcomeUI::ScreenType type, const std::string& domain_name, SkColor profile_color, base::OnceCallback<void(bool)> proceed_callback) - : type_(type), + : browser_(browser), + type_(type), domain_name_(domain_name), profile_color_(profile_color), proceed_callback_(std::move(proceed_callback)) { DCHECK(proceed_callback_); + DCHECK( + browser_ || + type_ != + EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation); + BrowserList::AddObserver(this); } -EnterpriseProfileWelcomeHandler::~EnterpriseProfileWelcomeHandler() = default; +EnterpriseProfileWelcomeHandler::~EnterpriseProfileWelcomeHandler() { + BrowserList::RemoveObserver(this); + HandleCancel(nullptr); +} void EnterpriseProfileWelcomeHandler::RegisterMessages() { profile_path_ = Profile::FromWebUI(web_ui())->GetPath(); @@ -83,6 +96,11 @@ base::BindRepeating(&EnterpriseProfileWelcomeHandler::HandleInitialized, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "initializedWithSize", + base::BindRepeating( + &EnterpriseProfileWelcomeHandler::HandleInitializedWithSize, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "proceed", base::BindRepeating(&EnterpriseProfileWelcomeHandler::HandleProceed, base::Unretained(this))); @@ -107,6 +125,11 @@ UpdateProfileInfo(profile_path); } +void EnterpriseProfileWelcomeHandler::OnBrowserRemoved(Browser* browser) { + if (browser_ == browser) + browser_ = nullptr; +} + void EnterpriseProfileWelcomeHandler::OnJavascriptAllowed() { observed_profile_.Observe( &g_browser_process->profile_manager()->GetProfileAttributesStorage()); @@ -124,6 +147,14 @@ ResolveJavascriptCallback(callback_id, GetProfileInfoValue()); } +void EnterpriseProfileWelcomeHandler::HandleInitializedWithSize( + const base::ListValue* args) { + AllowJavascript(); + + if (browser_) + signin::SetInitializedModalHeight(browser_, web_ui(), args); +} + void EnterpriseProfileWelcomeHandler::HandleProceed( const base::ListValue* args) { if (proceed_callback_) @@ -181,6 +212,12 @@ l10n_util::GetStringUTF8(IDS_SYNC_DISABLED_CONFIRMATION_DETAILS); dict.SetStringKey("proceedLabel", l10n_util::GetStringUTF8(IDS_DONE)); break; + case EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation: + dict.SetBoolKey("showEnterpriseBadge", false); + enterprise_title = GetManagedAccountTitle(entry, domain_name_); + enterprise_info = l10n_util::GetStringUTF8( + IDS_ENTERPRISE_PROFILE_WELCOME_MANAGED_DESCRIPTION_WITH_SYNC); + dict.SetStringKey("proceedLabel", "Create"); } dict.SetStringKey("enterpriseTitle", enterprise_title);
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h index 80bca30..9478b8a3 100644 --- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h +++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h
@@ -12,10 +12,13 @@ #include "base/scoped_observation.h" #include "base/values.h" #include "chrome/browser/profiles/profile_attributes_storage.h" +#include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h" #include "content/public/browser/web_ui_message_handler.h" #include "third_party/skia/include/core/SkColor.h" +class Browser; + namespace base { class FilePath; } @@ -24,9 +27,11 @@ // profile creation flow. class EnterpriseProfileWelcomeHandler : public content::WebUIMessageHandler, - public ProfileAttributesStorage::Observer { + public ProfileAttributesStorage::Observer, + public BrowserListObserver { public: EnterpriseProfileWelcomeHandler( + Browser* browser, EnterpriseProfileWelcomeUI::ScreenType type, const std::string& domain_name, SkColor profile_color, @@ -50,12 +55,19 @@ void OnProfileHostedDomainChanged( const base::FilePath& profile_path) override; + // BrowserListObserver: + void OnBrowserRemoved(Browser* browser) override; + // Access to construction parameters for tests. EnterpriseProfileWelcomeUI::ScreenType GetTypeForTesting(); void CallProceedCallbackForTesting(bool proceed); private: void HandleInitialized(const base::ListValue* args); + // Handles the web ui message sent when the html content is done being laid + // out and it's time to resize the native view hosting it to fit. |args| is + // a single integer value for the height the native view should resize to. + void HandleInitializedWithSize(const base::ListValue* args); void HandleProceed(const base::ListValue* args); void HandleCancel(const base::ListValue* args); @@ -75,6 +87,7 @@ ProfileAttributesStorage::Observer> observed_profile_{this}; + Browser* browser_ = nullptr; const EnterpriseProfileWelcomeUI::ScreenType type_; const std::string domain_name_; SkColor profile_color_;
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc index 45d64d6..7eecd18b 100644 --- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc +++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
@@ -19,7 +19,7 @@ #include "ui/resources/grit/webui_generated_resources.h" EnterpriseProfileWelcomeUI::EnterpriseProfileWelcomeUI(content::WebUI* web_ui) - : content::WebUIController(web_ui) { + : ui::WebDialogUI(web_ui) { content::WebUIDataSource* source = content::WebUIDataSource::Create( chrome::kChromeUIEnterpriseProfileWelcomeHost); webui::SetJSModuleDefaults(source); @@ -40,6 +40,7 @@ source->AddLocalizedString("enterpriseProfileWelcomeTitle", IDS_ENTERPRISE_PROFILE_WELCOME_TITLE); source->AddLocalizedString("cancelLabel", IDS_CANCEL); + source->AddBoolean("isModalDialog", false); content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source); } @@ -47,13 +48,25 @@ EnterpriseProfileWelcomeUI::~EnterpriseProfileWelcomeUI() = default; void EnterpriseProfileWelcomeUI::Initialize( + Browser* browser, EnterpriseProfileWelcomeUI::ScreenType type, const std::string& domain_name, SkColor profile_color, base::OnceCallback<void(bool)> proceed_callback) { auto handler = std::make_unique<EnterpriseProfileWelcomeHandler>( - type, domain_name, profile_color, std::move(proceed_callback)); + browser, type, domain_name, profile_color, std::move(proceed_callback)); handler_ = handler.get(); + + base::DictionaryValue update_data; + update_data.SetBoolKey( + "isModalDialog", + type == + EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation); + content::WebUIDataSource::Update( + Profile::FromWebUI(web_ui()), + chrome::kChromeUIEnterpriseProfileWelcomeHost, + update_data.CreateDeepCopy()); + web_ui()->AddMessageHandler(std::move(handler)); }
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h index 3e6c7d73..d30fadc 100644 --- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h +++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h
@@ -6,22 +6,24 @@ #define CHROME_BROWSER_UI_WEBUI_SIGNIN_ENTERPRISE_PROFILE_WELCOME_UI_H_ #include "base/callback.h" -#include "content/public/browser/web_ui_controller.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/web_dialogs/web_dialog_ui.h" +class Browser; class EnterpriseProfileWelcomeHandler; namespace content { class WebUI; } -class EnterpriseProfileWelcomeUI : public content::WebUIController { +class EnterpriseProfileWelcomeUI : public ui::WebDialogUI { public: // Type of a welcome screen for the enterprise flow. enum class ScreenType { kEntepriseAccountSyncEnabled, kEntepriseAccountSyncDisabled, - kConsumerAccountSyncDisabled + kConsumerAccountSyncDisabled, + kEnterpriseAccountCreation }; explicit EnterpriseProfileWelcomeUI(content::WebUI* web_ui); @@ -32,7 +34,8 @@ delete; // Initializes the EnterpriseProfileWelcomeUI. - void Initialize(ScreenType type, + void Initialize(Browser* browser, + ScreenType type, const std::string& domain_name, SkColor profile_color, base::OnceCallback<void(bool)> proceed_callback);
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc index 9e6e83a..6ccd365 100644 --- a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc +++ b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
@@ -45,7 +45,8 @@ : SigninWebDialogUI(web_ui), profile_(Profile::FromWebUI(web_ui)) { // Initializing the WebUIDataSource in the constructor is needed for polymer // tests. - Initialize(/*profile_creation_flow_color=*/absl::nullopt); + Initialize(/*profile_creation_flow_color=*/absl::nullopt, + /*is_modal_dialog=*/true); } SyncConfirmationUI::~SyncConfirmationUI() = default; @@ -57,12 +58,21 @@ void SyncConfirmationUI::InitializeMessageHandlerForCreationFlow( SkColor profile_color) { // Redo the initialization with `profile_color`. - Initialize(profile_color); + Initialize(profile_color, /*is_modal_dialog=*/false); InitializeMessageHandler(/*browser=*/nullptr); } +void SyncConfirmationUI::InitializeMessageHandlerForEnterpriseInterception( + Browser* browser, + SkColor profile_color) { + // Redo the initialization with `profile_color`. + Initialize(profile_color, /*is_modal_dialog=*/true); + InitializeMessageHandler(browser); +} + void SyncConfirmationUI::Initialize( - absl::optional<SkColor> profile_creation_flow_color) { + absl::optional<SkColor> profile_creation_flow_color, + bool is_modal_dialog) { const bool is_sync_allowed = SyncServiceFactory::IsSyncAllowed(profile_); content::WebUIDataSource* source = @@ -85,7 +95,8 @@ IDS_SYNC_LOADING_CONFIRMATION_TITLE); if (is_sync_allowed) { - InitializeForSyncConfirmation(source, profile_creation_flow_color); + InitializeForSyncConfirmation(source, profile_creation_flow_color, + is_modal_dialog); } else { InitializeForSyncDisabled(source); } @@ -107,7 +118,8 @@ void SyncConfirmationUI::InitializeForSyncConfirmation( content::WebUIDataSource* source, - absl::optional<SkColor> profile_creation_flow_color) { + absl::optional<SkColor> profile_creation_flow_color, + bool is_modal_dialog) { // Resources for testing. source->AddResourcePath("test_loader.js", IDR_WEBUI_JS_TEST_LOADER_JS); source->AddResourcePath("test_loader_util.js", @@ -148,8 +160,10 @@ IDR_SYNC_CONFIRMATION_APP_JS); source->SetDefaultResource(IDR_SYNC_CONFIRMATION_HTML); - source->AddBoolean("isProfileCreationFlow", - profile_creation_flow_color.has_value()); + source->AddBoolean("isNewDesign", profile_creation_flow_color.has_value()); + + source->AddBoolean("isModalDialog", is_modal_dialog); + if (!profile_creation_flow_color.has_value()) { AddStringResource(source, "syncConfirmationUndoLabel", IDS_CANCEL);
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_ui.h b/chrome/browser/ui/webui/signin/sync_confirmation_ui.h index 701c4af..4791272 100644 --- a/chrome/browser/ui/webui/signin/sync_confirmation_ui.h +++ b/chrome/browser/ui/webui/signin/sync_confirmation_ui.h
@@ -39,12 +39,17 @@ // no browser available). void InitializeMessageHandlerForCreationFlow(SkColor profile_color); + void InitializeMessageHandlerForEnterpriseInterception(Browser* browser, + SkColor profile_color); + private: - void Initialize(absl::optional<SkColor> profile_creation_flow_color); + void Initialize(absl::optional<SkColor> profile_creation_flow_color, + bool is_modal_dialog); void InitializeMessageHandler(Browser* browser); void InitializeForSyncConfirmation( content::WebUIDataSource* source, - absl::optional<SkColor> profile_creation_flow_color); + absl::optional<SkColor> profile_creation_flow_color, + bool is_modal_dialog); void InitializeForSyncDisabled(content::WebUIDataSource* source); // Adds a string resource with the given GRD |ids| to the WebUI data |source|
diff --git a/chrome/browser/ui/webui/tab_strip/tab_before_unload_tracker.h b/chrome/browser/ui/webui/tab_strip/tab_before_unload_tracker.h index 7988854..0b86453 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_before_unload_tracker.h +++ b/chrome/browser/ui/webui/tab_strip/tab_before_unload_tracker.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_UI_WEBUI_TAB_STRIP_TAB_BEFORE_UNLOAD_TRACKER_H_ #define CHROME_BROWSER_UI_WEBUI_TAB_STRIP_TAB_BEFORE_UNLOAD_TRACKER_H_ -#include "base/observer_list.h" #include "content/public/browser/web_contents.h" namespace tab_strip_ui {
diff --git a/chrome/browser/ui/zoom/chrome_zoom_level_prefs.h b/chrome/browser/ui/zoom/chrome_zoom_level_prefs.h index 96d63dd..053a46d 100644 --- a/chrome/browser/ui/zoom/chrome_zoom_level_prefs.h +++ b/chrome/browser/ui/zoom/chrome_zoom_level_prefs.h
@@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "components/prefs/json_pref_store.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/web_applications/components/app_registrar.h b/chrome/browser/web_applications/components/app_registrar.h index 5168e5e3..65a2b75 100644 --- a/chrome/browser/web_applications/components/app_registrar.h +++ b/chrome/browser/web_applications/components/app_registrar.h
@@ -85,6 +85,11 @@ const AppId& app_id, ExternalInstallSource install_source) const; + // Returns true if the web app with the |app_id| contains |protocol_scheme| + // as one of its approved launch protocols. + virtual bool IsApprovedLaunchProtocol(const AppId& app_id, + std::string protocol_scheme) const = 0; + // Count a number of all apps which are installed by user (non-default). // Requires app registry to be in a ready state. virtual int CountUserInstalledApps() const = 0;
diff --git a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc index c125a4a..9c1922e 100644 --- a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc +++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -946,6 +946,97 @@ http_server_.GetURL("/")); } +class ManifestUpdateManagerBrowserTest_PolicyAppsCanUpdate + : public ManifestUpdateManagerBrowserTest, + public testing::WithParamInterface<bool> { + public: + ManifestUpdateManagerBrowserTest_PolicyAppsCanUpdate() { + if (GetParam()) { + scoped_feature_list_.InitAndEnableFeature( + features::kWebAppManifestPolicyAppIdentityUpdate); + } + } + + bool ExpectUpdateAllowed() { return GetParam(); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest_PolicyAppsCanUpdate, + CheckDoesApplyIconURLChangeForPolicyAppsWithFlag) { + constexpr char kManifestTemplate[] = R"( + { + "name": "Test app name", + "start_url": ".", + "display": "standalone", + "icons": $1 + } + )"; + OverrideManifest(kManifestTemplate, {kInstallableIconList}); + AppId app_id = InstallPolicyApp(); + + OverrideManifest(kManifestTemplate, {kAnotherInstallableIconList}); + + if (ExpectUpdateAllowed()) { + // The icon should have updated (because the flag is enabled). + EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id), + ManifestUpdateResult::kAppUpdated); + histogram_tester_.ExpectBucketCount(kUpdateHistogramName, + ManifestUpdateResult::kAppUpdated, 1); + CheckShortcutInfoUpdated(app_id, kAnotherInstallableIconTopLeftColor); + } else { + // The icon should not have updated. + EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id), + ManifestUpdateResult::kAppUpToDate); + histogram_tester_.ExpectBucketCount(kUpdateHistogramName, + ManifestUpdateResult::kAppUpdated, 0); + CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor); + } +} + +// This test ensures app name cannot be changed for policy apps (without a flag +// allowing it). +IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest_PolicyAppsCanUpdate, + CheckNameUpdatesForPolicyApps) { + constexpr char kManifestTemplate[] = R"( + { + "name": "$1", + "start_url": ".", + "scope": "/", + "display": "standalone", + "icons": $2 + } + )"; + OverrideManifest(kManifestTemplate, {"Test app name", kInstallableIconList}); + AppId app_id = InstallPolicyApp(); + + OverrideManifest(kManifestTemplate, + {"Different app name", kInstallableIconList}); + + if (ExpectUpdateAllowed()) { + // Name should have updated (because the flag is enabled). + EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id), + ManifestUpdateResult::kAppUpdated); + histogram_tester_.ExpectBucketCount(kUpdateHistogramName, + ManifestUpdateResult::kAppUpdated, 1); + EXPECT_EQ(GetProvider().registrar().GetAppShortName(app_id), + "Different app name"); + } else { + // Name should not have updated (because the flag is missing). + EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id), + ManifestUpdateResult::kAppUpToDate); + histogram_tester_.ExpectBucketCount(kUpdateHistogramName, + ManifestUpdateResult::kAppUpdated, 0); + EXPECT_EQ(GetProvider().registrar().GetAppShortName(app_id), + "Test app name"); + } +} + +INSTANTIATE_TEST_SUITE_P(PolicyAppParameterizedTest, + ManifestUpdateManagerBrowserTest_PolicyAppsCanUpdate, + ::testing::Values(true, false)); + IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest, CheckFindsDisplayChange) { constexpr char kManifestTemplate[] = R"(
diff --git a/chrome/browser/web_applications/manifest_update_task.cc b/chrome/browser/web_applications/manifest_update_task.cc index 078240d..f2335287 100644 --- a/chrome/browser/web_applications/manifest_update_task.cc +++ b/chrome/browser/web_applications/manifest_update_task.cc
@@ -69,7 +69,14 @@ // considered safe and permitted to update their names. bool AllowNameUpdating(const AppId& app_id, const AppRegistrar& registrar) { const WebApp* web_app = registrar.AsWebAppRegistrar()->GetAppById(app_id); - return web_app && web_app->IsPreinstalledApp(); + if (!web_app) + return false; + if (web_app->IsPolicyInstalledApp() && + base::FeatureList::IsEnabled( + features::kWebAppManifestPolicyAppIdentityUpdate)) { + return true; + } + return web_app->IsPreinstalledApp(); } // Some apps, such as pre-installed apps, have been vetted and are therefore @@ -77,8 +84,14 @@ // flag needs to be on. bool AllowIconUpdating(const AppId& app_id, const AppRegistrar& registrar) { const WebApp* web_app = registrar.AsWebAppRegistrar()->GetAppById(app_id); - return web_app && - (web_app->IsPreinstalledApp() || + if (!web_app) + return false; + if (web_app->IsPolicyInstalledApp() && + base::FeatureList::IsEnabled( + features::kWebAppManifestPolicyAppIdentityUpdate)) { + return true; + } + return (web_app->IsPreinstalledApp() || base::FeatureList::IsEnabled(features::kWebAppManifestIconUpdating)); }
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto index 828c2207..15bc709a 100644 --- a/chrome/browser/web_applications/proto/web_app.proto +++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -214,4 +214,9 @@ // Whether the app should be loaded in a dedicated storage partition. optional bool is_storage_isolated = 36; + + // A list of approved launch protocols when launching the app with a protocol + // url. This list is checked to see if we can bypass the permission dialog + // when launching the web app. + repeated string approved_launch_protocols = 37; }
diff --git a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc index dee1553..00a2dea 100644 --- a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc +++ b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc
@@ -71,7 +71,7 @@ #include "chrome/browser/ash/web_applications/media_app/media_web_app_info.h" #include "chrome/browser/ash/web_applications/os_feedback_system_web_app_info.h" #include "chrome/browser/ash/web_applications/os_settings_web_app_info.h" -#include "chrome/browser/ash/web_applications/personalization_app_info.h" +#include "chrome/browser/ash/web_applications/personalization_app/personalization_app_info.h" #include "chrome/browser/ash/web_applications/print_management_web_app_info.h" #include "chrome/browser/ash/web_applications/scanning_system_web_app_info.h" #include "chrome/browser/ash/web_applications/shimless_rma_system_web_app_info.h"
diff --git a/chrome/browser/web_applications/test/test_app_registrar.cc b/chrome/browser/web_applications/test/test_app_registrar.cc index d51020a..059e1242 100644 --- a/chrome/browser/web_applications/test/test_app_registrar.cc +++ b/chrome/browser/web_applications/test/test_app_registrar.cc
@@ -82,6 +82,12 @@ return it != installed_apps_.end(); } +bool TestAppRegistrar::IsApprovedLaunchProtocol( + const AppId& app_id, + std::string protocol_scheme) const { + return false; +} + int TestAppRegistrar::CountUserInstalledApps() const { NOTIMPLEMENTED(); return 0;
diff --git a/chrome/browser/web_applications/test/test_app_registrar.h b/chrome/browser/web_applications/test/test_app_registrar.h index 916a284..7b29e73 100644 --- a/chrome/browser/web_applications/test/test_app_registrar.h +++ b/chrome/browser/web_applications/test/test_app_registrar.h
@@ -55,6 +55,8 @@ bool HasExternalAppWithInstallSource( const AppId& app_id, ExternalInstallSource install_source) const override; + bool IsApprovedLaunchProtocol(const AppId& app_id, + std::string protocol_scheme) const override; int CountUserInstalledApps() const override; std::string GetAppShortName(const AppId& app_id) const override; std::string GetAppDescription(const AppId& app_id) const override;
diff --git a/chrome/browser/web_applications/test/web_app_test_utils.cc b/chrome/browser/web_applications/test/web_app_test_utils.cc index 040f2a2..121e6e1 100644 --- a/chrome/browser/web_applications/test/web_app_test_utils.cc +++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -348,6 +348,19 @@ CreateRandomDownloadedShortcutsMenuIconsSizes(random)); app->SetManifestUrl(base_url.Resolve("/manifest" + seed_str + ".json")); + const int num_approved_launch_protocols = random.next_uint(8); + std::vector<std::string> approved_launch_protocols( + num_approved_launch_protocols); + for (int i = 0; i < num_approved_launch_protocols; ++i) { + approved_launch_protocols[i] = + "web+test_" + seed_str + "_" + base::NumberToString(i); + } + app->SetApprovedLaunchProtocols(std::move(approved_launch_protocols)); + + app->SetStorageIsolated(random.next_bool()); + + // `random` should not be used after the chromeos block if the result + // is expected to be deterministic across cros and non-cros builds. if (IsChromeOsDataMandatory()) { auto chromeos_data = absl::make_optional<WebAppChromeOsData>(); chromeos_data->show_in_launcher = random.next_bool(); @@ -369,8 +382,6 @@ sync_fallback_data.icon_infos = app->icon_infos(); app->SetSyncFallbackData(std::move(sync_fallback_data)); - app->SetStorageIsolated(random.next_bool()); - return app; }
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index dfc857e2..42fa3e0 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -239,6 +239,11 @@ protocol_handlers_ = std::move(handlers); } +void WebApp::SetApprovedLaunchProtocols( + std::vector<std::string> approved_launch_protocols) { + approved_launch_protocols_ = std::move(approved_launch_protocols); +} + void WebApp::SetUrlHandlers(apps::UrlHandlers url_handlers) { url_handlers_ = std::move(url_handlers); } @@ -483,6 +488,11 @@ out << " " << protocol_handler << std::endl; } + out << "approved_launch_protocols:" << std::endl; + for (const std::string& approved_launch_protocols : + app.approved_launch_protocols_) + out << " " << approved_launch_protocols << std::endl; + out << "url_handlers:" << std::endl; for (const apps::UrlHandlerInfo& url_handler : app.url_handlers_) out << Indent(url_handler) << std::endl; @@ -553,6 +563,7 @@ app.share_target_, app.additional_search_terms_, app.protocol_handlers_, + app.approved_launch_protocols_, app.url_handlers_, app.note_taking_new_note_url_, app.last_badging_time_,
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index c6de1b6..5a3e9aa2 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -140,6 +140,10 @@ return protocol_handlers_; } + const std::vector<std::string>& approved_launch_protocols() const { + return approved_launch_protocols_; + } + // URL within scope to launch for a "new note" action. Valid iff this is // considered a note-taking app. // TODO(crbug.com/1185678): Persist this in the database. @@ -247,6 +251,8 @@ std::vector<std::string> additional_search_terms); void SetProtocolHandlers( std::vector<apps::ProtocolHandlerInfo> protocol_handlers); + void SetApprovedLaunchProtocols( + std::vector<std::string> approved_launch_protocols); void SetUrlHandlers(apps::UrlHandlers url_handlers); void SetNoteTakingNewNoteUrl(const GURL& note_taking_new_note_url); void SetLastBadgingTime(const base::Time& time); @@ -308,6 +314,7 @@ absl::optional<apps::ShareTarget> share_target_; std::vector<std::string> additional_search_terms_; std::vector<apps::ProtocolHandlerInfo> protocol_handlers_; + std::vector<std::string> approved_launch_protocols_; apps::UrlHandlers url_handlers_; GURL note_taking_new_note_url_; base::Time last_badging_time_;
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc index b008114..c425c53c 100644 --- a/chrome/browser/web_applications/web_app_database.cc +++ b/chrome/browser/web_applications/web_app_database.cc
@@ -368,6 +368,12 @@ protocol_handler_proto->set_url(protocol_handler.url.spec()); } + for (const auto& approved_launch_protocols : + web_app.approved_launch_protocols()) { + DCHECK(!approved_launch_protocols.empty()); + local_data->add_approved_launch_protocols(approved_launch_protocols); + } + for (const auto& url_handler : web_app.url_handlers()) { WebAppUrlHandlerProto* url_handler_proto = local_data->add_url_handlers(); url_handler_proto->set_origin(url_handler.origin.Serialize()); @@ -756,6 +762,17 @@ } web_app->SetProtocolHandlers(std::move(protocol_handlers)); + std::vector<std::string> approved_launch_protocols; + for (const std::string& approved_launch_protocol : + local_data.approved_launch_protocols()) { + if (approved_launch_protocol.empty()) { + DLOG(ERROR) << "WebApp ApprovedLaunchProtocols proto action parse error"; + return nullptr; + } + approved_launch_protocols.push_back(approved_launch_protocol); + } + web_app->SetApprovedLaunchProtocols(std::move(approved_launch_protocols)); + std::vector<apps::UrlHandlerInfo> url_handlers; for (const auto& url_handler_proto : local_data.url_handlers()) { apps::UrlHandlerInfo url_handler;
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc index 1a800ef5..7ecc58b 100644 --- a/chrome/browser/web_applications/web_app_database_unittest.cc +++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -314,6 +314,7 @@ EXPECT_FALSE(app->share_target().has_value()); EXPECT_TRUE(app->additional_search_terms().empty()); EXPECT_TRUE(app->protocol_handlers().empty()); + EXPECT_TRUE(app->approved_launch_protocols().empty()); EXPECT_TRUE(app->url_handlers().empty()); EXPECT_TRUE(app->last_badging_time().is_null()); EXPECT_TRUE(app->last_launch_time().is_null()); @@ -378,6 +379,7 @@ EXPECT_TRUE(app_copy->file_handlers().empty()); EXPECT_FALSE(app_copy->share_target().has_value()); EXPECT_TRUE(app_copy->additional_search_terms().empty()); + EXPECT_TRUE(app_copy->approved_launch_protocols().empty()); EXPECT_TRUE(app_copy->url_handlers().empty()); EXPECT_TRUE(app_copy->shortcuts_menu_item_infos().empty()); EXPECT_TRUE(app_copy->downloaded_shortcuts_menu_icons_sizes().empty());
diff --git a/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc b/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc index cfb02c1e..fc05a3e 100644 --- a/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc +++ b/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
@@ -29,6 +29,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/base/window_open_disposition.h" #include "ui/gfx/image/image_skia.h" +#include "ui/views/image_model_utils.h" #include "url/gurl.h" namespace web_app { @@ -135,7 +136,8 @@ controller->SetReadIconCallbackForTesting(base::BindLambdaForTesting( [controller, &image_skia, &run_loop, this]() { EXPECT_TRUE(app_service_test().AreIconImageEqual( - image_skia, controller->GetWindowAppIcon())); + image_skia, views::GetImageSkiaFromImageModel( + controller->GetWindowAppIcon(), nullptr))); run_loop.Quit(); })); run_loop.Run(); @@ -145,7 +147,9 @@ controller->SetReadIconCallbackForTesting( base::BindLambdaForTesting([controller, &run_loop]() { - const SkBitmap* bitmap = controller->GetWindowAppIcon().bitmap(); + const SkBitmap* bitmap = views::GetImageSkiaFromImageModel( + controller->GetWindowAppIcon(), nullptr) + .bitmap(); EXPECT_EQ(SK_ColorBLUE, bitmap->getColor(0, 0)); EXPECT_EQ(32, bitmap->width()); EXPECT_EQ(32, bitmap->height());
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc index 1a55816a..9b9acd5 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -18,7 +18,6 @@ #include "base/time/time.h" #include "base/values.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/permissions/permission_manager_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/components/app_registrar.h" #include "chrome/browser/web_applications/components/os_integration_manager.h" @@ -40,8 +39,6 @@ #include "chrome/browser/web_applications/web_app_sync_bridge.h" #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" -#include "components/permissions/permission_manager.h" -#include "components/permissions/permission_result.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" @@ -387,14 +384,10 @@ } bool WebAppInstallFinalizer::IsFileHandlerPermissionBlocked(const GURL& scope) { - permissions::PermissionManager* permission_manager = - PermissionManagerFactory::GetForProfile(profile_); - DCHECK(permission_manager); - - permissions::PermissionResult status = - permission_manager->GetPermissionStatus( - ContentSettingsType::FILE_HANDLING, scope, scope); - return status.content_setting == CONTENT_SETTING_BLOCK; + return HostContentSettingsMapFactory::GetForProfile(profile_) + ->GetContentSetting(scope, scope, + ContentSettingsType::FILE_HANDLING) == + CONTENT_SETTING_BLOCK; } void WebAppInstallFinalizer::UpdateFileHandlerPermission( @@ -694,8 +687,8 @@ // "BLOCK", the `OnContentSettingChanged()` and // `DetectAndCorrectFileHandlingPermissionBlocks()` should capture the // permission change and make sure the OS and db state are in sync with the - // PermissionManager permission setting. Therefore, manifest update task - // should not update file handlers due to blocked permission state. + // HostContentSettingsMap setting. Therefore, manifest update task should not + // update file handlers due to blocked permission state. if (content_setting == CONTENT_SETTING_BLOCK) return FileHandlerUpdateAction::kNoUpdate; @@ -712,28 +705,24 @@ ContentSetting WebAppInstallFinalizer::MaybeResetFileHandlingPermission( const WebApplicationInfo& web_app_info) { - permissions::PermissionManager* permission_manager = - PermissionManagerFactory::GetForProfile(profile_); - DCHECK(permission_manager); const GURL& url = web_app_info.scope; - // Note: Since a frame is not available, using GetPermissionStatus() instead - // of GetPermissionStatusForFrame(). - permissions::PermissionResult status = - permission_manager->GetPermissionStatus( - ContentSettingsType::FILE_HANDLING, url, url); + HostContentSettingsMap* settings_map = + HostContentSettingsMapFactory::GetForProfile(profile_); + ContentSetting status = settings_map->GetContentSetting( + url, url, ContentSettingsType::FILE_HANDLING); // If file handling permission is "ALLOW", downgrade to "ASK" via reset, as // the user may not want to allow newly added file handlers, which may include // more dangerous extensions. - if (status.content_setting == CONTENT_SETTING_ALLOW && + if (status == CONTENT_SETTING_ALLOW && !AreFileHandlersAlreadyRegistered(profile_, url, web_app_info.file_handlers)) { - permission_manager->ResetPermission(content::PermissionType::FILE_HANDLING, - url, url); + settings_map->SetContentSettingDefaultScope( + url, url, ContentSettingsType::FILE_HANDLING, CONTENT_SETTING_DEFAULT); return CONTENT_SETTING_ASK; } - return status.content_setting; + return status; } void WebAppInstallFinalizer::OnDatabaseCommitCompletedForUpdate(
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc index 3a5e2bb..38d053a 100644 --- a/chrome/browser/web_applications/web_app_registrar.cc +++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/check_op.h" +#include "base/containers/contains.h" #include "base/strings/string_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile_manager.h" @@ -89,6 +90,14 @@ web_app->chromeos_data()->oem_installed; } +bool WebAppRegistrar::IsApprovedLaunchProtocol( + const AppId& app_id, + std::string protocol_scheme) const { + const WebApp* web_app = GetAppById(app_id); + return web_app && + base::Contains(web_app->approved_launch_protocols(), protocol_scheme); +} + int WebAppRegistrar::CountUserInstalledApps() const { int num_user_installed = 0; for (const WebApp& app : GetAppsIncludingStubs()) {
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h index 55f7704..569bb20 100644 --- a/chrome/browser/web_applications/web_app_registrar.h +++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -53,6 +53,8 @@ bool IsLocallyInstalled(const AppId& app_id) const override; bool WasInstalledByUser(const AppId& app_id) const override; bool WasInstalledByOem(const AppId& app_id) const override; + bool IsApprovedLaunchProtocol(const AppId& app_id, + std::string protocol_scheme) const override; int CountUserInstalledApps() const override; std::string GetAppShortName(const AppId& app_id) const override; std::string GetAppDescription(const AppId& app_id) const override;
diff --git a/chrome/browser/web_applications/web_app_unittest.cc b/chrome/browser/web_applications/web_app_unittest.cc index b259d1c..eb05513 100644 --- a/chrome/browser/web_applications/web_app_unittest.cc +++ b/chrome/browser/web_applications/web_app_unittest.cc
@@ -196,6 +196,7 @@ nullopt additional_search_terms: protocol_handlers: +approved_launch_protocols: url_handlers: note_taking_new_note_url: capture_links: kUndefined @@ -354,6 +355,9 @@ protocol: web+test244307312 url: https://example.com/244307312 protocol: web+test244307313 url: https://example.com/244307313 protocol: web+test244307314 url: https://example.com/244307314 +approved_launch_protocols: + web+test_1234_0 + web+test_1234_1 url_handlers: origin: https://app-9974471690.com has_origin_wildcard: true
diff --git a/chrome/browser/web_launch/web_launch_files_helper.cc b/chrome/browser/web_launch/web_launch_files_helper.cc index 13faba0..f1a4b3f9 100644 --- a/chrome/browser/web_launch/web_launch_files_helper.cc +++ b/chrome/browser/web_launch/web_launch_files_helper.cc
@@ -15,7 +15,6 @@ #include "chrome/browser/profiles/profile.h" #include "components/permissions/permission_manager.h" #include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/storage_partition.h" @@ -32,47 +31,6 @@ WEB_CONTENTS_USER_DATA_KEY_IMPL(WebLaunchFilesHelper) -// static -void WebLaunchFilesHelper::SetLaunchPaths( - content::WebContents* web_contents, - const GURL& launch_url, - std::vector<base::FilePath> launch_paths) { - if (launch_paths.size() == 0) - return; - - web_contents->SetUserData( - UserDataKey(), std::make_unique<WebLaunchFilesHelper>( - web_contents, launch_url, std::move(launch_paths))); -} - -// static -void WebLaunchFilesHelper::SetLaunchDirectoryAndLaunchPaths( - content::WebContents* web_contents, - const GURL& launch_url, - base::FilePath launch_dir, - std::vector<base::FilePath> launch_paths) { - if (launch_dir.empty()) - return; - - if (launch_paths.size() == 0) - return; - - web_contents->SetUserData(UserDataKey(), - std::make_unique<WebLaunchFilesHelper>( - web_contents, launch_url, std::move(launch_dir), - std::move(launch_paths))); -} - -void WebLaunchFilesHelper::DidFinishNavigation( - content::NavigationHandle* handle) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - // Currently, launch data is only sent for the main frame. - if (!handle->IsInMainFrame()) - return; - - MaybeSendLaunchEntries(); -} - namespace { // On Chrome OS paths that exist on an external mount point need to be treated @@ -119,6 +77,7 @@ context_, path_type, entry_path, content::FileSystemAccessEntryFactory::UserAction::kOpen)); } + void AddDirectoryEntry(const base::FilePath& path) { base::FilePath entry_path = path; content::FileSystemAccessEntryFactory::PathType path_type = @@ -136,24 +95,43 @@ } // namespace -WebLaunchFilesHelper::WebLaunchFilesHelper( +WebLaunchFilesHelper::~WebLaunchFilesHelper() = default; + +// static +void WebLaunchFilesHelper::SetLaunchPaths( content::WebContents* web_contents, const GURL& launch_url, - std::vector<base::FilePath> launch_paths) - : content::WebContentsObserver(web_contents), launch_url_(launch_url) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(launch_paths.size()); + std::vector<base::FilePath> launch_paths) { + if (launch_paths.size() == 0) + return; - launch_entries_.reserve(launch_paths.size()); + CreateHelperAndSendEntries(web_contents, launch_url, /*launch_dir=*/{}, + std::move(launch_paths)); +} - EntriesBuilder entries_builder(&launch_entries_, web_contents, launch_url); - for (const auto& path : launch_paths) - entries_builder.AddFileEntry(path); +// static +void WebLaunchFilesHelper::SetLaunchDirectoryAndLaunchPaths( + content::WebContents* web_contents, + const GURL& launch_url, + base::FilePath launch_dir, + std::vector<base::FilePath> launch_paths) { + if (launch_dir.empty()) + return; - // Asynchronously call MaybeSendLaunchEntries, since it may destroy |this|. - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&WebLaunchFilesHelper::MaybeSendLaunchEntries, - weak_ptr_factory_.GetWeakPtr())); + if (launch_paths.size() == 0) + return; + + CreateHelperAndSendEntries(web_contents, launch_url, launch_dir, + std::move(launch_paths)); +} + +void WebLaunchFilesHelper::DidFinishNavigation( + content::NavigationHandle* handle) { + // Currently, launch data is only sent for the main frame. + if (!handle->IsInMainFrame()) + return; + + MaybeSendLaunchEntries(); } WebLaunchFilesHelper::WebLaunchFilesHelper( @@ -162,28 +140,35 @@ base::FilePath launch_dir, std::vector<base::FilePath> launch_paths) : content::WebContentsObserver(web_contents), launch_url_(launch_url) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!launch_dir.empty()); DCHECK(launch_paths.size()); - launch_entries_.reserve(launch_paths.size() + 1); - EntriesBuilder entries_builder(&launch_entries_, web_contents, launch_url); - entries_builder.AddDirectoryEntry(launch_dir); + if (launch_dir.empty()) { + launch_entries_.reserve(launch_paths.size()); + } else { + launch_entries_.reserve(launch_paths.size() + 1); + entries_builder.AddDirectoryEntry(launch_dir); + } + for (const auto& path : launch_paths) entries_builder.AddFileEntry(path); - - // Asynchronously call MaybeSendLaunchEntries, since it may destroy |this|. - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&WebLaunchFilesHelper::MaybeSendLaunchEntries, - weak_ptr_factory_.GetWeakPtr())); } -WebLaunchFilesHelper::~WebLaunchFilesHelper() = default; +// static +void WebLaunchFilesHelper::CreateHelperAndSendEntries( + content::WebContents* web_contents, + const GURL& launch_url, + base::FilePath launch_dir, + std::vector<base::FilePath> launch_paths) { + auto helper = base::WrapUnique( + new WebLaunchFilesHelper(web_contents, launch_url, std::move(launch_dir), + std::move(launch_paths))); + WebLaunchFilesHelper* helper_ptr = helper.get(); + web_contents->SetUserData(UserDataKey(), std::move(helper)); + helper_ptr->MaybeSendLaunchEntries(); +} void WebLaunchFilesHelper::MaybeSendLaunchEntries() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (launch_entries_.size() == 0) return; if (launch_url_ != web_contents()->GetLastCommittedURL()) @@ -204,7 +189,6 @@ void WebLaunchFilesHelper::MaybeSendLaunchEntriesWithPermission( ContentSetting content_setting) { if (content_setting == CONTENT_SETTING_ALLOW) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); mojo::AssociatedRemote<blink::mojom::WebLaunchService> launch_service; web_contents() ->GetMainFrame()
diff --git a/chrome/browser/web_launch/web_launch_files_helper.h b/chrome/browser/web_launch/web_launch_files_helper.h index 13195023..736659d 100644 --- a/chrome/browser/web_launch/web_launch_files_helper.h +++ b/chrome/browser/web_launch/web_launch_files_helper.h
@@ -40,34 +40,38 @@ public content::WebContentsUserData<WebLaunchFilesHelper> { public: WEB_CONTENTS_USER_DATA_KEY_DECL(); + + ~WebLaunchFilesHelper() override; + + // For use with standard web apps, or system web apps that don't receive the + // launch directory in their launch params. static void SetLaunchPaths(content::WebContents* web_contents, const GURL& launch_url, std::vector<base::FilePath> launch_paths); - // System Web Apps Only. |launch_dir| is prepended to |launch_entries_| and - // sent to the JavaScript side. + // For use by System Web Apps Only. |launch_dir| is prepended to + // |launch_entries_| and sent to the JavaScript side. static void SetLaunchDirectoryAndLaunchPaths( content::WebContents* web_contents, const GURL& launch_url, base::FilePath launch_dir, std::vector<base::FilePath> launch_paths); - WebLaunchFilesHelper(content::WebContents* web_contents, - const GURL& launch_url, - std::vector<base::FilePath> launch_paths); + // content::WebContentsObserver: + void DidFinishNavigation(content::NavigationHandle* handle) override; - // System Web Apps Only. + private: WebLaunchFilesHelper(content::WebContents* web_contents, const GURL& launch_url, base::FilePath launch_dir, std::vector<base::FilePath> launch_paths); - ~WebLaunchFilesHelper() override; + static void CreateHelperAndSendEntries( + content::WebContents* web_contents, + const GURL& launch_url, + base::FilePath launch_dir, + std::vector<base::FilePath> launch_paths); - // content::WebContentsObserver: - void DidFinishNavigation(content::NavigationHandle* handle) override; - - private: // Sends the launch entries to the renderer if they have been created and the // renderer is ready to receive them. void MaybeSendLaunchEntries();
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 905ec32c..7e1735b 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1623056245-fcc3a9d89ac881252be573c70c765ad476913960.profdata +chrome-win64-master-1623088510-684df13693ce2578b07ca4a5ba3540a78fcc379f.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 0e2fe418..a1ee603b 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -976,6 +976,9 @@ "WebAppManifestIconUpdating", base::FEATURE_DISABLED_BY_DEFAULT}; #endif // defined(OS_ANDROID) +const base::Feature kWebAppManifestPolicyAppIdentityUpdate{ + "WebAppManifestPolicyAppIdentityUpdate", base::FEATURE_DISABLED_BY_DEFAULT}; + #if BUILDFLAG(IS_CHROMEOS_ASH) // When enabled, the Ash browser only manages system web apps, and non-system // web apps are managed by the Lacros browser. When disabled, the Ash browser
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 7028824..8c76f571 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -668,6 +668,9 @@ extern const base::Feature kWebAppManifestIconUpdating; #endif // !defined(OS_ANDROID) +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kWebAppManifestPolicyAppIdentityUpdate; + #if BUILDFLAG(IS_CHROMEOS_ASH) COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kWebAppsCrosapi;
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index b0aec24..722d138 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -1873,6 +1873,10 @@ // Defines administrator-set availability of developer tools. const char kDevToolsAvailability[] = "devtools.availability"; +// Defines administrator-set availability of developer tools remote debugging. +const char kDevToolsRemoteDebuggingAllowed[] = + "devtools.remote_debugging.allowed"; + // Dictionary from background service to recording expiration time. const char kDevToolsBackgroundServicesExpirationDict[] = "devtools.backgroundserviceexpiration";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 842d0734..a5e986f 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -636,6 +636,7 @@ extern const char kDevToolsAdbKey[]; extern const char kDevToolsAvailability[]; +extern const char kDevToolsRemoteDebuggingAllowed[]; extern const char kDevToolsBackgroundServicesExpirationDict[]; extern const char kDevToolsDiscoverUsbDevicesEnabled[]; extern const char kDevToolsEditedFiles[];
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc index fa2931ae..abf671ec 100644 --- a/chrome/renderer/chrome_render_frame_observer.cc +++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -250,8 +250,7 @@ return; static crash_reporter::CrashKeyString<8> view_count_key("view-count"); - view_count_key.Set( - base::NumberToString(content::RenderView::GetRenderViewCount())); + view_count_key.Set(base::NumberToString(blink::WebView::GetWebViewCount())); #if !defined(OS_ANDROID) if (render_frame()->GetEnabledBindings() &
diff --git a/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc b/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc index 9d9d887..2f62e9e 100644 --- a/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc +++ b/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc
@@ -24,6 +24,10 @@ RobotsRulesParser::CheckResult check_result) { switch (check_result) { case RobotsRulesParser::CheckResult::kAllowed: + if (ShouldEnableLoginRobotsCheckedImageCompression() && + !ShouldCompressRedirectSubresource()) { + return SubresourceRedirectResult::kIneligibleCompressionDisabled; + } return SubresourceRedirectResult::kRedirectable; case RobotsRulesParser::CheckResult::kDisallowed: case RobotsRulesParser::CheckResult::kInvalidated:
diff --git a/chrome/renderer/subresource_redirect/public_image_hints_decider_agent.cc b/chrome/renderer/subresource_redirect/public_image_hints_decider_agent.cc index 5a63ed3c..b34afbe5 100644 --- a/chrome/renderer/subresource_redirect/public_image_hints_decider_agent.cc +++ b/chrome/renderer/subresource_redirect/public_image_hints_decider_agent.cc
@@ -93,6 +93,8 @@ if (public_image_urls_->find(GetURLForPublicDecision(url)) != public_image_urls_->end()) { + if (!ShouldCompressRedirectSubresource()) + return SubresourceRedirectResult::kIneligibleCompressionDisabled; return SubresourceRedirectResult::kRedirectable; } @@ -160,6 +162,7 @@ case SubresourceRedirectResult::kIneligibleRedirectFailed: case SubresourceRedirectResult::kIneligibleBlinkDisallowed: case SubresourceRedirectResult::kIneligibleSubframeResource: + case SubresourceRedirectResult::kIneligibleCompressionDisabled: public_image_compression_data_use.SetIneligibleOtherImageBytes( content_length); break;
diff --git a/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc b/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc index eb139e4..983fe04 100644 --- a/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc +++ b/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc
@@ -150,9 +150,6 @@ if (IsCompressionServerOrigin(request->url)) return; - if (!ShouldCompressRedirectSubresource()) - return; - if (login_robots_compression_metrics_) login_robots_compression_metrics_->NotifyRequestStart();
diff --git a/chrome/services/cups_proxy/cups_proxy_service.h b/chrome/services/cups_proxy/cups_proxy_service.h index 8fc62fd..24b3e9ad 100644 --- a/chrome/services/cups_proxy/cups_proxy_service.h +++ b/chrome/services/cups_proxy/cups_proxy_service.h
@@ -9,7 +9,6 @@ #include "base/memory/weak_ptr.h" #include "base/no_destructor.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "chrome/services/cups_proxy/public/mojom/proxy.mojom.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 45b5075..d5f3e36c 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -4968,6 +4968,7 @@ "//components/sync_user_events:test_support", "//components/translate/core/browser:test_support", "//components/ukm/content", + "//components/variations:test_support", "//components/version_info:generate_version_info", "//content/app/resources", "//content/public/app", @@ -5227,7 +5228,6 @@ "../browser/lookalikes/lookalike_url_navigation_throttle_unittest.cc", "../browser/reputation/local_heuristics_unittest.cc", "../browser/reputation/reputation_service_unittest.cc", - "../browser/reputation/url_elision_policy_unittest.cc", # Media remoting is not supported on Android for now. "../browser/media/cast_remoting_connector_unittest.cc",
diff --git a/chrome/test/base/fake_profile_manager.cc b/chrome/test/base/fake_profile_manager.cc index 5ce31e8..3c7b07d 100644 --- a/chrome/test/base/fake_profile_manager.cc +++ b/chrome/test/base/fake_profile_manager.cc
@@ -23,7 +23,11 @@ const base::FilePath& path) { if (!base::PathExists(path) && !base::CreateDirectory(path)) return nullptr; - return BuildTestingProfile(path, nullptr); + auto profile = BuildTestingProfile(path, nullptr); + // Add the profile to |profiles_info_|. We need to do this manually, because + // TestingProfile does not call OnProfileCreationStarted(). + OnProfileCreationStarted(profile.get(), Profile::CREATE_MODE_SYNCHRONOUS); + return profile; } std::unique_ptr<Profile> FakeProfileManager::CreateProfileAsyncHelper(
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index 591810d6..87b2971 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -500,7 +500,8 @@ profile_manager->InitProfileUserPrefs(this); if (delegate_) { - delegate_->OnProfileCreated(this, true, false); + delegate_->OnProfileCreationFinished(this, CREATE_MODE_ASYNCHRONOUS, true, + false); } else { // It is the role of the delegate to ensure that the signout allowed is // properly updated after the profile is create is initialized.
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index a76c58e..ce33db5 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1701,6 +1701,20 @@ ] }, + "RemoteDebuggingAllowed": { + "os": ["win", "linux", "mac", "chromeos"], + "policy_pref_mapping_tests": [ + { + "policies": { "RemoteDebuggingAllowed": true }, + "prefs": { "devtools.remote_debugging.allowed": { + "location": "local_state", + "value": true + } + } + } + ] + }, + "HeadlessMode": {}, "RestoreOnStartup": {
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 5edd29b..74f9f41a 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -432,6 +432,7 @@ "chromeos/crostini_installer_browsertest.js", "chromeos/crostini_upgrader_browsertest.js", "chromeos/diagnostics/diagnostics_browsertest.js", + "chromeos/os_feedback_ui/os_feedback_browsertest.js", "chromeos/personalization_app/personalization_app_component_browsertest.js", "chromeos/print_management/print_management_browsertest.js", "chromeos/scanning/scanning_app_browsertest.js",
diff --git a/chrome/test/data/webui/chromeos/BUILD.gn b/chrome/test/data/webui/chromeos/BUILD.gn index 2ea5f0a3..c3dc1e1 100644 --- a/chrome/test/data/webui/chromeos/BUILD.gn +++ b/chrome/test/data/webui/chromeos/BUILD.gn
@@ -28,6 +28,7 @@ "diagnostics:closure_compile", "emoji_picker:closure_compile", "gaia_action_buttons:closure_compile", + "os_feedback_ui:closure_compile", "personalization_app:closure_compile", "scanning:closure_compile", "shimless_rma:closure_compile",
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/BUILD.gn b/chrome/test/data/webui/chromeos/os_feedback_ui/BUILD.gn new file mode 100644 index 0000000..8e4a576 --- /dev/null +++ b/chrome/test/data/webui/chromeos/os_feedback_ui/BUILD.gn
@@ -0,0 +1,29 @@ +# Copyright 2021 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("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + is_polymer3 = true + closure_flags = default_closure_args + [ + "browser_resolver_prefix_replacements=\"chrome://os-feedback/=../../ash/components/os_feedback_ui/resources/\"", + "js_module_root=../../chrome/test/data/webui/", + "js_module_root=./gen/chrome/test/data/webui/", + ] + deps = [ + ":confirmation_page_test", + ":os_feedback_unified_test", + ] +} + +js_library("confirmation_page_test") { + deps = [ + "../..:chai_assert", + "//ash/components/os_feedback_ui/resources:confirmation_page", + ] + externs_list = [ "$externs_path/mocha-2.5.js" ] +} + +js_library("os_feedback_unified_test") { +}
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js new file mode 100644 index 0000000..bf7ec6e5 --- /dev/null +++ b/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js
@@ -0,0 +1,31 @@ +// Copyright 2021 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 {ConfirmationPageElement} from 'chrome://os-feedback/confirmation_page.js'; + +import {assertEquals} from '../../chai_assert.js'; + +export function confirmationPageTest() { + /** @type {?ConfirmationPageElement} */ + let component = null; + + setup(() => { + document.body.innerHTML = ''; + component = /** @type {!ConfirmationPageElement} */ ( + document.createElement('confirmation-page')); + document.body.appendChild(component); + }); + + teardown(() => { + component.remove(); + component = null; + }); + + /**TODO(xiangdongkong): replace with real test */ + test('confirmationPageLoaded', () => { + assertEquals( + 'Thank you for your feedback', + component.shadowRoot.querySelector('#header').textContent); + }); +}
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/os_feedback_browsertest.js b/chrome/test/data/webui/chromeos/os_feedback_ui/os_feedback_browsertest.js new file mode 100644 index 0000000..607b86d8 --- /dev/null +++ b/chrome/test/data/webui/chromeos/os_feedback_ui/os_feedback_browsertest.js
@@ -0,0 +1,59 @@ +// Copyright 2021 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. + +/** + * @fileoverview Test fixture for chrome://os-feedback. + * Unifieid polymer testing suite for feedback tool. + * + * To run all tests in a single instance (default, faster): + * `browser_tests --gtest_filter=OSFeedback*`` + * + * To run each test in a new instance: + * `browser_tests --run-manual --gtest_filter=OSFeedback.MANUAL_*`` + * + * To run a single test suite, such as 'ConfirmationPageTest': + * `browser_tests --run-manual \ + * --gtest_filter=OSFeedback.MANUAL_ConfirmationPageTest` + * + */ + +GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']); + +GEN('#include "ash/constants/ash_features.h"'); +GEN('#include "content/public/test/browser_test.h"'); + +this.OSFeedbackBrowserTest = class extends PolymerTest { + /** @override */ + get browsePreload() { + return 'chrome://os-feedback/test_loader.html?module=chromeos/' + + 'os_feedback_ui/os_feedback_unified_test.js'; + } + + /** @override */ + get featureList() { + return {enabled: ['ash::features::kOsFeedback']}; + } +}; + +// List of names of suites in unified test to register for individual debugging. +// You must register all suites in unified test here as well for consistency, +// although technically is not necessary. +const debug_suites_list = [ + 'ConfirmationPageTest', +]; + +TEST_F('OSFeedbackBrowserTest', 'All', function() { + assertDeepEquals( + debug_suites_list, test_suites_list, + 'List of registered tests suites and debug suites do not match.\n' + + 'Did you forget to add your test in debug_suites_list?'); + mocha.run(); +}); + +// Register each suite listed as individual tests for debugging purposes. +for (const suiteName of debug_suites_list) { + TEST_F('OSFeedbackBrowserTest', `MANUAL_${suiteName}`, function() { + runMochaSuite(suiteName); + }); +}
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/os_feedback_unified_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/os_feedback_unified_test.js new file mode 100644 index 0000000..e6fa15d9 --- /dev/null +++ b/chrome/test/data/webui/chromeos/os_feedback_ui/os_feedback_unified_test.js
@@ -0,0 +1,16 @@ +// Copyright 2021 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 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; + +import {confirmationPageTest} from './confirmation_page_test.js'; + +window.test_suites_list = []; + +function runSuite(suiteName, testFn) { + window.test_suites_list.push(suiteName); + suite(suiteName, testFn); +} + +runSuite('ConfirmationPageTest', confirmationPageTest);
diff --git a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.js b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.js index 83bf445..e6a56bd 100644 --- a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.js +++ b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.js
@@ -164,6 +164,26 @@ } /** + * @param {!Object=} modifiers Things to override about the returned result. + * @return {!search.mojom.AutocompleteMatch} + */ +function createCalculatorMatch(modifiers = {}) { + return Object.assign( + createAutocompleteMatch(), { + isSearchType: true, + contents: mojoString16('2 + 3'), + contentsClass: [{offset: 0, style: 0}], + description: mojoString16('5'), + descriptionClass: [{offset: 0, style: 0}], + destinationUrl: {url: 'https://www.google.com/search?q=2+%2B+3'}, + fillIntoEdit: mojoString16('5'), + type: 'search-calculator-answer', + iconUrl: 'calculator.svg', + }, + modifiers); +} + +/** * Verifies the autocomplete match is showing. * @param {!search.mojom.AutocompleteMatch} match * @param {!Element} matchEl @@ -2200,4 +2220,48 @@ // Input is cleared. assertEquals('', realbox.$.input.value); }); + + //============================================================================ + // Test calculator answer type + //============================================================================ + + test('match calculator answer type', async () => { + const matches = [createCalculatorMatch()]; + + realbox.$.input.value = '2 + 3'; + realbox.$.input.dispatchEvent(new InputEvent('input')); + + testProxy.callbackRouterRemote.autocompleteResultChanged({ + input: mojoString16(realbox.$.input.value.trimLeft()), + matches, + suggestionGroupsMap: {}, + }); + await testProxy.callbackRouterRemote.$.flushForTesting(); + + assertTrue(areMatchesShowing()); + let matchEls = + realbox.$.matches.shadowRoot.querySelectorAll('ntp-realbox-match'); + assertEquals(1, matchEls.length); + + verifyMatch(matches[0], matchEls[0]); + assertIconMaskImageUrl(matchEls[0].$.icon, 'calculator.svg'); + assertIconMaskImageUrl(realbox.$.icon, 'search.svg'); + + // Separator is not displayed + assertEquals( + window.getComputedStyle(matchEls[0].$.separator).display, 'none'); + + let arrowDownEvent = new KeyboardEvent('keydown', { + bubbles: true, + cancelable: true, + composed: true, // So it propagates across shadow DOM boundary. + key: 'ArrowDown', + }); + realbox.$.input.dispatchEvent(arrowDownEvent); + assertTrue(arrowDownEvent.defaultPrevented); + + assertTrue(matchEls[0].classList.contains(CLASSES.SELECTED)); + assertEquals('5', realbox.$.input.value); + assertIconMaskImageUrl(realbox.$.icon, 'calculator.svg'); + }); });
diff --git a/chrome/test/data/webui/signin/profile_switch_test.js b/chrome/test/data/webui/signin/profile_switch_test.js index a95bf6e..448e9a3 100644 --- a/chrome/test/data/webui/signin/profile_switch_test.js +++ b/chrome/test/data/webui/signin/profile_switch_test.js
@@ -47,6 +47,18 @@ 'url'); assertEquals(profileSwitchElement.$$('#profileName').innerText, 'Work'); assertEquals(profileSwitchElement.$$('#gaiaName').innerText, 'Alice'); + assertTrue(profileSwitchElement.$$('#iconContainer').hidden); + }); + + test('getSwitchProfile_managed', async function() { + const profileState = /** @type {!ProfileState} */ ( + Object.assign({}, browserProxy.profileSample)); + profileState.isManaged = true; + + getSwitchProfilePromiseResolver.resolve(profileState); + await browserProxy.whenCalled('getSwitchProfile'); + + assertFalse(profileSwitchElement.$$('#iconContainer').hidden); }); test('confirmSwitch', async function() {
diff --git a/chrome/test/data/webui/signin/test_enterprise_profile_welcome_browser_proxy.js b/chrome/test/data/webui/signin/test_enterprise_profile_welcome_browser_proxy.js index f048ea9..e96b12ba 100644 --- a/chrome/test/data/webui/signin/test_enterprise_profile_welcome_browser_proxy.js +++ b/chrome/test/data/webui/signin/test_enterprise_profile_welcome_browser_proxy.js
@@ -30,6 +30,11 @@ return Promise.resolve(this.enterpriseProfileInfo_); } + /** @param {number} height */ + initializedWithSize(height) { + this.methodCalled('initializedWithSize'); + } + /** @override */ proceed() { this.methodCalled('proceed');
diff --git a/chrome/updater/app/server/win/service_main.cc b/chrome/updater/app/server/win/service_main.cc index e52414c..c10c320 100644 --- a/chrome/updater/app/server/win/service_main.cc +++ b/chrome/updater/app/server/win/service_main.cc
@@ -95,7 +95,7 @@ unsigned int flags = Microsoft::WRL::ModuleType::OutOfProc; HRESULT hr = Microsoft::WRL::Details::CreateClassFactory< - Microsoft::WRL::SimpleClassFactory<UpdaterImpl>>( + Microsoft::WRL::SimpleClassFactory<UpdaterInternalImpl>>( &flags, nullptr, __uuidof(IClassFactory), &factory); if (FAILED(hr)) { LOG(ERROR) << "Factory creation failed; hr: " << hr; @@ -115,7 +115,7 @@ std::extent<decltype(cookies_)>() == base::size(class_factories), "Arrays cookies_ and class_factories must be the same size."); - IID class_ids[] = {__uuidof(UpdaterClass)}; + IID class_ids[] = {__uuidof(UpdaterInternalClass)}; DCHECK_EQ(base::size(cookies_), base::size(class_ids)); static_assert(std::extent<decltype(cookies_)>() == base::size(class_ids), "Arrays cookies_ and class_ids must be the same size.");
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc index 72c00da..7d0ea62 100644 --- a/chrome/updater/updater.cc +++ b/chrome/updater/updater.cc
@@ -139,13 +139,15 @@ base::CommandLine::Init(argc, argv); const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - VLOG(1) << "Command line: " << command_line->GetCommandLineString(); if (command_line->HasSwitch(kTestSwitch)) return 0; const UpdaterScope updater_scope = GetUpdaterScope(); InitLogging(updater_scope, *command_line); + + VLOG(1) << "Command line: " << command_line->GetCommandLineString(); + if (command_line->HasSwitch(kCrashHandlerSwitch)) return CrashReporterMain(); InitializeCrashReporting(updater_scope);
diff --git a/chrome/updater/win/setup/setup.cc b/chrome/updater/win/setup/setup.cc index da0348f2..e06e82d 100644 --- a/chrome/updater/win/setup/setup.cc +++ b/chrome/updater/win/setup/setup.cc
@@ -171,26 +171,26 @@ static constexpr base::FilePath::StringPieceType kUpdaterExe = FILE_PATH_LITERAL("updater.exe"); - AddComServerWorkItems(key, versioned_dir->Append(kUpdaterExe), - install_list.get()); AddComInterfacesWorkItems(key, versioned_dir->Append(kUpdaterExe), install_list.get()); - - if (scope == UpdaterScope::kSystem) { - AddComServiceWorkItems(versioned_dir->Append(kUpdaterExe), - install_list.get()); + switch (scope) { + case UpdaterScope::kUser: + AddComServerWorkItems(key, versioned_dir->Append(kUpdaterExe), + install_list.get()); + break; + case UpdaterScope::kSystem: + AddComServiceWorkItems(versioned_dir->Append(kUpdaterExe), + install_list.get()); + break; } base::CommandLine run_updater_wake_command( versioned_dir->Append(kUpdaterExe)); run_updater_wake_command.AppendSwitch(kWakeSwitch); - -#if !defined(NDEBUG) run_updater_wake_command.AppendSwitch(kEnableLoggingSwitch); run_updater_wake_command.AppendSwitchASCII(kLoggingModuleSwitch, "*/chrome/updater/*=2"); -#endif if (!install_list->Do() || !RegisterWakeTask(run_updater_wake_command)) { LOG(ERROR) << "Install failed, rolling back..."; install_list->Rollback();
diff --git a/chrome/updater/win/setup/setup_util.cc b/chrome/updater/win/setup/setup_util.cc index 5838aae..e7471a5 100644 --- a/chrome/updater/win/setup/setup_util.cc +++ b/chrome/updater/win/setup/setup_util.cc
@@ -28,6 +28,7 @@ #include "chrome/updater/app/server/win/updater_internal_idl.h" #include "chrome/updater/app/server/win/updater_legacy_idl.h" #include "chrome/updater/constants.h" +#include "chrome/updater/updater_scope.h" #include "chrome/updater/util.h" #include "chrome/updater/win/task_scheduler.h" #include "chrome/updater/win/win_constants.h" @@ -53,7 +54,6 @@ }; namespace updater { - namespace { constexpr wchar_t kTaskName[] = L"UpdateApps"; @@ -61,6 +61,7 @@ } // namespace +// crbug.com(1216670) - the name of the task must be scoped for user or system. bool RegisterWakeTask(const base::CommandLine& run_command) { auto task_scheduler = TaskScheduler::CreateInstance(); if (!task_scheduler->RegisterTask( @@ -73,6 +74,7 @@ return true; } +// crbug.com(1216670) - the name of the task must be scoped for user or system. void UnregisterWakeTask() { auto task_scheduler = TaskScheduler::CreateInstance(); task_scheduler->DeleteTask(kTaskName); @@ -173,12 +175,9 @@ kServerServiceSwitch, internal_service ? kServerUpdateServiceInternalSwitchValue : kServerUpdateServiceSwitchValue); -#if !defined(NDEBUG) run_com_server_command.AppendSwitch(kEnableLoggingSwitch); run_com_server_command.AppendSwitchASCII(kLoggingModuleSwitch, "*/chrome/updater/*=2"); -#endif - list->AddSetRegValueWorkItem( root, local_server32_reg_path, WorkItem::kWow64Default, L"", run_com_server_command.GetCommandLineString(), true); @@ -194,10 +193,17 @@ return; } + // This assumes the COM service runs elevated and in the system updater scope. + base::CommandLine com_service_command(com_service_path); + com_service_command.AppendSwitch(kSystemSwitch); + com_service_command.AppendSwitch(kComServiceSwitch); + com_service_command.AppendSwitch(kEnableLoggingSwitch); + com_service_command.AppendSwitchASCII(kLoggingModuleSwitch, + "*/chrome/updater/*=2"); list->AddWorkItem(new installer::InstallServiceWorkItem( - kWindowsServiceName, kWindowsServiceName, - base::CommandLine(com_service_path), base::ASCIIToWide(UPDATER_KEY), - {__uuidof(UpdaterServiceClass)}, {})); + kWindowsServiceName, kWindowsServiceName, com_service_command, + base::ASCIIToWide(UPDATER_KEY), GetSideBySideServers(), + GetSideBySideInterfaces())); } std::wstring GetComServerClsidRegistryPath(REFCLSID clsid) {
diff --git a/chromecast/bindings/BUILD.gn b/chromecast/bindings/BUILD.gn index 210771d..70b9e24 100644 --- a/chromecast/bindings/BUILD.gn +++ b/chromecast/bindings/BUILD.gn
@@ -63,11 +63,14 @@ deps = [ ":bindings_manager", "//base", + "//chromecast/bindings/public/mojom", "//chromecast/browser:public", "//components/cast/api_bindings:manager", "//components/cast/message_port", "//components/cast/named_message_port_connector", "//components/on_load_script_injector/browser", + "//mojo/public/cpp/bindings", + "//third_party/blink/public/common", ] }
diff --git a/chromecast/bindings/bindings_manager_cast.cc b/chromecast/bindings/bindings_manager_cast.cc index 98ca4b7f..1ccb15c 100644 --- a/chromecast/bindings/bindings_manager_cast.cc +++ b/chromecast/bindings/bindings_manager_cast.cc
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/macros.h" +#include "base/notreached.h" #include "chromecast/bindings/named_message_port_connector_cast.h" #include "components/on_load_script_injector/browser/on_load_script_injector_host.h" @@ -31,14 +32,31 @@ BindingsManagerCast::~BindingsManagerCast() = default; +mojo::PendingRemote<mojom::ApiBindings> BindingsManagerCast::CreateRemote() { + DCHECK(!receiver_.is_bound()); + + mojo::PendingRemote<mojom::ApiBindings> pending_remote = + receiver_.BindNewPipeAndPassRemote(); + receiver_.set_disconnect_handler(base::BindOnce( + &BindingsManagerCast::OnClientDisconnected, base::Unretained(this))); + + return pending_remote; +} + void BindingsManagerCast::AddBinding(base::StringPiece binding_name, base::StringPiece binding_script) { - cast_web_contents_->script_injector()->AddScriptForAllOrigins( - std::string(binding_name), binding_script); + bindings_[std::string(binding_name)] = std::string(binding_script); +} + +void BindingsManagerCast::OnClientDisconnected() { + receiver_.reset(); } void BindingsManagerCast::OnPageStateChanged( CastWebContents* cast_web_contents) { + // TODO(b/183378843): Remove usage of CWC in this class and + // move the CWC::Observer logics to other components, e.g. + // NMPC or |ApiBindingsClient|. auto page_state = cast_web_contents->page_state(); switch (page_state) { @@ -58,5 +76,20 @@ } } +void BindingsManagerCast::GetAll(GetAllCallback callback) { + std::vector<chromecast::mojom::ApiBindingPtr> bindings_vector; + for (const auto& bindings_name_and_script : bindings_) { + bindings_vector.emplace_back( + chromecast::mojom::ApiBinding::New(bindings_name_and_script.second)); + } + std::move(callback).Run(std::move(bindings_vector)); +} + +void BindingsManagerCast::Connect(const std::string& port_name, + blink::MessagePortDescriptor port) { + // TODO(b/183378843): Implements this method and migrate NMPC to use it. + NOTIMPLEMENTED_LOG_ONCE(); +} + } // namespace bindings } // namespace chromecast
diff --git a/chromecast/bindings/bindings_manager_cast.h b/chromecast/bindings/bindings_manager_cast.h index 1499e8f..9c77e33 100644 --- a/chromecast/bindings/bindings_manager_cast.h +++ b/chromecast/bindings/bindings_manager_cast.h
@@ -6,8 +6,10 @@ #define CHROMECAST_BINDINGS_BINDINGS_MANAGER_CAST_H_ #include "chromecast/bindings/bindings_manager.h" +#include "chromecast/bindings/public/mojom/api_bindings.mojom.h" #include "chromecast/browser/cast_web_contents.h" #include "components/cast/api_bindings/manager.h" +#include "mojo/public/cpp/bindings/receiver.h" namespace chromecast { namespace bindings { @@ -16,7 +18,8 @@ // Implements the CastOS BindingsManager. class BindingsManagerCast : public BindingsManager, - public CastWebContents::Observer { + public CastWebContents::Observer, + public chromecast::mojom::ApiBindings { public: explicit BindingsManagerCast(chromecast::CastWebContents* cast_web_contents); ~BindingsManagerCast() override; @@ -24,16 +27,33 @@ BindingsManagerCast(const BindingsManagerCast&) = delete; void operator=(const BindingsManagerCast&) = delete; + // Creates an mojo::PendingRemote, binds it to |this| and returns it. + // At most one bound remote can exist at the same time. + mojo::PendingRemote<mojom::ApiBindings> CreateRemote(); + // BindingsManager implementation. void AddBinding(base::StringPiece binding_name, base::StringPiece binding_script) override; private: + void OnClientDisconnected(); + // CastWebContents::Observer implementation. void OnPageStateChanged(CastWebContents* cast_web_contents) override; + // chromecast::mojom::ApiBindings implementation. + void GetAll(GetAllCallback callback) override; + void Connect(const std::string& port_name, + blink::MessagePortDescriptor port) override; + chromecast::CastWebContents* cast_web_contents_; std::unique_ptr<NamedMessagePortConnectorCast> port_connector_; + + // Stores all bindings, keyed on the string-based IDs provided by the + // ApiBindings interface. + std::map<std::string, std::string> bindings_; + + mojo::Receiver<mojom::ApiBindings> receiver_{this}; }; } // namespace bindings
diff --git a/chromecast/bindings/bindings_manager_cast_browsertest.cc b/chromecast/bindings/bindings_manager_cast_browsertest.cc index 8cadee1..2fa79e1 100644 --- a/chromecast/bindings/bindings_manager_cast_browsertest.cc +++ b/chromecast/bindings/bindings_manager_cast_browsertest.cc
@@ -170,6 +170,8 @@ title_change_observer_.Observe(cast_web_contents_.get()); bindings_manager_ = std::make_unique<bindings::BindingsManagerCast>( cast_web_contents_.get()); + cast_web_contents_->ConnectToBindingsService( + bindings_manager_->CreateRemote()); } void PostRunTestOnMainThread() override {
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn index 6b1ec13..2e5242c 100644 --- a/chromecast/browser/BUILD.gn +++ b/chromecast/browser/BUILD.gn
@@ -549,6 +549,7 @@ deps = [ "//base", + "//chromecast/bindings/public/mojom", "//chromecast/graphics", "//chromecast/ui:back_gesture_router", "//chromecast/ui/mojom", @@ -648,15 +649,19 @@ deps = [ ":browser", + ":test_support", "//base", "//base/test:test_support", "//chromecast/base", + "//chromecast/bindings/public/mojom", + "//components/on_load_script_injector/browser", "//content/public/browser", "//content/test:test_support", "//net:test_support", "//services/network:test_support", "//testing/gmock", "//testing/gtest", + "//third_party/blink/public/common", "//ui/base", "//ui/base:test_support", "//ui/events/devices:devices",
diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS index f280d925c..a39769a 100644 --- a/chromecast/browser/DEPS +++ b/chromecast/browser/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+cc/base/switches.h", "+chromecast/activity", + "+chromecast/bindings/public/mojom", "+chromecast/common", "+chromecast/common/mojom", "+chromecast/graphics",
diff --git a/chromecast/browser/cast_web_contents.h b/chromecast/browser/cast_web_contents.h index 96d1774..3a44a135 100644 --- a/chromecast/browser/cast_web_contents.h +++ b/chromecast/browser/cast_web_contents.h
@@ -12,6 +12,7 @@ #include "base/containers/flat_set.h" #include "base/observer_list.h" #include "base/process/process.h" +#include "chromecast/bindings/public/mojom/api_bindings.mojom.h" #include "chromecast/common/mojom/feature_manager.mojom.h" #include "content/public/common/media_playback_renderer_type.mojom.h" #include "mojo/public/cpp/bindings/generic_pending_receiver.h" @@ -346,9 +347,24 @@ // Returns the script injector instance, which injects scripts at page load // time. - virtual on_load_script_injector::OnLoadScriptInjectorHost<std::string>* + virtual on_load_script_injector::OnLoadScriptInjectorHost<uint64_t>* script_injector() = 0; + // Executes a UTF-8 encoded |script| for every subsequent page load where + // the frame's URL has an origin reflected in |origins|. The script is + // executed early, prior to the execution of the document's scripts. + // + // Scripts are identified by a client-managed |id|. Any + // script previously injected using the same |id| will be replaced. + // + // The order in which multiple bindings are executed is the same as the + // order in which the bindings were added. If a script is added which + // clobbers an existing script of the same |id|, the previous script's + // precedence in the injection order will be preserved. + // |script| and |id| must be non-empty string. + virtual void AddBeforeLoadJavaScript(uint64_t id, + base::StringPiece script) = 0; + // Posts a message to the frame's onMessage handler. // // `target_origin` restricts message delivery to the specified origin. @@ -372,6 +388,13 @@ const std::u16string& javascript, base::OnceCallback<void(base::Value)> callback) = 0; + // Connects and fetches JS API bindings from |api_bindings_remote|. + // This method will fetch bindings scripts from |api_bindings_remote| + // immediately after the invocation, all of the bindings should be + // initialized before this point. + virtual void ConnectToBindingsService( + mojo::PendingRemote<mojom::ApiBindings> api_bindings_remote) = 0; + // =========================================================================== // Utility Methods // ===========================================================================
diff --git a/chromecast/browser/cast_web_contents_browsertest.cc b/chromecast/browser/cast_web_contents_browsertest.cc index b25b18de..7052463 100644 --- a/chromecast/browser/cast_web_contents_browsertest.cc +++ b/chromecast/browser/cast_web_contents_browsertest.cc
@@ -55,6 +55,7 @@ using ::testing::_; using ::testing::AllOf; using ::testing::AtLeast; +using ::testing::ElementsAre; using ::testing::Eq; using ::testing::Expectation; using ::testing::InSequence; @@ -63,6 +64,7 @@ using ::testing::Mock; using ::testing::NiceMock; using ::testing::Property; +using ::testing::WithArgs; namespace content { class WebContents; @@ -147,11 +149,11 @@ // Spins a Runloop until the title of the page matches the |expected_title| // that have been set. - void RunUntilTitleEquals(base::StringPiece expected_title) { - expected_title_ = std::string(expected_title); + void RunUntilTitleEquals(const std::u16string& expected_title) { + expected_title_ = expected_title; // Spin the runloop until the expected conditions are met. if (current_title_ != expected_title_) { - expected_title_ = std::string(expected_title); + expected_title_ = expected_title; base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); run_loop.Run(); @@ -162,8 +164,7 @@ void UpdateTitle(const std::u16string& title) override { // Resumes execution of RunUntilTitleEquals() if |title| matches // expectations. - std::string title_utf8 = base::UTF16ToUTF8(title); - current_title_ = title_utf8; + current_title_ = title; if (!quit_closure_.is_null() && current_title_ == expected_title_) { DCHECK_EQ(current_title_, expected_title_); std::move(quit_closure_).Run(); @@ -171,8 +172,8 @@ } private: - std::string current_title_; - std::string expected_title_; + std::u16string current_title_; + std::u16string expected_title_; base::OnceClosure quit_closure_; @@ -759,15 +760,141 @@ run_loop->Run(); } +IN_PROC_BROWSER_TEST_F(CastWebContentsBrowserTest, ExecuteJavaScriptOnLoad) { + // =========================================================================== + // Test: Injecting script to change title should work. + // =========================================================================== + const std::u16string kExpectedTitle = u"hello"; + const std::u16string kOriginalTitle = + u"Welcome to Stan the Offline Dino's Homepage"; + + // The script should be able to run before HTML <script> tag starts running. + // The original title will be loaded first and then the injected script. Other + // scripts must run after the injected script. + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kExpectedTitle)); + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kOriginalTitle)); + constexpr uint64_t kBindingsId = 1234; + + GURL gurl = content::GetFileUrlWithQuery( + GetTestDataFilePath("dynamic_title.html"), ""); + + cast_web_contents_->AddBeforeLoadJavaScript(kBindingsId, + "stashed_title = 'hello';"); + + cast_web_contents_->LoadUrl(gurl); + title_change_observer_.RunUntilTitleEquals(kExpectedTitle); +} + +IN_PROC_BROWSER_TEST_F(CastWebContentsBrowserTest, + ExecuteJavaScriptUpdatedOnLoad) { + // =========================================================================== + // Test: Verify that this script replaces the previous script with same + // binding id, as opposed to being injected alongside it. (The latter would + // result in the title being "helloclobber"). + // =========================================================================== + const std::u16string kReplaceTitle = u"clobber"; + const std::u16string kOriginalTitle = + u"Welcome to Stan the Offline Dino's Homepage"; + + // The script should be able to run before HTML <script> tag starts running. + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kReplaceTitle)); + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kOriginalTitle)); + + constexpr uint64_t kBindingsId = 1234; + + GURL gurl = content::GetFileUrlWithQuery( + GetTestDataFilePath("dynamic_title.html"), ""); + + cast_web_contents_->AddBeforeLoadJavaScript(kBindingsId, + "stashed_title = 'hello';"); + + cast_web_contents_->AddBeforeLoadJavaScript( + kBindingsId, "stashed_title = document.title + 'clobber';"); + + cast_web_contents_->LoadUrl(gurl); + title_change_observer_.RunUntilTitleEquals(kReplaceTitle); +} + +IN_PROC_BROWSER_TEST_F(CastWebContentsBrowserTest, + ExecuteJavaScriptOnLoadOrdered) { + // =========================================================================== + // Test: Verifies that bindings are injected in order by producing a + // cumulative, non-commutative result. + // =========================================================================== + const std::u16string kExpectedTitle = u"hello there"; + const std::u16string kOriginalTitle = + u"Welcome to Stan the Offline Dino's Homepage"; + constexpr int64_t kBindingsId1 = 1234; + constexpr int64_t kBindingsId2 = 5678; + + // The script should be able to run before HTML <script> tag starts running. + // The original title will be loaded first and then the injected script. Other + // scripts must run after the injected script. + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kExpectedTitle)); + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kOriginalTitle)); + + GURL gurl = content::GetFileUrlWithQuery( + GetTestDataFilePath("dynamic_title.html"), ""); + + cast_web_contents_->AddBeforeLoadJavaScript(kBindingsId1, + "stashed_title = 'hello';"); + + cast_web_contents_->AddBeforeLoadJavaScript(kBindingsId2, + "stashed_title += ' there';"); + + cast_web_contents_->LoadUrl(gurl); + title_change_observer_.RunUntilTitleEquals(kExpectedTitle); +} + +IN_PROC_BROWSER_TEST_F(CastWebContentsBrowserTest, + ExecuteJavaScriptOnLoadEarlyAndLateRegistrations) { + // =========================================================================== + // Test: Tests that we can inject scripts before and after RenderFrame + // creation. + // =========================================================================== + const std::u16string kExpectedTitle1 = u"foo"; + const std::u16string kExpectedTitle2 = u"foo bar"; + const std::u16string kOriginalTitle = + u"Welcome to Stan the Offline Dino's Homepage"; + constexpr int64_t kBindingsId1 = 1234; + constexpr int64_t kBindingsId2 = 5678; + + // The script should be able to run before HTML <script> tag starts running. + // The original title will be loaded first and then the injected script. Other + // scripts must run after the injected script. + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kExpectedTitle2)); + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kExpectedTitle1)); + EXPECT_CALL(mock_cast_wc_observer_, UpdateTitle(kOriginalTitle)).Times(2); + + GURL gurl = content::GetFileUrlWithQuery( + GetTestDataFilePath("dynamic_title.html"), ""); + + cast_web_contents_->AddBeforeLoadJavaScript(kBindingsId1, + "stashed_title = 'foo';"); + cast_web_contents_->LoadUrl(gurl); + title_change_observer_.RunUntilTitleEquals(kExpectedTitle1); + + // Inject bindings after RenderFrameCreation + cast_web_contents_->AddBeforeLoadJavaScript(kBindingsId2, + "stashed_title += ' bar';"); + + // Navigate away to clean the state. + cast_web_contents_->LoadUrl(GURL(url::kAboutBlankURL)); + + // Navigate back and see if both scripts are working. + cast_web_contents_->LoadUrl(gurl); + title_change_observer_.RunUntilTitleEquals(kExpectedTitle2); +} + IN_PROC_BROWSER_TEST_F(CastWebContentsBrowserTest, PostMessageToMainFrame) { // =========================================================================== // Test: Tests that we can trigger onmessage event on a web page. This test // would post a message to the test page to redirect it to |title1.html|. // =========================================================================== - constexpr char kOriginalTitle[] = "postmessage"; + const std::u16string kOriginalTitle = u"postmessage"; constexpr char16_t kOriginalTitle16[] = u"postmessage"; - constexpr char kPage1Path[] = "title1.html"; - constexpr char kPage1Title[] = "title 1"; + const std::u16string kPage1Path = u"title1.html"; + const std::u16string kPage1Title = u"title 1"; constexpr char16_t kPage1Title16[] = u"title 1"; EXPECT_CALL(mock_cast_wc_observer_, @@ -783,7 +910,7 @@ title_change_observer_.RunUntilTitleEquals(kOriginalTitle); cast_web_contents_->PostMessageToMainFrame( - gurl.GetOrigin().spec(), std::string(kPage1Path), + gurl.GetOrigin().spec(), base::UTF16ToUTF8(kPage1Path), std::vector<blink::WebMessagePort>()); title_change_observer_.RunUntilTitleEquals(kPage1Title); } @@ -793,7 +920,7 @@ // Test: Send a MessagePort to the page, then perform bidirectional messaging // through the port. // =========================================================================== - constexpr char kOriginalTitle[] = "messageport"; + const std::u16string kOriginalTitle = u"messageport"; constexpr char16_t kOriginalTitle16[] = u"messageport"; constexpr char kHelloMsg[] = "hi"; constexpr char16_t kPingMsg[] = u"ping"; @@ -862,7 +989,7 @@ // through the port. Make sure mojo counterpart pipe handle could receive the // MessagePort disconnection event. // =========================================================================== - constexpr char kOriginalTitle[] = "messageport"; + const std::u16string kOriginalTitle = u"messageport"; constexpr char16_t kOriginalTitle16[] = u"messageport"; constexpr char kHelloMsg[] = "hi"; @@ -968,6 +1095,141 @@ run_loop2.Run(); } +// Mock class used by the following test case. +class MockApiBindings : public mojom::ApiBindings { + public: + MockApiBindings() = default; + ~MockApiBindings() override = default; + + mojo::PendingRemote<mojom::ApiBindings> CreateRemote() { + DCHECK(!receiver_.is_bound()); + + mojo::PendingRemote<mojom::ApiBindings> pending_remote = + receiver_.BindNewPipeAndPassRemote(); + + return pending_remote; + } + + // mojom::ApiBindings implementation: + MOCK_METHOD(void, GetAll, (GetAllCallback), (override)); + MOCK_METHOD(void, + Connect, + (const std::string&, blink::MessagePortDescriptor), + (override)); + + private: + mojo::Receiver<mojom::ApiBindings> receiver_{this}; +}; + +IN_PROC_BROWSER_TEST_F(CastWebContentsBrowserTest, + InjectBindingsFromApiBindingsRemote) { + // Start test server for hosting test HTML pages. + embedded_test_server()->ServeFilesFromSourceDirectory(GetTestDataPath()); + StartTestServer(); + auto run_loop = std::make_unique<base::RunLoop>(); + auto quit_closure = [&run_loop]() { + if (run_loop->running()) { + run_loop->QuitWhenIdle(); + } + }; + + // =========================================================================== + // Test: Inject a set of scripts to eval an result. Retrieve that value and + // match against the right answer. + // =========================================================================== + MockApiBindings mock_api_bindings; + EXPECT_CALL(mock_api_bindings, GetAll(_)) + .Times(1) + .WillOnce( + WithArgs<0>(Invoke([](MockApiBindings::GetAllCallback callback) { + std::vector<chromecast::mojom::ApiBindingPtr> bindings_vector; + bindings_vector.emplace_back( + chromecast::mojom::ApiBinding::New("let res = 0;")); + bindings_vector.emplace_back( + chromecast::mojom::ApiBinding::New("res += 1;")); + bindings_vector.emplace_back( + chromecast::mojom::ApiBinding::New("res += 2;")); + bindings_vector.emplace_back( + chromecast::mojom::ApiBinding::New("res += 3;")); + std::move(callback).Run(std::move(bindings_vector)); + }))); + + // Binds mocked |mojom::ApiBindings|. + cast_web_contents_->ConnectToBindingsService( + mock_api_bindings.CreateRemote()); + + { + InSequence seq; + EXPECT_CALL( + mock_cast_wc_observer_, + OnPageStateChanged(CheckPageState( + cast_web_contents_.get(), CastWebContents::PageState::LOADING))); + EXPECT_CALL( + mock_cast_wc_observer_, + OnPageStateChanged(CheckPageState(cast_web_contents_.get(), + CastWebContents::PageState::LOADED))) + .WillOnce(InvokeWithoutArgs(quit_closure)); + } + + // Loads a blank page. + cast_web_contents_->LoadUrl(GURL(url::kAboutBlankURL)); + run_loop->Run(); + + // Evaluates the value of |res|. + EXPECT_EQ(6, content::EvalJs(cast_web_contents_->web_contents(), "res;")); +} + +IN_PROC_BROWSER_TEST_F(CastWebContentsBrowserTest, + StopPageInCaseOfEmptyBindingsReceived) { + // Start test server for hosting test HTML pages. + embedded_test_server()->ServeFilesFromSourceDirectory(GetTestDataPath()); + StartTestServer(); + auto run_loop = std::make_unique<base::RunLoop>(); + auto quit_closure = [&run_loop]() { + if (run_loop->running()) { + run_loop->QuitWhenIdle(); + } + }; + + // =========================================================================== + // Test: Sending empty set of bindings should result in error page state. + // =========================================================================== + MockApiBindings mock_api_bindings; + EXPECT_CALL(mock_api_bindings, GetAll(_)) + .Times(1) + .WillOnce( + WithArgs<0>(Invoke([](MockApiBindings::GetAllCallback callback) { + std::vector<chromecast::mojom::ApiBindingPtr> bindings_vector; + std::move(callback).Run(std::move(bindings_vector)); + }))); + + // Binds mocked |mojom::ApiBindings|. + cast_web_contents_->ConnectToBindingsService( + mock_api_bindings.CreateRemote()); + + { + InSequence seq; + EXPECT_CALL( + mock_cast_wc_observer_, + OnPageStateChanged(CheckPageState( + cast_web_contents_.get(), CastWebContents::PageState::LOADING))); + EXPECT_CALL( + mock_cast_wc_observer_, + OnPageStateChanged(CheckPageState(cast_web_contents_.get(), + CastWebContents::PageState::LOADED))) + .WillOnce(InvokeWithoutArgs(quit_closure)); + } + + EXPECT_CALL(mock_cast_wc_observer_, + OnPageStopped(CheckPageState(cast_web_contents_.get(), + CastWebContents::PageState::ERROR), + net::ERR_UNEXPECTED)); + + // Loads a blank page. + cast_web_contents_->LoadUrl(GURL(url::kAboutBlankURL)); + run_loop->Run(); +} + // Helper for the test below. This exposes two interfaces, TestAdder and // TestDoubler. TestAdder is exposed only through a binder (see MakeAdderBinder) // which the test will register in the CastWebContents' binder_registry().
diff --git a/chromecast/browser/cast_web_contents_impl.cc b/chromecast/browser/cast_web_contents_impl.cc index 795651e..baefe29 100644 --- a/chromecast/browser/cast_web_contents_impl.cc +++ b/chromecast/browser/cast_web_contents_impl.cc
@@ -226,6 +226,14 @@ void CastWebContentsImpl::LoadUrl(const GURL& url) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (api_bindings_ && !bindings_received_) { + LOG(INFO) << "Will load URL: " << url.possibly_invalid_spec() + << " once bindings has been received."; + pending_load_url_ = url; + return; + } + if (!web_contents_) { LOG(ERROR) << "Cannot load URL for deleted WebContents"; return; @@ -338,11 +346,16 @@ web_contents_, session_id, is_audio_app); } -on_load_script_injector::OnLoadScriptInjectorHost<std::string>* +on_load_script_injector::OnLoadScriptInjectorHost<uint64_t>* CastWebContentsImpl::script_injector() { return &script_injector_; } +void CastWebContentsImpl::AddBeforeLoadJavaScript(uint64_t id, + base::StringPiece script) { + script_injector_.AddScriptForAllOrigins(id, std::string(script)); +} + void CastWebContentsImpl::PostMessageToMainFrame( const std::string& target_origin, const std::string& data, @@ -353,8 +366,8 @@ data_utf16 = base::UTF8ToUTF16(data); // If origin is set as wildcard, no origin scoping would be applied. - constexpr char kWildcardOrigin[] = "*"; absl::optional<std::u16string> target_origin_utf16; + constexpr char kWildcardOrigin[] = "*"; if (target_origin != kWildcardOrigin) target_origin_utf16 = base::UTF8ToUTF16(target_origin); @@ -375,6 +388,18 @@ std::move(callback)); } +void CastWebContentsImpl::ConnectToBindingsService( + mojo::PendingRemote<mojom::ApiBindings> api_bindings_remote) { + DCHECK(api_bindings_remote); + + bindings_received_ = false; + + api_bindings_.Bind(std::move(api_bindings_remote)); + // Fetch bindings and inject scripts into |script_injector_|. + api_bindings_->GetAll(base::BindOnce(&CastWebContentsImpl::OnBindingsReceived, + base::Unretained(this))); +} + void CastWebContentsImpl::AddObserver(CastWebContents::Observer* observer) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(observer); @@ -545,6 +570,31 @@ return features; } +void CastWebContentsImpl::OnBindingsReceived( + std::vector<chromecast::mojom::ApiBindingPtr> bindings) { + bindings_received_ = true; + + if (bindings.empty()) { + LOG(ERROR) << "ApiBindings remote sent empty bindings. Stopping the page."; + Stop(net::ERR_UNEXPECTED); + } else { + constexpr uint64_t kBindingsIdStart = 0xFF0000; + + // Enumerate and inject all scripts in |bindings|. + uint64_t bindings_id = kBindingsIdStart; + for (auto& entry : bindings) { + AddBeforeLoadJavaScript(bindings_id++, entry->script); + } + } + + DVLOG(1) << "Bindings has been received. Start loading URL if requested."; + if (!pending_load_url_.is_empty()) { + auto gurl = std::move(pending_load_url_); + pending_load_url_ = GURL(); + LoadUrl(gurl); + } +} + void CastWebContentsImpl::OnInterfaceRequestFromFrame( content::RenderFrameHost* /* render_frame_host */, const std::string& interface_name,
diff --git a/chromecast/browser/cast_web_contents_impl.h b/chromecast/browser/cast_web_contents_impl.h index de3e8e57..c170124 100644 --- a/chromecast/browser/cast_web_contents_impl.h +++ b/chromecast/browser/cast_web_contents_impl.h
@@ -19,6 +19,7 @@ #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "base/time/time.h" +#include "chromecast/bindings/public/mojom/api_bindings.mojom.h" #include "chromecast/browser/cast_media_blocker.h" #include "chromecast/browser/cast_web_contents.h" #include "components/on_load_script_injector/browser/on_load_script_injector_host.h" @@ -26,6 +27,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/common/media_playback_renderer_type.mojom.h" +#include "mojo/public/cpp/bindings/remote.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -73,8 +75,9 @@ void BlockMediaLoading(bool blocked) override; void BlockMediaStarting(bool blocked) override; void EnableBackgroundVideoPlayback(bool enabled) override; - on_load_script_injector::OnLoadScriptInjectorHost<std::string>* - script_injector() override; + on_load_script_injector::OnLoadScriptInjectorHost<uint64_t>* script_injector() + override; + void AddBeforeLoadJavaScript(uint64_t id, base::StringPiece script) override; void PostMessageToMainFrame( const std::string& target_origin, const std::string& data, @@ -82,6 +85,8 @@ void ExecuteJavaScript( const std::u16string& javascript, base::OnceCallback<void(base::Value)> callback) override; + void ConnectToBindingsService( + mojo::PendingRemote<mojom::ApiBindings> api_bindings_remote) override; void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; void SetEnabledForRemoteDebugging(bool enabled) override; @@ -147,6 +152,8 @@ void OnClosePageTimeout(); void RemoveRenderProcessHostObserver(); std::vector<chromecast::shell::mojom::FeaturePtr> GetRendererFeatures(); + void OnBindingsReceived( + std::vector<chromecast::mojom::ApiBindingPtr> bindings); content::WebContents* web_contents_; base::WeakPtr<Delegate> delegate_; @@ -183,8 +190,14 @@ bool notifying_; int last_error_; - on_load_script_injector::OnLoadScriptInjectorHost<std::string> - script_injector_; + on_load_script_injector::OnLoadScriptInjectorHost<uint64_t> script_injector_; + mojo::Remote<mojom::ApiBindings> api_bindings_; + + // If |ConnectToBindingsService| is invoked, |bindings_received_| is set + // false. Following |LoadUrl| will be stored in |pending_load_url_|, and + // will be invoked once bindings are received. + bool bindings_received_{false}; + GURL pending_load_url_; base::ObserverList<Observer>::Unchecked observer_list_;
diff --git a/chromecast/browser/cast_web_view_default.h b/chromecast/browser/cast_web_view_default.h index e83b260..d1c056f 100644 --- a/chromecast/browser/cast_web_view_default.h +++ b/chromecast/browser/cast_web_view_default.h
@@ -10,7 +10,6 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/time/time.h" #include "build/build_config.h" #include "chromecast/browser/cast_content_window.h"
diff --git a/chromecast/browser/exo/cast_wm_helper.h b/chromecast/browser/exo/cast_wm_helper.h index 52947f64..0552306 100644 --- a/chromecast/browser/exo/cast_wm_helper.h +++ b/chromecast/browser/exo/cast_wm_helper.h
@@ -10,7 +10,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "components/exo/vsync_timing_manager.h" #include "components/exo/wm_helper.h" #include "mojo/public/cpp/bindings/pending_remote.h"
diff --git a/chromecast/browser/test/mock_cast_web_view.h b/chromecast/browser/test/mock_cast_web_view.h index c8d747b..ef1c1a7f 100644 --- a/chromecast/browser/test/mock_cast_web_view.h +++ b/chromecast/browser/test/mock_cast_web_view.h
@@ -41,11 +41,15 @@ MOCK_METHOD(void, BlockMediaLoading, (bool), (override)); MOCK_METHOD(void, BlockMediaStarting, (bool), (override)); MOCK_METHOD(void, EnableBackgroundVideoPlayback, (bool), (override)); - MOCK_METHOD(on_load_script_injector::OnLoadScriptInjectorHost<std::string>*, + MOCK_METHOD(on_load_script_injector::OnLoadScriptInjectorHost<uint64_t>*, script_injector, (), (override)); MOCK_METHOD(void, + AddBeforeLoadJavaScript, + (uint64_t, base::StringPiece), + (override)); + MOCK_METHOD(void, PostMessageToMainFrame, (const std::string&, const std::string&, @@ -55,6 +59,10 @@ ExecuteJavaScript, (const std::u16string&, base::OnceCallback<void(base::Value)>), (override)); + MOCK_METHOD(void, + ConnectToBindingsService, + (mojo::PendingRemote<mojom::ApiBindings> api_bindings_remote), + (override)); MOCK_METHOD(void, AddObserver, (Observer*), (override)); MOCK_METHOD(void, RemoveObserver, (Observer*), (override)); MOCK_METHOD(void, SetEnabledForRemoteDebugging, (bool), (override));
diff --git a/chromeos/components/phonehub/notification_access_manager_impl.cc b/chromeos/components/phonehub/notification_access_manager_impl.cc index f9a277c..047f68b 100644 --- a/chromeos/components/phonehub/notification_access_manager_impl.cc +++ b/chromeos/components/phonehub/notification_access_manager_impl.cc
@@ -21,6 +21,8 @@ prefs::kNotificationAccessStatus, static_cast<int>(AccessStatus::kAvailableButNotGranted)); registry->RegisterBooleanPref(prefs::kHasDismissedSetupRequiredUi, false); + registry->RegisterBooleanPref(prefs::kNeedsOneTimeNotificationAccessUpdate, + true); } NotificationAccessManagerImpl::NotificationAccessManagerImpl( @@ -60,8 +62,25 @@ void NotificationAccessManagerImpl::SetAccessStatusInternal( AccessStatus access_status) { - if (access_status == GetAccessStatus()) + // TODO(http://crbug.com/1215559): Deprecate when there are no more active + // Phone Hub notification users on M89. Some users had notifications + // automatically disabled when updating from M89 to M90+ because the + // notification feature state went from enabled-by-default to + // disabled-by-default. To re-enable those users, we once and only once notify + // observers if access has been granted by the phone. Notably, the + // MultideviceSetupStateUpdate will decide whether or not the notification + // feature should be enabled. See MultideviceSetupStateUpdater's method + // IsWaitingForAccessToInitiallyEnableNotifications() for more details. + bool needs_one_time_notifications_access_update = + pref_service_->GetBoolean(prefs::kNeedsOneTimeNotificationAccessUpdate) && + access_status == AccessStatus::kAccessGranted; + + if (access_status == GetAccessStatus() && + !needs_one_time_notifications_access_update) { return; + } + pref_service_->SetBoolean(prefs::kNeedsOneTimeNotificationAccessUpdate, + false); PA_LOG(INFO) << "Notification access: " << GetAccessStatus() << " => " << access_status;
diff --git a/chromeos/components/phonehub/notification_access_manager_impl_unittest.cc b/chromeos/components/phonehub/notification_access_manager_impl_unittest.cc index 5e5e4e7..bbaad67 100644 --- a/chromeos/components/phonehub/notification_access_manager_impl_unittest.cc +++ b/chromeos/components/phonehub/notification_access_manager_impl_unittest.cc
@@ -76,6 +76,7 @@ void Initialize(NotificationAccessManager::AccessStatus expected_status) { pref_service_.SetInteger(prefs::kNotificationAccessStatus, static_cast<int>(expected_status)); + SetNeedsOneTimeNotificationAccessUpdate(/*needs_update=*/false); manager_ = std::make_unique<NotificationAccessManagerImpl>( &pref_service_, fake_feature_status_provider_.get(), fake_message_sender_.get(), fake_connection_scheduler_.get()); @@ -130,6 +131,11 @@ size_t GetNumObserverCalls() const { return fake_observer_.num_calls(); } + void SetNeedsOneTimeNotificationAccessUpdate(bool needs_update) { + pref_service_.SetBoolean(prefs::kNeedsOneTimeNotificationAccessUpdate, + needs_update); + } + private: TestingPrefServiceSimple pref_service_; @@ -404,6 +410,7 @@ NotificationAccessManager::AccessStatus::kAvailableButNotGranted); VerifyNotificationAccessGrantedState( NotificationAccessManager::AccessStatus::kAvailableButNotGranted); + EXPECT_EQ(1u, GetNumObserverCalls()); } TEST_F(NotificationAccessManagerImplTest, FlipAccessGrantedToProhibited) { @@ -415,6 +422,58 @@ SetAccessStatusInternal(NotificationAccessManager::AccessStatus::kProhibited); VerifyNotificationAccessGrantedState( NotificationAccessManager::AccessStatus::kProhibited); + EXPECT_EQ(1u, GetNumObserverCalls()); +} + +TEST_F(NotificationAccessManagerImplTest, AccessNotChanged) { + Initialize(NotificationAccessManager::AccessStatus::kAccessGranted); + VerifyNotificationAccessGrantedState( + NotificationAccessManager::AccessStatus::kAccessGranted); + + // If the access state is unchanged, we do not expect any notifications. + SetAccessStatusInternal( + NotificationAccessManager::AccessStatus::kAccessGranted); + VerifyNotificationAccessGrantedState( + NotificationAccessManager::AccessStatus::kAccessGranted); + EXPECT_EQ(0u, GetNumObserverCalls()); +} + +TEST_F(NotificationAccessManagerImplTest, + NeedsOneTimeNotificationAccessUpdate_AccessGranted) { + Initialize(NotificationAccessManager::AccessStatus::kAccessGranted); + VerifyNotificationAccessGrantedState( + NotificationAccessManager::AccessStatus::kAccessGranted); + + // Send a one-time signal to observers if access is granted. See + // http://crbug.com/1215559. + SetNeedsOneTimeNotificationAccessUpdate(/*needs_update=*/true); + SetAccessStatusInternal( + NotificationAccessManager::AccessStatus::kAccessGranted); + VerifyNotificationAccessGrantedState( + NotificationAccessManager::AccessStatus::kAccessGranted); + EXPECT_EQ(1u, GetNumObserverCalls()); + + // Observers should be notified only once ever. + SetAccessStatusInternal( + NotificationAccessManager::AccessStatus::kAccessGranted); + VerifyNotificationAccessGrantedState( + NotificationAccessManager::AccessStatus::kAccessGranted); + EXPECT_EQ(1u, GetNumObserverCalls()); +} + +TEST_F(NotificationAccessManagerImplTest, + NeedsOneTimeNotificationAccessUpdate_Prohibited) { + Initialize(NotificationAccessManager::AccessStatus::kProhibited); + VerifyNotificationAccessGrantedState( + NotificationAccessManager::AccessStatus::kProhibited); + + // Only send the one-time signal to observers if access is granted. See + // http://crbug.com/1215559. + SetNeedsOneTimeNotificationAccessUpdate(/*needs_update=*/true); + SetAccessStatusInternal(NotificationAccessManager::AccessStatus::kProhibited); + VerifyNotificationAccessGrantedState( + NotificationAccessManager::AccessStatus::kProhibited); + EXPECT_EQ(0u, GetNumObserverCalls()); } } // namespace phonehub
diff --git a/chromeos/components/phonehub/notification_click_handler.h b/chromeos/components/phonehub/notification_click_handler.h index 1f96f687..728b785f 100644 --- a/chromeos/components/phonehub/notification_click_handler.h +++ b/chromeos/components/phonehub/notification_click_handler.h
@@ -5,7 +5,7 @@ #ifndef CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_CLICK_HANDLER_H_ #define CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_CLICK_HANDLER_H_ -#include "base/observer_list.h" +#include "base/observer_list_types.h" namespace chromeos { namespace phonehub {
diff --git a/chromeos/components/phonehub/pref_names.cc b/chromeos/components/phonehub/pref_names.cc index 45a4c73..79f8d7d 100644 --- a/chromeos/components/phonehub/pref_names.cc +++ b/chromeos/components/phonehub/pref_names.cc
@@ -32,6 +32,18 @@ const char kHasDismissedSetupRequiredUi[] = "cros.phonehub.has_dismissed_setup_required_ui"; +// TODO(http://crbug.com/1215559): Deprecate when there are no more active Phone +// Hub notification users on M89. Some users had notifications automatically +// disabled when updating from M89 to M90+ because the notification feature +// state went from enabled-by-default to disabled-by-default. To re-enable those +// users, we once and only once notify observers if access has been granted by +// the phone. Notably, the MultideviceSetupStateUpdate will decide whether or +// not the notification feature should be enabled. See +// MultideviceSetupStateUpdater's method +// IsWaitingForAccessToInitiallyEnableNotifications() for more details. +const char kNeedsOneTimeNotificationAccessUpdate[] = + "cros.phonehub.needs_one_time_notification_access_update"; + } // namespace prefs } // namespace phonehub } // namespace chromeos
diff --git a/chromeos/components/phonehub/pref_names.h b/chromeos/components/phonehub/pref_names.h index 971e702..ebdb67c 100644 --- a/chromeos/components/phonehub/pref_names.h +++ b/chromeos/components/phonehub/pref_names.h
@@ -13,6 +13,7 @@ extern const char kHideOnboardingUi[]; extern const char kIsAwaitingVerifiedHost[]; extern const char kHasDismissedSetupRequiredUi[]; +extern const char kNeedsOneTimeNotificationAccessUpdate[]; } // namespace prefs } // namespace phonehub
diff --git a/chromeos/components/tether/fake_active_host.h b/chromeos/components/tether/fake_active_host.h index 5f58d0ae..d411116 100644 --- a/chromeos/components/tether/fake_active_host.h +++ b/chromeos/components/tether/fake_active_host.h
@@ -10,7 +10,6 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "chromeos/components/tether/active_host.h" namespace chromeos {
diff --git a/chromeos/components/tether/fake_disconnect_tethering_request_sender.h b/chromeos/components/tether/fake_disconnect_tethering_request_sender.h index b27f8d9..e4b6d48 100644 --- a/chromeos/components/tether/fake_disconnect_tethering_request_sender.h +++ b/chromeos/components/tether/fake_disconnect_tethering_request_sender.h
@@ -9,7 +9,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/components/tether/disconnect_tethering_request_sender.h" namespace chromeos {
diff --git a/chromeos/components/tether/fake_gms_core_notifications_state_tracker.h b/chromeos/components/tether/fake_gms_core_notifications_state_tracker.h index f24f9fd..f1dea712 100644 --- a/chromeos/components/tether/fake_gms_core_notifications_state_tracker.h +++ b/chromeos/components/tether/fake_gms_core_notifications_state_tracker.h
@@ -9,7 +9,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/components/tether/gms_core_notifications_state_tracker.h" namespace chromeos {
diff --git a/chromeos/components/tether/gms_core_notifications_state_tracker_impl.h b/chromeos/components/tether/gms_core_notifications_state_tracker_impl.h index 69cec6df..ac183b7 100644 --- a/chromeos/components/tether/gms_core_notifications_state_tracker_impl.h +++ b/chromeos/components/tether/gms_core_notifications_state_tracker_impl.h
@@ -10,7 +10,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/tether/gms_core_notifications_state_tracker.h" #include "chromeos/components/tether/host_scanner_operation.h"
diff --git a/chromeos/components/tether/notification_presenter.h b/chromeos/components/tether/notification_presenter.h index 210b7f5..17817a5d 100644 --- a/chromeos/components/tether/notification_presenter.h +++ b/chromeos/components/tether/notification_presenter.h
@@ -6,7 +6,6 @@ #define CHROMEOS_COMPONENTS_TETHER_NOTIFICATION_PRESENTER_H_ #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/network/network_state.h"
diff --git a/chromeos/components/tether/wifi_hotspot_connector.h b/chromeos/components/tether/wifi_hotspot_connector.h index ba1bf4f..a6e4300c 100644 --- a/chromeos/components/tether/wifi_hotspot_connector.h +++ b/chromeos/components/tether/wifi_hotspot_connector.h
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/time/clock.h" #include "base/timer/timer.h" #include "base/values.h"
diff --git a/chromeos/crosapi/cpp/keystore_service_util.cc b/chromeos/crosapi/cpp/keystore_service_util.cc index 1f589fe..21d4fa1 100644 --- a/chromeos/crosapi/cpp/keystore_service_util.cc +++ b/chromeos/crosapi/cpp/keystore_service_util.cc
@@ -90,5 +90,25 @@ return absl::nullopt; } +mojom::KeystoreSigningAlgorithmPtr MakeRsaKeystoreSigningAlgorithm( + unsigned int modulus_length) { + mojom::KeystoreSigningAlgorithmPtr algorithm = + mojom::KeystoreSigningAlgorithm::New(); + mojom::KeystorePKCS115ParamsPtr params = mojom::KeystorePKCS115Params::New(); + params->modulus_length = modulus_length; + algorithm->set_pkcs115(std::move(params)); + return algorithm; +} + +mojom::KeystoreSigningAlgorithmPtr MakeEcKeystoreSigningAlgorithm( + const std::string& named_curve) { + mojom::KeystoreSigningAlgorithmPtr algorithm = + mojom::KeystoreSigningAlgorithm::New(); + mojom::KeystoreECDSAParamsPtr params = mojom::KeystoreECDSAParams::New(); + params->named_curve = named_curve; + algorithm->set_ecdsa(std::move(params)); + return algorithm; +} + } // namespace keystore_service_util } // namespace crosapi
diff --git a/chromeos/crosapi/cpp/keystore_service_util.h b/chromeos/crosapi/cpp/keystore_service_util.h index f19be2c..8c458a24 100644 --- a/chromeos/crosapi/cpp/keystore_service_util.h +++ b/chromeos/crosapi/cpp/keystore_service_util.h
@@ -29,14 +29,26 @@ // absl::nullopt on error. COMPONENT_EXPORT(CROSAPI) absl::optional<base::DictionaryValue> DictionaryFromSigningAlgorithm( - const crosapi::mojom::KeystoreSigningAlgorithmPtr& algorithm); + const mojom::KeystoreSigningAlgorithmPtr& algorithm); // Converts a WebCrypto dictionary into a crosapi signing algorithm. Returns // absl::nullopt on error. COMPONENT_EXPORT(CROSAPI) -absl::optional<crosapi::mojom::KeystoreSigningAlgorithmPtr> +absl::optional<mojom::KeystoreSigningAlgorithmPtr> SigningAlgorithmFromDictionary(const base::DictionaryValue& dictionary); +// Creates the KeystorePKCS115Params variant of the KeystoreSigningAlgorithm +// union and populates the modulus_length field with |modulus_length|. +COMPONENT_EXPORT(CROSAPI) +mojom::KeystoreSigningAlgorithmPtr MakeRsaKeystoreSigningAlgorithm( + unsigned int modulus_length); + +// Creates the KeystoreECDSAParams variant of the KeystoreSigningAlgorithm +// union and populates the named_curve field with |modulus_length|. +COMPONENT_EXPORT(CROSAPI) +mojom::KeystoreSigningAlgorithmPtr MakeEcKeystoreSigningAlgorithm( + const std::string& named_curve); + } // namespace keystore_service_util } // namespace crosapi
diff --git a/chromeos/crosapi/mojom/local_printer.mojom b/chromeos/crosapi/mojom/local_printer.mojom index 43db151..3918303 100644 --- a/chromeos/crosapi/mojom/local_printer.mojom +++ b/chromeos/crosapi/mojom/local_printer.mojom
@@ -275,4 +275,10 @@ // Gets print policies. GetPolicies@9() => (Policies policies); + + // Checks if |kPrintingSendUsernameAndFilenameEnabled| is enabled for the + // current Ash profile. Returns the profile's corresponding username if pref + // enabled. + [MinVersion=1] + IsSendUsernameFilenameEnabled@10() => (string? username); };
diff --git a/chromeos/dbus/audio/cras_audio_client.h b/chromeos/dbus/audio/cras_audio_client.h index 8c46d765..9623b8ea 100644 --- a/chromeos/dbus/audio/cras_audio_client.h +++ b/chromeos/dbus/audio/cras_audio_client.h
@@ -15,7 +15,6 @@ #include "base/component_export.h" #include "base/containers/flat_map.h" #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/dbus/audio/audio_node.h" #include "chromeos/dbus/audio/volume_state.h" #include "chromeos/dbus/dbus_method_call_status.h"
diff --git a/chromeos/dbus/audio/fake_cras_audio_client.h b/chromeos/dbus/audio/fake_cras_audio_client.h index ef97a38..02c3825d 100644 --- a/chromeos/dbus/audio/fake_cras_audio_client.h +++ b/chromeos/dbus/audio/fake_cras_audio_client.h
@@ -11,6 +11,7 @@ #include "base/component_export.h" #include "base/macros.h" +#include "base/observer_list.h" #include "chromeos/dbus/audio/cras_audio_client.h" namespace chromeos {
diff --git a/chromeos/dbus/biod/biod_client.h b/chromeos/dbus/biod/biod_client.h index 37c94928..8f2ec070 100644 --- a/chromeos/dbus/biod/biod_client.h +++ b/chromeos/dbus/biod/biod_client.h
@@ -12,7 +12,6 @@ #include "base/callback.h" #include "base/component_export.h" #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/dbus/biod/constants.pb.h" #include "chromeos/dbus/dbus_method_call_status.h" #include "third_party/cros_system_api/dbus/service_constants.h"
diff --git a/chromeos/dbus/chunneld_client.h b/chromeos/dbus/chunneld_client.h index 210f019..4fd1b62d 100644 --- a/chromeos/dbus/chunneld_client.h +++ b/chromeos/dbus/chunneld_client.h
@@ -6,7 +6,7 @@ #define CHROMEOS_DBUS_CHUNNELD_CLIENT_H_ #include "base/component_export.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "chromeos/dbus/chunneld/chunneld_service.pb.h" #include "chromeos/dbus/dbus_client.h" #include "chromeos/dbus/dbus_method_call_status.h"
diff --git a/chromeos/dbus/cicerone/cicerone_client.h b/chromeos/dbus/cicerone/cicerone_client.h index bf7cedb0..3752525 100644 --- a/chromeos/dbus/cicerone/cicerone_client.h +++ b/chromeos/dbus/cicerone/cicerone_client.h
@@ -6,7 +6,6 @@ #define CHROMEOS_DBUS_CICERONE_CICERONE_CLIENT_H_ #include "base/component_export.h" -#include "base/observer_list.h" #include "chromeos/dbus/cicerone/cicerone_service.pb.h" #include "chromeos/dbus/dbus_client.h" #include "chromeos/dbus/dbus_method_call_status.h"
diff --git a/chromeos/dbus/dlcservice/dlcservice_client.h b/chromeos/dbus/dlcservice/dlcservice_client.h index e1765f56..d97ce3b 100644 --- a/chromeos/dbus/dlcservice/dlcservice_client.h +++ b/chromeos/dbus/dlcservice/dlcservice_client.h
@@ -13,7 +13,6 @@ #include "base/callback.h" #include "base/component_export.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "chromeos/dbus/dbus_client.h" #include "chromeos/dbus/dbus_client_implementation_type.h"
diff --git a/chromeos/dbus/dlcservice/fake_dlcservice_client.h b/chromeos/dbus/dlcservice/fake_dlcservice_client.h index 2dcba28..336418c 100644 --- a/chromeos/dbus/dlcservice/fake_dlcservice_client.h +++ b/chromeos/dbus/dlcservice/fake_dlcservice_client.h
@@ -9,6 +9,7 @@ #include "base/component_export.h" #include "base/containers/queue.h" +#include "base/observer_list.h" #include "chromeos/dbus/dlcservice/dlcservice_client.h" namespace chromeos {
diff --git a/chromeos/dbus/fake_runtime_probe_client.h b/chromeos/dbus/fake_runtime_probe_client.h index ecfb7b9..4a9005c 100644 --- a/chromeos/dbus/fake_runtime_probe_client.h +++ b/chromeos/dbus/fake_runtime_probe_client.h
@@ -7,7 +7,6 @@ #include "base/component_export.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "chromeos/dbus/runtime_probe_client.h" namespace chromeos {
diff --git a/chromeos/dbus/fake_update_engine_client.h b/chromeos/dbus/fake_update_engine_client.h index 132b52f..483d6bb 100644 --- a/chromeos/dbus/fake_update_engine_client.h +++ b/chromeos/dbus/fake_update_engine_client.h
@@ -9,6 +9,7 @@ #include "base/component_export.h" #include "base/containers/queue.h" +#include "base/observer_list.h" #include "chromeos/dbus/update_engine_client.h" namespace chromeos {
diff --git a/chromeos/dbus/seneschal/seneschal_client.h b/chromeos/dbus/seneschal/seneschal_client.h index f14f55f..3861e0f 100644 --- a/chromeos/dbus/seneschal/seneschal_client.h +++ b/chromeos/dbus/seneschal/seneschal_client.h
@@ -6,7 +6,7 @@ #define CHROMEOS_DBUS_SENESCHAL_SENESCHAL_CLIENT_H_ #include "base/component_export.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "chromeos/dbus/dbus_client.h" #include "chromeos/dbus/dbus_method_call_status.h" #include "chromeos/dbus/seneschal/seneschal_service.pb.h"
diff --git a/chromeos/dbus/update_engine_client.h b/chromeos/dbus/update_engine_client.h index 564c3e5..1ff9be3 100644 --- a/chromeos/dbus/update_engine_client.h +++ b/chromeos/dbus/update_engine_client.h
@@ -12,7 +12,6 @@ #include "base/callback.h" #include "base/component_export.h" #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/dbus/dbus_client.h" #include "chromeos/dbus/dbus_client_implementation_type.h" #include "chromeos/dbus/update_engine/update_engine.pb.h"
diff --git a/chromeos/network/managed_network_configuration_handler.h b/chromeos/network/managed_network_configuration_handler.h index 36dd3e27..5f55d73 100644 --- a/chromeos/network/managed_network_configuration_handler.h +++ b/chromeos/network/managed_network_configuration_handler.h
@@ -13,7 +13,6 @@ #include "base/compiler_specific.h" #include "base/component_export.h" #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_handler_callbacks.h" #include "components/onc/onc_constants.h"
diff --git a/chromeos/network/managed_network_configuration_handler_impl.h b/chromeos/network/managed_network_configuration_handler_impl.h index b4e0de6..7c28a41 100644 --- a/chromeos/network/managed_network_configuration_handler_impl.h +++ b/chromeos/network/managed_network_configuration_handler_impl.h
@@ -14,6 +14,7 @@ #include "base/component_export.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/observer_list.h" #include "chromeos/network/managed_network_configuration_handler.h" #include "chromeos/network/network_handler_callbacks.h" #include "chromeos/network/network_profile_observer.h"
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt index e7adc8f..9e0bf8a 100644 --- a/chromeos/profiles/orderfile.newest.txt +++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@ -chromeos-chrome-orderfile-field-92-4515.9-1622461123-benchmark-92.0.4515.44-r1.orderfile.xz +chromeos-chrome-orderfile-field-92-4515.9-1622461123-benchmark-92.0.4515.45-r1.orderfile.xz
diff --git a/chromeos/services/cellular_setup/ota_activator_impl.cc b/chromeos/services/cellular_setup/ota_activator_impl.cc index 40a22602..3056d5d 100644 --- a/chromeos/services/cellular_setup/ota_activator_impl.cc +++ b/chromeos/services/cellular_setup/ota_activator_impl.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" #include "chromeos/dbus/shill/shill_device_client.h" #include "chromeos/network/cellular_utils.h" #include "chromeos/network/device_state.h" @@ -201,6 +202,8 @@ network_state_handler_ = nullptr; NET_LOG(EVENT) << "Finished attempt with result " << activation_result << "."; + base::UmaHistogramEnumeration("Network.Cellular.PSim.OtaActivationResult", + activation_result); if (activation_delegate_) activation_delegate_->OnActivationFinished(activation_result);
diff --git a/chromeos/services/cellular_setup/ota_activator_impl_unittest.cc b/chromeos/services/cellular_setup/ota_activator_impl_unittest.cc index 4f5bf0a..980cd8f0 100644 --- a/chromeos/services/cellular_setup/ota_activator_impl_unittest.cc +++ b/chromeos/services/cellular_setup/ota_activator_impl_unittest.cc
@@ -8,6 +8,7 @@ #include <utility> #include "base/run_loop.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "base/test/test_simple_task_runner.h" #include "chromeos/network/fake_network_activation_handler.h" @@ -236,6 +237,10 @@ ASSERT_EQ(1u, activation_results.size()); EXPECT_EQ(activation_result, activation_results[0]); + histogram_tester_.ExpectBucketCount( + "Network.Cellular.PSim.OtaActivationResult", activation_result, + /*expected_count=*/1); + EXPECT_TRUE(is_finished_); } @@ -270,6 +275,7 @@ base::test::TaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; NetworkStateTestHelper test_helper_; + base::HistogramTester histogram_tester_; std::unique_ptr<FakeActivationDelegate> fake_activation_delegate_; std::unique_ptr<FakeNetworkConnectionHandler>
diff --git a/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom b/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom index cbfebb6..0bd49817 100644 --- a/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom +++ b/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom
@@ -23,18 +23,20 @@ kPortalLoadedAndUserCompletedPayment, }; -// Potential results for an activation attempt. +// Potential results for an activation attempt. These values are persisted to +// logs. Entries should not be renumbered and numeric values should never be +// reused. enum ActivationResult { // Activation was initiated successfully by the attempt. Note that the device // may not be fully activated by the time this result occurs since the process // completes in the background. - kSuccessfullyStartedActivation, + kSuccessfullyStartedActivation = 0, // Activation was unnecessary because the SIM is already activated. - kAlreadyActivated, + kAlreadyActivated = 1, // Activation failed (e.g., due to a failure within Shill). - kFailedToActivate, + kFailedToActivate = 2, }; // Metadata corresponding to a cellular activation request which allows the
diff --git a/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h b/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h index 8c4cfd82..51a8f99 100644 --- a/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h +++ b/chromeos/services/device_sync/cryptauth_enrollment_manager_impl.h
@@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/time/time.h" #include "chromeos/services/device_sync/cryptauth_enrollment_manager.h" #include "chromeos/services/device_sync/cryptauth_feature_type.h"
diff --git a/chromeos/services/libassistant/audio/audio_input_impl.h b/chromeos/services/libassistant/audio/audio_input_impl.h index e8bc77a..9cc1d05 100644 --- a/chromeos/services/libassistant/audio/audio_input_impl.h +++ b/chromeos/services/libassistant/audio/audio_input_impl.h
@@ -10,7 +10,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "base/sequence_checker.h" #include "base/synchronization/lock.h" #include "chromeos/services/assistant/public/cpp/assistant_service.h"
diff --git a/chromeos/services/multidevice_setup/wifi_sync_feature_manager.h b/chromeos/services/multidevice_setup/wifi_sync_feature_manager.h index 8a235ef..5982363 100644 --- a/chromeos/services/multidevice_setup/wifi_sync_feature_manager.h +++ b/chromeos/services/multidevice_setup/wifi_sync_feature_manager.h
@@ -6,7 +6,6 @@ #define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_WIFI_SYNC_FEATURE_MANAGER_H_ #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/services/multidevice_setup/host_status_provider.h" #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chromeos/services/secure_channel/connection_attempt_base.h b/chromeos/services/secure_channel/connection_attempt_base.h index d89c73c..b669196 100644 --- a/chromeos/services/secure_channel/connection_attempt_base.h +++ b/chromeos/services/secure_channel/connection_attempt_base.h
@@ -11,7 +11,6 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/time/default_clock.h" #include "chromeos/components/multidevice/logging/logging.h" #include "chromeos/services/secure_channel/authenticated_channel.h"
diff --git a/chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h b/chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h index 62d46d4f..8d9da907 100644 --- a/chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h +++ b/chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h
@@ -8,7 +8,6 @@ #include <string> #include "base/macros.h" -#include "base/observer_list.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/services/secure_channel/public/cpp/shared/connection_medium.h" #include "chromeos/services/secure_channel/public/cpp/shared/connection_priority.h"
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni index fe0360d..a312a3b 100644 --- a/chromeos/tast_control.gni +++ b/chromeos/tast_control.gni
@@ -73,4 +73,7 @@ # crbug.com/1212689 "policy.AllowWakeLocks", + + # crbug.com/1186991 + "launcher.SearchBuiltInApps", ]
diff --git a/chromeos/tpm/tpm_token_loader.h b/chromeos/tpm/tpm_token_loader.h index 4559a937..005c4eb 100644 --- a/chromeos/tpm/tpm_token_loader.h +++ b/chromeos/tpm/tpm_token_loader.h
@@ -14,7 +14,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/threading/thread_checker.h" #include "chromeos/dbus/userdataauth/userdataauth_client.h" #include "chromeos/login/login_state/login_state.h"
diff --git a/components/BUILD.gn b/components/BUILD.gn index e0be7ab..18017146 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -242,7 +242,6 @@ } else { # !is_ios deps += [ "//components/accuracy_tips:unit_tests", - "//components/android_autofill/browser:unit_tests", "//components/autofill/content/browser:unit_tests", "//components/autofill/content/renderer:unit_tests", "//components/autofill/core/common/mojom:unit_tests", @@ -315,7 +314,6 @@ "//components/safe_browsing/core/browser:token_fetcher_unit_tests", "//components/safe_browsing/core/common:unit_tests", "//components/safe_browsing/core/realtime:unit_tests", - "//components/safe_browsing/core/triggers:unit_tests", "//components/safety_check:unit_tests", "//components/security_interstitials/content:unit_tests", "//components/security_state/content:unit_tests", @@ -378,6 +376,7 @@ if (is_android) { deps += [ "//base:base_java_unittest_support", + "//components/android_autofill/browser:unit_tests", "//components/autofill_assistant/browser:unit_tests", "//components/browser_ui/sms/android:unit_tests", "//components/cdm/browser:unit_tests", @@ -842,7 +841,7 @@ if (is_android) { junit_binary("components_junit_tests") { deps = [ - "//components/android_autofill/android/junit:components_autofill_junit_tests", + "//components/android_autofill/browser/junit:components_autofill_junit_tests", "//components/background_task_scheduler:components_background_task_scheduler_junit_tests", "//components/browser_ui/bottomsheet/android/internal:junit_tests", "//components/browser_ui/client_certificate/android:junit",
diff --git a/components/account_manager_core/account_manager_facade_impl_unittest.cc b/components/account_manager_core/account_manager_facade_impl_unittest.cc index dac4499..76dcfc46 100644 --- a/components/account_manager_core/account_manager_facade_impl_unittest.cc +++ b/components/account_manager_core/account_manager_facade_impl_unittest.cc
@@ -107,6 +107,10 @@ OnGetTokenFailure, (const GoogleServiceAuthError& error), (override)); + + std::string GetConsumerName() const override { + return "account_manager_facade_impl_unittest"; + } }; class FakeAccountManager : public crosapi::mojom::AccountManager {
diff --git a/components/android_autofill/DEPS b/components/android_autofill/DEPS index 6a6f159..a0d14e6b 100644 --- a/components/android_autofill/DEPS +++ b/components/android_autofill/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+components/autofill", + "+content/public/android", "+content/public/browser", "+ui", ]
diff --git a/components/android_autofill/android/BUILD.gn b/components/android_autofill/android/BUILD.gn deleted file mode 100644 index 8c8016c..0000000 --- a/components/android_autofill/android/BUILD.gn +++ /dev/null
@@ -1,64 +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("//build/config/android/rules.gni") -import("//build/config/locales.gni") - -android_aidl("autofill_aidl") { - import_include = [ "java/src" ] - sources = [ - "java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl", - "java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl", - "java/src/org/chromium/components/autofill_public/ViewType.aidl", - ] -} - -android_library("java") { - srcjar_deps = [ ":autofill_aidl" ] - deps = [ - "//base:base_java", - "//components/autofill/android:autofill_java", - "//components/autofill/core/common/mojom:mojo_types_java", - "//components/version_info/android:version_constants_java", - "//content/public/android:content_java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//ui/android:ui_no_recycler_view_java", - ] - annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] - sources = [ - "java/src/org/chromium/components/autofill/AutofillActionModeCallback.java", - "java/src/org/chromium/components/autofill/AutofillHintsService.java", - "java/src/org/chromium/components/autofill/AutofillManagerWrapper.java", - "java/src/org/chromium/components/autofill/AutofillProvider.java", - "java/src/org/chromium/components/autofill/AutofillProviderUMA.java", - "java/src/org/chromium/components/autofill/FormData.java", - "java/src/org/chromium/components/autofill/FormFieldData.java", - "java/src/org/chromium/components/autofill_public/ViewType.java", - ] -} - -generate_jni("jni_headers") { - sources = [ - "java/src/org/chromium/components/autofill/AutofillProvider.java", - "java/src/org/chromium/components/autofill/FormData.java", - "java/src/org/chromium/components/autofill/FormFieldData.java", - ] -} - -static_library("android") { - sources = [ - "autofill_provider_android.cc", - "autofill_provider_android.h", - "form_data_android.cc", - "form_data_android.h", - "form_field_data_android.cc", - "form_field_data_android.h", - ] - public_deps = [ "//components/android_autofill/browser" ] - deps = [ - ":jni_headers", - "//content/public/browser", - "//ui/android", - ] -}
diff --git a/components/android_autofill/android/DEPS b/components/android_autofill/android/DEPS deleted file mode 100644 index fd3f4c7..0000000 --- a/components/android_autofill/android/DEPS +++ /dev/null
@@ -1,5 +0,0 @@ -include_rules = [ - "+content/public/android", - "+components/autofill/content", - "+ui/android", -]
diff --git a/components/android_autofill/browser/BUILD.gn b/components/android_autofill/browser/BUILD.gn index 560d173..464e2202 100644 --- a/components/android_autofill/browser/BUILD.gn +++ b/components/android_autofill/browser/BUILD.gn
@@ -2,6 +2,67 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/android/rules.gni") +import("//build/config/locales.gni") + +android_aidl("autofill_aidl") { + import_include = [ "java/src" ] + sources = [ + "java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl", + "java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl", + "java/src/org/chromium/components/autofill_public/ViewType.aidl", + ] +} + +android_library("java") { + srcjar_deps = [ ":autofill_aidl" ] + deps = [ + "//base:base_java", + "//components/autofill/android:autofill_java", + "//components/autofill/core/common/mojom:mojo_types_java", + "//components/version_info/android:version_constants_java", + "//content/public/android:content_java", + "//third_party/androidx:androidx_annotation_annotation_java", + "//ui/android:ui_no_recycler_view_java", + ] + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] + sources = [ + "java/src/org/chromium/components/autofill/AutofillActionModeCallback.java", + "java/src/org/chromium/components/autofill/AutofillHintsService.java", + "java/src/org/chromium/components/autofill/AutofillManagerWrapper.java", + "java/src/org/chromium/components/autofill/AutofillProvider.java", + "java/src/org/chromium/components/autofill/AutofillProviderUMA.java", + "java/src/org/chromium/components/autofill/FormData.java", + "java/src/org/chromium/components/autofill/FormFieldData.java", + "java/src/org/chromium/components/autofill_public/ViewType.java", + ] +} + +generate_jni("jni_headers") { + sources = [ + "java/src/org/chromium/components/autofill/AutofillProvider.java", + "java/src/org/chromium/components/autofill/FormData.java", + "java/src/org/chromium/components/autofill/FormFieldData.java", + ] +} + +static_library("android") { + sources = [ + "autofill_provider_android.cc", + "autofill_provider_android.h", + "form_data_android.cc", + "form_data_android.h", + "form_field_data_android.cc", + "form_field_data_android.h", + ] + public_deps = [ ":browser" ] + deps = [ + ":jni_headers", + "//content/public/browser", + "//ui/android", + ] +} + static_library("browser") { sources = [ "android_autofill_manager.cc",
diff --git a/components/android_autofill/android/autofill_provider_android.cc b/components/android_autofill/browser/autofill_provider_android.cc similarity index 98% rename from components/android_autofill/android/autofill_provider_android.cc rename to components/android_autofill/browser/autofill_provider_android.cc index f38a27a..0aba4ccc 100644 --- a/components/android_autofill/android/autofill_provider_android.cc +++ b/components/android_autofill/browser/autofill_provider_android.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/android_autofill/android/autofill_provider_android.h" +#include "components/android_autofill/browser/autofill_provider_android.h" #include <memory> @@ -10,9 +10,9 @@ #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/feature_list.h" -#include "components/android_autofill/android/form_data_android.h" -#include "components/android_autofill/android/jni_headers/AutofillProvider_jni.h" #include "components/android_autofill/browser/android_autofill_manager.h" +#include "components/android_autofill/browser/form_data_android.h" +#include "components/android_autofill/browser/jni_headers/AutofillProvider_jni.h" #include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h"
diff --git a/components/android_autofill/android/autofill_provider_android.h b/components/android_autofill/browser/autofill_provider_android.h similarity index 94% rename from components/android_autofill/android/autofill_provider_android.h rename to components/android_autofill/browser/autofill_provider_android.h index 64af979..9758f97 100644 --- a/components/android_autofill/android/autofill_provider_android.h +++ b/components/android_autofill/browser/autofill_provider_android.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_ANDROID_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_ -#define COMPONENTS_ANDROID_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_ +#ifndef COMPONENTS_ANDROID_AUTOFILL_BROWSER_AUTOFILL_PROVIDER_ANDROID_H_ +#define COMPONENTS_ANDROID_AUTOFILL_BROWSER_AUTOFILL_PROVIDER_ANDROID_H_ #include "base/android/jni_weak_ref.h" #include "base/memory/weak_ptr.h" @@ -33,6 +33,9 @@ ~AutofillProviderAndroid() override; + AutofillProviderAndroid(const AutofillProviderAndroid&) = delete; + AutofillProviderAndroid& operator=(const AutofillProviderAndroid&) = delete; + // Attach this detached object to |jcaller|. void AttachToJavaAutofillProvider( JNIEnv* env, @@ -135,9 +138,7 @@ bool check_submission_; // Valid only if check_submission_ is true. mojom::SubmissionSource pending_submission_source_; - - DISALLOW_COPY_AND_ASSIGN(AutofillProviderAndroid); }; } // namespace autofill -#endif // COMPONENTS_ANDROID_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_ +#endif // COMPONENTS_ANDROID_AUTOFILL_BROWSER_AUTOFILL_PROVIDER_ANDROID_H_
diff --git a/components/android_autofill/android/form_data_android.cc b/components/android_autofill/browser/form_data_android.cc similarity index 95% rename from components/android_autofill/android/form_data_android.cc rename to components/android_autofill/browser/form_data_android.cc index e848e45..71beba4 100644 --- a/components/android_autofill/android/form_data_android.cc +++ b/components/android_autofill/browser/form_data_android.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/android_autofill/android/form_data_android.h" +#include "components/android_autofill/browser/form_data_android.h" #include <memory> #include "base/android/jni_string.h" -#include "components/android_autofill/android/form_field_data_android.h" -#include "components/android_autofill/android/jni_headers/FormData_jni.h" +#include "components/android_autofill/browser/form_field_data_android.h" +#include "components/android_autofill/browser/jni_headers/FormData_jni.h" #include "components/autofill/core/browser/form_structure.h" using base::android::AttachCurrentThread;
diff --git a/components/android_autofill/android/form_data_android.h b/components/android_autofill/browser/form_data_android.h similarity index 89% rename from components/android_autofill/android/form_data_android.h rename to components/android_autofill/browser/form_data_android.h index 454d7dc..8457f9e 100644 --- a/components/android_autofill/android/form_data_android.h +++ b/components/android_autofill/browser/form_data_android.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_ANDROID_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_ -#define COMPONENTS_ANDROID_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_ +#ifndef COMPONENTS_ANDROID_AUTOFILL_BROWSER_FORM_DATA_ANDROID_H_ +#define COMPONENTS_ANDROID_AUTOFILL_BROWSER_FORM_DATA_ANDROID_H_ #include "base/android/jni_weak_ref.h" #include "base/android/scoped_java_ref.h" @@ -25,6 +25,9 @@ base::RepeatingCallback<gfx::RectF(const gfx::RectF&)>; FormDataAndroid(const FormData& form, const TransformCallback& callback); + FormDataAndroid(const FormDataAndroid&) = delete; + FormDataAndroid& operator=(const FormDataAndroid&) = delete; + virtual ~FormDataAndroid(); base::android::ScopedJavaLocalRef<jobject> GetJavaPeer( @@ -65,10 +68,8 @@ JavaObjectWeakGlobalRef java_ref_; // keep track of index when popping up fields to Java. size_t index_; - - DISALLOW_COPY_AND_ASSIGN(FormDataAndroid); }; } // namespace autofill -#endif // COMPONENTS_ANDROID_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_ +#endif // COMPONENTS_ANDROID_AUTOFILL_BROWSER_FORM_DATA_ANDROID_H_
diff --git a/components/android_autofill/android/form_field_data_android.cc b/components/android_autofill/browser/form_field_data_android.cc similarity index 97% rename from components/android_autofill/android/form_field_data_android.cc rename to components/android_autofill/browser/form_field_data_android.cc index 6ba4a6b40..71d44fd 100644 --- a/components/android_autofill/android/form_field_data_android.cc +++ b/components/android_autofill/browser/form_field_data_android.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/android_autofill/android/form_field_data_android.h" +#include "components/android_autofill/browser/form_field_data_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" -#include "components/android_autofill/android/jni_headers/FormFieldData_jni.h" +#include "components/android_autofill/browser/jni_headers/FormFieldData_jni.h" #include "components/autofill/core/common/autofill_util.h" using base::android::AttachCurrentThread;
diff --git a/components/android_autofill/android/form_field_data_android.h b/components/android_autofill/browser/form_field_data_android.h similarity index 80% rename from components/android_autofill/android/form_field_data_android.h rename to components/android_autofill/browser/form_field_data_android.h index de132fe..9ebd9888 100644 --- a/components/android_autofill/android/form_field_data_android.h +++ b/components/android_autofill/browser/form_field_data_android.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_ANDROID_AUTOFILL_ANDROID_FORM_FIELD_DATA_ANDROID_H_ -#define COMPONENTS_ANDROID_AUTOFILL_ANDROID_FORM_FIELD_DATA_ANDROID_H_ +#ifndef COMPONENTS_ANDROID_AUTOFILL_BROWSER_FORM_FIELD_DATA_ANDROID_H_ +#define COMPONENTS_ANDROID_AUTOFILL_BROWSER_FORM_FIELD_DATA_ANDROID_H_ #include "base/android/jni_weak_ref.h" #include "base/android/scoped_java_ref.h" @@ -17,6 +17,9 @@ class FormFieldDataAndroid { public: explicit FormFieldDataAndroid(FormFieldData* field); + FormFieldDataAndroid(const FormFieldDataAndroid&) = delete; + FormFieldDataAndroid& operator=(const FormFieldDataAndroid&) = delete; + virtual ~FormFieldDataAndroid(); base::android::ScopedJavaLocalRef<jobject> GetJavaPeer(); @@ -37,10 +40,8 @@ // Not owned. FormFieldData* field_ptr_; JavaObjectWeakGlobalRef java_ref_; - - DISALLOW_COPY_AND_ASSIGN(FormFieldDataAndroid); }; } // namespace autofill -#endif // COMPONENTS_ANDROID_AUTOFILL_ANDROID_FORM_FIELD_DATA_ANDROID_H_ +#endif // COMPONENTS_ANDROID_AUTOFILL_BROWSER_FORM_FIELD_DATA_ANDROID_H_
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java rename to components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillActionModeCallback.java
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillHintsService.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillHintsService.java similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillHintsService.java rename to components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillHintsService.java
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java rename to components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java rename to components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillProviderUMA.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProviderUMA.java similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill/AutofillProviderUMA.java rename to components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProviderUMA.java
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill/FormData.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/FormData.java similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill/FormData.java rename to components/android_autofill/browser/java/src/org/chromium/components/autofill/FormData.java
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill/FormFieldData.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/FormFieldData.java similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill/FormFieldData.java rename to components/android_autofill/browser/java/src/org/chromium/components/autofill/FormFieldData.java
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl b/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl rename to components/android_autofill/browser/java/src/org/chromium/components/autofill_public/IAutofillHintsService.aidl
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl b/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl rename to components/android_autofill/browser/java/src/org/chromium/components/autofill_public/IViewTypeCallback.aidl
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill_public/OWNERS b/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/OWNERS similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill_public/OWNERS rename to components/android_autofill/browser/java/src/org/chromium/components/autofill_public/OWNERS
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill_public/README.md b/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/README.md similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill_public/README.md rename to components/android_autofill/browser/java/src/org/chromium/components/autofill_public/README.md
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill_public/ViewType.aidl b/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.aidl similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill_public/ViewType.aidl rename to components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.aidl
diff --git a/components/android_autofill/android/java/src/org/chromium/components/autofill_public/ViewType.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.java similarity index 100% rename from components/android_autofill/android/java/src/org/chromium/components/autofill_public/ViewType.java rename to components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.java
diff --git a/components/android_autofill/android/junit/BUILD.gn b/components/android_autofill/browser/junit/BUILD.gn similarity index 93% rename from components/android_autofill/android/junit/BUILD.gn rename to components/android_autofill/browser/junit/BUILD.gn index f8bdffe..a063958 100644 --- a/components/android_autofill/android/junit/BUILD.gn +++ b/components/android_autofill/browser/junit/BUILD.gn
@@ -13,7 +13,7 @@ deps = [ "//base:base_java_test_support", "//base:base_junit_test_support", - "//components/android_autofill/android:java", + "//components/android_autofill/browser:java", "//content/public/android:content_java", "//third_party/android_deps:robolectric_all_java", "//third_party/junit",
diff --git a/components/android_autofill/android/junit/src/org/chromium/components/autofill/AutofillProviderTest.java b/components/android_autofill/browser/junit/src/org/chromium/components/autofill/AutofillProviderTest.java similarity index 100% rename from components/android_autofill/android/junit/src/org/chromium/components/autofill/AutofillProviderTest.java rename to components/android_autofill/browser/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
diff --git a/components/android_autofill/android/test_support/BUILD.gn b/components/android_autofill/browser/test_support/BUILD.gn similarity index 87% rename from components/android_autofill/android/test_support/BUILD.gn rename to components/android_autofill/browser/test_support/BUILD.gn index ad2c5c2..06a8953 100644 --- a/components/android_autofill/android/test_support/BUILD.gn +++ b/components/android_autofill/browser/test_support/BUILD.gn
@@ -17,8 +17,8 @@ "//base:base_java", "//base:base_java_test_support", "//base:jni_java", - "//components/android_autofill/android:autofill_aidl", - "//components/android_autofill/android:java", + "//components/android_autofill/browser:autofill_aidl", + "//components/android_autofill/browser:java", "//content/public/android:content_java", "//third_party/androidx:androidx_annotation_annotation_java", ] @@ -34,7 +34,7 @@ deps = [ ":jni_headers", "//base", - "//components/android_autofill/android", + "//components/android_autofill/browser:android", "//components/autofill/core/browser:test_support", "//content/public/browser", ]
diff --git a/components/android_autofill/android/test_support/autofill_provider_test_helper.cc b/components/android_autofill/browser/test_support/autofill_provider_test_helper.cc similarity index 98% rename from components/android_autofill/android/test_support/autofill_provider_test_helper.cc rename to components/android_autofill/browser/test_support/autofill_provider_test_helper.cc index 3416231..a0d13ea 100644 --- a/components/android_autofill/android/test_support/autofill_provider_test_helper.cc +++ b/components/android_autofill/browser/test_support/autofill_provider_test_helper.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/android_autofill/android/test_support/jni_headers/AutofillProviderTestHelper_jni.h" +#include "components/android_autofill/browser/test_support/jni_headers/AutofillProviderTestHelper_jni.h" #include <string>
diff --git a/components/android_autofill/android/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java b/components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java similarity index 100% rename from components/android_autofill/android/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java rename to components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java
diff --git a/components/android_autofill/android/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java b/components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java similarity index 100% rename from components/android_autofill/android/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java rename to components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn index 8eae419b..d57af0d 100644 --- a/components/arc/BUILD.gn +++ b/components/arc/BUILD.gn
@@ -406,6 +406,7 @@ ] deps = [ + "//ash/constants", "//base", "//components/arc/enterprise", "//components/keyed_service/content",
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc index f8edede..70481207 100644 --- a/components/arc/arc_util.cc +++ b/components/arc/arc_util.cc
@@ -250,11 +250,6 @@ chromeos::switches::kArcForceShowOptInUi); } -void SetArcAlwaysStartWithoutPlayStoreForTesting() { - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - chromeos::switches::kArcStartMode, kAlwaysStartWithNoPlayStore); -} - bool IsArcKioskAvailable() { const auto* command_line = base::CommandLine::ForCurrentProcess(); @@ -274,11 +269,6 @@ return IsArcAvailable(); } -void SetArcAvailableCommandLineForTesting(base::CommandLine* command_line) { - command_line->AppendSwitchASCII(chromeos::switches::kArcAvailability, - kAvailabilityOfficiallySupported); -} - bool IsArcKioskMode() { return user_manager::UserManager::IsInitialized() && user_manager::UserManager::Get()->IsLoggedInAsArcKioskApp();
diff --git a/components/arc/arc_util.h b/components/arc/arc_util.h index 79937bd..b55d23fd 100644 --- a/components/arc/arc_util.h +++ b/components/arc/arc_util.h
@@ -20,7 +20,6 @@ } // namespace aura namespace base { -class CommandLine; struct SystemMemoryInfoKB; } // namespace base @@ -122,10 +121,6 @@ // Returns true if ARC OptIn ui needs to be shown for testing. bool ShouldShowOptInForTesting(); -// Enables to always start ARC without Play Store for testing, by appending the -// command line flag. -void SetArcAlwaysStartWithoutPlayStoreForTesting(); - // Returns true if ARC is installed and running ARC kiosk apps on the current // device is officially supported. // It doesn't follow that ARC is available for user sessions and @@ -137,13 +132,6 @@ // Kiosk mode, it checks only ARC Kiosk availability. bool IsArcKioskAvailable(); -// For testing ARC in browser tests, this function should be called in -// SetUpCommandLine(), and its argument should be passed to this function. -// Also, in unittests, this can be called in SetUp() with -// base::CommandLine::ForCurrentProcess(). -// |command_line| must not be nullptr. -void SetArcAvailableCommandLineForTesting(base::CommandLine* command_line); - // Returns true if ARC should run under Kiosk mode for the current profile. // As it can return true only when user is already initialized, it implies // that ARC availability was checked before and IsArcKioskAvailable()
diff --git a/components/arc/compat_mode/arc_splash_screen_dialog_view.cc b/components/arc/compat_mode/arc_splash_screen_dialog_view.cc index f890d46..8da291a5 100644 --- a/components/arc/compat_mode/arc_splash_screen_dialog_view.cc +++ b/components/arc/compat_mode/arc_splash_screen_dialog_view.cc
@@ -14,6 +14,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/bubble/bubble_border.h" @@ -51,7 +52,8 @@ close_button.get(), vector_icons::kCloseRoundedIcon, GetContentLayerColor(ContentLayerType::kIconColorPrimary)); close_button->SetSize(kCloseButtonSize); - close_button->ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(close_button.get()) + ->SetMode(views::InkDropHost::InkDropMode::OFF); close_button->SetAccessibleName( l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); close_button->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_CLOSE));
diff --git a/components/arc/enterprise/snapshot_session_controller.h b/components/arc/enterprise/snapshot_session_controller.h index 7bd8d618..ea47d21 100644 --- a/components/arc/enterprise/snapshot_session_controller.h +++ b/components/arc/enterprise/snapshot_session_controller.h
@@ -6,7 +6,7 @@ #define COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_SESSION_CONTROLLER_H_ #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "base/timer/timer.h" #include "components/arc/enterprise/arc_apps_tracker.h" #include "components/session_manager/core/session_manager_observer.h"
diff --git a/components/arc/session/connection_holder.h b/components/arc/session/connection_holder.h index 19f33fe..32c81fc 100644 --- a/components/arc/session/connection_holder.h +++ b/components/arc/session/connection_holder.h
@@ -12,7 +12,6 @@ #include "base/bind.h" #include "base/logging.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/threading/thread_checker.h" #include "components/arc/session/connection_notifier.h" #include "components/arc/session/connection_observer.h"
diff --git a/components/arc/test/arc_util_test_support.cc b/components/arc/test/arc_util_test_support.cc index 0781626..47a6dd6d 100644 --- a/components/arc/test/arc_util_test_support.cc +++ b/components/arc/test/arc_util_test_support.cc
@@ -4,6 +4,8 @@ #include "components/arc/test/arc_util_test_support.h" +#include "ash/constants/ash_switches.h" +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/path_service.h" @@ -12,6 +14,24 @@ namespace arc { +namespace { + +constexpr char kAvailabilityOfficiallySupported[] = "officially-supported"; +constexpr char kAlwaysStartWithNoPlayStore[] = + "always-start-with-no-play-store"; + +} // namespace + +void SetArcAlwaysStartWithoutPlayStoreForTesting() { + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + chromeos::switches::kArcStartMode, kAlwaysStartWithNoPlayStore); +} + +void SetArcAvailableCommandLineForTesting(base::CommandLine* command_line) { + command_line->AppendSwitchASCII(chromeos::switches::kArcAvailability, + kAvailabilityOfficiallySupported); +} + bool GetSystemMemoryInfoForTesting(const std::string& file_name, base::SystemMemoryInfoKB* mem_info) { base::FilePath base_path;
diff --git a/components/arc/test/arc_util_test_support.h b/components/arc/test/arc_util_test_support.h index fabfe8a..aa9ec338 100644 --- a/components/arc/test/arc_util_test_support.h +++ b/components/arc/test/arc_util_test_support.h
@@ -8,15 +8,22 @@ #include <string> namespace base { +class CommandLine; struct SystemMemoryInfoKB; } // namespace base namespace arc { -// TODO: Refactor following test functions from arc_util.h/.cc as well. -// - ShouldShowOptInForTesting -// - SetArcAlwaysStartWithoutPlayStoreForTesting -// - SetArcAvailableCommandLineForTesting +// Enables to always start ARC without Play Store for testing, by appending the +// command line flag. +void SetArcAlwaysStartWithoutPlayStoreForTesting(); + +// For testing ARC in browser tests, this function should be called in +// SetUpCommandLine(), and its argument should be passed to this function. +// Also, in unittests, this can be called in SetUp() with +// base::CommandLine::ForCurrentProcess(). +// |command_line| must not be nullptr. +void SetArcAvailableCommandLineForTesting(base::CommandLine* command_line); // Gets a system memory profile based on file name. bool GetSystemMemoryInfoForTesting(const std::string& file_name,
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index c1814c8..bc750b4 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -436,6 +436,7 @@ "//components/sync", "//components/translate/core/browser", "//components/translate/core/common", + "//components/variations", "//components/variations/net", "//components/variations/service:service", "//components/version_info",
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc index 84562ee..7432e64 100644 --- a/components/autofill/core/browser/autofill_download_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -41,6 +41,7 @@ #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/signatures.h" #include "components/prefs/pref_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_ids_provider.h" #include "net/http/http_status_code.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -248,6 +249,8 @@ ScopedActiveAutofillExperiments scoped_active_autofill_experiments; base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::list<ResponseData> responses_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; network::TestURLLoaderFactory test_url_loader_factory_; @@ -1531,6 +1534,8 @@ base::test::ScopedCommandLine scoped_command_line_; base::test::ScopedFeatureList scoped_feature_list_1_; base::test::ScopedFeatureList scoped_feature_list_2_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; EmbeddedTestServer server_; int cache_expiration_in_milliseconds_ = 100000; std::unique_ptr<base::RunLoop> run_loop_;
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc index ce95df8..ca9623b 100644 --- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc +++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -57,6 +57,7 @@ #include "components/security_state/core/security_state.h" #include "components/strings/grit/components_strings.h" #include "components/sync/driver/test_sync_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/version_info/channel.h" #include "net/base/url_util.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -399,6 +400,8 @@ protected: std::unique_ptr<TestAccessor> accessor_; base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; payments::TestPaymentsClient* payments_client_; TestAutofillClient autofill_client_; std::unique_ptr<TestAutofillDriver> autofill_driver_;
diff --git a/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc index 353fe03..349ae7e1 100644 --- a/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc +++ b/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
@@ -54,6 +54,7 @@ #include "components/security_state/core/security_state.h" #include "components/strings/grit/components_strings.h" #include "components/sync/driver/test_sync_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/version_info/channel.h" #include "net/base/url_util.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -146,6 +147,8 @@ protected: std::unique_ptr<TestAuthenticationRequester> requester_; base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; TestAutofillClient autofill_client_; std::unique_ptr<TestAutofillDriver> autofill_driver_; scoped_refptr<AutofillWebDataService> database_;
diff --git a/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc index a4ef9e9..d6418f6a 100644 --- a/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc +++ b/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
@@ -57,6 +57,7 @@ #include "components/security_state/core/security_state.h" #include "components/strings/grit/components_strings.h" #include "components/sync/driver/test_sync_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_associated_data.h" #include "components/variations/variations_params_manager.h" #include "components/version_info/channel.h" @@ -239,6 +240,8 @@ protected: std::unique_ptr<TestAuthenticationRequester> requester_; base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; TestAutofillClient autofill_client_; std::unique_ptr<TestAutofillDriver> autofill_driver_; scoped_refptr<AutofillWebDataService> database_;
diff --git a/components/autofill/core/browser/payments/full_card_request_unittest.cc b/components/autofill/core/browser/payments/full_card_request_unittest.cc index bae38947..2f72a2e 100644 --- a/components/autofill/core/browser/payments/full_card_request_unittest.cc +++ b/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -22,6 +22,7 @@ #include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_payments_features.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/url_request/url_request_test_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -129,6 +130,8 @@ private: base::test::SingleThreadTaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; MockPersonalDataManager personal_data_; MockResultDelegate result_delegate_; MockUIDelegate ui_delegate_;
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc index 3def478..bc59032 100644 --- a/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -31,6 +31,7 @@ #include "components/autofill/core/common/autofill_switches.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/variations/net/variations_http_headers.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_associated_data.h" #include "components/variations/variations_ids_provider.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -335,6 +336,8 @@ #endif // !defined(OS_ANDROID) && !defined(OS_IOS) base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; TestPersonalDataManager test_personal_data_; @@ -686,16 +689,12 @@ TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTest) { // Register a trial and variation id, so that there is data in variations - // headers. Also, the variations header provider may have been registered to - // observe some other field trial list, so reset it. - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); + // headers. CreateFieldTrialWithId("AutofillTest", "Group", 369); StartGettingUploadDetails(); // Note that experiment information is stored in X-Client-Data. EXPECT_TRUE(HasVariationsHeader()); - - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); } TEST_F(PaymentsClientTest, GetDetailsIncludeBillableServiceNumber) { @@ -779,32 +778,24 @@ TEST_F(PaymentsClientTest, UploadCardVariationsTest) { // Register a trial and variation id, so that there is data in variations - // headers. Also, the variations header provider may have been registered to - // observe some other field trial list, so reset it. - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); + // headers. CreateFieldTrialWithId("AutofillTest", "Group", 369); StartUploading(/*include_cvc=*/true); IssueOAuthToken(); // Note that experiment information is stored in X-Client-Data. EXPECT_TRUE(HasVariationsHeader()); - - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); } TEST_F(PaymentsClientTest, UnmaskCardVariationsTest) { // Register a trial and variation id, so that there is data in variations - // headers. Also, the variations header provider may have been registered to - // observe some other field trial list, so reset it. - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); + // headers. CreateFieldTrialWithId("AutofillTest", "Group", 369); StartUnmasking(CardUnmaskOptions()); IssueOAuthToken(); // Note that experiment information is stored in X-Client-Data. EXPECT_TRUE(HasVariationsHeader()); - - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); } TEST_F(PaymentsClientTest, UploadSuccessWithoutServerId) { @@ -1030,17 +1021,13 @@ TEST_F(PaymentsClientTest, MigrateCardsVariationsTest) { // Register a trial and variation id, so that there is data in variations - // headers. Also, the variations header provider may have been registered to - // observe some other field trial list, so reset it. - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); + // headers. CreateFieldTrialWithId("AutofillTest", "Group", 369); StartMigrating(/*has_cardholder_name=*/true); IssueOAuthToken(); // Note that experiment information is stored in X-Client-Data. EXPECT_TRUE(HasVariationsHeader()); - - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); } TEST_F(PaymentsClientTest, MigrationRequestIncludesUniqueId) {
diff --git a/components/autofill_assistant/browser/controller_observer.h b/components/autofill_assistant/browser/controller_observer.h index 4b3b9eb..6575dd18b 100644 --- a/components/autofill_assistant/browser/controller_observer.h +++ b/components/autofill_assistant/browser/controller_observer.h
@@ -9,7 +9,7 @@ #include <string> #include <vector> -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "components/autofill_assistant/browser/details.h" #include "components/autofill_assistant/browser/info_box.h" #include "components/autofill_assistant/browser/metrics.h"
diff --git a/components/autofill_assistant/browser/public/runtime_observer.h b/components/autofill_assistant/browser/public/runtime_observer.h index 9229529..b93c50b0 100644 --- a/components/autofill_assistant/browser/public/runtime_observer.h +++ b/components/autofill_assistant/browser/public/runtime_observer.h
@@ -5,7 +5,7 @@ #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_RUNTIME_OBSERVER_H_ #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_RUNTIME_OBSERVER_H_ -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "components/autofill_assistant/browser/public/ui_state.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/starter_heuristic.cc b/components/autofill_assistant/browser/starter_heuristic.cc index 639c298..5b12566 100644 --- a/components/autofill_assistant/browser/starter_heuristic.cc +++ b/components/autofill_assistant/browser/starter_heuristic.cc
@@ -46,6 +46,7 @@ std::string parameters = kFieldTrialParams.Get(); if (parameters.empty()) { + VLOG(2) << "Field trial parameter not set"; return; } absl::optional<base::Value> dict = base::JSONReader::Read(parameters); @@ -106,6 +107,8 @@ } } + VLOG(2) << "Read " << condition_sets.size() << " condition sets and " + << denylisted_domains.size() << " denylisted domains."; denylisted_domains_ = std::move(denylisted_domains); url_matcher_.AddConditionSets(condition_sets); matcher_id_to_intent_map_ = std::move(mapping);
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h index c6dd1f35..2104a91e 100644 --- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h +++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h
@@ -11,7 +11,6 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "base/time/time.h" #include "components/autofill_assistant/browser/client.h"
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index 360c243..ea9513e 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp
@@ -504,6 +504,9 @@ <message name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EXP_DATE_LABEL" desc="Text shown next to the virtual card expiration date in the virtual card manual fallback bubble on Desktop. This bubble shows the complete information for the virtual card selected to fill the form."> Month/Year: </message> + <message name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_CARDHOLDER_NAME_LABEL" desc="Text shown next to the virtual card name on card field in the virtual card manual fallback bubble on Desktop. This bubble shows the complete information for the virtual card selected to fill the form."> + Name on card: + </message> <message name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_CVC_LABEL" desc="Text shown next to the virtual card CVC code in the virtual card manual fallback bubble on Desktop. This bubble shows the complete information for the virtual card selected to fill the form."> CVC: </message>
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_CARDHOLDER_NAME_LABEL.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_CARDHOLDER_NAME_LABEL.png.sha1 new file mode 100644 index 0000000..086c8e6 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_CARDHOLDER_NAME_LABEL.png.sha1
@@ -0,0 +1 @@ +7b8bb45e729ab5bbcf8e2d33c18801f022d9fa53 \ No newline at end of file
diff --git a/components/blocked_content/BUILD.gn b/components/blocked_content/BUILD.gn index e5f9e8a..7faad68 100644 --- a/components/blocked_content/BUILD.gn +++ b/components/blocked_content/BUILD.gn
@@ -95,6 +95,7 @@ "//components/subresource_filter/core/browser:test_support", "//components/sync_preferences:test_support", "//components/user_prefs", + "//components/variations:test_support", "//content/test:test_support", "//net:test_support", "//testing/gtest",
diff --git a/components/blocked_content/DEPS b/components/blocked_content/DEPS index 44d6af21..5e3ff550 100644 --- a/components/blocked_content/DEPS +++ b/components/blocked_content/DEPS
@@ -11,6 +11,7 @@ "+components/sync_preferences", "+components/ukm", "+components/user_prefs", + "+components/variations", "+content/public/browser", "+content/public/test", "+services/metrics/public",
diff --git a/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc b/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc index 5611c9d..e6514960 100644 --- a/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc +++ b/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
@@ -28,6 +28,7 @@ #include "components/subresource_filter/core/browser/subresource_filter_constants.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/user_prefs/user_prefs.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/navigation_handle.h" @@ -147,6 +148,8 @@ } std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_; SafeBrowsingTriggeredPopupBlocker* popup_blocker_ = nullptr; std::unique_ptr<content::TestNavigationThrottleInserter> throttle_inserter_;
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc index 6c254cd..256b94e 100644 --- a/components/bookmarks/browser/bookmark_model.cc +++ b/components/bookmarks/browser/bookmark_model.cc
@@ -580,6 +580,7 @@ size_t index, const std::u16string& title, const BookmarkNode::MetaInfoMap* meta_info, + absl::optional<base::Time> creation_time, absl::optional<base::GUID> guid) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(loaded_); @@ -589,10 +590,14 @@ DCHECK(IsValidIndex(parent, index, true)); DCHECK(!guid || guid->is_valid()); + const base::Time provided_creation_time_or_now = + creation_time.value_or(Time::Now()); + auto new_node = std::make_unique<BookmarkNode>( - generate_next_node_id(), guid ? *guid : base::GUID::GenerateRandomV4(), + generate_next_node_id(), guid.value_or(base::GUID::GenerateRandomV4()), GURL()); - new_node->set_date_folder_modified(Time::Now()); + new_node->set_date_added(provided_creation_time_or_now); + new_node->set_date_folder_modified(provided_creation_time_or_now); // Folders shouldn't have line breaks in their titles. new_node->SetTitle(title); if (meta_info) @@ -618,18 +623,18 @@ DCHECK(IsValidIndex(parent, index, true)); DCHECK(!guid || guid->is_valid()); - if (!creation_time) - creation_time = Time::Now(); + const base::Time provided_creation_time_or_now = + creation_time.value_or(Time::Now()); // Syncing may result in dates newer than the last modified date. - if (*creation_time > parent->date_folder_modified()) - SetDateFolderModified(parent, *creation_time); + if (provided_creation_time_or_now > parent->date_folder_modified()) + SetDateFolderModified(parent, provided_creation_time_or_now); auto new_node = std::make_unique<BookmarkNode>( - generate_next_node_id(), guid ? *guid : base::GUID::GenerateRandomV4(), + generate_next_node_id(), guid.value_or(base::GUID::GenerateRandomV4()), url); new_node->SetTitle(title); - new_node->set_date_added(*creation_time); + new_node->set_date_added(provided_creation_time_or_now); if (meta_info) new_node->SetMetaInfoMap(*meta_info);
diff --git a/components/bookmarks/browser/bookmark_model.h b/components/bookmarks/browser/bookmark_model.h index 2aa13d8..4864b2b 100644 --- a/components/bookmarks/browser/bookmark_model.h +++ b/components/bookmarks/browser/bookmark_model.h
@@ -203,14 +203,16 @@ // same or not. void GetBookmarks(std::vector<UrlAndTitle>* urls); - // Adds a new folder node at the specified position with the given |guid| and - // |meta_info|. If no GUID is provided (i.e. nullopt), then a random one will - // be generated. If a GUID is provided, it must be valid. + // Adds a new folder node at the specified position with the given + // |creation_time|, |guid| and |meta_info|. If no GUID is provided (i.e. + // nullopt), then a random one will be generated. If a GUID is provided, it + // must be valid. const BookmarkNode* AddFolder( const BookmarkNode* parent, size_t index, const std::u16string& title, const BookmarkNode::MetaInfoMap* meta_info = nullptr, + absl::optional<base::Time> creation_time = absl::nullopt, absl::optional<base::GUID> guid = absl::nullopt); // Adds a url at the specified position with the given |creation_time|,
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc index 96488236..4b0a263 100644 --- a/components/bookmarks/browser/bookmark_model_unittest.cc +++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -631,6 +631,19 @@ observer_details_.ExpectEquals(root, nullptr, 0, size_t{-1}); } +TEST_F(BookmarkModelTest, AddFolderWithCreationTime) { + const BookmarkNode* root = model_->bookmark_bar_node(); + const std::u16string title(u"foo"); + BookmarkNode::MetaInfoMap meta_info; + const base::Time creation_time(base::Time::Now() - + base::TimeDelta::FromDays(1)); + + const BookmarkNode* new_node = + model_->AddFolder(root, /*index=*/0, title, &meta_info, creation_time); + + EXPECT_EQ(creation_time, new_node->date_added()); +} + TEST_F(BookmarkModelTest, AddFolderWithGUID) { const BookmarkNode* root = model_->bookmark_bar_node(); const std::u16string title(u"foo"); @@ -638,7 +651,8 @@ const base::GUID guid = base::GUID::GenerateRandomV4(); const BookmarkNode* new_node = - model_->AddFolder(root, /*index=*/0, title, &meta_info, guid); + model_->AddFolder(root, /*index=*/0, title, &meta_info, + /*creation_time=*/Time::Now(), guid); EXPECT_EQ(guid, new_node->guid()); }
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonRenderTest.java index ad525c5b..e747e215 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonRenderTest.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonRenderTest.java
@@ -42,9 +42,9 @@ private static List<ParameterSet> sClassParams = new NightModeTestUtils.NightModeParams().getParameters(); - private static final int REVISION = 2; + private static final int REVISION = 3; private static final String REVISION_DESCRIPTION = - "Added RadioButtonWithDescriptionAndAuxButton to the test."; + "Use Google standard colors as the background."; @Rule public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() @@ -87,19 +87,17 @@ mLayout = content.findViewById(R.id.test_radio_button_layout); mLayout.setBackgroundColor(mFakeBgColor); - mRadioButtonWithDescription1 = content.findViewById(R.id.test_radio_description_1); - mRadioButtonWithDescription2 = content.findViewById(R.id.test_radio_description_2); - mRadioButtonWithDescription3 = content.findViewById(R.id.test_radio_description_3); - mRadioButtonWithEditText1 = content.findViewById(R.id.test_radio_edit_text_1); - mRadioButtonWithEditText2 = content.findViewById(R.id.test_radio_edit_text_2); - mRadioButtonWithEditText3 = content.findViewById(R.id.test_radio_edit_text_3); - mRadioButtonWithEditText4 = content.findViewById(R.id.test_radio_edit_text_4); - mRadioButtonWithDescriptonAndAuxButton1 = - content.findViewById(R.id.test_radio_description_and_aux_button_1); + mRadioButtonWithDescription1 = content.findViewById(R.id.base_primary_only); + mRadioButtonWithDescription2 = content.findViewById(R.id.base_primary_description); + mRadioButtonWithDescription3 = content.findViewById(R.id.base_primary_bg_override); + mRadioButtonWithEditText1 = content.findViewById(R.id.edittext_primary_description); + mRadioButtonWithEditText2 = content.findViewById(R.id.edittext_primary_only); + mRadioButtonWithEditText3 = content.findViewById(R.id.edittext_hint_description); + mRadioButtonWithEditText4 = content.findViewById(R.id.edittext_hint_only); + mRadioButtonWithDescriptonAndAuxButton1 = content.findViewById(R.id.aux_primary_only); mRadioButtonWithDescriptonAndAuxButton2 = - content.findViewById(R.id.test_radio_description_and_aux_button_2); - mRadioButtonWithDescriptonAndAuxButton3 = - content.findViewById(R.id.test_radio_description_and_aux_button_3); + content.findViewById(R.id.aux_primary_description); + mRadioButtonWithDescriptonAndAuxButton3 = content.findViewById(R.id.aux_bg_override); }); Assert.assertNotNull(mLayout); @@ -119,18 +117,15 @@ @SmallTest @Feature({"RenderTest", "RadioButton"}) public void testRadioButtonWithDescriptionLayout() throws Exception { - mRenderTestRule.render(mRadioButtonWithDescription1, "test_radio_description_1"); - mRenderTestRule.render(mRadioButtonWithDescription2, "test_radio_description_2"); - mRenderTestRule.render(mRadioButtonWithDescription3, "test_radio_description_3"); - mRenderTestRule.render(mRadioButtonWithEditText1, "test_radio_edit_text_1"); - mRenderTestRule.render(mRadioButtonWithEditText2, "test_radio_edit_text_2"); - mRenderTestRule.render(mRadioButtonWithEditText3, "test_radio_edit_text_3"); - mRenderTestRule.render(mRadioButtonWithEditText4, "test_radio_edit_text_4"); - mRenderTestRule.render( - mRadioButtonWithDescriptonAndAuxButton1, "test_radio_description_and_aux_button_1"); - mRenderTestRule.render( - mRadioButtonWithDescriptonAndAuxButton2, "test_radio_description_and_aux_button_2"); - mRenderTestRule.render( - mRadioButtonWithDescriptonAndAuxButton3, "test_radio_description_and_aux_button_3"); + mRenderTestRule.render(mRadioButtonWithDescription1, "base_primary_only"); + mRenderTestRule.render(mRadioButtonWithDescription2, "base_primary_description"); + mRenderTestRule.render(mRadioButtonWithDescription3, "base_primary_bg_override"); + mRenderTestRule.render(mRadioButtonWithEditText1, "edittext_primary_description"); + mRenderTestRule.render(mRadioButtonWithEditText2, "edittext_primary_only"); + mRenderTestRule.render(mRadioButtonWithEditText3, "edittext_hint_description"); + mRenderTestRule.render(mRadioButtonWithEditText4, "edittext_hint_only"); + mRenderTestRule.render(mRadioButtonWithDescriptonAndAuxButton1, "aux_primary_only"); + mRenderTestRule.render(mRadioButtonWithDescriptonAndAuxButton2, "aux_primary_description"); + mRenderTestRule.render(mRadioButtonWithDescriptonAndAuxButton3, "aux_bg_override"); } }
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java index c04f678..6c2fede0 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java
@@ -40,8 +40,15 @@ private static List<ParameterSet> sClassParams = new NightModeTestUtils.NightModeParams().getParameters(); + private static final int REVISION = 2; + private static final String REVISION_DESCRIPTION = + "Use Google standard colors as the background."; + @Rule - public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build(); + public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() + .setRevision(REVISION) + .setDescription(REVISION_DESCRIPTION) + .build(); private RadioButtonWithDescriptionLayout mLayout; @@ -69,9 +76,9 @@ mLayout = content.findViewById(R.id.test_radio_button_layout); mLayout.setBackgroundColor(mFakeBgColor); - mRadioButtonWithIcon1 = content.findViewById(R.id.test_radio_icon_1); - mRadioButtonWithIcon2 = content.findViewById(R.id.test_radio_icon_2); - mRadioButtonWithIcon3 = content.findViewById(R.id.test_radio_icon_3); + mRadioButtonWithIcon1 = content.findViewById(R.id.icon_primary_only); + mRadioButtonWithIcon2 = content.findViewById(R.id.icon_primary_description); + mRadioButtonWithIcon3 = content.findViewById(R.id.icon_bg_override); }); Assert.assertNotNull(mLayout); @@ -84,8 +91,8 @@ @SmallTest @Feature({"RenderTest", "RadioButton"}) public void testRadioButtonWithIcon() throws Exception { - mRenderTestRule.render(mRadioButtonWithIcon1, "test_radio_icon_1"); - mRenderTestRule.render(mRadioButtonWithIcon2, "test_radio_icon_2"); - mRenderTestRule.render(mRadioButtonWithIcon3, "test_radio_icon_3"); + mRenderTestRule.render(mRadioButtonWithIcon1, "icon_primary_only"); + mRenderTestRule.render(mRadioButtonWithIcon2, "icon_primary_description"); + mRenderTestRule.render(mRadioButtonWithIcon3, "icon_bg_override"); } -} \ No newline at end of file +}
diff --git a/components/browser_ui/widget/android/test/java/res/layout/radio_button_render_test.xml b/components/browser_ui/widget/android/test/java/res/layout/radio_button_render_test.xml index 6579dcc5..699aa88 100644 --- a/components/browser_ui/widget/android/test/java/res/layout/radio_button_render_test.xml +++ b/components/browser_ui/widget/android/test/java/res/layout/radio_button_render_test.xml
@@ -15,14 +15,14 @@ <!-- RadioButtonWithDescription - With primary, without description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescription - android:id="@+id/test_radio_description_1" + android:id="@+id/base_primary_only" android:layout_width="match_parent" android:layout_height="wrap_content" app:primaryText="@string/test_string" /> <!-- RadioButtonWithDescription - With primary and description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescription - android:id="@+id/test_radio_description_2" + android:id="@+id/base_primary_description" android:layout_width="match_parent" android:layout_height="wrap_content" app:primaryText="@string/test_string" @@ -30,16 +30,16 @@ <!-- RadioButtonWithDescription - With background override. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescription - android:id="@+id/test_radio_description_3" + android:id="@+id/base_primary_bg_override" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@color/background_color_non_empty" + android:background="@color/modern_grey_100" app:primaryText="@string/test_string" app:descriptionText="@string/test_string" /> - <!-- RadioButtonWithDescription - With primary and description. --> + <!-- RadioButtonWithEditText - With primary and description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithEditText - android:id="@+id/test_radio_edit_text_1" + android:id="@+id/edittext_primary_description" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/min_touch_target_size" @@ -50,9 +50,9 @@ app:primaryText="@string/test_string" app:descriptionText="@string/test_string" /> - <!-- RadioButtonWithDescription - With primary, without description. --> + <!-- RadioButtonWithEditText - With primary, without description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithEditText - android:id="@+id/test_radio_edit_text_2" + android:id="@+id/edittext_primary_only" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/min_touch_target_size" @@ -62,9 +62,9 @@ android:hint="@string/test_uri" app:primaryText="@string/test_string" /> - <!-- RadioButtonWithDescription - Without primary, with hint, with description. --> + <!-- RadioButtonWithEditText - Without primary, with hint, with description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithEditText - android:id="@+id/test_radio_edit_text_3" + android:id="@+id/edittext_hint_description" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/min_touch_target_size" @@ -74,9 +74,9 @@ android:hint="@string/test_uri" app:descriptionText="@string/test_string" /> - <!-- RadioButtonWithDescription - Without primary, without description. --> + <!-- RadioButtonWithEditText - Hint only. --> <org.chromium.components.browser_ui.widget.RadioButtonWithEditText - android:id="@+id/test_radio_edit_text_4" + android:id="@+id/edittext_hint_only" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/min_touch_target_size" @@ -87,14 +87,14 @@ <!-- RadioButtonWithDescriptionAndAuxButton - With primary, without description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionAndAuxButton - android:id="@+id/test_radio_description_and_aux_button_1" + android:id="@+id/aux_primary_only" android:layout_width="match_parent" android:layout_height="wrap_content" app:primaryText="@string/test_string" /> <!-- RadioButtonWithDescriptionAndAuxButton - With primary and description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionAndAuxButton - android:id="@+id/test_radio_description_and_aux_button_2" + android:id="@+id/aux_primary_description" android:layout_width="match_parent" android:layout_height="wrap_content" app:primaryText="@string/test_string" @@ -102,10 +102,10 @@ <!-- RadioButtonWithDescriptionAndAuxButton - With background override. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionAndAuxButton - android:id="@+id/test_radio_description_and_aux_button_3" + android:id="@+id/aux_bg_override" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@color/background_color_non_empty" + android:background="@color/modern_grey_100" app:primaryText="@string/test_string" app:descriptionText="@string/test_string" /> </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout>
diff --git a/components/browser_ui/widget/android/test/java/res/layout/radio_button_with_icon_render_test.xml b/components/browser_ui/widget/android/test/java/res/layout/radio_button_with_icon_render_test.xml index 1d479a0c..0912539 100644 --- a/components/browser_ui/widget/android/test/java/res/layout/radio_button_with_icon_render_test.xml +++ b/components/browser_ui/widget/android/test/java/res/layout/radio_button_with_icon_render_test.xml
@@ -15,7 +15,7 @@ <!-- RadioButtonWithDescription - With icon and primary, without description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescription - android:id="@+id/test_radio_icon_1" + android:id="@+id/icon_primary_only" android:layout_width="match_parent" android:layout_height="wrap_content" app:iconSrc="@drawable/test_ic_more_vert_black_24dp" @@ -23,7 +23,7 @@ <!-- RadioButtonWithDescription - With icon, primary and description. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescription - android:id="@+id/test_radio_icon_2" + android:id="@+id/icon_primary_description" android:layout_width="match_parent" android:layout_height="wrap_content" app:iconSrc="@drawable/test_ic_more_vert_black_24dp" @@ -32,13 +32,13 @@ <!-- RadioButtonWithDescription - With background override. --> <org.chromium.components.browser_ui.widget.RadioButtonWithDescription - android:id="@+id/test_radio_icon_3" + android:id="@+id/icon_bg_override" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@color/background_color_non_empty" + android:background="@color/modern_grey_100" app:iconSrc="@drawable/test_ic_more_vert_black_24dp" app:primaryText="@string/test_string" app:descriptionText="@string/test_string" /> </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout> -</FrameLayout> \ No newline at end of file +</FrameLayout>
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index d584946..d31f038 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -962,6 +962,12 @@ "//third_party/google-truth:google_truth_java", "//third_party/junit", "//third_party/mockito:mockito_java", + + # Transitive Mockito dependencies + "//third_party/byte_buddy:byte_buddy_agent_java", + "//third_party/byte_buddy:byte_buddy_android_java", + "//third_party/byte_buddy:dx_25_0_2_java", + "//third_party/byte_buddy:byte_buddy_java", ] android_library("cronet_javatests") {
diff --git a/components/data_reduction_proxy/core/browser/BUILD.gn b/components/data_reduction_proxy/core/browser/BUILD.gn index c975619..9fa58c38 100644 --- a/components/data_reduction_proxy/core/browser/BUILD.gn +++ b/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -148,6 +148,7 @@ "//components/data_reduction_proxy/proto:data_reduction_proxy_proto", "//components/data_use_measurement/core:ascriber", "//components/prefs:test_support", + "//components/variations:test_support", "//net:test_support", "//services/network:test_support", "//services/network/public/cpp",
diff --git a/components/data_reduction_proxy/core/browser/DEPS b/components/data_reduction_proxy/core/browser/DEPS index 367a20af..cc968059 100644 --- a/components/data_reduction_proxy/core/browser/DEPS +++ b/components/data_reduction_proxy/core/browser/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+components/data_use_measurement/core", + "+components/variations", "+mojo/public/cpp", "+services/network/public", "+services/network/test",
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc index e9ed7ee..62d8f02f 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
@@ -11,6 +11,7 @@ #include "base/cxx17_backports.h" #include "base/test/task_environment.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/base/request_priority.h" #include "net/nqe/effective_connection_type.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" @@ -28,6 +29,8 @@ private: base::test::SingleThreadTaskEnvironment task_environment_{ base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; }; TEST_F(DataReductionProxyDataTest, BasicSettersAndGetters) {
diff --git a/components/error_page/common/alt_game_images.cc b/components/error_page/common/alt_game_images.cc index 5da0f77a..6ffd77c 100644 --- a/components/error_page/common/alt_game_images.cc +++ b/components/error_page/common/alt_game_images.cc
@@ -16,2761 +16,2772 @@ namespace error_page { namespace { -const char* kAltGameImages1x[] = { - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x40, 0xcc, 0xc1, 0x2f, - 0xc8, 0x25, 0x29, 0x6e, 0xe, 0x12, 0x32, 0xe9, 0xe3, 0xad, 0xfa, 0xdf, - 0x55, 0x8a, 0x6, 0x12, 0xa2, 0x4e, 0xa6, 0x2e, 0xbd, 0x3, 0xeb, 0xdc, - 0x54, 0x29, 0xf4, 0x22, 0x7f, 0xdc, 0x80, 0xb3, 0xe1, 0xe2, 0xa5, 0xcf, - 0xa7, 0x7f, 0x7, 0x8a, 0xe, 0xa, 0x50, 0x50, 0xf7, 0x45, 0xa9, 0x9, - 0xee, 0xea, 0x93, 0xdb, 0xb2, 0xe5, 0x41, 0xfd, 0xc2, 0xf9, 0x2f, 0xf2, - 0x41, 0x0, 0x6d, 0x68, 0x2, 0x9e, 0x20, 0xe7, 0x90, 0x73, 0x6b, 0x57, - 0x44, 0x54, 0xcd, 0xd2, 0x90, 0x0, 0x2d, 0x58, 0xe8, 0x9d, 0x53, 0x59, - 0x32, 0xee, 0xca, 0xf0, 0xd4, 0xa6, 0x3c, 0x3, 0x52, 0x75, 0x7d, 0x83, - 0x97, 0x4e, 0x44, 0x79, 0xf2, 0xb6, 0x2, 0xab, 0xcc, 0xc9, 0xa8, 0x3, - 0xb9, 0x11, 0x2f, 0xe2, 0x1e, 0x16, 0xc6, 0x6c, 0x5b, 0x8c, 0xfb, 0xbb, - 0xe2, 0xd3, 0x86, 0xe9, 0x1b, 0xfa, 0xcc, 0x4c, 0xf8, 0xa, 0xd7, 0x1c, - 0xa1, 0x7, 0xd6, 0xf9, 0x13, 0x1, 0xb, 0x3c, 0x18, 0x1f, 0x1e, 0x6f, - 0x7d, 0xdf, 0xb8, 0xd6, 0xbd, 0xb3, 0x36, 0x8f, 0xef, 0xd3, 0x5, 0x17, - 0x2d, 0xf, 0x57, 0xcf, 0xa5, 0x73, 0x14, 0xc8, 0xee, 0x4e, 0xc2, 0x22, - 0x71, 0x8d, 0x29, 0x4b, 0xc2, 0xd5, 0xa0, 0x37, 0xe6, 0xad, 0xa4, 0xc1, - 0x8a, 0x72, 0xc1, 0x29, 0x87, 0x16, 0xb1, 0xad, 0xd3, 0xc7, 0x0, 0xa0, - 0x14, 0x5c, 0x2a, 0x10, 0x4f, 0xff, 0xe2, 0xb0, 0x3a, 0x93, 0xa8, 0xd5, - 0x43, 0xb, 0xa3, 0x78, 0x87, 0xbf, 0xf5, 0x79, 0x37, 0x34, 0xa8, 0xb2, - 0x1b, 0xab, 0x44, 0x86, 0x9c, 0x23, 0xc4, 0x76, 0x89, 0x6, 0x2e, 0x6c, - 0x8f, 0x5a, 0xfe, 0x96, 0xd4, 0xbf, 0x8, 0x3c, 0x3b, 0xd6, 0x34, 0xb4, - 0xc7, 0xb1, 0xa0, 0x38, 0x8f, 0x4b, 0xb4, 0xc6, 0x16, 0xaf, 0xc9, 0x28, - 0x8, 0xf1, 0x6a, 0xaa, 0x72, 0xf0, 0x53, 0xa8, 0x4b, 0x7, 0x22, 0x4b, - 0xa6, 0xa0, 0x65, 0xfc, 0xa8, 0xcd, 0x98, 0x26, 0x3c, 0xe6, 0xa6, 0x64, - 0x0, 0x3d, 0xd9, 0xa2, 0x77, 0xe1, 0x75, 0x5f, 0xf0, 0x1f, 0x69, 0xee, - 0x5b, 0x2f, 0x47, 0xdb, 0x75, 0x73, 0xed, 0xe4, 0x9f, 0x41, 0xd8, 0xb1, - 0x58, 0x6e, 0x5f, 0x45, 0xe1, 0x39, 0xae, 0xd1, 0xc, 0x78, 0x62, 0xb, - 0xef, 0x40, 0xd4, 0x15, 0xea, 0x7f, 0xa3, 0xb1, 0x5b, 0x44, 0xc0, 0xd, - 0x7f, 0x69, 0xb, 0x43, 0xbe, 0x11, 0xd, 0x7d, 0xaa, 0xd9, 0xaf, 0x78, - 0x99, 0xad, 0x1c, 0x25, 0xd2, 0x88, 0xb5, 0x5c, 0xf0, 0x27, 0xd9, 0x31, - 0xf0, 0x84, 0xbb, 0xf4, 0x66, 0x9f, 0x8b, 0xc, 0x18, 0x6e, 0xf7, 0x4d, - 0x3, 0xb5, 0x66, 0xb2, 0xdf, 0xf2, 0xd4, 0x8e, 0xef, 0xca, 0x99, 0xdd, - 0xd, 0x47, 0x86, 0xa, 0xc, 0xba, 0xce, 0xab, 0x7f, 0xae, 0x2f, 0xa9, - 0x49, 0x2b, 0x20, 0xe1, 0x80, 0x73, 0x0, 0xa9, 0x91, 0xe5, 0xce, 0x34, - 0x2c, 0xdb, 0x3c, 0xe3, 0x13, 0xdb, 0x65, 0x80, 0x90, 0xe4, 0x10, 0x8f, - 0x9b, 0xa5, 0xaa, 0xfe, 0x87, 0x6a, 0x73, 0x3, 0x64, 0x32, 0xe, 0xc4, - 0x3b, 0x8b, 0xb7, 0x2b, 0x42, 0x79, 0x60, 0x9d, 0x83, 0x12, 0xe3, 0x6a, - 0x65, 0x1f, 0x47, 0x3e, 0x6c, 0xa5, 0xe9, 0xda, 0x1e, 0x21, 0xe7, 0x44, - 0xdb, 0x72, 0x3c, 0xd4, 0x25, 0x39, 0x5a, 0x2, 0xb6, 0x53, 0xbe, 0x18, - 0x9a, 0x99, 0x26, 0xc6, 0x86, 0xfb, 0x2e, 0x79, 0xe2, 0x21, 0xaa, 0x56, - 0x52, 0x2b, 0xa0, 0xd9, 0x1f, 0x75, 0x99, 0x4c, 0xe2, 0x3f, 0x87, 0x90, - 0xc1, 0x29, 0x99, 0x78, 0xab, 0x15, 0x27, 0x55, 0xa2, 0x4f, 0x5c, 0x72, - 0x49, 0x4e, 0xc2, 0xd6, 0xaa, 0xe1, 0x0, 0x8, 0x70, 0x50, 0x64, 0x13, - 0xf0, 0x97, 0x38, 0x0, 0x95, 0x8f, 0x87, 0x4a, 0x46, 0x3f, 0xba, 0x83, - 0x96, 0x20, 0x29, 0x11, 0x19, 0xe5, 0x5b, 0x31, 0x8, 0xf1, 0x4a, 0x97, - 0xdd, 0x52, 0x1c, 0x6a, 0xc, 0xc, 0x6a, 0x13, 0x5b, 0x23, 0x49, 0xdf, - 0x95, 0x86, 0x82, 0x43, 0xde, 0x4a, 0x35, 0x88, 0x9a, 0x83, 0x2, 0xcc, - 0xc3, 0x16, 0x48, 0x0, 0x46, 0xeb, 0xde, 0x87, 0x98, 0xbd, 0xf7, 0x81, - 0xb9, 0xc6, 0xfc, 0xf4, 0x46, 0x98, 0x1, 0xd5, 0x7a, 0xf6, 0x1b, 0x3f, - 0xdb, 0x98, 0xf3, 0x22, 0x37, 0x5b, 0x7c, 0x3c, 0xd2, 0x41, 0x19, 0x11, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, - 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, - 0x13, 0x4a, 0xf5, 0xa0, 0x9b, 0x79, 0xc7, 0xcb, 0x4c, 0x57, 0xce, 0xbc, - 0x34, 0x95, 0x4e, 0xd9, 0xb6, 0x68, 0x9e, 0xf3, 0xaa, 0xea, 0xa3, 0x5a, - 0x57, 0x58, 0x30, 0x2c, 0xc8, 0x4b, 0x68, 0xd7, 0x11, 0x8a, 0x36, 0xdb, - 0x60, 0xb4, 0x3e, 0xca, 0xa, 0xba, 0x12, 0x36, 0x38, 0x56, 0xc0, 0x61, - 0xbc, 0xd3, 0x4b, 0x95, 0x3, 0x9a, 0x8e, 0x7b, 0xd2, 0x62, 0x81, 0x7, - 0x56, 0x42, 0x88, 0xbe, 0xea, 0x2c, 0xdd, 0x7e, 0xf2, 0x5a, 0xb5, 0x5a, - 0xc7, 0x35, 0x4d, 0xe8, 0x8f, 0xd2, 0x4a, 0x3, 0x5c, 0xb7, 0xcf, 0x23, - 0x5f, 0xd1, 0x11, 0x13, 0x7a, 0xc1, 0x46, 0x26, 0x6c, 0x4d, 0xa2, 0x56, - 0x30, 0xf6, 0x5d, 0x27, 0xa, 0x35, 0x50, 0x2f, 0xee, 0xe1, 0x3, 0x9d, - 0xdd, 0xa5, 0x85, 0xb, 0xcc, 0x46, 0xbc, 0x95, 0x40, 0x97, 0xd, 0xba, - 0x9d, 0x24, 0x47, 0xe0, 0xd1, 0xca, 0x4b, 0x30, 0x87, 0x23, 0x3c, 0xe1, - 0xc8, 0x50, 0x29, 0x56, 0x9b, 0xee, 0x4c, 0xb8, 0x1c, 0x26, 0xce, 0xb, - 0x8a, 0xd5, 0xb5, 0x75, 0xbc, 0x76, 0xad, 0x87, 0xc, 0x47, 0x62, 0xf5, - 0x57, 0xf4, 0x0, 0xa1, 0xad, 0xfa, 0xc6, 0xc3, 0xf7, 0x83, 0xfe, 0x9d, - 0x25, 0xdd, 0x35, 0x81, 0xf5, 0x1a, 0x82, 0x1b, 0x93, 0xa5, 0x40, 0x11, - 0xe9, 0xe5, 0x6e, 0xac, 0x36, 0x33, 0xcc, 0x99, 0x7e, 0x11, 0x85, 0x79, - 0x24, 0x22, 0x74, 0xf7, 0x8d, 0xfb, 0x40, 0x80, 0x9a, 0xca, 0xb5, 0xbe, - 0x3a, 0x58, 0x6f, 0xa9, 0x76, 0xd4, 0xe8, 0x29, 0x80, 0xc7, 0xe, 0xdd, - 0xe, 0x75, 0xf6, 0xc8, 0x11, 0x21, 0x81, 0xce, 0x3f, 0x41, 0x4d, 0xd8, - 0x4c, 0x4b, 0x2e, 0xeb, 0x9f, 0xb3, 0x1a, 0xa4, 0x2f, 0xa5, 0x44, 0xbb, - 0xcd, 0x46, 0xe6, 0x1f, 0xd, 0xd0, 0xc3, 0x27, 0x8b, 0x3a, 0xbf, 0xda, - 0x8f, 0xaa, 0xfd, 0xc2, 0x49, 0xd, 0x5c, 0xb7, 0xbc, 0x23, 0x57, 0x2f, - 0x83, 0xd4, 0x8, 0xee, 0x1, 0x56, 0x78, 0xee, 0x90, 0xb8, 0x5a, 0x64, - 0x51, 0xad, 0xad, 0xfe, 0xe9, 0xae, 0x8e, 0xae, 0xe9, 0x26, 0x57, 0xf0, - 0x77, 0xe1, 0xc1, 0xd8, 0x9d, 0x49, 0x8e, 0x8f, 0x7, 0x8, 0xcc, 0x45, - 0x6a, 0x3c, 0xf2, 0xbf, 0xee, 0x4f, 0xb, 0xe9, 0x5a, 0xaf, 0xd4, 0x12, - 0xb0, 0xcd, 0x3, 0x3c, 0x96, 0x1e, 0xa9, 0x24, 0xab, 0x1d, 0x16, 0xea, - 0x1a, 0x41, 0x56, 0xc6, 0xc1, 0xb7, 0x96, 0x36, 0xec, 0x20, 0xeb, 0xc2, - 0x19, 0x37, 0x55, 0x66, 0x12, 0xf5, 0x3, 0x55, 0x2d, 0x27, 0x28, 0x65, - 0xdb, 0x64, 0xc5, 0x71, 0xfc, 0x76, 0x2f, 0xc0, 0x7b, 0x49, 0x90, 0x5f, - 0x5d, 0x4d, 0x6a, 0x66, 0x7d, 0xfb, 0xe2, 0x16, 0x72, 0x84, 0xb6, 0xcb, - 0x65, 0x2d, 0x8b, 0x22, 0x4b, 0x1d, 0x4a, 0xde, 0x6b, 0x8c, 0x2c, 0x45, - 0x6, 0xe6, 0x92, 0x2e, 0xaf, 0x55, 0x66, 0xb, 0xae, 0xe9, 0xd7, 0xd2, - 0x3e, 0xc1, 0xdc, 0xe4, 0x4, 0x58, 0x4a, 0x64, 0x30, 0x20, 0xc6, 0x2f, - 0xa9, 0xee, 0xed, 0xb3, 0xe4, 0xc9, 0xca, 0x34, 0x71, 0xfc, 0x2, 0x95, - 0x51, 0xe4, 0xd2, 0x3, 0x4d, 0x3d, 0x10, 0xa5, 0xdc, 0xc6, 0x5e, 0x5c, - 0x1f, 0x27, 0xc4, 0x7c, 0xd, 0xfc, 0xdb, 0xd6, 0xd5, 0x2b, 0xaa, 0xbc, - 0x22, 0x61, 0x56, 0x10, 0xc2, 0xfc, 0x58, 0x53, 0xea, 0x12, 0x9d, 0x49, - 0xbd, 0x7e, 0xf7, 0x8d, 0x16, 0x25, 0x86, 0x84, 0x92, 0x70, 0x5f, 0xdd, - 0x73, 0xc1, 0x7, 0xfa, 0xd3, 0xc1, 0xdc, 0x61, 0x36, 0x1c, 0x74, 0xa2, - 0x9, 0x3f, 0x66, 0x90, 0x47, 0x9e, 0x27, 0x39, 0x44, 0xde, 0x48, 0xa8, - 0x5b, 0xdc, 0x42, 0xc1, 0x49, 0x87, 0x64, 0xa, 0xea, 0x5, 0x7e, 0x48, - 0xf9, 0x42, 0xf0, 0xf6, 0x5a, 0x4c, 0xc2, 0xd2, 0xb2, 0x4f, 0x16, 0x63, - 0xce, 0x10, 0x13, 0xce, 0xf7, 0x6a, 0xa4, 0xe8, 0x3, 0xe3, 0xd6, 0x10, - 0x6f, 0xbd, 0xf4, 0x24, 0x3, 0x16, 0x1f, 0x51, 0x2f, 0x85, 0x5f, 0x5d, - 0xd6, 0xc4, 0xd2, 0x3f, 0xd2, 0xab, 0x6b, 0x89, 0x52, 0xdb, 0x6c, 0x7a, - 0xa1, 0xf8, 0xe3, 0x19, 0x47, 0x2e, 0x64, 0xe3, 0xf0, 0x4e, 0x6d, 0x5e, - 0xbc, 0x54, 0x54, 0x5d, 0x9a, 0xdf, 0xed, 0xa7, 0xcf, 0xa0, 0x6f, 0x5e, - 0x23, 0x6f, 0x52, 0x90, 0x50, 0x35, 0x68, 0x45, 0xd8, 0xc2, 0x9a, 0x9e, - 0xae, 0x13, 0x8a, 0xc1, 0x60, 0x72, 0xb7, 0x6d, 0xd, 0x61, 0xe9, 0x3c, - 0xe1, 0xbe, 0x22, 0xc5, 0xa2, 0x7d, 0x8a, 0x8b, 0x43, 0x14, 0xef, 0x5c, - 0xa4, 0x10, 0xb7, 0x7, 0x73, 0xad, 0xb4, 0x86, 0xae, 0xc0, 0x1c, 0xf4, - 0xd2, 0x6, 0xda, 0x1, 0x35, 0x17, 0xcd, 0xa6, 0x28, 0x44, 0xc9, 0xbf, - 0x97, 0xe5, 0x41, 0x37, 0xe5, 0xcf, 0x3f, 0x96, 0xb5, 0x67, 0xcc, 0xea, - 0x69, 0x8e, 0xfd, 0xd6, 0x92, 0x5d, 0x72, 0xf5, 0xfd, 0x57, 0xb8, 0x4e, - 0x1b, 0x2d, 0x31, 0x3b, 0x99, 0x1a, 0x3e, 0xd4, 0x54, 0x77, 0x2e, 0x4b, - 0x2e, 0x5f, 0xcd, 0x56, 0xd4, 0xf7, 0xfc, 0x7, 0x92, 0x28, 0x3f, 0xdb, - 0x4f, 0x41, 0x1e, 0x43, 0xbc, 0x37, 0x81, 0xda, 0xe4, 0xeb, 0x9c, 0xf3, - 0xa5, 0x5b, 0xf7, 0x11, 0xf6, 0x5b, 0x12, 0x85, 0x57, 0xdb, 0xf, 0x1, - 0xc5, 0xfb, 0x33, 0x65, 0xa6, 0x51, 0xfa, 0x43, 0x8d, 0x9d, 0x42, 0xe2, - 0xe, 0x61, 0x9d, 0xcb, 0x6b, 0xe2, 0xa0, 0x60, 0x67, 0xba, 0x7e, 0x55, - 0xaf, 0x24, 0x7d, 0x32, 0xb0, 0x27, 0xa8, 0xa1, 0xad, 0xa, 0xd, 0xed, - 0xed, 0x2c, 0xeb, 0x98, 0xd9, 0x49, 0xcb, 0xd5, 0x2e, 0x7, 0x32, 0x87, - 0x37, 0xa4, 0x2a, 0x1c, 0xf2, 0xce, 0xfb, 0xa8, 0x6a, 0xf2, 0xf7, 0x70, - 0x20, 0xbd, 0xca, 0x48, 0x76, 0xc9, 0x49, 0x58, 0x15, 0xbb, 0xcc, 0x21, - 0x60, 0x37, 0x31, 0xee, 0xbb, 0xff, 0xde, 0xd8, 0x6c, 0xeb, 0x55, 0x12, - 0xf8, 0xbb, 0x36, 0x11, 0xa4, 0x6f, 0x1d, 0x81, 0xd, 0xc3, 0xd9, 0xa7, - 0xee, 0xc2, 0x9c, 0x45, 0x78, 0x12, 0xd, 0x73, 0x11, 0x69, 0x14, 0x7d, - 0x23, 0xdb, 0x69, 0xdf, 0xc2, 0xc8, 0x5b, 0x4, 0xd5, 0x4f, 0xa, 0xfb, - 0x4f, 0x2d, 0x52, 0x3c, 0x99, 0x15, 0xec, 0xf8, 0x2b, 0x98, 0x3c, 0x2a, - 0xd5, 0x59, 0x57, 0xbb, 0xa0, 0x14, 0x5f, 0x9, 0x7e, 0xd5, 0xbe, 0x0, - 0x99, 0x61, 0x7c, 0x8b, 0xdb, 0x94, 0xc6, 0x43, 0x7c, 0x13, 0xee, 0x1c, - 0xfa, 0x61, 0x2b, 0xd2, 0xc6, 0xa, 0xba, 0x30, 0x55, 0x50, 0x9a, 0xa1, - 0x14, 0x78, 0x97, 0x46, 0x6f, 0xe0, 0xa8, 0xd4, 0x3f, 0xf5, 0x39, 0xc8, - 0x1e, 0x4f, 0x3f, 0xc8, 0x67, 0x10, 0x25, 0x36, 0x8a, 0x8, 0x2, 0x67, - 0x6a, 0x73, 0x93, 0x76, 0x74, 0x54, 0x9, 0x87, 0xac, 0x9f, 0x90, 0x3, - 0xb6, 0xb4, 0x79, 0xa7, 0x56, 0x7f, 0x71, 0x9a, 0x41, 0xb0, 0xf4, 0xc7, - 0xbb, 0xd8, 0x68, 0xa7, 0xa, 0xfe, 0xe, 0x15, 0xe2, 0xcf, 0x2d, 0xd4, - 0x3, 0xee, 0x12, 0xa9, 0xef, 0x81, 0xa1, 0xa6, 0x12, 0x38, 0x6c, 0x37, - 0xd3, 0x11, 0xaa, 0x7, 0x8f, 0xfe, 0xb4, 0xf0, 0x92, 0x66, 0xfc, 0xa, - 0xc2, 0x21, 0xa3, 0x62, 0xec, 0xec, 0xda, 0x4f, 0xb3, 0xeb, 0x1d, 0x8c, - 0x1a, 0x7c, 0x58, 0x12, 0x30, 0x52, 0x1f, 0xf3, 0x90, 0xcf, 0x8e, 0xc5, - 0xd5, 0x5d, 0xe3, 0x92, 0xf3, 0x66, 0x7a, 0x1d, 0xea, 0x9c, 0x95, 0x91, - 0xe9, 0x13, 0x82, 0xe6, 0xea, 0x66, 0x3f, 0x31, 0xab, 0xb7, 0x46, 0x87, - 0x4d, 0xc4, 0x1a, 0x4a, 0x34, 0xfb, 0x0, 0x85, 0xd2, 0xa5, 0x18, 0xf3, - 0x50, 0x3f, 0x79, 0x5c, 0xe5, 0x5b, 0xc2, 0xcb, 0xd5, 0xa3, 0x63, 0x6f, - 0x11, 0xae, 0xf1, 0x5, 0xb1, 0x53, 0x8b, 0x65, 0x80, 0x8d, 0xd3, 0x98, - 0x1e, 0xba, 0xe4, 0xe1, 0x4f, 0xd0, 0x9c, 0x2, 0x6c, 0xd1, 0x6e, 0x18, - 0xce, 0xec, 0x10, 0x28, 0x29, 0xd8, 0xd2, 0xfa, 0x38, 0xb0, 0x3, 0xb7, - 0xc4, 0x99, 0xa7, 0x56, 0x24, 0xba, 0x70, 0xf3, 0x8, 0xae, 0x7f, 0xf4, - 0xb1, 0x84, 0xb5, 0xa8, 0xd7, 0x7a, 0xd8, 0x53, 0xde, 0x2d, 0xc9, 0xd3, - 0x27, 0x95, 0xe3, 0x5a, 0x11, 0xcc, 0xdf, 0x5b, 0x13, 0x36, 0x25, 0x92, - 0x49, 0x31, 0x1d, 0x83, 0x87, 0x61, 0x91, 0x9b, 0x18, 0xb, 0xc0, 0x6e, - 0xab, 0xfc, 0x73, 0x76, 0x92, 0xbc, 0x27, 0xc4, 0x37, 0x83, 0xb0, 0x80, - 0x71, 0x82, 0x17, 0x8c, 0x8f, 0x9e, 0x32, 0xb, 0x5a, 0x3d, 0x4d, 0xb1, - 0x24, 0x7, 0x91, 0x2a, 0x42, 0x43, 0xcc, 0xba, 0xbc, 0xee, 0x7f, 0x41, - 0x46, 0xcf, 0x5e, 0x85, 0xd7, 0x4d, 0xbc, 0x9, 0xe7, 0xbe, 0xab, 0x4d, - 0x63, 0x5c, 0xc7, 0x1a, 0x7f, 0x57, 0xf8, 0xd7, 0xbe, 0x50, 0x1, 0xa1, - 0xe, 0x27, 0x9a, 0xb2, 0x3f, 0x2a, 0xbc, 0x8f, 0x1b, 0x6a, 0xe0, 0x3e, - 0x5b, 0x97, 0x3f, 0x2b, 0xdb, 0x1e, 0x4f, 0x7, 0xbf, 0x29, 0x7b, 0x8e, - 0x2a, 0x64, 0x30, 0xbd, 0x1f, 0x53, 0xaa, 0x63, 0xad, 0x1d, 0x3e, 0xfd, - 0xd6, 0x6b, 0x32, 0x94, 0x84, 0xbe, 0x7e, 0x49, 0x72, 0x20, 0xec, 0xd4, - 0x63, 0xe7, 0xd, 0xbb, 0x3f, 0x70, 0x70, 0x43, 0x3a, 0xab, 0x6f, 0xb7, - 0x5b, 0x23, 0x7f, 0x23, 0xe, 0x36, 0xa2, 0xee, 0x72, 0xf9, 0x5d, 0x63, - 0x78, 0xfc, 0x19, 0x1e, 0x9c, 0x64, 0x87, 0xdb, 0xe6, 0x70, 0xd6, 0x60, - 0x1c, 0x3e, 0x38, 0x31, 0x94, 0xf4, 0xd9, 0x3f, 0xa1, 0x9c, 0x16, 0xae, - 0x80, 0x7b, 0x8d, 0x20, 0xa6, 0xf6, 0xd4, 0x37, 0x74, 0x44, 0x94, 0xaf, - 0x3c, 0x89, 0x8c, 0xdb, 0x3b, 0x96, 0x79, 0x15, 0xa, 0x2f, 0x1, 0xd, - 0x74, 0x99, 0x82, 0x51, 0x17, 0x97, 0x47, 0x68, 0x80, 0x55, 0x2d, 0x6c, - 0x11, 0x45, 0x5a, 0xee, 0x4a, 0xd6, 0x84, 0x76, 0x97, 0xad, 0x58, 0x40, - 0xf7, 0x15, 0x2f, 0xdc, 0x5c, 0x4a, 0x7b, 0x65, 0xc6, 0x20, 0x5a, 0x24, - 0xc5, 0xf4, 0xb0, 0x36, 0xb9, 0x61, 0xd, 0xbf, 0xe, 0x9f, 0x2d, 0x97, - 0xbb, 0x86, 0x5c, 0x40, 0x70, 0x86, 0x0, 0x4, 0x70, 0x66, 0x70, 0x65, - 0xdb, 0x39, 0x1d, 0x78, 0xd5, 0x7d, 0x92, 0xae, 0x0, 0x19, 0xef, 0x90, - 0x21, 0x92, 0x4, 0xcd, 0x22, 0x19, 0xa7, 0xc8, 0x3f, 0xa0, 0x38, 0x5b, - 0xfb, 0x46, 0x56, 0xd2, 0x11, 0xf1, 0xf9, 0x37, 0x53, 0xc, 0x98, 0x38, - 0x87, 0xc4, 0xed, 0x88, 0xf9, 0xc3, 0x6, 0x50, 0x19, 0x4b, 0xa8, 0x43, - 0x5f, 0xe5, 0xf, 0x79, 0x5f, 0x59, 0x22, 0x3c, 0x76, 0xdc, 0x51, 0x6d, - 0xb0, 0x2b, 0xf0, 0x95, 0x5c, 0xe4, 0x33, 0xb0, 0xff, 0xa3, 0xc8, 0xe0, - 0x85, 0xe0, 0x8a, 0xfe, 0xf, 0x63, 0x2d, 0x2b, 0x4a, 0x1a, 0xf9, 0xcb, - 0xb4, 0x86, 0x1, 0x1, 0xd4, 0x8f, 0x57, 0x82, 0xb0, 0xac, 0x52, 0x5d, - 0x5a, 0x79, 0x2c, 0x2d, 0x18, 0x1, 0x78, 0x3f, 0xb8, 0x31, 0x66, 0x9, - 0x61, 0x0, 0x8f, 0x4c, 0x4f, 0x18, 0x57, 0xc8, 0x39, 0x7, 0x44, 0x15, - 0xe4, 0x64, 0xed, 0x3c, 0xa2, 0x59, 0x38, 0x88, 0x13, 0xd0, 0x4c, 0xef, - 0xc6, 0x7, 0x37, 0x3, 0x81, 0xb1, 0x9, 0xce, 0xa6, 0x8e, 0x3b, 0x70, - 0x25, 0x87, 0xc4, 0x46, 0x60, 0x9a, 0xb5, 0xa8, 0xd3, 0x39, 0xd7, 0xa1, - 0xc8, 0x84, 0xa, 0x96, 0xe8, 0x73, 0x9, 0x1e, 0xb9, 0xde, 0x38, 0xc4, - 0x5, 0x60, 0x26, 0xc6, 0x51, 0x1b, 0x65, 0x66, 0x53, 0xd6, 0xa2, 0x2d, - 0x97, 0x5a, 0xb0, 0x9a, 0xb9, 0xf0, 0xcb, 0x7a, 0x94, 0xac, 0x9b, 0x9d, - 0xc3, 0x22, 0xf3, 0x44, 0x59, 0x13, 0x88, 0x18, 0x76, 0x26, 0x16, 0x67, - 0x85, 0x2a, 0x3d, 0x11, 0xc3, 0x69, 0x81, 0x9e, 0x96, 0x1e, 0x8, 0x23, - 0x9, 0x1a, 0x39, 0x44, 0xf2, 0x21, 0xd7, 0xa0, 0xc2, 0xb3, 0x6d, 0x42, - 0x6, 0xee, 0x6e, 0xf9, 0xad, 0x9c, 0x8c, 0x1, 0x6, 0xe6, 0x6, 0x19, - 0x7, 0xb1, 0x18, 0xdf, 0xe2, 0xa2, 0x97, 0x25, 0x32, 0x27, 0x1, 0x50, - 0xfc, 0xef, 0xa, 0x84, 0xd7, 0x43, 0x1b, 0xa2, 0xa0, 0x1e, 0x7e, 0x72, - 0x84, 0xce, 0xee, 0x25, 0x90, 0xcb, 0x47, 0xe3, 0xa0, 0xd1, 0x96, 0xbb, - 0xec, 0x95, 0x95, 0x73, 0xe7, 0xbc, 0x9c, 0xc5, 0x49, 0x8e, 0x71, 0x85, - 0x52, 0xf4, 0x27, 0x35, 0x89, 0xbb, 0x73, 0x78, 0xe2, 0xdb, 0xd8, 0xd2, - 0xe7, 0x92, 0xa3, 0x31, 0x22, 0x28, 0xf9, 0x56, 0x72, 0x9f, 0x3c, 0x72, - 0xda, 0x77, 0x5a, 0xd8, 0x9f, 0xc5, 0x75, 0xc6, 0xc5, 0xae, 0xb2, 0x33, - 0x40, 0x35, 0x71, 0x88, 0x11, 0xb0, 0xf1, 0xeb, 0xa0, 0x4d, 0xed, 0x46, - 0xd9, 0x6b, 0x8a, 0xf1, 0xcc, 0x36, 0x6d, 0x90, 0x58, 0x79, 0x7b, 0xad, - 0x81, 0xef, 0xd6, 0x39, 0xa3, 0xeb, 0x14, 0xd4, 0x82, 0x3a, 0x5a, 0x51, - 0x53, 0xf9, 0x9a, 0x54, 0x52, 0x76, 0xd, 0xa, 0xc3, 0x15, 0x87, 0x65, - 0x11, 0x38, 0x61, 0x83, 0x67, 0xd6, 0x6a, 0x9b, 0xbf, 0xf2, 0x1c, 0x65, - 0x7c, 0x58, 0xd9, 0x7f, 0x49, 0xa1, 0x63, 0x61, 0x17, 0xc9, 0x3d, 0x9a, - 0x26, 0xc0, 0xd3, 0x6a, 0x71, 0x95, 0xeb, 0x62, 0x26, 0xca, 0x14, 0x60, - 0x49, 0x32, 0xa, 0x5a, 0x8f, 0x29, 0x80, 0xc8, 0xfb, 0x6, 0xff, 0x1a, - 0x7e, 0x55, 0x65, 0x5c, 0x44, 0xc4, 0xa0, 0x72, 0xf0, 0xa1, 0xad, 0x4d, - 0xad, 0x3, 0xbe, 0x6e, 0xdb, 0x75, 0xd5, 0x6c, 0x5f, 0xaf, 0xa3, 0xaf, - 0xef, 0x62, 0x15, 0x49, 0x73, 0x87, 0x1, 0x78, 0xbc, 0xe, 0x85, 0xa2, - 0x81, 0xb4, 0xb5, 0xea, 0x65, 0xc0, 0x8c, 0xf2, 0x9b, 0x5a, 0x2c, 0x2f, - 0xcf, 0xd6, 0x9c, 0xdf, 0x74, 0x62, 0x68, 0x40, 0xf7, 0x30, 0xff, 0x96, - 0x9d, 0x66, 0x6c, 0x2d, 0x11, 0x7f, 0x90, 0x28, 0x16, 0xc7, 0xa5, 0x4a, - 0xe2, 0xd6, 0x5c, 0xdb, 0x97, 0xe7, 0xc6, 0x37, 0xe1, 0x5b, 0x7d, 0x4e, - 0xaa, 0x2b, 0x7f, 0xf5, 0x77, 0x20, 0x71, 0xec, 0xa9, 0x2f, 0x57, 0x6f, - 0xea, 0xb4, 0x43, 0x57, 0xc5, 0xee, 0xd8, 0xf6, 0xef, 0xf, 0xc, 0x6c, - 0x3c, 0xb2, 0x77, 0x83, 0x81, 0xaa, 0x8a, 0x2a, 0xc9, 0x9f, 0x2, 0xab, - 0xcc, 0x58, 0x3c, 0xb0, 0x42, 0x4, 0x1e, 0xe0, 0xf0, 0xf9, 0xa9, 0x2c, - 0xe8, 0x76, 0x5e, 0x39, 0xa0, 0xd6, 0xa8, 0x1, 0x56, 0x32, 0xc1, 0x27, - 0x96, 0xbe, 0x27, 0x5b, 0x74, 0xa7, 0x77, 0xf0, 0x6e, 0x2, 0xdf, 0x4a, - 0x5, 0x50, 0x2b, 0xf8, 0x73, 0xb0, 0x73, 0xce, 0xb8, 0xfa, 0xaf, 0xd2, - 0x9a, 0x2, 0x6d, 0xe0, 0x5d, 0x5e, 0x3, 0xff, 0x2d, 0x6a, 0xb0, 0xd6, - 0xa0, 0x1a, 0xd7, 0x77, 0x7, 0x27, 0xf8, 0x3f, 0xe0, 0x5, 0xe4, 0x42, - 0x18, 0xa4, 0xe9, 0xf0, 0xd7, 0xb4, 0xf1, 0x2b, 0x92, 0x76, 0x39, 0xb1, - 0x48, 0x62, 0xa3, 0xf, 0x95, 0x1c, 0x8a, 0xd, 0x79, 0xf6, 0x3d, 0x35, - 0x64, 0xa1, 0x66, 0x61, 0xa1, 0x38, 0xdd, 0x48, 0x5, 0xa4, 0x73, 0x59, - 0xca, 0x80, 0x57, 0x4a, 0x65, 0x73, 0x64, 0x5e, 0x9b, 0x7c, 0x85, 0x97, - 0x52, 0x89, 0x74, 0x79, 0x6f, 0x66, 0xe2, 0x3e, 0x69, 0x89, 0x78, 0xe3, - 0xee, 0x0, 0xae, 0x8e, 0xbd, 0x91, 0x76, 0xfe, 0x12, 0x7c, 0x2, 0x1d, - 0x55, 0x62, 0xba, 0x38, 0xf4, 0xba, 0x83, 0x18, 0xba, 0x9e, 0xa1, 0x15, - 0xdb, 0x7c, 0x56, 0xdb, 0x4f, 0xf3, 0x7a, 0xbe, 0xbd, 0x63, 0x61, 0x72, - 0xf2, 0x9d, 0x78, 0x4e, 0xa4, 0x22, 0xec, 0xfa, 0xa5, 0xf4, 0x3a, 0x5d, - 0xd9, 0x30, 0x3a, 0xd9, 0x3c, 0x88, 0xd8, 0x56, 0x59, 0xfb, 0xbd, 0xa6, - 0xe2, 0x37, 0x47, 0x7b, 0xf3, 0x6f, 0x3b, 0x8f, 0x81, 0xab, 0xbd, 0x95, - 0xe9, 0xaa, 0xfc, 0x33, 0xe4, 0x5e, 0x3, 0x9c, 0xb2, 0xfe, 0x6a, 0x7d, - 0xc, 0xcb, 0x17, 0x82, 0xfa, 0xb6, 0xf1, 0xa1, 0x6, 0x95, 0xda, 0x75, - 0xb8, 0x3f, 0x1, 0x49, 0x7d, 0x9, 0x8d, 0x7e, 0x8b, 0xa0, 0x73, 0xfc, - 0x37, 0x95, 0xa0, 0x4f, 0x2c, 0x37, 0x98, 0xd5, 0x76, 0xed, 0xd4, 0xc9, - 0xbd, 0x11, 0x63, 0x67, 0x5e, 0x8f, 0x85, 0x32, 0x57, 0x59, 0xd7, 0xaa, - 0xc8, 0x66, 0x61, 0xf, 0xea, 0x2b, 0x68, 0x57, 0xa8, 0x90, 0x29, 0x50, - 0xed, 0x78, 0xb6, 0xe, 0x5a, 0x6b, 0x15, 0x8d, 0xb7, 0xd5, 0x7d, 0x9, - 0x22, 0x54, 0x43, 0x96, 0x58, 0xa1, 0x2b, 0xe8, 0x89, 0x77, 0x3, 0xa6, - 0x18, 0xd7, 0xe7, 0x34, 0xe6, 0xe7, 0xbf, 0xae, 0x17, 0x27, 0x63, 0x10, - 0x1e, 0x4f, 0x97, 0x51, 0x28, 0x90, 0x11, 0x44, 0x8c, 0xe5, 0x15, 0xcb, - 0x3e, 0xa3, 0x6c, 0xc4, 0xfc, 0xa7, 0x5e, 0x54, 0x4a, 0x70, 0xc1, 0x31, - 0xf7, 0xd5, 0xed, 0xb0, 0xd1, 0x36, 0x1f, 0xfc, 0x49, 0x60, 0xe9, 0x88, - 0x3, 0x3d, 0xae, 0x7d, 0x4d, 0x55, 0x69, 0x62, 0xed, 0x16, 0x9a, 0xcc, - 0xf1, 0x8e, 0xf5, 0x86, 0xec, 0x60, 0x8c, 0x88, 0xa4, 0x6, 0xe4, 0xb8, - 0xdc, 0x35, 0xad, 0x2e, 0x13, 0xe, 0x7e, 0x90, 0x8c, 0x9f, 0xe5, 0xb1, - 0xa1, 0x9d, 0x1d, 0xa7, 0x4f, 0x94, 0x44, 0xc6, 0xe6, 0x45, 0xc2, 0x6, - 0x50, 0x96, 0xa0, 0x84, 0xca, 0x99, 0xc, 0xbf, 0x3c, 0x11, 0xf8, 0xb, - 0x74, 0x25, 0xf2, 0x91, 0xc9, 0x63, 0xe, 0xe4, 0x3c, 0x3b, 0xfd, 0xe8, - 0xe, 0xfb, 0x19, 0xe, 0x4b, 0x3c, 0x5d, 0x3f, 0x96, 0xa1, 0x76, 0x20, - 0x4c, 0x8d, 0x2a, 0x5f, 0xd2, 0x7c, 0x43, 0xf8, 0xb8, 0x49, 0x95, 0xad, - 0x6, 0xfa, 0x44, 0x4f, 0x72, 0x9, 0xa, 0x85, 0x3e, 0xca, 0xc0, 0x20, - 0x34, 0x6b, 0xc9, 0x3c, 0xa6, 0xad, 0xbe, 0xe4, 0x80, 0x40, 0x89, 0xee, - 0x87, 0x34, 0x22, 0xd1, 0xd0, 0x53, 0xb0, 0xb8, 0x65, 0xe6, 0x0, 0xb5, - 0x41, 0xfb, 0x6b, 0xeb, 0x6, 0x56, 0xd1, 0x83, 0x85, 0x1, 0x46, 0x6e, - 0x31, 0x43, 0xa2, 0x91, 0xe4, 0xcd, 0xa4, 0x43, 0x43, 0x8c, 0x26, 0xc, - 0xcb, 0x9b, 0xe1, 0x38, 0x42, 0xf1, 0xcd, 0x8f, 0x64, 0x3d, 0xd9, 0x4e, - 0x82, 0x80, 0x3, 0x16, 0xb5, 0x25, 0xc6, 0x6b, 0x5e, 0xfc, 0x5a, 0x97, - 0xe9, 0xa2, 0x24, 0x1e, 0xcd, 0x2d, 0xae, 0xca, 0x8, 0x4b, 0x29, 0x61, - 0xd1, 0xe6, 0xd, 0xc3, 0x98, 0x12, 0xf5, 0x23, 0xf8, 0x54, 0xcd, 0x51, - 0xec, 0x2e, 0x6c, 0x61, 0xdb, 0xa5, 0xaf, 0xf7, 0x48, 0x47, 0x27, 0x70, - 0xb3, 0xf6, 0xa3, 0x6e, 0x9c, 0xfb, 0x32, 0xd1, 0x23, 0x29, 0xe7, 0x43, - 0xa1, 0xa, 0x1, 0x3, 0xce, 0x45, 0x8d, 0x63, 0xd7, 0x23, 0x1d, 0xdb, - 0x3c, 0x66, 0xf9, 0x1e, 0x4b, 0x7f, 0x7, 0x3e, 0xd2, 0xd6, 0xf4, 0xcb, - 0xa2, 0x3a, 0xb2, 0x99, 0xd5, 0xc3, 0x53, 0x19, 0x79, 0xd9, 0x24, 0xe2, - 0x3e, 0xbd, 0x9e, 0x5, 0x3a, 0xa9, 0x67, 0x2c, 0x85, 0xdb, 0xd7, 0x17, - 0x9c, 0x59, 0xaa, 0xe6, 0x9f, 0x10, 0xb0, 0x2e, 0x20, 0x61, 0xcc, 0xf2, - 0x18, 0x88, 0xd0, 0x1c, 0x52, 0xc8, 0xab, 0x8c, 0x7a, 0x49, 0xee, 0x97, - 0x55, 0xf5, 0x48, 0x54, 0x4b, 0xbb, 0x11, 0xde, 0x8d, 0x26, 0x3f, 0x18, - 0x68, 0x15, 0xa7, 0x4c, 0x5c, 0x23, 0xf2, 0x74, 0x59, 0x4e, 0xca, 0x61, - 0x4c, 0x93, 0x7d, 0x84, 0x26, 0xf9, 0x13, 0x67, 0xc3, 0x76, 0xe5, 0x59, - 0x96, 0xab, 0xb, 0x23, 0x53, 0xef, 0x5, 0xae, 0x1, 0x2f, 0xe, 0xe5, - 0xc6, 0x2b, 0xc7, 0x73, 0xaa, 0x14, 0x48, 0xfe, 0x16, 0x97, 0xd5, 0xc8, - 0xbb, 0xd1, 0xb7, 0x5f, 0x70, 0xcc, 0xce, 0x49, 0x1b, 0x5d, 0x1a, 0xbb, - 0x6b, 0x93, 0xde, 0xdf, 0x98, 0x37, 0x9b, 0xcc, 0x4b, 0x35, 0xe0, 0xce, - 0xcb, 0x77, 0x29, 0x1e, 0x4d, 0x23, 0x42, 0x97, 0xa0, 0x4f, 0x7b, 0x95, - 0x44, 0x3d, 0x4f, 0x98, 0x32, 0x8, 0x77, 0xcd, 0xc5, 0x3f, 0xe5, 0xb6, - 0xc5, 0xf4, 0x50, 0x29, 0x71, 0x79, 0xca, 0x65, 0x80, 0x8c, 0xa7, 0xdc, - 0xcd, 0xbe, 0x57, 0x3a, 0xab, 0x75, 0x73, 0x38, 0x32, 0x20, 0x4b, 0xd8, - 0xe8, 0xed, 0xf, 0x6f, 0x8b, 0x47, 0xb4, 0x1a, 0xc3, 0x4e, 0x3c, 0x27, - 0xfc, 0x4a, 0x8a, 0xbd, 0x56, 0xe5, 0xc5, 0x6f, 0x47, 0x2e, 0xc1, 0x3e, - 0xf5, 0x82, 0x9a, 0x36, 0xc, 0xd0, 0x68, 0x17, 0x43, 0x93, 0xb1, 0xb2, - 0x11, 0xa0, 0x8f, 0xed, 0xc0, 0xca, 0x6c, 0x52, 0x92, 0x2e, 0x96, 0x86, - 0x90, 0x0, 0x37, 0x18, 0xf5, 0x66, 0xee, 0xa1, 0x3, 0x95, 0x1e, 0x16, - 0xa9, 0xe8, 0xce, 0xb4, 0x50, 0x16, 0x5b, 0xb0, 0x75, 0x8a, 0x99, 0xb0, - 0x29, 0x52, 0x9d, 0x1d, 0xe2, 0xa5, 0xfe, 0x38, 0x56, 0x61, 0x22, 0xb5, - 0x77, 0x9, 0xfc, 0x5f, 0x31, 0x2b, 0xa2, 0x83, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, - 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, - 0xda, 0x49, 0x65, 0xea, 0xd, 0xbe, 0xe2, 0x3e, 0xad, 0x5e, 0x7d, 0xf9, - 0x74, 0xac, 0xe9, 0xfd, 0xf3, 0x6f, 0x3, 0x3f, 0xaf, 0x80, 0xf8, 0x6a, - 0xdb, 0xcf, 0x1c, 0xc7, 0x93, 0x4, 0x9c, 0x1c, 0x66, 0xb8, 0xf2, 0x38, - 0x54, 0xa3, 0x3f, 0x85, 0xf4, 0x6e, 0x2f, 0xa9, 0x3d, 0xe2, 0xd7, 0x3, - 0xcc, 0x46, 0x13, 0x89, 0x85, 0xd1, 0xc6, 0xa2, 0xd4, 0x58, 0xb5, 0x4c, - 0x2c, 0xfc, 0x76, 0x2c, 0x7a, 0x51, 0xb3, 0xc9, 0xd7, 0x33, 0xe0, 0x64, - 0xd6, 0xfe, 0xab, 0xae, 0xaa, 0x72, 0x52, 0x91, 0xf1, 0x67, 0xfe, 0xd8, - 0x63, 0xb4, 0xec, 0x50, 0xbd, 0xe1, 0xe7, 0x61, 0xfd, 0xfb, 0x69, 0x9d, - 0x2d, 0xf2, 0xc1, 0x35, 0xed, 0x7a, 0x8e, 0x3b, 0x2e, 0xd9, 0x56, 0xf8, - 0xf2, 0xd2, 0x4f, 0x10, 0x0, 0x57, 0x75, 0x96, 0xce, 0x4e, 0x70, 0x71, - 0x7b, 0x98, 0x80, 0x7d, 0xe8, 0x51, 0xde, 0x79, 0xa0, 0xd9, 0xaa, 0xf3, - 0x2, 0x20, 0xee, 0x9c, 0x75, 0x8, 0x44, 0x79, 0xf, 0xd9, 0x29, 0xba, - 0x89, 0x2e, 0xac, 0x6f, 0xdf, 0xdd, 0x2d, 0x1a, 0xde, 0xf4, 0x7b, 0x52, - 0x0, 0xc1, 0x19, 0x6d, 0xae, 0x93, 0x22, 0x53, 0x6d, 0xe0, 0xe1, 0x96, - 0x8c, 0x6, 0xcb, 0x84, 0x73, 0xde, 0x37, 0xf7, 0x2d, 0xb, 0x8a, 0xca, - 0x15, 0xd0, 0x46, 0xa7, 0x33, 0x32, 0xea, 0xfe, 0x64, 0x11, 0x6e, 0x90, - 0x3b, 0xa, 0x81, 0x4, 0xbe, 0x1b, 0x13, 0x7a, 0xb3, 0xbe, 0x98, 0x35, - 0x22, 0x99, 0x66, 0x75, 0x75, 0x87, 0x66, 0x4, 0x1c, 0xec, 0x8d, 0x90, - 0xc3, 0xe4, 0x8c, 0x7f, 0x1e, 0x60, 0x18, 0xff, 0x2, 0x80, 0xdf, 0x21, - 0x87, 0x32, 0x8, 0x71, 0xd3, 0xf5, 0xfa, 0x21, 0x10, 0x15, 0x38, 0x9a, - 0xd9, 0x1a, 0x28, 0xae, 0xd5, 0xaf, 0xba, 0x40, 0xe9, 0xa5, 0x73, 0x48, - 0xbf, 0xc, 0xf0, 0x60, 0xc0, 0x1f, 0x88, 0xa, 0x7d, 0x22, 0x57, 0x68, - 0xff, 0x4e, 0xb, 0x4, 0x86, 0x80, 0x4d, 0x5a, 0x88, 0x4c, 0x54, 0xb7, - 0x5b, 0x6d, 0x1c, 0xe5, 0xe8, 0xeb, 0x74, 0x20, 0xf6, 0x7e, 0x51, 0x44, - 0x16, 0x1a, 0x9a, 0xe8, 0x11, 0x5c, 0xd0, 0xa, 0xf9, 0x58, 0xa0, 0xcf, - 0x41, 0x98, 0x6a, 0x4d, 0x5b, 0x6b, 0xca, 0x9a, 0xe3, 0x2a, 0xd1, 0xe5, - 0x74, 0xb6, 0xe1, 0x9b, 0xb9, 0x45, 0xdb, 0xeb, 0x15, 0x71, 0xdb, 0x29, - 0x92, 0xc3, 0x9f, 0xdf, 0xb9, 0x7, 0x3f, 0x4f, 0xe9, 0x96, 0x11, 0x94, - 0x5e, 0x40, 0x4b, 0x74, 0x2c, 0x9c, 0x8a, 0x5c, 0x44, 0x4d, 0x1c, 0x54, - 0x47, 0x40, 0x4a, 0xa6, 0xdf, 0x43, 0x6b, 0xa1, 0x6a, 0x4d, 0xe4, 0x84, - 0x7b, 0x18, 0x7f, 0x84, 0x76, 0x2f, 0xd6, 0x57, 0x70, 0xe1, 0xa, 0xf6, - 0xb5, 0xc6, 0xe2, 0xf7, 0x31, 0x4f, 0xde, 0xa4, 0x2c, 0x35, 0x33, 0xb1, - 0x77, 0x39, 0xb7, 0xac, 0xe5, 0xf6, 0x59, 0x74, 0x7, 0xb9, 0x8, 0xf9, - 0x5c, 0x9e, 0x13, 0x7, 0x23, 0x81, 0x60, 0xf9, 0xa, 0xf3, 0x41, 0xbb, - 0x8a, 0x72, 0xdb, 0x99, 0x47, 0x4a, 0x86, 0xc0, 0x9, 0x8f, 0xf9, 0x8a, - 0xf5, 0xdf, 0x73, 0x34, 0xa9, 0x88, 0xf6, 0x79, 0x12, 0xbe, 0x50, 0xc5, - 0x4, 0x79, 0x35, 0x24, 0xe9, 0x71, 0x4f, 0xef, 0x13, 0xeb, 0x54, 0x94, - 0x9c, 0x20, 0x68, 0x81, 0xa9, 0x33, 0xac, 0xe6, 0xa7, 0x4b, 0x3f, 0x52, - 0x67, 0xab, 0x1a, 0xd6, 0x78, 0x2b, 0xd0, 0x8d, 0x98, 0x2f, 0x90, 0xaa, - 0xe5, 0x80, 0x5d, 0x1f, 0xa9, 0x33, 0x7, 0x5a, 0xe5, 0x2d, 0x5a, 0xa2, - 0x28, 0x84, 0x83, 0x7, 0xb7, 0xfd, 0x84, 0xc7, 0x6d, 0x53, 0xd4, 0x46, - 0xc2, 0xc6, 0x24, 0xbe, 0xe2, 0x25, 0xcf, 0x24, 0x5b, 0x3e, 0x39, 0xcb, - 0xbb, 0x7a, 0x3b, 0x2e, 0xc, 0x92, 0x68, 0x30, 0xa6, 0xe0, 0x69, 0xd5, - 0x1d, 0x6c, 0x95, 0x7b, 0xe2, 0x48, 0x10, 0xed, 0x1e, 0xbd, 0x10, 0x14, - 0x25, 0x41, 0xd7, 0x1b, 0xf2, 0x74, 0x12, 0x2c, 0x17, 0xd6, 0x36, 0x65, - 0x1, 0x3e, 0x87, 0x11, 0x90, 0x8e, 0x12, 0x71, 0xb2, 0xd1, 0x37, 0xda, - 0xa2, 0x5d, 0x80, 0x64, 0x32, 0x8e, 0x37, 0x3a, 0x8e, 0x4c, 0xbb, 0x40, - 0xe3, 0x1a, 0x73, 0x83, 0xb0, 0x82, 0x2d, 0x5e, 0x48, 0x20, 0xd2, 0xaf, - 0x0, 0x55, 0xff, 0x56, 0x7e, 0x8e, 0xb3, 0x6b, 0xc4, 0x11, 0x40, 0x17, - 0x25, 0x76, 0x35, 0xc, 0x9d, 0x3d, 0xe2, 0xea, 0x7, 0xec, 0xe2, 0xe3, - 0xd4, 0x10, 0xda, 0xf6, 0xb5, 0xe8, 0xf6, 0x7a, 0xb7, 0xe1, 0x38, 0x65, - 0x27, 0x97, 0x2b, 0x5a, 0x4, 0x1b, 0xd2, 0x21, 0xea, 0x5b, 0x9f, 0x5b, - 0xdf, 0xca, 0xd1, 0xad, 0x47, 0x25, 0xd, 0xed, 0xbb, 0xca, 0x6d, 0x45, - 0x29, 0x6d, 0xb7, 0xef, 0x70, 0x2b, 0x79, 0xc2, 0x29, 0x83, 0x75, 0xdb, - 0xa5, 0x60, 0xcd, 0x6f, 0x1a, 0xd4, 0xad, 0x6f, 0x8a, 0x51, 0xfb, 0x92, - 0x62, 0xd4, 0x97, 0x41, 0x8a, 0xb8, 0x79, 0x2a, 0x95, 0x14, 0x9, 0x95, - 0x6b, 0x7f, 0xf, 0xfb, 0xf5, 0x0, 0xf, 0x25, 0xc3, 0x81, 0xb, 0x81, - 0xa3, 0x5e, 0x29, 0xc5, 0x9c, 0xd1, 0x45, 0xff, 0xfc, 0x80, 0x24, 0x75, - 0xa1, 0x33, 0xd5, 0x6e, 0x8b, 0x85, 0x39, 0x93, 0x8f, 0x7c, 0xd0, 0x7e, - 0x39, 0xde, 0xdf, 0x93, 0x28, 0x4f, 0xf3, 0xe6, 0x41, 0xcf, 0x85, 0x32, - 0x82, 0xe5, 0x65, 0x52, 0xff, 0x37, 0x79, 0x54, 0x2, 0x47, 0x63, 0x1a, - 0xd4, 0xf0, 0xcf, 0x5, 0x11, 0xbd, 0x8c, 0x4, 0x47, 0xfe, 0xa2, 0x34, - 0x32, 0xda, 0x82, 0xfd, 0xe6, 0x3f, 0x7a, 0x1c, 0x5c, 0x43, 0x6d, 0x4c, - 0xa2, 0xad, 0x33, 0x15, 0x2d, 0xd4, 0xbd, 0xdf, 0x97, 0xa2, 0x1a, 0x3b, - 0x89, 0x3c, 0xd5, 0x19, 0x7d, 0x24, 0x13, 0xa, 0xeb, 0xd7, 0x66, 0x79, - 0xc5, 0x61, 0xea, 0x4c, 0x2d, 0x6d, 0xca, 0xea, 0x81, 0x81, 0x29, 0x88, - 0xaf, 0xcd, 0x3b, 0xff, 0xba, 0x1a, 0xe6, 0x60, 0x8, 0xdb, 0x17, 0x3e, - 0x37, 0xc2, 0xb8, 0x39, 0x91, 0x18, 0x74, 0xa4, 0xe0, 0x5f, 0xf1, 0x8d, - 0x7d, 0x30, 0x7d, 0xac, 0x3a, 0x2b, 0x80, 0x4e, 0x7e, 0xe0, 0x25, 0x39, - 0xeb, 0x0, 0xe1, 0x52, 0xe1, 0xa1, 0x31, 0x2d, 0x3c, 0xf1, 0xe3, 0xfd, - 0xa3, 0xf6, 0x3, 0xec, 0xf3, 0x0, 0x7a, 0x55, 0xe3, 0x21, 0x19, 0xea, - 0x5a, 0xb5, 0x7b, 0xc9, 0xdb, 0xa5, 0x3b, 0x9e, 0x62, 0xd5, 0x2f, 0x2a, - 0xbb, 0xae, 0x86, 0x61, 0xff, 0x45, 0x91, 0xce, 0x92, 0x51, 0x24, 0x8b, - 0x9c, 0x49, 0x2a, 0xbd, 0xa4, 0x54, 0x80, 0xa6, 0xe6, 0x88, 0xe, 0x40, - 0x95, 0xe4, 0x9e, 0xd0, 0xd3, 0x42, 0x3b, 0xda, 0xe5, 0xf, 0x11, 0x0, - 0x55, 0x69, 0xe1, 0xba, 0x65, 0x1a, 0x6f, 0x9f, 0x64, 0x76, 0xdc, 0xa5, - 0xc6, 0x32, 0xe8, 0x80, 0x6d, 0x10, 0xa7, 0x21, 0xdf, 0x35, 0xb1, 0xbe, - 0x2c, 0xf9, 0xa6, 0xcc, 0x2e, 0xe5, 0xeb, 0x6c, 0x10, 0xf7, 0x85, 0xd9, - 0xac, 0xd3, 0x4c, 0x5c, 0xe5, 0xc0, 0x3b, 0xcf, 0x27, 0x8f, 0xde, 0xc2, - 0x4e, 0xd6, 0x94, 0x58, 0xea, 0x37, 0xaa, 0x3b, 0x21, 0x38, 0x1e, 0x5d, - 0x3d, 0xa7, 0xe3, 0x3c, 0x5e, 0x2b, 0x45, 0x81, 0x22, 0x55, 0x66, 0xcf, - 0xfd, 0x5b, 0xec, 0xc6, 0xd1, 0x9f, 0xa9, 0x4c, 0x4, 0xe4, 0x33, 0x36, - 0xa3, 0xd6, 0x4d, 0x8c, 0xd3, 0xe9, 0xe9, 0x5c, 0xc2, 0xff, 0x75, 0x2c, - 0x4c, 0x87, 0x4f, 0x6b, 0xb9, 0x96, 0xa, 0x8c, 0x4d, 0x44, 0x8, 0x9e, - 0x3d, 0x2f, 0x8, 0xca, 0x84, 0x33, 0x38, 0x2a, 0xcf, 0xf, 0x69, 0xe, - 0x2d, 0xd3, 0xad, 0x2d, 0xe, 0xdb, 0x79, 0x6c, 0x85, 0xf2, 0x13, 0xc8, - 0xf2, 0x97, 0x7e, 0x8d, 0x40, 0xb6, 0x10, 0x52, 0x58, 0xd0, 0xec, 0x50, - 0xc7, 0x38, 0x68, 0xad, 0xfb, 0x27, 0xb6, 0xde, 0x96, 0x8c, 0x4, 0x97, - 0xb1, 0x39, 0x6c, 0x1b, 0xe8, 0xfb, 0x4b, 0x37, 0xc2, 0xa4, 0x61, 0xc8, - 0x71, 0xee, 0x49, 0x8c, 0x12, 0x59, 0xbf, 0x46, 0x78, 0xe, 0x8d, 0x4d, - 0xd5, 0x1c, 0x57, 0x1c, 0x38, 0x2, 0xd2, 0x1b, 0x8a, 0xe3, 0x7b, 0x65, - 0x1e, 0xf8, 0x77, 0xa0, 0xb4, 0xbd, 0x1a, 0x29, 0xee, 0x8b, 0xc2, 0xa5, - 0x34, 0x82, 0x44, 0x9c, 0x4a, 0x7f, 0xc1, 0x28, 0x9e, 0xc6, 0x42, 0xca, - 0xaf, 0xeb, 0x19, 0xd7, 0x77, 0xf1, 0x60, 0xfa, 0x17, 0xf, 0x82, 0x97, - 0xcd, 0xe0, 0x11, 0x56, 0xe0, 0x85, 0x8a, 0x5f, 0xc, 0x1d, 0xe6, 0x66, - 0x2b, 0xfe, 0x3f, 0x42, 0x45, 0x91, 0x1c, 0xda, 0xf3, 0xe2, 0xea, 0x4b, - 0xe5, 0x18, 0x3a, 0xb2, 0x2b, 0x5f, 0x3e, 0x74, 0x97, 0xff, 0x4e, 0x95, - 0xbc, 0xa6, 0x66, 0x24, 0xb5, 0x15, 0x18, 0xd8, 0x2e, 0x33, 0x12, 0x27, - 0x16, 0xa2, 0xe5, 0x3d, 0xf, 0x38, 0xc3, 0x75, 0x40, 0xc, 0x94, 0x67, - 0x65, 0xf, 0x6b, 0x78, 0x69, 0xa1, 0x61, 0xb7, 0xf, 0xf2, 0x61, 0x29, - 0x83, 0x4e, 0x34, 0xc6, 0xc0, 0x3b, 0xe8, 0x5d, 0x8c, 0x81, 0xe4, 0x81, - 0x18, 0xdf, 0x3c, 0xd1, 0x6e, 0x7e, 0x7c, 0xf3, 0x76, 0xb4, 0x79, 0x49, - 0x7, 0xc1, 0x83, 0xb6, 0x86, 0x26, 0x70, 0x57, 0x2, 0xfc, 0xa1, 0xcc, - 0xa6, 0x4b, 0xac, 0x7e, 0x9e, 0x3c, 0xf, 0xa7, 0xe4, 0xb, 0x58, 0xcb, - 0x13, 0xb7, 0x4, 0xec, 0xd2, 0xa8, 0xb2, 0x53, 0x32, 0x2c, 0x8a, 0x70, - 0xfb, 0xec, 0xa4, 0xde, 0xf3, 0xbd, 0x4b, 0xbd, 0x86, 0x72, 0x96, 0x4b, - 0x94, 0x8c, 0x5a, 0x47, 0x4a, 0x46, 0xda, 0xb9, 0xe, 0x16, 0x63, 0x85, - 0x9f, 0xdf, 0xa4, 0xef, 0x82, 0x78, 0x68, 0x0, 0xd7, 0x4f, 0x2, 0x37, - 0x67, 0x7a, 0x33, 0x51, 0x3f, 0xd6, 0x29, 0x99, 0xa3, 0x63, 0x7, 0x82, - 0x2b, 0x12, 0xe5, 0xa0, 0xb6, 0x2a, 0xc4, 0x28, 0xee, 0xac, 0xd2, 0xd2, - 0x39, 0x62, 0x37, 0xf6, 0x3e, 0x91, 0xd1, 0x14, 0x89, 0xea, 0x52, 0xc8, - 0x62, 0xc7, 0xb, 0x9f, 0x9b, 0x81, 0x9d, 0x18, 0x1e, 0x3f, 0x70, 0x5b, - 0x6c, 0x34, 0x33, 0x21, 0x23, 0xba, 0x6f, 0xed, 0x28, 0x63, 0x53, 0x4, - 0x72, 0x85, 0xa3, 0x16, 0xc0, 0xd2, 0x81, 0xfe, 0x67, 0x22, 0x3, 0x9, - 0xd8, 0xbf, 0x94, 0x4, 0x6c, 0xc4, 0x43, 0x27, 0x5d, 0x36, 0xe0, 0x6d, - 0x4e, 0xec, 0xa5, 0x54, 0xb4, 0x7d, 0xd4, 0xb0, 0xce, 0x47, 0x67, 0x8c, - 0x81, 0x19, 0x42, 0x48, 0x83, 0x43, 0x3c, 0x14, 0xe8, 0x41, 0xd, 0xe, - 0xa7, 0xdc, 0xa7, 0x7e, 0x78, 0x6d, 0xe3, 0xc3, 0x9c, 0xf0, 0xb8, 0xf6, - 0x16, 0xc7, 0xfd, 0xef, 0xe2, 0x59, 0xc, 0xda, 0x46, 0x58, 0x6a, 0x33, - 0xdf, 0x4d, 0xc7, 0x1b, 0x89, 0xca, 0xd3, 0xe1, 0xc6, 0x24, 0xcf, 0x83, - 0x99, 0xa4, 0xf4, 0xd2, 0x55, 0xff, 0x47, 0x94, 0xfe, 0xb2, 0xdc, 0x6f, - 0xb7, 0x47, 0x3b, 0xfc, 0xdc, 0xa2, 0x92, 0x87, 0xbc, 0xc0, 0x15, 0x6, - 0xbf, 0xd0, 0x99, 0xa4, 0x2b, 0x38, 0xdb, 0xae, 0xe, 0x77, 0x9c, 0xa1, - 0xc, 0x76, 0xec, 0xbf, 0x34, 0x9f, 0x8f, 0x11, 0xc8, 0xb9, 0x6e, 0xf5, - 0xdf, 0xf0, 0x47, 0x1e, 0xf0, 0x8e, 0x41, 0x1b, 0xb5, 0x85, 0xdd, 0x50, - 0xf6, 0xdf, 0x84, 0x8e, 0x8c, 0x4, 0x9e, 0x1c, 0x7, 0xe3, 0x70, 0x37, - 0xc2, 0xb2, 0x6f, 0x9a, 0x4f, 0xb7, 0x92, 0xcf, 0xc2, 0x51, 0x5f, 0xd4, - 0x7, 0xc, 0xc5, 0x61, 0x1b, 0x6a, 0x2e, 0x4c, 0x76, 0x78, 0x69, 0x47, - 0x97, 0x0, 0xa, 0x5, 0x3e, 0xef, 0xeb, 0x25, 0xd9, 0x3e, 0x17, 0xf7, - 0x98, 0xea, 0xc, 0xa7, 0x14, 0x5, 0x1f, 0x21, 0x4a, 0x21, 0xef, 0x36, - 0x95, 0xcd, 0xed, 0xda, 0x95, 0x69, 0x7f, 0x62, 0x7e, 0x6c, 0xb4, 0x89, - 0x54, 0xe9, 0x95, 0x0, 0x1d, 0xa4, 0xa1, 0x18, 0xfb, 0x35, 0xf6, 0x3b, - 0xe0, 0x2a, 0x3f, 0x86, 0x6e, 0x21, 0xc7, 0xb5, 0x2c, 0xa4, 0x8c, 0xc, - 0x87, 0xb6, 0xb7, 0x1c, 0xa, 0xf6, 0x4a, 0x47, 0x88, 0x18, 0x88, 0x5, - 0x1e, 0x40, 0xee, 0xe9, 0xc3, 0x10, 0x9c, 0x9a, 0xd5, 0xdb, 0x8b, 0x13, - 0xa8, 0x24, 0x5c, 0xd0, 0xc9, 0x29, 0x3f, 0xa, 0x90, 0x6d, 0x92, 0x7d, - 0x24, 0xad, 0x64, 0x7f, 0xf1, 0x6, 0x7e, 0x31, 0xb8, 0x7, 0xac, 0x8d, - 0xf7, 0x50, 0x46, 0x79, 0x63, 0x50, 0xa4, 0x66, 0xb3, 0x86, 0xa0, 0xb2, - 0xa4, 0x29, 0x66, 0x13, 0x1f, 0xea, 0x9b, 0x12, 0xf1, 0x13, 0x31, 0x18, - 0x3c, 0x4c, 0x2d, 0xff, 0x29, 0xe5, 0x27, 0xb3, 0xcf, 0xcc, 0xfe, 0x21, - 0xde, 0x54, 0xc5, 0xcf, 0xdd, 0x4f, 0x28, 0x7e, 0x7a, 0xcb, 0x8, 0x4f, - 0x84, 0x9b, 0xb4, 0x91, 0x28, 0x2c, 0x67, 0xee, 0xfd, 0xed, 0x58, 0xc0, - 0xda, 0xc5, 0x23, 0xed, 0xd7, 0xa0, 0x68, 0xf4, 0xc7, 0xd0, 0xd9, 0x33, - 0xa2, 0xd5, 0x78, 0x94, 0x91, 0x1f, 0x12, 0x12, 0xef, 0x8f, 0xdd, 0xd0, - 0x77, 0x6c, 0x50, 0xd7, 0xd5, 0x1b, 0xde, 0x2, 0xaf, 0x63, 0x91, 0xb5, - 0xce, 0xa2, 0x2c, 0x35, 0xf0, 0x21, 0xf3, 0xca, 0x3a, 0xe2, 0xc8, 0xa3, - 0x8d, 0x10, 0x95, 0x40, 0xfb, 0x2f, 0xbd, 0x50, 0x93, 0x8b, 0xa2, 0x75, - 0x82, 0xcd, 0xf8, 0x8f, 0x42, 0x64, 0x1a, 0xed, 0x59, 0x8c, 0xb1, 0x86, - 0xb6, 0xc8, 0x99, 0xed, 0x13, 0x86, 0x9, 0xfd, 0x2d, 0x21, 0x51, 0x90, - 0xac, 0x34, 0x2f, 0xe5, 0x2d, 0xb, 0xbc, 0xec, 0x99, 0x45, 0xde, 0xef, - 0xb2, 0xfd, 0xca, 0xc5, 0xdc, 0x47, 0xb2, 0xd6, 0xf6, 0x13, 0x4, 0x16, - 0x50, 0x1c, 0xf7, 0x24, 0xc7, 0xb4, 0x75, 0xdf, 0x21, 0x26, 0xbb, 0x41, - 0x8c, 0x4f, 0xe, 0xaa, 0x5c, 0x3a, 0x5f, 0xa4, 0x31, 0x58, 0xab, 0x58, - 0xb9, 0xce, 0x8, 0x32, 0xa0, 0xbc, 0xbc, 0x7f, 0x6, 0x75, 0x65, 0xed, - 0x2d, 0x9, 0x9b, 0xbe, 0xea, 0xf9, 0x21, 0x5d, 0xca, 0x1d, 0x98, 0x8c, - 0xc0, 0x50, 0xf4, 0x91, 0xec, 0x54, 0xf, 0xe7, 0x34, 0x67, 0x5f, 0x41, - 0xbf, 0x60, 0xd8, 0xcf, 0x37, 0xc0, 0x5f, 0x46, 0x9e, 0x2b, 0x3c, 0xda, - 0xcf, 0x1, 0x24, 0xd3, 0xe9, 0x49, 0x3f, 0x64, 0x5b, 0x41, 0xe4, 0x3f, - 0x7c, 0xb0, 0xad, 0xf, 0xe7, 0x90, 0x32, 0x65, 0xd0, 0x46, 0xb9, 0x55, - 0x22, 0xdb, 0xc0, 0xdf, 0xce, 0x63, 0x9b, 0xbe, 0xc9, 0xf9, 0x6b, 0x35, - 0x63, 0x75, 0xc3, 0x80, 0x6d, 0x66, 0xaf, 0x3b, 0x8a, 0x1e, 0x55, 0x74, - 0x23, 0xbc, 0xb9, 0x6b, 0x72, 0x8, 0x19, 0xa, 0x8b, 0x73, 0xc1, 0x92, - 0x34, 0x1, 0xba, 0x3b, 0xa4, 0xa2, 0x76, 0x2a, 0x35, 0xd6, 0xe0, 0x16, - 0xa8, 0x7f, 0xa8, 0xdc, 0xf, 0x93, 0x85, 0x8b, 0xc9, 0xa7, 0x98, 0x2a, - 0xf9, 0x91, 0x9a, 0x2a, 0x50, 0x2, 0x7e, 0x44, 0xa8, 0x10, 0xc5, 0x93, - 0x1b, 0xbe, 0xb1, 0xa7, 0x45, 0x3c, 0xb4, 0x5e, 0xe0, 0x4f, 0x39, 0x48, - 0xa3, 0x74, 0x2, 0x6d, 0xc7, 0x1a, 0x79, 0xb5, 0x8b, 0xb7, 0x14, 0x88, - 0x4c, 0xaf, 0x64, 0x3f, 0x70, 0xf8, 0xb6, 0xa0, 0xcc, 0x2, 0xd6, 0x75, - 0xfc, 0x75, 0x72, 0x12, 0x9d, 0x27, 0x1d, 0x75, 0x33, 0x25, 0xb1, 0x14, - 0xc, 0x66, 0xc6, 0x7a, 0x9e, 0xde, 0x26, 0xbb, 0x6e, 0xe, 0x25, 0xd2, - 0xf1, 0xe6, 0x8d, 0x85, 0x64, 0x75, 0xb7, 0xe8, 0x96, 0x84, 0xe, 0x8f, - 0x25, 0x24, 0x12, 0x41, 0x52, 0xdb, 0xa6, 0x7, 0x44, 0x60, 0x91, 0xd1, - 0xee, 0x9e, 0x19, 0x4c, 0xfc, 0x4a, 0x69, 0x97, 0x27, 0xc1, 0x7c, 0x32, - 0x19, 0x4b, 0x21, 0xe5, 0xc7, 0x38, 0x42, 0x86, 0x90, 0x47, 0x5c, 0xdc, - 0x73, 0xff, 0x5f, 0xba, 0xc1, 0xf4, 0x26, 0xa0, 0x38, 0xa5, 0xdb, 0x41, - 0x76, 0x49, 0x5, 0x58, 0xa8, 0xe8, 0xf9, 0x6, 0x57, 0x6d, 0xd4, 0x8e, - 0x86, 0x5a, 0xc1, 0xd8, 0x8f, 0x7b, 0xa6, 0x4b, 0xe5, 0xff, 0xd7, 0x6c, - 0x4d, 0x9f, 0x51, 0xa9, 0xdf, 0xe9, 0xe6, 0x91, 0xf, 0xe9, 0x13, 0xd1, - 0x7e, 0x28, 0x67, 0x1b, 0xb0, 0xac, 0x88, 0x25, 0xc3, 0x17, 0x6c, 0xde, - 0x6e, 0x88, 0xa8, 0x65, 0xb8, 0xd5, 0xf0, 0x40, 0x85, 0xc4, 0x52, 0x79, - 0x8c, 0x19, 0xe7, 0x33, 0x3a, 0x76, 0x34, 0x2d, 0x4c, 0x77, 0xc1, 0x3, - 0xc0, 0x11, 0xc1, 0x2f, 0x9c, 0xa0, 0x19, 0x51, 0x5f, 0x5, 0x9e, 0xfe, - 0x3b, 0x88, 0x5f, 0x59, 0x24, 0xb9, 0x8, 0x97, 0x44, 0xee, 0x56, 0xa8, - 0x12, 0xd6, 0x80, 0x9c, 0x51, 0xa3, 0x12, 0xaf, 0x47, 0xc4, 0x73, 0x8b, - 0x55, 0xc0, 0x4b, 0xe7, 0xf0, 0x4, 0x47, 0xeb, 0x5e, 0xad, 0xee, 0x64, - 0x83, 0xcd, 0xaa, 0x9, 0x57, 0x8f, 0x9, 0xae, 0x31, 0x70, 0x90, 0x49, - 0x61, 0xd7, 0x7, 0xf4, 0x8, 0xb0, 0xe9, 0xff, 0xfe, 0x8f, 0x9c, 0x6f, - 0xf7, 0x3, 0x11, 0xf5, 0x74, 0xe4, 0xd3, 0x84, 0xf6, 0x10, 0x58, 0xdf, - 0x17, 0xc9, 0x2e, 0x30, 0xcd, 0x1b, 0xe4, 0xab, 0x53, 0x43, 0x13, 0xb8, - 0x49, 0x54, 0x7a, 0xd9, 0xe7, 0xc8, 0xe7, 0xa9, 0xe1, 0xb6, 0x87, 0xa6, - 0x45, 0xcb, 0x5d, 0x21, 0xd7, 0xa4, 0x37, 0xc, 0x95, 0x70, 0xd8, 0x11, - 0x15, 0x41, 0x3a, 0xee, 0x92, 0xe7, 0xfc, 0x9, 0x19, 0x18, 0xcc, 0xe0, - 0x85, 0x2f, 0x55, 0xe5, 0x7d, 0x5e, 0x33, 0x3a, 0x21, 0x2c, 0xa5, 0x95, - 0x95, 0xc8, 0x55, 0xe4, 0x21, 0x18, 0x43, 0xb7, 0x98, 0x4, 0x6d, 0xb4, - 0x3a, 0x87, 0x5f, 0xc9, 0xc0, 0x6c, 0xf5, 0x2a, 0x7c, 0xb4, 0xd5, 0x16, - 0x63, 0x5c, 0xed, 0xb3, 0x82, 0xf6, 0x71, 0x2d, 0xd5, 0x82, 0x28, 0x5c, - 0x7f, 0x2e, 0x1a, 0xdd, 0xa5, 0x22, 0x89, 0x77, 0x3a, 0xba, 0x30, 0xa6, - 0x1c, 0xb3, 0x2, 0x64, 0x52, 0xf8, 0xd9, 0x6f, 0xd0, 0xab, 0xbe, 0x39, - 0x65, 0xb6, 0x5e, 0x51, 0x28, 0xec, 0x4, 0xc, 0x66, 0x7, 0x73, 0xc4, - 0x74, 0xe3, 0xc4, 0xb0, 0x7e, 0x97, 0x4d, 0xe4, 0x4c, 0x83, 0x5a, 0x61, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, - 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, - 0x94, 0x23, 0x34, 0xaa, 0x29, 0xa0, 0x98, 0xd7, 0xc3, 0x15, 0xf2, 0xab, - 0xe, 0xc2, 0x5c, 0xff, 0x19, 0xeb, 0xa6, 0x5a, 0x79, 0x8d, 0xd7, 0x68, - 0xd2, 0x75, 0xc2, 0x4a, 0xc3, 0x9d, 0xd1, 0xba, 0xaf, 0x15, 0x12, 0xeb, - 0x87, 0xab, 0xc2, 0xaf, 0x45, 0xa3, 0x15, 0x8f, 0x47, 0x85, 0x13, 0xfc, - 0xb2, 0x90, 0x5, 0xac, 0x30, 0xa0, 0x6b, 0x93, 0xb5, 0x93, 0xcb, 0x4b, - 0x8c, 0xb9, 0x30, 0x56, 0x57, 0xa0, 0xfb, 0xba, 0x1e, 0xfb, 0x46, 0xac, - 0xe5, 0xa1, 0x7b, 0xf1, 0xf4, 0xfd, 0xf7, 0x92, 0xa3, 0x38, 0x5, 0x4a, - 0x2b, 0x67, 0x91, 0xd, 0x48, 0xf6, 0x5a, 0xf, 0x68, 0xeb, 0xb4, 0xfa, - 0x12, 0xd, 0x6d, 0x62, 0x3c, 0xcc, 0x92, 0x40, 0x5a, 0x74, 0x2f, 0xad, - 0xf0, 0x18, 0x66, 0x71, 0xc7, 0xcd, 0xd3, 0xde, 0x7b, 0x56, 0x53, 0x95, - 0x5, 0xae, 0x8, 0x44, 0xe2, 0xe0, 0xfd, 0x6c, 0x6f, 0xa0, 0xc1, 0x81, - 0xcf, 0x45, 0x41, 0x90, 0x7, 0x1, 0xd9, 0x74, 0x2c, 0x5, 0x56, 0x98, - 0x2e, 0x82, 0x89, 0xeb, 0xfc, 0xe, 0xd3, 0x14, 0x96, 0x38, 0xe0, 0x85, - 0xac, 0x77, 0xf, 0x2e, 0xdc, 0xaf, 0x8f, 0x19, 0xa2, 0x31, 0x72, 0xe9, - 0xe3, 0xc1, 0x8e, 0xb9, 0xff, 0x7d, 0xb9, 0x28, 0x8d, 0x3d, 0x51, 0xeb, - 0x43, 0xef, 0x4c, 0x0, 0xde, 0xb8, 0x36, 0xe8, 0x2e, 0xcb, 0x39, 0xba, - 0xcd, 0x93, 0x8d, 0x5, 0xf, 0x6f, 0xab, 0xe6, 0xbe, 0xaf, 0x40, 0xab, - 0xf8, 0x7b, 0x7e, 0x4, 0x90, 0x8, 0xbd, 0x2e, 0x13, 0x3d, 0x8a, 0x8, - 0xf, 0x96, 0x8f, 0xfd, 0x20, 0xc7, 0x21, 0x36, 0x66, 0x4c, 0x67, 0x66, - 0xa1, 0x88, 0x80, 0x14, 0x8b, 0xb4, 0x4a, 0x8, 0x6c, 0x5c, 0x84, 0xa8, - 0x5c, 0x22, 0x0, 0x31, 0x60, 0x77, 0x96, 0xda, 0x99, 0xe4, 0x24, 0x6f, - 0xd2, 0xb4, 0x2a, 0xe, 0x69, 0xa8, 0x13, 0x13, 0x4e, 0x7f, 0xed, 0xdb, - 0x26, 0x35, 0xaa, 0x34, 0x38, 0x16, 0xbb, 0x1, 0x7c, 0x25, 0x28, 0x13, - 0xbb, 0x28, 0x8a, 0xdd, 0x9b, 0xfc, 0x71, 0xa9, 0xb6, 0x92, 0xc5, 0x3b, - 0x14, 0xae, 0xdc, 0xf0, 0x7, 0x14, 0x70, 0xaf, 0xd6, 0xf7, 0xb4, 0x22, - 0x4a, 0x7e, 0x16, 0x76, 0x63, 0x48, 0xb5, 0xdd, 0xec, 0x1, 0xa, 0x97, - 0xab, 0xb, 0x52, 0x7e, 0xeb, 0x76, 0x3e, 0xbb, 0xd5, 0x9e, 0x4f, 0xe1, - 0x84, 0x6d, 0x31, 0xcc, 0x10, 0x2a, 0xd5, 0x8a, 0xea, 0x43, 0x1e, 0xe5, - 0x8f, 0xa7, 0x3f, 0x9c, 0xfb, 0x1e, 0xc2, 0xd2, 0xb4, 0xa1, 0x4a, 0x42, - 0xdf, 0x82, 0x5, 0x76, 0xbb, 0xd5, 0x14, 0x10, 0xf2, 0xd9, 0x6f, 0xca, - 0x7f, 0x61, 0x78, 0x2d, 0xf2, 0x75, 0xbb, 0x47, 0x6e, 0x1d, 0xe4, 0xc, - 0xe7, 0xdf, 0x5, 0x1c, 0x68, 0x51, 0xf, 0xc6, 0x8, 0xcc, 0xbd, 0xe7, - 0x82, 0x26, 0xc3, 0x8b, 0xa2, 0x3a, 0xda, 0x12, 0x8, 0xef, 0xdd, 0x89, - 0x48, 0xb9, 0x59, 0xca, 0x91, 0xd4, 0xe0, 0x53, 0xff, 0xb8, 0xb6, 0x2e, - 0xc5, 0xa7, 0x35, 0x8d, 0x24, 0x30, 0xe3, 0x81, 0x94, 0x1a, 0xe8, 0xe6, - 0x30, 0x56, 0x1, 0xe1, 0x22, 0x8e, 0x10, 0x78, 0x2e, 0x9c, 0x79, 0x6f, - 0x6c, 0xa7, 0xa1, 0x50, 0xfe, 0xe8, 0xc4, 0x31, 0x1a, 0xa7, 0xb5, 0x62, - 0x9c, 0xff, 0xf, 0x1e, 0x3c, 0x5c, 0x3a, 0x2a, 0xce, 0x3e, 0xb, 0xcf, - 0x2b, 0xfa, 0xfa, 0x40, 0x7b, 0x86, 0xbd, 0xf1, 0xed, 0xa7, 0x6f, 0x9e, - 0xde, 0xc8, 0xaf, 0xd6, 0x5f, 0x1c, 0x75, 0xb7, 0xb8, 0x27, 0xca, 0x67, - 0xe1, 0xee, 0x52, 0x73, 0x48, 0xb7, 0xd5, 0x4a, 0xa7, 0x9b, 0x1f, 0x3, - 0xbf, 0x6e, 0x17, 0x18, 0xb9, 0xed, 0xa3, 0x28, 0xf9, 0x1d, 0x42, 0x97, - 0x5, 0x9a, 0x1b, 0x7c, 0xc2, 0x55, 0xa9, 0xdc, 0x16, 0x1a, 0xdb, 0x81, - 0x4e, 0x21, 0xa5, 0x66, 0x69, 0x1d, 0xcf, 0x7c, 0x43, 0x66, 0xc5, 0x96, - 0xcd, 0xd, 0xf8, 0x25, 0x19, 0x90, 0xfe, 0x1d, 0x99, 0x22, 0x93, 0x9, - 0x54, 0xe8, 0xa2, 0x36, 0x1d, 0x4d, 0xe9, 0x86, 0xe1, 0xa8, 0x45, 0x3b, - 0xb6, 0x17, 0x38, 0x39, 0xbd, 0xc7, 0xed, 0x87, 0xcf, 0xa4, 0xec, 0x4e, - 0x12, 0x7c, 0xe, 0x36, 0x1a, 0x95, 0xd7, 0xe3, 0xe8, 0xd4, 0xb5, 0x83, - 0x50, 0xfd, 0x7d, 0xfd, 0x22, 0xcd, 0x72, 0x26, 0x55, 0x75, 0x86, 0x70, - 0xdb, 0xd6, 0x18, 0x10, 0x6b, 0x12, 0x27, 0xce, 0xa4, 0x92, 0x69, 0xdf, - 0xa2, 0xcb, 0xaa, 0x48, 0x99, 0xd6, 0xd2, 0xe1, 0x7b, 0xd6, 0xf5, 0x97, - 0x54, 0x26, 0xc1, 0xe5, 0xba, 0xb9, 0x5e, 0x15, 0x26, 0xd6, 0x1d, 0x84, - 0xa6, 0xdf, 0x54, 0xb6, 0x9f, 0x9c, 0x2, 0x7, 0x5e, 0x12, 0xad, 0x9a, - 0x68, 0x22, 0x52, 0xec, 0xcd, 0xc8, 0x11, 0x62, 0xf7, 0x1a, 0xb8, 0x7c, - 0x58, 0x67, 0x2f, 0xa1, 0xb, 0xdd, 0xb, 0xaf, 0x62, 0x4, 0x1d, 0x4a, - 0x31, 0x3, 0xa, 0xc8, 0xb1, 0x56, 0x1, 0x1f, 0x8d, 0xc0, 0x65, 0x5a, - 0x84, 0x7b, 0x55, 0xda, 0x88, 0x32, 0xac, 0x52, 0x3b, 0xd, 0x10, 0x48, - 0x64, 0x51, 0xa9, 0xa5, 0xbb, 0xe7, 0xd8, 0xee, 0xc6, 0xd0, 0x4e, 0x71, - 0xe9, 0x8f, 0xdf, 0x5c, 0x87, 0xa4, 0x5d, 0x38, 0x1e, 0xbf, 0xd5, 0xe7, - 0xc9, 0xb0, 0x4, 0xd4, 0xdf, 0xde, 0xd7, 0x64, 0xe9, 0x2, 0xce, 0x31, - 0x4e, 0x56, 0xc0, 0x90, 0xb0, 0xc5, 0x46, 0x36, 0x5a, 0xb8, 0x9e, 0x44, - 0xc3, 0x76, 0x5d, 0xfa, 0x79, 0xe6, 0x67, 0x16, 0x17, 0xde, 0x31, 0xb2, - 0x74, 0x21, 0x1c, 0xf3, 0x26, 0x4c, 0xd6, 0xf7, 0x4b, 0x73, 0x52, 0x5e, - 0x4d, 0xdd, 0xc0, 0x5b, 0x6b, 0xd8, 0x75, 0x83, 0x60, 0x3, 0x9e, 0xcb, - 0xac, 0x9f, 0x39, 0xc8, 0x66, 0x47, 0x4a, 0x2f, 0x72, 0x2c, 0x93, 0x16, - 0xb4, 0xb8, 0x73, 0xc1, 0x2c, 0xbe, 0xe6, 0x6e, 0xaf, 0x71, 0x66, 0xcd, - 0xc5, 0x91, 0xdd, 0x13, 0xf3, 0x70, 0x3, 0xc9, 0x63, 0xf6, 0x20, 0xed, - 0x62, 0x13, 0x40, 0xe9, 0x68, 0x3f, 0xc8, 0x74, 0xa7, 0x29, 0x51, 0xa2, - 0xa5, 0xa9, 0x3d, 0x67, 0x6b, 0xa7, 0x43, 0xa4, 0x97, 0x66, 0x57, 0x54, - 0x6a, 0xe2, 0xae, 0xe0, 0xff, 0xed, 0xbd, 0xe, 0x71, 0x78, 0xf, 0xf9, - 0xdf, 0x82, 0x5, 0x1a, 0x8f, 0xc9, 0x69, 0x23, 0x90, 0xd1, 0x85, 0x96, - 0x70, 0xa4, 0x92, 0xaf, 0xec, 0x82, 0x98, 0xbc, 0x12, 0x48, 0xd3, 0x20, - 0x88, 0x80, 0xbd, 0xc5, 0xc4, 0xca, 0x1c, 0x72, 0xa8, 0xe1, 0xc, 0x31, - 0xa3, 0x5a, 0x85, 0x66, 0x18, 0xed, 0x93, 0x58, 0xae, 0x53, 0x33, 0x76, - 0xfa, 0xc0, 0x52, 0x51, 0x59, 0xf4, 0xf, 0xc9, 0xc0, 0x62, 0xfe, 0x30, - 0xdf, 0x4d, 0xdb, 0x4c, 0x61, 0xde, 0x3d, 0x84, 0x7b, 0x82, 0x2b, 0x29, - 0xc0, 0xab, 0x1a, 0x94, 0x30, 0xf, 0x6b, 0xb2, 0xd8, 0x7e, 0x54, 0x38, - 0xdd, 0xfd, 0x8, 0xaf, 0x1, 0x62, 0xef, 0x2f, 0x43, 0x56, 0xc5, 0x5e, - 0x9a, 0x78, 0x62, 0xe7, 0x67, 0x2, 0xbe, 0xa7, 0xcc, 0x9c, 0x3d, 0x72, - 0xbb, 0xff, 0x37, 0x6a, 0xe4, 0xb2, 0x36, 0x27, 0x6d, 0x35, 0xcd, 0x60, - 0xd4, 0x93, 0xc2, 0x34, 0xbe, 0x6c, 0x16, 0x46, 0x97, 0x4c, 0x6d, 0x99, - 0xd5, 0xb3, 0x5a, 0x68, 0xdf, 0x4f, 0x8, 0x93, 0x28, 0xe2, 0x76, 0x66, - 0x1d, 0x50, 0xfb, 0xec, 0x63, 0x14, 0x36, 0xc8, 0x68, 0xd6, 0xcf, 0xa1, - 0x2d, 0x4e, 0x41, 0x25, 0x3f, 0xe0, 0x25, 0x40, 0xdb, 0xe1, 0xff, 0x7b, - 0xf0, 0x5b, 0x69, 0x4a, 0x31, 0xf5, 0xd0, 0xf4, 0x1d, 0xc4, 0x78, 0x3d, - 0xa7, 0x78, 0xea, 0xa9, 0x72, 0x22, 0xae, 0x67, 0x65, 0x82, 0x63, 0x2d, - 0x91, 0x5d, 0xed, 0xad, 0xb, 0xc3, 0xd2, 0xa7, 0xaf, 0xae, 0x8e, 0xb5, - 0x78, 0xf8, 0xca, 0x68, 0x67, 0xfe, 0x91, 0x3, 0x49, 0xa7, 0x35, 0x6a, - 0x87, 0x9d, 0x2d, 0x3a, 0x9f, 0x63, 0xf1, 0x68, 0x72, 0xb9, 0x35, 0xc3, - 0xd5, 0xe4, 0x7c, 0x5a, 0x5d, 0x9e, 0x3f, 0xc1, 0xc1, 0xed, 0xaa, 0x1e, - 0x88, 0xe5, 0xad, 0x27, 0x79, 0x80, 0x4, 0x1f, 0xec, 0xb1, 0x3c, 0x5f, - 0x15, 0x3c, 0x20, 0xce, 0x4e, 0xc6, 0xda, 0x39, 0x88, 0xef, 0xb5, 0xf2, - 0x39, 0x96, 0xb8, 0xbe, 0xc7, 0x3, 0x32, 0xcf, 0xe4, 0x33, 0x5b, 0x1, - 0xc, 0xfc, 0x3e, 0x63, 0xec, 0x67, 0x24, 0xec, 0x24, 0x97, 0xdf, 0xff, - 0x0, 0xcb, 0xa, 0x14, 0xbf, 0x5c, 0x10, 0xa6, 0x52, 0x29, 0xee, 0xc2, - 0x56, 0xe5, 0x25, 0x67, 0xe5, 0xf9, 0xd0, 0xb, 0x8b, 0xee, 0xd6, 0x19, - 0x8, 0x6f, 0x2a, 0xcc, 0xc7, 0x7a, 0xcd, 0xec, 0xc3, 0xbd, 0xdd, 0xd4, - 0x54, 0xa2, 0x76, 0xe1, 0x9f, 0x21, 0xa5, 0xde, 0x6, 0x7, 0x4d, 0x56, - 0xa7, 0x71, 0x93, 0x8, 0xd8, 0x56, 0xea, 0xbe, 0x78, 0xe4, 0x8d, 0xce, - 0x7a, 0xda, 0xc6, 0xb6, 0xb6, 0xc0, 0xce, 0x30, 0x18, 0xbd, 0x6e, 0x20, - 0xc6, 0xa0, 0x96, 0x26, 0x7e, 0xef, 0x6b, 0x1f, 0xe5, 0xc9, 0x15, 0x77, - 0xa7, 0xe9, 0xda, 0x9f, 0x53, 0x24, 0xe1, 0x2f, 0x70, 0x68, 0x62, 0x99, - 0xcb, 0xcd, 0xa0, 0xe1, 0xef, 0xe2, 0x38, 0x17, 0x9d, 0xfd, 0x5c, 0x41, - 0xee, 0x4d, 0x3b, 0xeb, 0x7d, 0x72, 0x45, 0x6e, 0x1b, 0x75, 0x46, 0x9d, - 0x75, 0x9f, 0xf4, 0xff, 0x31, 0x0, 0xaa, 0x2, 0xcc, 0x93, 0xa4, 0xbe, - 0x84, 0x8d, 0xd7, 0xb0, 0x42, 0x80, 0x8e, 0x29, 0xfb, 0x6, 0x32, 0x26, - 0xc, 0xe9, 0x67, 0x3a, 0xff, 0x9, 0xa2, 0x30, 0x70, 0xe2, 0xcc, 0x73, - 0xe8, 0x94, 0xf, 0xdb, 0xbb, 0x53, 0x43, 0x68, 0x15, 0x56, 0x9c, 0x75, - 0x61, 0xae, 0x59, 0xa4, 0x42, 0xcd, 0xe0, 0xbc, 0x5e, 0xc, 0x8c, 0xd1, - 0x3e, 0x8d, 0x8d, 0xf3, 0x2f, 0x2b, 0xbc, 0x98, 0x3, 0xec, 0xd9, 0xd3, - 0x38, 0x59, 0x9f, 0xde, 0x15, 0x6b, 0x55, 0x8, 0xef, 0xf, 0x5c, 0x9f, - 0xe, 0x74, 0xf9, 0x10, 0xde, 0xdc, 0x3d, 0x1d, 0xcf, 0xc9, 0xfd, 0x1, - 0xd7, 0x84, 0x44, 0xa0, 0xc4, 0x5e, 0xda, 0x6f, 0x6a, 0x97, 0x7e, 0x17, - 0x8d, 0x77, 0x62, 0x5b, 0x87, 0xd7, 0xa7, 0x31, 0x38, 0x41, 0xbf, 0x2b, - 0x7b, 0x5c, 0x72, 0x96, 0x6f, 0xe5, 0xa2, 0x99, 0xe, 0xdc, 0x69, 0x54, - 0xf0, 0x35, 0x78, 0xc6, 0xbc, 0x7e, 0x9d, 0x67, 0x73, 0xa6, 0x14, 0xf6, - 0xde, 0x6e, 0x91, 0x8e, 0x16, 0x2e, 0x18, 0xdd, 0xd, 0x16, 0x3, 0xbc, - 0x6f, 0x4, 0xfa, 0x20, 0xbf, 0xc1, 0x7c, 0x47, 0x45, 0x59, 0xc9, 0x5a, - 0xf7, 0xbd, 0x6, 0xa, 0x50, 0xf, 0x29, 0xa3, 0x12, 0x67, 0x58, 0x88, - 0xeb, 0x8d, 0x37, 0x8f, 0x6b, 0xef, 0xf, 0xc6, 0x13, 0xde, 0x8f, 0xe4, - 0xd, 0x2b, 0x93, 0x34, 0x48, 0x5e, 0x27, 0xf1, 0xaa, 0xc3, 0x7c, 0x79, - 0x7d, 0xc3, 0x89, 0xca, 0xce, 0xb3, 0x7a, 0x5a, 0xfe, 0xef, 0x83, 0x1f, - 0x43, 0xd5, 0xe4, 0x2b, 0x59, 0x2c, 0x44, 0x96, 0xba, 0xbc, 0x25, 0xe5, - 0x13, 0x7b, 0xbb, 0x78, 0x86, 0xef, 0x4d, 0x33, 0xf9, 0x95, 0xc5, 0x26, - 0x46, 0x80, 0x3f, 0xed, 0xf9, 0x9f, 0x76, 0x7f, 0xe6, 0x72, 0xa, 0xf6, - 0xc7, 0x55, 0x81, 0x43, 0x72, 0x41, 0xe9, 0x7e, 0x35, 0x3f, 0x8d, 0xf1, - 0x4b, 0x21, 0xdb, 0x58, 0xb4, 0x3a, 0xf2, 0x0, 0xab, 0x5c, 0xfd, 0x4e, - 0xe5, 0x30, 0x14, 0xe6, 0x5c, 0xa0, 0x15, 0x50, 0x2b, 0xb4, 0xd8, 0xe7, - 0x99, 0xb4, 0xd3, 0x98, 0x1c, 0x8, 0x4, 0xbc, 0x38, 0x88, 0x36, 0x51, - 0x94, 0x2f, 0xdc, 0x5e, 0x95, 0xa3, 0xf6, 0xde, 0x39, 0x90, 0x8c, 0x7c, - 0xfd, 0x3b, 0xbd, 0x23, 0xf4, 0x15, 0x74, 0x7c, 0x6f, 0xc0, 0x37, 0x48, - 0x85, 0xce, 0xa9, 0xd8, 0x67, 0xae, 0x1c, 0x22, 0x7d, 0x75, 0x5c, 0x61, - 0xb6, 0x96, 0x1a, 0xec, 0x91, 0xd8, 0x54, 0xe3, 0xdc, 0xf5, 0x4a, 0xf3, - 0x3a, 0xda, 0x48, 0xdc, 0xfa, 0x3d, 0xcc, 0xe7, 0xad, 0x4c, 0x8d, 0x49, - 0xdc, 0xa9, 0xd7, 0x1f, 0xf3, 0xef, 0xa8, 0x28, 0x2, 0x68, 0x79, 0x82, - 0x27, 0x81, 0x32, 0x5f, 0x55, 0x9, 0x28, 0xf6, 0xc9, 0x6e, 0xe5, 0x4b, - 0xa9, 0x3c, 0x46, 0xb4, 0xec, 0xd3, 0x77, 0xda, 0x62, 0x3d, 0x1f, 0xe6, - 0x3a, 0xc5, 0x8d, 0x32, 0xdb, 0xf8, 0x53, 0xb4, 0xca, 0xd6, 0xd5, 0x40, - 0xaf, 0x3e, 0x4f, 0x3e, 0x64, 0x21, 0xc2, 0xa9, 0x6a, 0x3a, 0x86, 0xd1, - 0x29, 0x18, 0xfb, 0xb8, 0xe1, 0x39, 0xd1, 0xb1, 0x18, 0xf3, 0x58, 0x6f, - 0x32, 0xf9, 0x28, 0x42, 0xbe, 0x9, 0x9d, 0xef, 0xb5, 0x7b, 0xa8, 0x12, - 0x7d, 0xc8, 0x4c, 0x32, 0x24, 0xca, 0x62, 0x6a, 0xd7, 0x23, 0xfc, 0x3d, - 0xc, 0xcb, 0x55, 0x75, 0x75, 0x1e, 0x84, 0x8d, 0xa4, 0x8f, 0x7d, 0x14, - 0x79, 0xe1, 0x2e, 0xf9, 0xaa, 0x7a, 0x13, 0x83, 0x30, 0xa4, 0x41, 0x56, - 0x2a, 0x13, 0xcc, 0x38, 0x5e, 0xfa, 0xbd, 0x1b, 0xba, 0x3d, 0xf6, 0xcc, - 0x68, 0x4a, 0x6b, 0xa9, 0x3b, 0xe5, 0x87, 0x43, 0xb3, 0xd2, 0x78, 0xcb, - 0x3e, 0x3, 0xd7, 0x8e, 0x49, 0xc7, 0x7b, 0xd5, 0x44, 0x61, 0x56, 0xd2, - 0x8e, 0x0, 0xd2, 0xde, 0x5c, 0xae, 0xbf, 0x35, 0x4, 0x11, 0xc4, 0x5, - 0x9, 0x50, 0x31, 0xf4, 0x4f, 0x1c, 0x5e, 0x1b, 0xf3, 0x91, 0x99, 0x1, - 0x7f, 0x69, 0xcc, 0xba, 0x91, 0xba, 0xb6, 0x2d, 0xc7, 0x99, 0x7e, 0xf2, - 0x1b, 0x68, 0x8, 0x7, 0x11, 0xe2, 0x31, 0x29, 0xd1, 0xc6, 0x68, 0x45, - 0x17, 0x7e, 0xf9, 0x0, 0x27, 0x23, 0x18, 0xa4, 0xb2, 0x61, 0xd5, 0x24, - 0xe8, 0x8, 0xb7, 0xb2, 0xb1, 0x14, 0x6f, 0xb, 0x3e, 0xe7, 0x37, 0x64, - 0xdb, 0x2f, 0x5e, 0x93, 0xf0, 0xa9, 0xf6, 0xad, 0x83, 0xa3, 0xba, 0xcc, - 0x92, 0x65, 0x15, 0x60, 0x11, 0x6c, 0x88, 0x2f, 0xf5, 0x52, 0x98, 0x2d, - 0xd0, 0x6e, 0x5d, 0x68, 0x24, 0xf6, 0xcf, 0xea, 0x33, 0xb9, 0x4d, 0xc8, - 0xa0, 0x87, 0x65, 0xfa, 0xc7, 0x6a, 0x7f, 0xae, 0xa9, 0x44, 0x19, 0x92, - 0xc3, 0x36, 0x1f, 0xf1, 0xf1, 0x4f, 0x9e, 0x1f, 0x2b, 0x4c, 0x2c, 0x94, - 0x34, 0x52, 0x70, 0x43, 0x73, 0x90, 0xfe, 0x24, 0x7a, 0x2d, 0x3b, 0x8a, - 0x24, 0x1d, 0xbd, 0xf5, 0xc6, 0x58, 0x65, 0x89, 0x9, 0xcc, 0x26, 0x46, - 0xeb, 0x8b, 0x1b, 0x6a, 0x80, 0x31, 0xf, 0xc2, 0xd4, 0xf3, 0x63, 0x75, - 0x1c, 0x77, 0x14, 0xe2, 0xcc, 0xc9, 0x94, 0x2c, 0x74, 0x7d, 0x29, 0x86, - 0x7f, 0x81, 0x5, 0xa9, 0x18, 0x3d, 0x1d, 0xa4, 0x50, 0xea, 0x86, 0x3, - 0x1f, 0xb, 0x49, 0xfd, 0x43, 0xf4, 0xa1, 0xe3, 0xbb, 0x17, 0x7c, 0x63, - 0x57, 0xbb, 0x5d, 0x5d, 0x3c, 0xca, 0xf2, 0x7b, 0x49, 0xd0, 0x30, 0x77, - 0x71, 0x71, 0x44, 0x9c, 0xc2, 0xfc, 0x2b, 0x4c, 0x1c, 0xc8, 0xe7, 0x35, - 0x6b, 0x1a, 0x72, 0xfe, 0xf4, 0xc1, 0x67, 0x18, 0x49, 0x32, 0x64, 0xef, - 0x85, 0x46, 0xfc, 0x5a, 0x94, 0xe7, 0x98, 0x6f, 0xb5, 0xbc, 0xb, 0x0, - 0x87, 0x3, 0x7f, 0x8a, 0x99, 0xc2, 0x60, 0x9a, 0xc7, 0x50, 0x80, 0x66, - 0x20, 0x55, 0x18, 0x89, 0xde, 0xf0, 0x2e, 0x32, 0x6b, 0xc5, 0xc1, 0x5b, - 0x70, 0x1f, 0xbb, 0xde, 0x87, 0xa1, 0x22, 0x4c, 0x8d, 0x6e, 0x95, 0x6f, - 0x9e, 0x71, 0x21, 0xdc, 0x5d, 0x55, 0xa2, 0xb1, 0xd4, 0x6, 0x61, 0x7, - 0x3c, 0x52, 0xa, 0xf4, 0x93, 0x21, 0xd7, 0x6f, 0xa4, 0xf3, 0x4f, 0xd0, - 0xda, 0x9, 0xf0, 0x31, 0x8b, 0xc, 0xb2, 0x8b, 0x2d, 0x33, 0xc4, 0x72, - 0xdc, 0xf, 0x2c, 0xd0, 0x2d, 0xd5, 0xf4, 0xff, 0x62, 0xaf, 0x85, 0xf7, - 0x10, 0xc8, 0x40, 0xba, 0x8b, 0x8a, 0xad, 0xcf, 0xc0, 0x24, 0xa5, 0xa3, - 0x64, 0x5d, 0x71, 0x2b, 0xba, 0xc1, 0x13, 0xea, 0x32, 0x2a, 0xb7, 0x6d, - 0x5d, 0xa5, 0x32, 0x12, 0x92, 0x71, 0xaf, 0xda, 0x3e, 0x0, 0xae, 0x13, - 0x37, 0x50, 0x44, 0xb4, 0x4c, 0xfb, 0xa0, 0x79, 0x6d, 0x97, 0x52, 0x9b, - 0x1b, 0x8d, 0xdf, 0x98, 0x78, 0xd9, 0xed, 0x90, 0x2, 0xb8, 0x1f, 0x4f, - 0xeb, 0xbf, 0x97, 0x19, 0x9c, 0x3f, 0x1a, 0x58, 0x1e, 0x77, 0x53, 0x5f, - 0xa2, 0xce, 0xf6, 0x36, 0x28, 0x8f, 0xbc, 0x7c, 0x39, 0x8f, 0x2, 0x6, - 0x29, 0x84, 0x37, 0x96, 0x86, 0x8a, 0x90, 0x6d, 0xcd, 0x72, 0xbf, 0xf0, - 0xc0, 0x51, 0xcf, 0xda, 0x7f, 0xd0, 0x42, 0x30, 0xe9, 0x83, 0xb2, 0x7d, - 0xbd, 0xd2, 0xe2, 0x47, 0x96, 0xd6, 0xc0, 0x34, 0xdc, 0x90, 0x45, 0x29, - 0x11, 0x11, 0xb0, 0x65, 0x44, 0xec, 0xe, 0xe4, 0x20, 0xba, 0x9a, 0xe0, - 0x85, 0x78, 0xa8, 0x37, 0x53, 0x8b, 0x2a, 0x1, 0x19, 0x84, 0xad, 0xa, - 0x5c, 0xba, 0x10, 0x38, 0xe1, 0x88, 0xdc, 0x52, 0x41, 0x19, 0xf4, 0x4c, - 0xad, 0x97, 0xa8, 0xa, 0xfc, 0x29, 0x3e, 0x9a, 0xd8, 0x34, 0x4f, 0xe7, - 0x17, 0xfb, 0x4a, 0x1c, 0x7d, 0x39, 0x8f, 0xc0, 0xb8, 0xf4, 0xcd, 0x9a, - 0xe2, 0x83, 0x76, 0x61, 0xc6, 0x30, 0x54, 0xa6, 0x2, 0xb0, 0x11, 0x8f, - 0xae, 0x90, 0x7c, 0x66, 0x9e, 0x3e, 0xb7, 0x82, 0xc2, 0x22, 0xaa, 0x53, - 0xca, 0x26, 0x5e, 0x94, 0x15, 0x68, 0xcd, 0xc1, 0x1e, 0x3a, 0x2, 0xec, - 0xfb, 0x48, 0xb6, 0x61, 0x15, 0x3b, 0x26, 0x8a, 0x1d, 0xfd, 0xb, 0x48, - 0xa0, 0x81, 0x2e, 0xd0, 0xc6, 0x24, 0x9e, 0x37, 0x90, 0xc5, 0x80, 0xaa, - 0xcf, 0x96, 0xee, 0xc5, 0x1d, 0xa9, 0xbe, 0x20, 0xc4, 0xb8, 0x59, 0x5f, - 0x95, 0x2b, 0x3a, 0x58, 0xe3, 0xe8, 0xe0, 0x3d, 0x43, 0x5b, 0x4b, 0x2a, - 0xf5, 0x8c, 0x36, 0x43, 0xaf, 0x8, 0x84, 0xbb, 0xa2, 0x2f, 0xd2, 0xac, - 0x6f, 0x55, 0x34, 0x45, 0x4, 0xbd, 0xa7, 0x53, 0x4f, 0x92, 0x9c, 0xba, - 0xf7, 0x50, 0x17, 0x5a, 0x47, 0x69, 0x96, 0x8f, 0x87, 0xb0, 0xd6, 0x4c, - 0xd6, 0xe3, 0x93, 0x7a, 0x9, 0xe4, 0x35, 0x18, 0xea, 0x83, 0xe4, 0x71, - 0xb2, 0xed, 0x94, 0x31, 0x20, 0xab, 0xdf, 0xb8, 0xab, 0xe0, 0x33, 0xcf, - 0x4d, 0x68, 0x15, 0x87, 0x5c, 0xbf, 0x97, 0x7f, 0xbc, 0xa3, 0xa1, 0x99, - 0x54, 0x3, 0x60, 0xc9, 0xb6, 0xe6, 0x82, 0xc6, 0x38, 0xab, 0x5b, 0xf0, - 0xe5, 0x2d, 0x51, 0x53, 0x91, 0x72, 0xf4, 0x14, 0xfc, 0x45, 0x66, 0xed, - 0x8, 0x24, 0x8d, 0xf0, 0x35, 0x14, 0xb9, 0xb4, 0xa7, 0xe, 0xa2, 0x45, - 0x20, 0xe5, 0x70, 0x2d, 0x46, 0xd2, 0x6b, 0x8f, 0xf1, 0xa4, 0xc6, 0x25, - 0xa0, 0x75, 0xcf, 0x5a, 0xce, 0xee, 0x33, 0xda, 0xf4, 0x46, 0x33, 0x1c, - 0x95, 0x87, 0xe1, 0xbe, 0x62, 0x88, 0x75, 0x40, 0x1d, 0xcb, 0x92, 0x86, - 0x98, 0xc3, 0x61, 0x6b, 0xd9, 0x46, 0x2d, 0xbb, 0x74, 0xb6, 0x57, 0xc4, - 0xea, 0xc, 0x53, 0x5c, 0x3, 0x39, 0x9e, 0x93, 0x70, 0x1b, 0xcb, 0x21, - 0xac, 0x87, 0xa4, 0x91, 0x37, 0xa1, 0x61, 0xed, 0xbe, 0xb3, 0x85, 0x75, - 0x35, 0x98, 0xf, 0x89, 0x1a, 0xcb, 0x5a, 0x54, 0xad, 0x5b, 0x6b, 0x1a, - 0x3d, 0x77, 0xab, 0x2d, 0x4e, 0x23, 0xef, 0x9c, 0x74, 0x46, 0x15, 0x4a, - 0x0, 0xe2, 0xfd, 0xfe, 0xe4, 0x3d, 0x73, 0xc6, 0x4f, 0x29, 0xe6, 0x89, - 0xd9, 0xb6, 0x9f, 0x8c, 0x37, 0x96, 0xc1, 0x8f, 0x55, 0x6b, 0x6a, 0x33, - 0xc3, 0x6c, 0xa5, 0x5b, 0x2f, 0x34, 0x25, 0xa4, 0x74, 0x3c, 0x3f, 0x4e, - 0xf4, 0xcf, 0xe9, 0x15, 0x57, 0xba, 0x65, 0x55, 0x2e, 0x3f, 0x1c, 0xc9, - 0x3c, 0x20, 0x99, 0xd1, 0x3d, 0x86, 0x5c, 0x9c, 0xd5, 0x93, 0x86, 0x39, - 0x6f, 0x6c, 0xd1, 0xe2, 0x26, 0xf8, 0xae, 0xed, 0x59, 0x6e, 0x15, 0xde, - 0xc9, 0xc7, 0x3f, 0xc6, 0x5c, 0x6c, 0x5b, 0x34, 0xce, 0x97, 0xe2, 0xfd, - 0xb8, 0xc8, 0xff, 0xd0, 0x4d, 0x7b, 0xbb, 0x59, 0x64, 0xc5, 0x2a, 0x70, - 0x37, 0x9d, 0xc5, 0x8d, 0xe4, 0xf, 0x16, 0x37, 0x98, 0x5c, 0xe2, 0x14, - 0xcb, 0x3f, 0x69, 0x46, 0xcf, 0xf1, 0xa8, 0x61, 0x8d, 0xcd, 0x99, 0x20, - 0x3, 0x53, 0xf7, 0xca, 0x4f, 0x2d, 0x23, 0x4c, 0xab, 0x94, 0xf5, 0xd9, - 0x4c, 0x32, 0xfa, 0xc3, 0x3, 0x21, 0x7a, 0x5e, 0x8b, 0xd4, 0x1c, 0xc0, - 0x1d, 0x85, 0x28, 0x36, 0xeb, 0x40, 0xac, 0xae, 0xb6, 0x13, 0x2e, 0x77, - 0xc2, 0xf5, 0xbe, 0x84, 0x47, 0xa0, 0xe3, 0x28, 0x4a, 0xf8, 0x17, 0x9e, - 0x3c, 0x29, 0x51, 0x86, 0xf9, 0x12, 0x7a, 0x5b, 0xdf, 0x75, 0x1e, 0x87, - 0x6f, 0xff, 0x3d, 0x32, 0x48, 0x79, 0x6e, 0x58, 0xa2, 0xc7, 0x9a, 0xc4, - 0xf3, 0x2, 0x1c, 0xf1, 0x7f, 0xb, 0x31, 0xb7, 0x19, 0xd, 0x62, 0xcf, - 0x3e, 0xa8, 0x59, 0x92, 0xfb, 0x61, 0xea, 0x8c, 0xca, 0x76, 0x1, 0x15, - 0xa6, 0xf, 0xff, 0x8a, 0xc7, 0xb3, 0xed, 0xee, 0xa4, 0x8d, 0x8d, 0x7, - 0xce, 0xb2, 0xc, 0x1c, 0xbc, 0x48, 0xad, 0xcb, 0x17, 0x9a, 0x61, 0x99, - 0x38, 0x4b, 0x40, 0xc9, 0xed, 0x21, 0x4, 0x9e, 0xd0, 0x4f, 0xc7, 0x71, - 0xb9, 0xf1, 0x11, 0x0, 0x7d, 0x4, 0xe3, 0xd5, 0xb7, 0xd9, 0x3, 0xe0, - 0xf9, 0x87, 0xdb, 0xf7, 0x96, 0x7d, 0x93, 0x24, 0x70, 0x8d, 0xbc, 0x17, - 0x41, 0x1a, 0x4d, 0x6b, 0x9e, 0x9b, 0x83, 0x67, 0x96, 0x67, 0x5a, 0x60, - 0xa8, 0xa8, 0xbe, 0x8e, 0x27, 0xa1, 0x2c, 0xfa, 0xc0, 0xe1, 0xd6, 0x69, - 0xea, 0x65, 0x58, 0x56, 0x9b, 0x3c, 0x92, 0x10, 0x76, 0xaf, 0x6b, 0x97, - 0xe1, 0x64, 0x19, 0x14, 0x1b, 0xc4, 0xe9, 0xc, 0xd0, 0x1a, 0x9c, 0x8, - 0x74, 0x3b, 0xd2, 0x48, 0x92, 0xa8, 0x5e, 0xbf, 0xc9, 0x5a, 0x2b, 0xe0, - 0x3, 0xbc, 0x62, 0x9e, 0xe9, 0x5d, 0x23, 0xd4, 0xdb, 0xf6, 0x8, 0x6d, - 0x67, 0x6f, 0x38, 0xe6, 0xb0, 0x83, 0xae, 0x82, 0xe4, 0xa9, 0xd8, 0xaf, - 0x7f, 0xd2, 0x45, 0xa4, 0x49, 0xc3, 0x68, 0xcc, 0x79, 0x65, 0xad, 0xfa, - 0x1b, 0x9f, 0x89, 0xd6, 0xe3, 0xbc, 0xe8, 0x7a, 0x7, 0xf9, 0x2d, 0x58, - 0xa3, 0x50, 0xe4, 0xc2, 0x0, 0xe1, 0x8b, 0xfe, 0x2d, 0x46, 0x1, 0xaa, - 0xa0, 0x1, 0x20, 0xef, 0x6a, 0x9, 0x69, 0x88, 0xf2, 0x4, 0xf5, 0xe1, - 0x15, 0x54, 0x5a, 0x26, 0x14, 0x6b, 0x9, 0xf5, 0x90, 0x9e, 0x44, 0x55, - 0x2d, 0x7e, 0xd5, 0xa9, 0xc1, 0x2a, 0xa2, 0x49, 0xec, 0x5c, 0xf8, 0x39, - 0x81, 0xe3, 0x86, 0xb7, 0xa3, 0x2a, 0xfd, 0xb2, 0x61, 0xa8, 0xb2, 0x80, - 0x9c, 0xb4, 0x48, 0x79, 0x17, 0x36, 0xe1, 0x30, 0x7d, 0xad, 0xde, 0x32, - 0x85, 0xbd, 0x54, 0xa1, 0x9, 0xf2, 0x74, 0xa0, 0x5f, 0xf6, 0xcd, 0x96, - 0xc4, 0x1c, 0x7a, 0x18, 0x8d, 0xae, 0xc1, 0x96, 0xbb, 0xdd, 0x8, 0x4e, - 0x2d, 0x86, 0xc, 0x89, 0xe, 0xf0, 0xd0, 0xae, 0x31, 0x96, 0xda, 0xa4, - 0x4e, 0x81, 0xaf, 0x27, 0x98, 0x53, 0xaf, 0x39, 0x9a, 0x2d, 0x92, 0x97, - 0x20, 0x5e, 0xfb, 0x4f, 0x6f, 0x4f, 0xa6, 0x7f, 0x2f, 0x92, 0x8b, 0xc6, - 0x51, 0x31, 0x2, 0x92, 0xbc, 0xdb, 0x48, 0x22, 0x7c, 0x8f, 0x84, 0x50, - 0x21, 0x43, 0x65, 0x2d, 0x6, 0xdd, 0xe0, 0x9f, 0x8a, 0x7c, 0x2f, 0xa9, - 0xc3, 0x1b, 0xde, 0x7a, 0x81, 0x7e, 0x1c, 0xb2, 0x2a, 0x53, 0xa0, 0xf7, - 0xc4, 0xb9, 0xfe, 0xce, 0x18, 0xba, 0xf2, 0x10, 0xfb, 0x54, 0x68, 0xa1, - 0x26, 0xb0, 0x0, 0x6b, 0x2e, 0x2f, 0x9e, 0xb2, 0x68, 0xea, 0x20, 0xe5, - 0x76, 0xf3, 0xe2, 0xe6, 0x4f, 0x40, 0x7d, 0x5e, 0x20, 0x96, 0xdf, 0x45, - 0x77, 0xb6, 0xd8, 0xf0, 0x5, 0x31, 0xf7, 0x86, 0xd3, 0x70, 0x12, 0x80, - 0x3a, 0xde, 0x75, 0x4a, 0x82, 0x1c, 0x9d, 0xe8, 0xc0, 0xed, 0xd7, 0x7, - 0xd5, 0x79, 0x24, 0x75, 0x5a, 0xac, 0x64, 0x8e, 0xb8, 0xc1, 0x19, 0xe, - 0xe4, 0xa9, 0xca, 0xc6, 0x27, 0xcc, 0x8c, 0xe8, 0xd8, 0xf4, 0xda, 0x4c, - 0x14, 0x88, 0x16, 0xe8, 0xae, 0x84, 0x71, 0xc5, 0x54, 0x21, 0x12, 0x98, - 0xa6, 0x43, 0x44, 0x48, 0x1, 0xf, 0x57, 0xf4, 0x4, 0x33, 0x50, 0x8c, - 0xe0, 0xbf, 0x3d, 0x36, 0x76, 0xfe, 0x72, 0x41, 0xe2, 0xfb, 0x4c, 0x35, - 0x1c, 0x65, 0x16, 0xaa, 0xb7, 0x1d, 0x13, 0xcb, 0x5f, 0x5a, 0x3f, 0x1c, - 0xaa, 0x1d, 0x6a, 0xe3, 0x54, 0x77, 0xd8, 0x15, 0x51, 0xe9, 0x7d, 0x50, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, - 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, - 0x71, 0x24, 0xa1, 0xbd, 0x1f, 0x3f, 0x12, 0x23, 0x43, 0x2, 0x1e, 0x8e, - 0x36, 0xe5, 0x4e, 0xb8, 0x69, 0xf1, 0xd0, 0x12, 0xbe, 0x32, 0x17, 0x2f, - 0xd9, 0x54, 0x88, 0xf7, 0x67, 0x6e, 0xb, 0xdf, 0x39, 0x9e, 0xeb, 0x79, - 0x18, 0x2a, 0x16, 0x50, 0x90, 0x55, 0xc0, 0x2a, 0xc0, 0xbf, 0x77, 0xa3, - 0x47, 0xa4, 0xf3, 0x3f, 0xb, 0x74, 0xa9, 0x83, 0x4f, 0x2f, 0x4e, 0x73, - 0x84, 0x2c, 0x73, 0x7e, 0xd3, 0xc1, 0xc0, 0x2d, 0x36, 0xb5, 0x60, 0xb, - 0xc6, 0xd5, 0x50, 0x10, 0x1a, 0x2f, 0xa5, 0xa0, 0x17, 0x49, 0xaf, 0xcf, - 0xd9, 0xb7, 0xde, 0xeb, 0xc0, 0x9a, 0x4c, 0xf7, 0xf4, 0x96, 0xe1, 0x1, - 0x68, 0xe3, 0x26, 0xa3, 0xd3, 0x45, 0x7b, 0x57, 0xac, 0xc2, 0xa9, 0x88, - 0x8d, 0xdb, 0x4, 0x56, 0x34, 0xf5, 0x97, 0xd1, 0x7a, 0x60, 0xf8, 0x46, - 0xa, 0xf1, 0x19, 0x92, 0x2d, 0x7, 0x66, 0xec, 0x6f, 0x86, 0xc4, 0x3b, - 0x4b, 0xc8, 0xa8, 0x39, 0xe3, 0x94, 0x63, 0xb4, 0x5e, 0x9b, 0x5e, 0xd, - 0x9a, 0x32, 0xa8, 0x4e, 0xc5, 0x58, 0x39, 0x1b, 0x83, 0x74, 0x4e, 0x6d, - 0xa9, 0xf7, 0x14, 0x94, 0xbd, 0xa2, 0xd2, 0xe2, 0xa2, 0x66, 0x7, 0xc9, - 0x2b, 0xe0, 0x43, 0x8d, 0x6d, 0x28, 0x0, 0x9f, 0x3f, 0x94, 0x4b, 0xe5, - 0x68, 0xf8, 0x4d, 0x27, 0xcd, 0x33, 0x1d, 0xee, 0x11, 0x11, 0xe4, 0x2d, - 0x36, 0x64, 0xd4, 0xd0, 0xce, 0xa9, 0xa, 0x91, 0x7c, 0x1d, 0x6e, 0xe2, - 0xcb, 0x8, 0x65, 0x8b, 0x6f, 0xe1, 0x1b, 0x3c, 0xed, 0xa7, 0x42, 0x32, - 0x28, 0xa8, 0xbc, 0x8d, 0x1, 0x9b, 0x3b, 0x7e, 0xa3, 0xcf, 0x7d, 0x8e, - 0x6, 0x23, 0x42, 0xe9, 0xda, 0xa6, 0xf2, 0xa3, 0x15, 0x4a, 0x7c, 0xa5, - 0xba, 0xd3, 0xd5, 0x89, 0x44, 0x82, 0x86, 0xa, 0x3d, 0x9c, 0xfc, 0x64, - 0x43, 0x2e, 0xc5, 0x17, 0xe2, 0x24, 0x65, 0xc5, 0x73, 0x9c, 0x12, 0x37, - 0x7, 0x58, 0x7b, 0x12, 0xc, 0x82, 0x7, 0xad, 0x52, 0x7c, 0x43, 0x15, - 0xb5, 0xc0, 0x67, 0x99, 0x3, 0x2a, 0x5a, 0xf3, 0x66, 0xcf, 0xd7, 0x23, - 0xec, 0xb8, 0xf, 0x66, 0x48, 0x60, 0x74, 0x10, 0xe4, 0x61, 0xb2, 0x51, - 0x52, 0xbf, 0x87, 0xd5, 0x20, 0x5b, 0x5c, 0x63, 0xe5, 0x45, 0x18, 0x43, - 0xb4, 0xfe, 0x50, 0x6e, 0x57, 0xe0, 0x34, 0xe5, 0x12, 0x2d, 0xbf, 0x38, - 0xa5, 0x15, 0x1d, 0x8e, 0xf5, 0xfe, 0x4d, 0x59, 0x14, 0xde, 0xc1, 0xd1, - 0xf7, 0x34, 0x11, 0xac, 0xb5, 0xef, 0x76, 0xee, 0xb6, 0x2c, 0x1f, 0x23, - 0x0, 0xa3, 0x93, 0x9d, 0x77, 0xa9, 0x8f, 0x32, 0x16, 0x4, 0x6f, 0xe3, - 0xa8, 0x21, 0x45, 0xd4, 0x5a, 0x6d, 0xc, 0xb9, 0x7, 0x29, 0x2b, 0x17, - 0x6c, 0x3c, 0x58, 0xb7, 0x8, 0x4b, 0xb3, 0x20, 0x83, 0xf1, 0x60, 0xaa, - 0xfe, 0xf1, 0x38, 0xd7, 0xf5, 0x59, 0x5, 0x76, 0x74, 0xd, 0x5, 0xf4, - 0x8c, 0x8f, 0xbb, 0xb9, 0x32, 0x41, 0xb7, 0x7e, 0x14, 0xdc, 0xf1, 0xe2, - 0x39, 0xf4, 0xf9, 0x25, 0x4d, 0xc5, 0xb2, 0xa8, 0x9f, 0x77, 0x31, 0xe4, - 0x75, 0xf4, 0x6b, 0x73, 0xc8, 0xed, 0x8b, 0x1c, 0xe3, 0xfa, 0x5d, 0x30, - 0xbc, 0x71, 0x64, 0xe8, 0xde, 0x98, 0x11, 0xe6, 0x4b, 0xd6, 0x70, 0x72, - 0x45, 0xe3, 0x6b, 0xd6, 0x8c, 0x4f, 0xff, 0xec, 0x81, 0x34, 0x14, 0x26, - 0xed, 0xee, 0x8d, 0x53, 0x5d, 0xe0, 0x52, 0xdd, 0x9c, 0x31, 0x14, 0x51, - 0xbc, 0x1f, 0x6d, 0xfc, 0x91, 0xd4, 0xa3, 0xe6, 0xaf, 0x46, 0x9e, 0x41, - 0xe0, 0x2d, 0xa7, 0xfb, 0xd, 0x3b, 0x64, 0x3e, 0x67, 0x63, 0x96, 0xd4, - 0xe0, 0x40, 0xa5, 0x71, 0xbd, 0x67, 0xd1, 0xdb, 0xf5, 0x7d, 0xb0, 0x98, - 0x38, 0xc5, 0xe1, 0x13, 0x6e, 0x99, 0xb4, 0x92, 0x2c, 0x46, 0x40, 0x8, - 0x52, 0x9, 0xae, 0x70, 0x67, 0x1, 0x3f, 0xd2, 0x25, 0x61, 0x98, 0x9e, - 0xef, 0xcd, 0x1f, 0x37, 0x96, 0xce, 0xf1, 0x53, 0xff, 0xb8, 0x95, 0x2b, - 0xc6, 0x8d, 0xa2, 0xae, 0x9, 0xf8, 0x9b, 0xf4, 0x18, 0x17, 0x15, 0xed, - 0x98, 0xdf, 0x1c, 0xb8, 0xd5, 0x32, 0xf6, 0xbd, 0xdd, 0x8, 0xea, 0x38, - 0xb, 0x2b, 0x2f, 0x13, 0xab, 0x59, 0xcf, 0xce, 0xbe, 0x49, 0x39, 0xc, - 0x98, 0xe4, 0xbc, 0x1c, 0xe4, 0xf9, 0x88, 0x96, 0xe2, 0xf2, 0x8d, 0xac, - 0xa0, 0x31, 0xe9, 0x4a, 0x42, 0x37, 0x92, 0x7a, 0xcf, 0xb7, 0xee, 0x65, - 0xcd, 0xcd, 0x2f, 0xe8, 0x2f, 0xe2, 0x70, 0x8a, 0x7, 0xd5, 0x93, 0x3e, - 0xc4, 0xf1, 0x9, 0x19, 0x4a, 0xb1, 0x96, 0x4c, 0xb0, 0x9b, 0x41, 0x5a, - 0x1e, 0x52, 0x0, 0x2b, 0xa4, 0xc3, 0xd2, 0x9, 0xd8, 0x7f, 0x93, 0x53, - 0x25, 0x96, 0xe6, 0xbe, 0x41, 0x84, 0x6c, 0x3b, 0x72, 0x51, 0xec, 0x4e, - 0x91, 0xbd, 0x6c, 0x37, 0x34, 0xb7, 0x6f, 0xda, 0x3c, 0xac, 0xc, 0x1a, - 0xb, 0xdc, 0x4a, 0x55, 0xc8, 0x37, 0x4, 0x48, 0xd5, 0x1f, 0x27, 0x66, - 0xb9, 0x2c, 0x82, 0x9f, 0x62, 0xd, 0x1a, 0xdc, 0x7e, 0x44, 0x62, 0x51, - 0xf1, 0x30, 0x82, 0x90, 0x42, 0x4f, 0x3e, 0xda, 0x22, 0xca, 0xf4, 0x98, - 0x38, 0x46, 0xd0, 0x74, 0x2b, 0x71, 0x2d, 0x7d, 0x8e, 0x48, 0xae, 0xcb, - 0x19, 0xb6, 0x95, 0xf3, 0x53, 0xf6, 0x14, 0xff, 0xc, 0x56, 0xe1, 0x16, - 0x68, 0xb3, 0xc6, 0x59, 0xf5, 0x4e, 0x58, 0x7f, 0x42, 0x4a, 0xa4, 0xa4, - 0x7d, 0xc9, 0x1b, 0xd7, 0xa0, 0x5e, 0x1a, 0xec, 0xf9, 0xd7, 0xe3, 0x8b, - 0xbf, 0xde, 0x2, 0xab, 0x39, 0x6b, 0x8a, 0xf1, 0xe9, 0xc3, 0x4d, 0x3f, - 0x50, 0xd8, 0xa1, 0xed, 0x40, 0xb9, 0xb7, 0x42, 0xa7, 0x25, 0x78, 0xab, - 0x2, 0x3f, 0xd, 0x8e, 0x3c, 0x8a, 0x6b, 0xa7, 0xb2, 0x74, 0xf2, 0x0, - 0xd9, 0xaf, 0x8e, 0x1c, 0x8a, 0xd5, 0xd8, 0x2, 0x3a, 0xf3, 0x55, 0xbf, - 0x57, 0x31, 0x20, 0xf9, 0xa9, 0x2d, 0x62, 0x79, 0xac, 0xa0, 0xd4, 0xac, - 0x9b, 0x73, 0xc0, 0x6, 0x2d, 0x20, 0xa6, 0x49, 0x35, 0x3, 0x76, 0x81, - 0xec, 0x2f, 0xfc, 0x1e, 0x6d, 0x9d, 0x28, 0xfc, 0xe5, 0x27, 0x4d, 0x50, - 0x74, 0x41, 0xbf, 0x33, 0x51, 0x90, 0x41, 0x9, 0x6c, 0x8d, 0xe9, 0xff, - 0x48, 0xaf, 0x77, 0xe1, 0xfd, 0xe5, 0x45, 0x37, 0x45, 0x33, 0x6a, 0x8c, - 0xf3, 0x19, 0x31, 0x92, 0x4f, 0xbb, 0xd4, 0xc, 0x4c, 0x81, 0xd3, 0xab, - 0xde, 0x57, 0xb4, 0xc6, 0x31, 0xf5, 0xc6, 0x2c, 0xa, 0x7b, 0x98, 0xf7, - 0x13, 0x7d, 0x51, 0x77, 0x92, 0x71, 0xce, 0x1a, 0xb1, 0xf4, 0x44, 0xee, - 0xba, 0x8a, 0x66, 0x57, 0x16, 0x9a, 0x33, 0xca, 0xc3, 0xa4, 0x7a, 0xd8, - 0xcf, 0x3b, 0x89, 0x5e, 0x87, 0xa5, 0x52, 0x13, 0xa8, 0xc0, 0xab, 0xac, - 0xd2, 0xa7, 0xdd, 0xb3, 0xe8, 0x35, 0x69, 0xab, 0x44, 0xec, 0x4b, 0x1d, - 0x92, 0x36, 0x26, 0x5d, 0xdb, 0xa7, 0x32, 0x17, 0x56, 0x9a, 0x8f, 0x87, - 0xdd, 0x54, 0xba, 0x37, 0xd2, 0x4d, 0x2e, 0xfc, 0xc9, 0xc6, 0xb0, 0x34, - 0x20, 0x53, 0x71, 0xbb, 0x40, 0xc1, 0xd7, 0x6, 0x37, 0xc9, 0x26, 0x1b, - 0xd7, 0xb8, 0x69, 0x23, 0xab, 0xa3, 0xfc, 0xd1, 0xc, 0x0, 0x67, 0xb0, - 0xb3, 0x2c, 0xfc, 0xc2, 0xd4, 0x0, 0x16, 0xad, 0x65, 0x57, 0x4d, 0x4, - 0x5b, 0x9c, 0xa4, 0x80, 0xb2, 0xa, 0x92, 0xad, 0x60, 0x2f, 0x4e, 0xba, - 0x16, 0x36, 0x8f, 0xe7, 0x64, 0xf7, 0xfc, 0xa1, 0x68, 0xa4, 0x70, 0x26, - 0x67, 0x34, 0x6b, 0x1a, 0x9d, 0xf, 0x1d, 0xf4, 0x92, 0x9d, 0xc, 0x8b, - 0x3e, 0xdd, 0xcf, 0x5c, 0x52, 0x69, 0x98, 0x5c, 0x44, 0x47, 0x52, 0xc6, - 0x1d, 0xf5, 0xf9, 0xc3, 0x52, 0xd7, 0x88, 0x6d, 0x20, 0xf, 0x97, 0x28, - 0x36, 0x8d, 0x60, 0x18, 0x9e, 0x7a, 0xaf, 0xcc, 0x84, 0xc1, 0x50, 0x8f, - 0x7c, 0x59, 0x1f, 0x42, 0x20, 0x33, 0x59, 0x74, 0x20, 0x25, 0x67, 0xf8, - 0x17, 0x49, 0x6c, 0xf, 0x2e, 0x35, 0x6a, 0xd4, 0x53, 0x60, 0x80, 0x84, - 0x29, 0x85, 0x5c, 0x99, 0x87, 0x3, 0x22, 0xa5, 0xe5, 0xe5, 0x57, 0x4f, - 0xfc, 0x29, 0xcf, 0x4, 0x8b, 0x58, 0xe6, 0x21, 0x17, 0x9a, 0xc4, 0x13, - 0x22, 0x32, 0x46, 0x6f, 0x7f, 0xc4, 0xd8, 0x38, 0xc, 0xb1, 0xce, 0xe2, - 0xe0, 0x36, 0x4f, 0xcf, 0x6, 0xb, 0xa, 0xc1, 0x5e, 0x92, 0x3, 0x5c, - 0x73, 0x6, 0x54, 0x67, 0xe8, 0x52, 0x9f, 0xd8, 0x94, 0x48, 0x45, 0x65, - 0x54, 0xf, 0xa, 0x1d, 0x28, 0xd7, 0x72, 0x69, 0xbf, 0xe, 0xf1, 0xc8, - 0x50, 0x8e, 0x4a, 0xf1, 0x4e, 0x31, 0x92, 0xca, 0x48, 0x18, 0xc9, 0x53, - 0xfe, 0x92, 0xf5, 0xcf, 0x90, 0xe0, 0x66, 0x16, 0xf4, 0xc1, 0x33, 0x66, - 0xff, 0xf1, 0x3e, 0x33, 0x6f, 0xfe, 0xc5, 0xbf, 0x14, 0x70, 0xf3, 0xfc, - 0xc4, 0x2, 0xd3, 0x0, 0xd0, 0x78, 0x20, 0xbb, 0x71, 0x25, 0x7c, 0x47, - 0x33, 0xd7, 0xbb, 0x1e, 0xa8, 0x10, 0x5e, 0xe4, 0xcb, 0xcb, 0x5b, 0x2b, - 0x5f, 0xcb, 0x37, 0x87, 0x8f, 0xa3, 0x87, 0x37, 0x1, 0xa8, 0x8a, 0xf5, - 0x79, 0xae, 0xb0, 0x68, 0x80, 0x41, 0x1, 0x98, 0xf8, 0xbd, 0x7f, 0x59, - 0x65, 0xea, 0xc8, 0x92, 0xb5, 0x29, 0xa9, 0x38, 0xb0, 0x1a, 0x24, 0x36, - 0x48, 0xfc, 0xe9, 0x7e, 0xb2, 0x65, 0xb5, 0x18, 0x42, 0xc6, 0xe5, 0xa7, - 0xf, 0x5, 0x85, 0xff, 0x27, 0x52, 0xe7, 0x17, 0xf3, 0x27, 0xca, 0xf6, - 0xeb, 0x64, 0xf8, 0x52, 0x66, 0xa1, 0xe9, 0xc8, 0x7d, 0x6f, 0x1, 0x53, - 0x41, 0x64, 0xe9, 0x5, 0xd, 0x44, 0xf4, 0x81, 0x63, 0x25, 0xc6, 0xe8, - 0xb1, 0x83, 0x4f, 0x73, 0x5d, 0xbf, 0xa7, 0x27, 0x99, 0x7b, 0xbe, 0xa9, - 0x8d, 0x1, 0xe9, 0xd9, 0x3c, 0xb, 0x8d, 0xd5, 0x0, 0xf7, 0x49, 0xcf, - 0x14, 0x50, 0x4e, 0x26, 0x13, 0xd3, 0x80, 0x93, 0x6e, 0x3a, 0xde, 0x8d, - 0x1, 0xcd, 0x78, 0xf3, 0xe, 0x26, 0xe3, 0x1a, 0xe, 0xd6, 0xa7, 0xc0, - 0xac, 0xcb, 0x1d, 0x13, 0x6, 0xaf, 0xdb, 0x8f, 0x65, 0xd4, 0x5b, 0x19, - 0x48, 0xae, 0x6a, 0x63, 0x43, 0xa9, 0x86, 0x43, 0x93, 0x27, 0x1b, 0x41, - 0x68, 0x3a, 0xe9, 0xec, 0xdb, 0xe6, 0xa6, 0x6e, 0xd5, 0x6f, 0x30, 0xcc, - 0xda, 0x15, 0x2c, 0xb, 0x13, 0x6f, 0xf, 0xc7, 0xbd, 0x42, 0x6f, 0x3e, - 0x58, 0x95, 0xc6, 0x29, 0x30, 0x19, 0x9f, 0x50, 0x4f, 0x4c, 0x1, 0x48, - 0x69, 0xcb, 0x57, 0x14, 0xbc, 0xd0, 0x94, 0x9f, 0xe, 0x31, 0x16, 0xde, - 0x1e, 0x15, 0x18, 0x33, 0xc7, 0x8, 0x63, 0x9, 0xb2, 0x99, 0x31, 0x99, - 0xde, 0x7c, 0xaf, 0x15, 0x13, 0xf6, 0x32, 0x8f, 0x48, 0xe0, 0xd7, 0xc1, - 0xbe, 0x7e, 0x66, 0x98, 0xf3, 0x6, 0xe2, 0x99, 0x4, 0x9d, 0x23, 0x3f, - 0x44, 0xea, 0xbb, 0x2a, 0xf9, 0x33, 0xf0, 0xbc, 0xd, 0x23, 0x3e, 0x5e, - 0x89, 0xf4, 0x6, 0x1, 0xfe, 0x77, 0x2d, 0x9d, 0xd5, 0xfa, 0xc3, 0x39, - 0x3c, 0x41, 0x53, 0x40, 0xbb, 0x77, 0xc3, 0x56, 0x16, 0xd, 0x7c, 0x86, - 0x1c, 0x9, 0x2c, 0xad, 0x38, 0x59, 0x70, 0xdc, 0x38, 0x9e, 0x3b, 0x8a, - 0x34, 0xa5, 0x93, 0xcf, 0xc5, 0x34, 0x87, 0xe5, 0xca, 0x61, 0x96, 0x7d, - 0xa, 0x57, 0x8b, 0x8, 0x76, 0x8f, 0x4b, 0x8c, 0x96, 0xc8, 0xdf, 0x7e, - 0x5d, 0x51, 0x9a, 0x8c, 0x82, 0x8a, 0x8b, 0xa, 0x92, 0x87, 0xd5, 0x39, - 0xb, 0xac, 0xbf, 0x65, 0x62, 0x12, 0x71, 0x35, 0xda, 0x74, 0x2d, 0xdc, - 0xd0, 0x64, 0x25, 0xe9, 0x9f, 0xe9, 0x99, 0xf2, 0x46, 0xf9, 0x9d, 0xe6, - 0x4, 0xa3, 0x3e, 0x6c, 0x90, 0xd8, 0xa0, 0xc9, 0x11, 0xd1, 0xf4, 0x35, - 0xfc, 0x9e, 0xf, 0xb8, 0xca, 0x30, 0xd, 0xa4, 0x90, 0x61, 0x1e, 0x2a, - 0xca, 0x29, 0xbd, 0x72, 0x1f, 0xf6, 0x42, 0x14, 0x86, 0xbe, 0x69, 0x82, - 0x2b, 0xd5, 0xa4, 0x33, 0x62, 0x34, 0x3, 0x78, 0xa2, 0x92, 0x4b, 0x43, - 0x98, 0x84, 0xd3, 0x30, 0xba, 0x9, 0x22, 0xb2, 0xfd, 0xbd, 0x94, 0x63, - 0x1f, 0x38, 0x39, 0x0, 0x9e, 0x6b, 0xe8, 0x57, 0xb, 0xf5, 0x75, 0xec, - 0x73, 0xdf, 0x75, 0xba, 0x79, 0xe7, 0x4a, 0x88, 0xf0, 0xf0, 0xb0, 0x10, - 0xc3, 0xe3, 0x48, 0x4e, 0xc1, 0x2c, 0x9c, 0x5, 0x58, 0x7e, 0xd6, 0x2e, - 0xea, 0x99, 0xad, 0xa2, 0x6, 0xd6, 0xd7, 0xcc, 0x1c, 0x4c, 0x68, 0x64, - 0x59, 0xab, 0xcf, 0xdd, 0xc1, 0x1d, 0x70, 0xaf, 0x72, 0xe2, 0x61, 0x49, - 0xc7, 0x63, 0x40, 0x94, 0x1b, 0xae, 0xbd, 0xc0, 0xc0, 0xfd, 0x76, 0xa9, - 0x1b, 0x83, 0x91, 0x2, 0xe, 0xf2, 0xad, 0xd8, 0x0, 0x67, 0x1f, 0x6d, - 0xfc, 0xca, 0x77, 0x76, 0xe8, 0x59, 0xc, 0x51, 0x5d, 0x2d, 0xb1, 0x1e, - 0xb8, 0xc4, 0x0, 0x6a, 0xae, 0xd7, 0x3b, 0xe6, 0xb4, 0xe3, 0xb3, 0x59, - 0xf5, 0x5a, 0xde, 0x7d, 0x22, 0x45, 0x71, 0xe6, 0xdb, 0x23, 0x18, 0x35, - 0xaa, 0x0, 0x41, 0xfd, 0x56, 0xce, 0xd9, 0x2b, 0x5f, 0x2a, 0xa5, 0xa7, - 0xd5, 0x53, 0x34, 0x27, 0xbd, 0x26, 0x92, 0x2d, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, - 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, - 0x48, 0x31, 0x55, 0x3a, 0xc9, 0x57, 0x30, 0x6a, 0x80, 0x88, 0xe8, 0x56, - 0xc4, 0x30, 0x4c, 0x85, 0x3a, 0x32, 0x5a, 0xd1, 0x44, 0xa4, 0x15, 0xa, - 0x2f, 0xac, 0xff, 0x9b, 0x25, 0x6c, 0x7, 0x68, 0x72, 0x79, 0x31, 0x4b, - 0xed, 0x2e, 0xdb, 0xf9, 0x82, 0xf4, 0xf, 0xf7, 0xf6, 0x7e, 0x64, 0xe7, - 0xa2, 0xef, 0xbd, 0x20, 0x71, 0x5b, 0xbc, 0xa7, 0xed, 0x70, 0x93, 0x1f, - 0xe9, 0x65, 0x1d, 0xb8, 0xd2, 0xfd, 0xc1, 0x4, 0x24, 0x56, 0xee, 0xf, - 0xca, 0x41, 0x77, 0xf7, 0x1c, 0x16, 0x39, 0x33, 0x66, 0x26, 0x81, 0x9c, - 0x3, 0xa2, 0x41, 0x8a, 0x71, 0x44, 0xb6, 0xc8, 0x2b, 0x31, 0xb6, 0x21, - 0xe2, 0x41, 0x92, 0xcd, 0x71, 0x98, 0x81, 0x75, 0x97, 0xdc, 0x0, 0x66, - 0x1c, 0xfc, 0x4a, 0xaa, 0x43, 0x75, 0x5d, 0x6c, 0xa7, 0xbe, 0x45, 0xa2, - 0x61, 0x47, 0x8b, 0x59, 0x4e, 0xe3, 0x0, 0x7, 0x3a, 0xb2, 0xc6, 0xdf, - 0x70, 0x28, 0xe6, 0xbd, 0x55, 0x20, 0x8b, 0x36, 0x72, 0xb9, 0x8a, 0x7d, - 0x6c, 0xbd, 0x73, 0x2d, 0x6, 0xe2, 0x9b, 0xc4, 0x3b, 0x1f, 0xdf, 0x1d, - 0xc8, 0x67, 0x87, 0x2c, 0x15, 0x22, 0xe1, 0xaf, 0x6f, 0x1a, 0x90, 0xb, - 0x25, 0x10, 0xd0, 0xdb, 0x5f, 0xd8, 0x69, 0x81, 0xf2, 0xf7, 0xf8, 0xca, - 0xfb, 0xa3, 0x76, 0x24, 0xc0, 0xd3, 0xc4, 0xfb, 0xa1, 0x94, 0xc2, 0x15, - 0x8d, 0x91, 0x6d, 0x3, 0x8e, 0x8d, 0xf, 0x46, 0xfd, 0x4a, 0x1, 0x95, - 0xf3, 0xf7, 0x6e, 0x45, 0x35, 0xb8, 0x3d, 0x4a, 0x19, 0xd3, 0x4a, 0x9b, - 0x6e, 0x81, 0x67, 0xe1, 0x5b, 0x25, 0xcd, 0x4e, 0x8e, 0x8d, 0x17, 0x1a, - 0x98, 0xb, 0xc2, 0xe6, 0x6e, 0x2a, 0x6b, 0x65, 0x30, 0x8a, 0x54, 0x21, - 0xd4, 0xbe, 0x1d, 0x2, 0x68, 0x7c, 0xee, 0x3c, 0x48, 0xba, 0xf7, 0xe7, - 0x46, 0xd6, 0x57, 0xf9, 0x1a, 0x63, 0x55, 0x70, 0x0, 0x87, 0x82, 0x42, - 0xc8, 0x5b, 0x7b, 0xf0, 0x88, 0x55, 0x4, 0xa6, 0x6d, 0x5c, 0x3a, 0x88, - 0xa0, 0xf4, 0xd3, 0x5f, 0xcd, 0x27, 0x8d, 0x2e, 0x1a, 0x76, 0xe8, 0x73, - 0x11, 0x32, 0xde, 0x4e, 0x44, 0x4e, 0x3e, 0x35, 0xfe, 0x8c, 0x90, 0x6, - 0x9c, 0x6b, 0x52, 0x73, 0xd0, 0x2a, 0x57, 0x77, 0x2c, 0xf1, 0xe6, 0x8a, - 0x7, 0x97, 0x9f, 0xae, 0x82, 0xa9, 0xfd, 0xe7, 0x25, 0x2f, 0xde, 0x2b, - 0xf1, 0x7e, 0x64, 0xcf, 0xd4, 0x1, 0xa5, 0x29, 0xe9, 0x2d, 0xde, 0x30, - 0x80, 0xe9, 0xdc, 0x9c, 0x20, 0x1d, 0x12, 0xd3, 0xa6, 0x74, 0x5d, 0xb0, - 0x25, 0x10, 0x7a, 0xa2, 0x65, 0x3, 0x8d, 0xfc, 0x9b, 0x2a, 0xfb, 0xa8, - 0xa0, 0x7e, 0x75, 0x10, 0x3f, 0xc2, 0x97, 0x4b, 0xd8, 0x19, 0x84, 0xd6, - 0xb1, 0x14, 0x39, 0xb8, 0x90, 0x29, 0x93, 0xaa, 0x3c, 0x62, 0x35, 0xa, - 0x11, 0x1a, 0x0, 0xf2, 0xf3, 0xb2, 0x4, 0xe, 0x6d, 0xa2, 0x14, 0x34, - 0xbd, 0x70, 0xb4, 0x8e, 0xa1, 0x92, 0x32, 0xc3, 0xa1, 0xdb, 0xdd, 0xac, - 0xa2, 0x4e, 0x35, 0x53, 0x16, 0xbb, 0xa7, 0x7b, 0x87, 0x7a, 0x37, 0x33, - 0xf6, 0x49, 0xa6, 0x36, 0xd8, 0xdd, 0x3f, 0x8, 0x5b, 0xe4, 0xcb, 0xe4, - 0xc7, 0x85, 0x8e, 0x17, 0x6d, 0xed, 0xe8, 0x8e, 0x6d, 0xa1, 0xb, 0x19, - 0x7c, 0x2c, 0xf9, 0xff, 0xb5, 0x77, 0x91, 0xa9, 0x59, 0x10, 0x16, 0x92, - 0x89, 0xcb, 0x8a, 0xb9, 0xa2, 0x28, 0x36, 0xf6, 0x36, 0x8b, 0xf1, 0xaa, - 0x5e, 0x3, 0x88, 0x76, 0xd9, 0x47, 0xa8, 0x67, 0x71, 0x7f, 0xeb, 0xd, - 0x84, 0x48, 0xa2, 0x90, 0x35, 0xe3, 0xbd, 0x8d, 0xe7, 0xeb, 0x7, 0xa6, - 0x2a, 0x9a, 0xe4, 0xb5, 0xab, 0x3e, 0xf2, 0x92, 0x84, 0x78, 0x42, 0x9, - 0xb0, 0xd7, 0x1c, 0x1c, 0x27, 0xd6, 0x78, 0x50, 0xad, 0x2a, 0xe8, 0x33, - 0x91, 0xa, 0xf9, 0x7c, 0xf, 0x5d, 0x75, 0x5c, 0xf8, 0x59, 0x7f, 0xa1, - 0x6f, 0x3d, 0xf9, 0xb8, 0x4b, 0x6a, 0x5, 0x54, 0xa0, 0x8a, 0xf1, 0xc, - 0x95, 0x25, 0x10, 0xb2, 0x1c, 0xfe, 0x36, 0x0, 0x83, 0xbe, 0x79, 0xd2, - 0x7e, 0xe9, 0x3f, 0x6c, 0x8a, 0xa7, 0x92, 0x86, 0xff, 0x56, 0xa9, 0x28, - 0x86, 0xf1, 0x94, 0xf1, 0xf7, 0x25, 0xd4, 0xe6, 0xd8, 0x71, 0xf8, 0xf5, - 0x7e, 0x20, 0x13, 0xb7, 0xa3, 0x38, 0xf0, 0x90, 0x17, 0x24, 0x45, 0xda, - 0x6e, 0xb4, 0xbd, 0x59, 0xba, 0x29, 0xba, 0x25, 0x78, 0xb8, 0xdd, 0x91, - 0x1c, 0x50, 0x8e, 0x5c, 0x2f, 0x57, 0x98, 0x5f, 0x61, 0xb0, 0x83, 0xeb, - 0x88, 0xe9, 0x42, 0x67, 0x51, 0x83, 0x9c, 0x4d, 0xd8, 0x5, 0x1d, 0x6c, - 0x7c, 0x83, 0xb7, 0xdb, 0x92, 0xa4, 0x3, 0xf8, 0x91, 0x90, 0xbb, 0xa5, - 0x64, 0xff, 0xb1, 0x1e, 0xf8, 0x46, 0x6f, 0x3b, 0xce, 0x9f, 0x70, 0x1d, - 0x5a, 0x64, 0x43, 0x8f, 0xcd, 0xcf, 0xa2, 0xa8, 0x38, 0x52, 0xcf, 0xf2, - 0x91, 0x1b, 0x32, 0xae, 0x32, 0xf7, 0x29, 0x36, 0x6f, 0xb3, 0x9d, 0x25, - 0x78, 0x3e, 0xbf, 0x41, 0x6b, 0xb4, 0x79, 0x5f, 0xf1, 0x92, 0x63, 0xd6, - 0xec, 0xbe, 0x4b, 0xef, 0x72, 0xca, 0x19, 0xca, 0x23, 0x98, 0xe2, 0xca, - 0x7d, 0x55, 0x87, 0xcc, 0xac, 0xb1, 0x33, 0xc4, 0xd6, 0x1e, 0xc6, 0xf8, - 0x82, 0x5, 0x23, 0x11, 0xe6, 0xf9, 0x85, 0x13, 0xa0, 0x81, 0xf1, 0x4, - 0x92, 0xbe, 0x43, 0xff, 0x3c, 0x96, 0xa0, 0x93, 0xe0, 0x72, 0xa, 0xee, - 0x4c, 0xf7, 0x25, 0x60, 0x74, 0xa2, 0xc7, 0xe8, 0xe4, 0xb9, 0x39, 0x6b, - 0xd5, 0xcb, 0x18, 0x71, 0x56, 0x53, 0xad, 0xe1, 0x7e, 0xa4, 0x33, 0x50, - 0x42, 0xd1, 0x2e, 0x12, 0x30, 0xd3, 0x32, 0xfd, 0xc8, 0x48, 0x86, 0x75, - 0xae, 0x37, 0xb2, 0x1b, 0x87, 0x3d, 0x9a, 0xd7, 0x10, 0xb0, 0xe1, 0x39, - 0xb9, 0xfb, 0xf5, 0xc6, 0x18, 0x9c, 0xb2, 0x6e, 0x6c, 0x64, 0x52, 0x5f, - 0x3e, 0xa7, 0x37, 0xb0, 0x9d, 0xc7, 0x85, 0x40, 0x71, 0xf3, 0xa6, 0xd6, - 0x80, 0x83, 0xa7, 0xc5, 0x46, 0x0, 0x9c, 0x88, 0x4e, 0x7d, 0x26, 0x87, - 0x7, 0x53, 0x1d, 0x27, 0x1f, 0xa5, 0x58, 0x6d, 0x73, 0xbb, 0x53, 0xa8, - 0xb1, 0x76, 0xc8, 0xe, 0xb7, 0x3a, 0x44, 0x87, 0x4a, 0x82, 0x1a, 0x25, - 0x2a, 0x96, 0x31, 0x16, 0xc8, 0xaf, 0x9a, 0x39, 0x9d, 0xf7, 0x2e, 0x79, - 0x70, 0x68, 0x2f, 0xdc, 0x6d, 0xe0, 0xb1, 0xee, 0x86, 0x2e, 0x24, 0xae, - 0x42, 0x95, 0xa3, 0xd8, 0xdf, 0xe0, 0xb6, 0xa3, 0x96, 0xf8, 0x4f, 0xfb, - 0x43, 0x9d, 0x50, 0x54, 0x41, 0x17, 0x75, 0xf4, 0xac, 0x8f, 0xcb, 0x9a, - 0x5b, 0x34, 0x75, 0x75, 0x50, 0xa7, 0x22, 0x4c, 0xae, 0x7, 0x46, 0xce, - 0x61, 0xa3, 0x53, 0xa7, 0xe9, 0x6b, 0x79, 0x32, 0xe0, 0xd1, 0xe8, 0xbf, - 0xf9, 0xce, 0x20, 0xae, 0xef, 0xc0, 0xf4, 0x4b, 0x95, 0x19, 0x13, 0xf0, - 0x89, 0x92, 0x12, 0xdc, 0x23, 0xa6, 0xb0, 0x2a, 0xc6, 0x47, 0xcc, 0xa9, - 0x4, 0x95, 0x69, 0x64, 0xb7, 0x21, 0x7f, 0xd, 0x4b, 0x60, 0x6d, 0x55, - 0xad, 0x11, 0xbe, 0xfe, 0x8a, 0x7e, 0x3, 0xa9, 0xc8, 0xc1, 0xbb, 0x12, - 0xd2, 0x3e, 0xfa, 0x8b, 0x53, 0xce, 0x54, 0x65, 0xfc, 0x79, 0xd3, 0x7b, - 0xdd, 0x6, 0xc3, 0x43, 0xc6, 0x5f, 0xe0, 0xe9, 0xfc, 0xca, 0xda, 0x1b, - 0xd6, 0xf4, 0xe4, 0x86, 0x1b, 0x6b, 0xb2, 0x8c, 0x16, 0x26, 0x33, 0xe6, - 0xca, 0xa4, 0x36, 0x80, 0x13, 0xf0, 0x90, 0xf3, 0x5, 0xff, 0x0, 0x61, - 0x13, 0x71, 0xab, 0x35, 0x83, 0xa2, 0x35, 0x24, 0x61, 0x91, 0xb0, 0x0, - 0x6f, 0x74, 0xb0, 0xeb, 0x46, 0xb3, 0x94, 0x46, 0x78, 0x55, 0x2e, 0x1d, - 0x6e, 0x1, 0x39, 0xea, 0x73, 0x8e, 0xcf, 0x97, 0x7b, 0xb3, 0xa9, 0x2f, - 0xc9, 0xfa, 0x74, 0x0, 0x35, 0x44, 0x58, 0x2f, 0x70, 0x3a, 0x1b, 0x44, - 0x56, 0x8b, 0xca, 0x34, 0x7f, 0x72, 0xd5, 0x77, 0x60, 0x7b, 0xce, 0x90, - 0x33, 0x7d, 0xd1, 0x39, 0x6d, 0x26, 0xa9, 0xc0, 0x51, 0x8c, 0x49, 0x24, - 0x16, 0xe6, 0xa5, 0x7d, 0x67, 0x40, 0x9a, 0xc9, 0xb4, 0x36, 0x3c, 0x6f, - 0x83, 0x65, 0xe2, 0x1a, 0xce, 0x95, 0xae, 0x58, 0xe0, 0x8a, 0x5d, 0xdc, - 0x70, 0xd2, 0xb9, 0x78, 0xb8, 0xc0, 0x12, 0xc1, 0xdd, 0x39, 0x52, 0x4c, - 0x8f, 0x19, 0xcf, 0x78, 0xf9, 0xcc, 0xc6, 0x44, 0xce, 0x95, 0x17, 0x8c, - 0x74, 0x7b, 0xfd, 0x73, 0x20, 0xe9, 0x3a, 0x5c, 0x51, 0x39, 0xc6, 0x99, - 0x1a, 0x57, 0x13, 0x37, 0xa7, 0x9a, 0x55, 0x20, 0x3f, 0x86, 0x27, 0x11, - 0xa5, 0x48, 0xc7, 0xee, 0xf3, 0xba, 0x1a, 0xc4, 0xce, 0x9, 0x14, 0xa8, - 0x90, 0x5, 0xe6, 0x96, 0xe4, 0x89, 0xc5, 0x42, 0x53, 0xdb, 0xce, 0xe5, - 0xf5, 0x36, 0x7c, 0x42, 0xb3, 0x1a, 0x43, 0xe, 0xcc, 0xbf, 0x98, 0x88, - 0x44, 0xc2, 0x4a, 0x2, 0xad, 0xc4, 0x46, 0xbc, 0x66, 0x8f, 0x18, 0x41, - 0xf9, 0xfa, 0x33, 0x86, 0x87, 0x4d, 0x94, 0x67, 0x79, 0x2a, 0x88, 0xbc, - 0xf6, 0x46, 0x7c, 0x8e, 0xb1, 0x35, 0xb1, 0xfd, 0xe7, 0xf, 0xec, 0x9b, - 0x90, 0xfe, 0x1e, 0x96, 0xf9, 0x91, 0xcc, 0x71, 0xca, 0xb8, 0x2d, 0x2b, - 0x9a, 0x5a, 0x19, 0xa9, 0x30, 0x3c, 0x64, 0xe, 0x84, 0xb4, 0x92, 0x7b, - 0xa6, 0x76, 0x35, 0xa4, 0xa, 0x39, 0x67, 0xdb, 0xf4, 0x1e, 0xda, 0x5, - 0xc8, 0x50, 0xff, 0xbc, 0xa0, 0x68, 0x66, 0x54, 0xf0, 0xcf, 0xb0, 0x39, - 0x77, 0x39, 0x23, 0xc8, 0x19, 0x27, 0xa, 0x2a, 0xf1, 0xd6, 0xe6, 0x55, - 0x38, 0x1e, 0xa8, 0xe3, 0x5e, 0x8f, 0xed, 0x90, 0xe1, 0x35, 0x1d, 0x8a, - 0x1, 0xac, 0xe7, 0x43, 0xc5, 0x43, 0xc7, 0x87, 0x5f, 0x35, 0xe0, 0x4c, - 0xfd, 0xef, 0x63, 0x1b, 0x70, 0xf2, 0x5c, 0x9f, 0x67, 0xe8, 0xe8, 0x1, - 0xe2, 0x89, 0x4c, 0x85, 0x2d, 0xf0, 0x91, 0x78, 0x8e, 0xe6, 0x7e, 0x9a, - 0x12, 0xa3, 0x99, 0x8, 0x3f, 0x93, 0x7f, 0x7e, 0x19, 0x95, 0x93, 0xf, - 0x43, 0x86, 0x1b, 0xe8, 0x74, 0xdf, 0xe6, 0x89, 0xa, 0xbd, 0x37, 0x82, - 0x5f, 0xa4, 0x84, 0xf1, 0x12, 0xc2, 0xbd, 0x45, 0x89, 0x17, 0xc9, 0x41, - 0x87, 0x77, 0x59, 0x1b, 0x72, 0x3f, 0x69, 0x90, 0xa0, 0x43, 0x8f, 0xad, - 0xc5, 0xa, 0x44, 0x33, 0x2b, 0xef, 0x7e, 0x81, 0x3a, 0x48, 0x43, 0x1a, - 0xf5, 0x3b, 0x2d, 0x15, 0x57, 0x41, 0x29, 0x5a, 0x25, 0x93, 0xb7, 0xdd, - 0x6, 0x9d, 0x96, 0xf7, 0x54, 0xd7, 0x9d, 0x1f, 0x96, 0x5f, 0xb4, 0xfb, - 0x43, 0x8f, 0xed, 0xbe, 0x82, 0x7d, 0xbb, 0x84, 0xb9, 0x58, 0x8e, 0x2d, - 0xc8, 0xff, 0x98, 0x2b, 0x8a, 0xe5, 0x2d, 0x38, 0xc7, 0x46, 0x63, 0x26, - 0x27, 0x70, 0x29, 0x99, 0x61, 0x5b, 0x72, 0xee, 0x7d, 0x3b, 0xd7, 0x56, - 0xfe, 0x96, 0xb0, 0xc0, 0x59, 0x91, 0x91, 0x43, 0xd6, 0x54, 0x7d, 0xce, - 0xf6, 0x76, 0x20, 0xb1, 0x24, 0x77, 0x66, 0x16, 0xd3, 0x1, 0xb4, 0x6b, - 0xdf, 0x3d, 0xc4, 0xab, 0xbf, 0xd1, 0x9d, 0xaa, 0x9f, 0xd0, 0x15, 0x2c, - 0x3b, 0x1d, 0x19, 0xa3, 0x8, 0x1f, 0xfb, 0xb6, 0xb4, 0x4c, 0x2e, 0x62, - 0x3f, 0x4e, 0x8, 0x55, 0x61, 0x17, 0xc, 0x60, 0xbe, 0xa, 0xf1, 0xf3, - 0xe7, 0xbd, 0x6a, 0x6d, 0xe2, 0x48, 0x74, 0x65, 0xd1, 0x3c, 0x39, 0x85, - 0xe3, 0xbc, 0x58, 0x59, 0x32, 0x49, 0x70, 0x8, 0xfd, 0x40, 0x76, 0xb7, - 0xdf, 0x61, 0xb7, 0x6e, 0xcc, 0x40, 0xc2, 0x2, 0xb0, 0x74, 0x59, 0x2d, - 0xf, 0xe, 0xd5, 0x56, 0x9b, 0x15, 0x1e, 0xcd, 0xdb, 0x27, 0xe5, 0x4c, - 0x3f, 0x86, 0x9a, 0x10, 0x47, 0x68, 0x7b, 0xa9, 0xca, 0xa2, 0x5d, 0xc1, - 0xd0, 0x26, 0x80, 0xb0, 0x14, 0x0, 0x33, 0xc4, 0xb7, 0x4d, 0x24, 0xcc, - 0x99, 0xe9, 0x62, 0xad, 0xc, 0xa5, 0x4e, 0x1f, 0x6c, 0x2f, 0xc7, 0xb0, - 0x62, 0xe7, 0xa6, 0xb9, 0x20, 0x44, 0x4a, 0xd8, 0xe3, 0x6, 0xbc, 0x26, - 0x84, 0xc9, 0x94, 0xfa, 0xc0, 0xa5, 0xc0, 0x3a, 0xaa, 0x58, 0x96, 0x56, - 0xe0, 0x6c, 0x4b, 0x75, 0xc3, 0x90, 0x46, 0xe0, 0xfd, 0x1d, 0xc5, 0x94, - 0xb7, 0xf0, 0x37, 0x5d, 0x42, 0x38, 0x20, 0x75, 0x90, 0x95, 0x6b, 0xff, - 0xcd, 0xf4, 0x56, 0xca, 0xf7, 0x26, 0xee, 0xaf, 0x75, 0x5f, 0x52, 0xdc, - 0x3b, 0xac, 0x98, 0x7, 0x72, 0xbb, 0xb9, 0xb3, 0x38, 0x21, 0xac, 0x2c, - 0xf9, 0xe9, 0xee, 0xbf, 0x93, 0x15, 0x75, 0xd6, 0xa7, 0xd, 0xae, 0x5e, - 0x22, 0x79, 0x8e, 0x84, 0x17, 0xb2, 0x49, 0x8, 0x2c, 0x13, 0x12, 0x72, - 0x70, 0x31, 0x4c, 0xba, 0x6c, 0x82, 0x10, 0x69, 0xf3, 0x43, 0x16, 0x47, - 0x96, 0xbd, 0xc6, 0x43, 0xbd, 0xe0, 0xf6, 0xa5, 0x2a, 0x64, 0x7a, 0xe0, - 0x4f, 0x91, 0xf2, 0x51, 0x42, 0x80, 0xba, 0x11, 0xf7, 0x61, 0x3f, 0xa9, - 0xb9, 0x62, 0x21, 0x78, 0xef, 0x99, 0x68, 0x2a, 0x82, 0xcf, 0x62, 0xb3, - 0xb7, 0xe9, 0x79, 0x69, 0x9c, 0x84, 0xcb, 0x3f, 0x59, 0x79, 0xc8, 0x17, - 0x5b, 0x7, 0x74, 0xf0, 0x8c, 0x65, 0x85, 0x3, 0x48, 0x7b, 0x80, 0x3c, - 0xcd, 0xe3, 0xf6, 0x50, 0xc1, 0x0, 0x3b, 0x14, 0xa, 0xfd, 0xcb, 0x46, - 0x99, 0x31, 0xb5, 0xa2, 0x72, 0x94, 0x25, 0x10, 0xd4, 0x7f, 0x2a, 0x2d, - 0x91, 0x47, 0xff, 0x55, 0xb3, 0x4f, 0x99, 0xfe, 0x9d, 0xbf, 0xb1, 0xf8, - 0xec, 0xac, 0x6d, 0xc, 0xe0, 0x94, 0x49, 0xe2, 0x1b, 0x73, 0xcc, 0x9a, - 0xc9, 0x95, 0xdb, 0x4b, 0x0, 0x86, 0xb9, 0x85, 0x42, 0xbc, 0xd5, 0xb8, - 0xc3, 0x2b, 0x39, 0xa2, 0x8, 0xc8, 0x2e, 0x1, 0xf0, 0x39, 0x6d, 0x7e, - 0xe1, 0x67, 0x42, 0xad, 0xc7, 0x3, 0x6f, 0x7a, 0x84, 0x5, 0xe0, 0x6a, - 0xbe, 0x24, 0x59, 0x87, 0x46, 0xcf, 0x1d, 0x3b, 0xa, 0x8c, 0xd9, 0x8e, - 0x60, 0xc1, 0x52, 0xb2, 0x18, 0xfc, 0x56, 0x1a, 0x20, 0x55, 0x8a, 0xa5, - 0x41, 0x2e, 0x4d, 0x4d, 0x0, 0x11, 0x93, 0xe3, 0x7f, 0xdc, 0x7f, 0x2d, - 0xde, 0xe3, 0x81, 0x1c, 0xf7, 0x11, 0xeb, 0x2a, 0xc3, 0x5f, 0x2c, 0xdb, - 0x45, 0xa3, 0x9a, 0x94, 0x6c, 0x5c, 0xd6, 0x38, 0xf, 0xe6, 0x91, 0x13, - 0xc4, 0xd7, 0xe2, 0x19, 0xfd, 0x90, 0x31, 0xc0, 0x9e, 0xeb, 0x2d, 0xfa, - 0x8c, 0xdc, 0xee, 0x27, 0xb9, 0x62, 0xb0, 0xa2, 0x4b, 0x4f, 0xb6, 0xd8, - 0x38, 0xe6, 0xb5, 0x39, 0xc0, 0xfa, 0x7, 0x62, 0xd2, 0xf0, 0x53, 0xa5, - 0x10, 0x9e, 0x5a, 0xe6, 0xdf, 0x89, 0x9f, 0x14, 0x1c, 0x1c, 0xd4, 0x59, - 0x85, 0x67, 0x90, 0xa2, 0xe6, 0xb0, 0xfa, 0x2d, 0x26, 0x7b, 0xcc, 0xab, - 0xde, 0xd5, 0xc7, 0x24, 0xfd, 0xfe, 0xa7, 0x5a, 0x77, 0x63, 0x1c, 0x8e, - 0xe8, 0x85, 0x83, 0x16, 0x77, 0x44, 0x34, 0xda, 0xd4, 0x98, 0x1d, 0x22, - 0xa5, 0xe6, 0x95, 0xe7, 0x7b, 0xd8, 0xfa, 0xde, 0xdf, 0x5, 0x27, 0x4b, - 0x29, 0x80, 0xbf, 0x5f, 0x87, 0x14, 0xe0, 0xa0, 0xa0, 0xe9, 0xc7, 0xc1, - 0xa1, 0x48, 0x22, 0x30, 0x37, 0xb3, 0x9, 0xd9, 0xa6, 0x18, 0x54, 0xe, - 0xb1, 0x3d, 0x48, 0xa4, 0x63, 0x70, 0x3e, 0xcb, 0x1d, 0x9b, 0x6f, 0x97, - 0xd2, 0xbf, 0x22, 0x93, 0xd0, 0x51, 0xdf, 0x9c, 0xf8, 0x47, 0x57, 0x74, - 0xc8, 0x40, 0x1b, 0x51, 0x3a, 0x14, 0x4b, 0x6e, 0xce, 0xd5, 0x38, 0x81, - 0x94, 0xda, 0x2f, 0x39, 0x84, 0x46, 0x8a, 0xf, 0x46, 0x6f, 0x7b, 0x5e, - 0x7d, 0x53, 0x30, 0x7, 0xea, 0xb, 0xaa, 0xd0, 0x7a, 0x98, 0xf4, 0xb8, - 0x51, 0x10, 0xca, 0x83, 0x72, 0x10, 0x86, 0x91, 0x81, 0x12, 0x53, 0x64, - 0x9a, 0xc8, 0xab, 0x9f, 0xd0, 0x82, 0x99, 0xb1, 0x43, 0x97, 0xc8, 0xa5, - 0x8, 0x7, 0xe, 0x23, 0xdb, 0xaf, 0x2d, 0x31, 0x3a, 0x87, 0xfa, 0x77, - 0x28, 0x49, 0x5e, 0x2c, 0x82, 0x40, 0x15, 0xa5, 0xb4, 0x46, 0x1, 0x93, - 0x5c, 0x19, 0x56, 0x67, 0x39, 0x23, 0x76, 0x67, 0x8d, 0xa9, 0xb4, 0x44, - 0x59, 0x1e, 0x5e, 0x93, 0x4c, 0x6e, 0xb0, 0x30, 0xd3, 0x87, 0x57, 0xfa, - 0xa5, 0xee, 0x42, 0xa0, 0xe5, 0x8d, 0x15, 0x8b, 0xd4, 0x12, 0x1c, 0x60, - 0xdf, 0xc, 0x27, 0xdf, 0x8f, 0x1, 0x7c, 0x31, 0xae, 0xd9, 0xd0, 0xad, - 0x3, 0x27, 0x32, 0x28, 0xbb, 0xd8, 0xb, 0x3b, 0xd, 0x3e, 0x9c, 0x3a, - 0x73, 0x8b, 0xd, 0x52, 0x8d, 0x4, 0x11, 0xe6, 0x65, 0x61, 0xcb, 0x9b, - 0x89, 0xe2, 0x1d, 0x43, 0xb3, 0xd5, 0x1, 0x1b, 0x0, 0xe0, 0xd1, 0x10, - 0x26, 0xf0, 0xda, 0x2, 0x56, 0xf4, 0x10, 0x39, 0xab, 0xc, 0x2f, 0x57, - 0x66, 0x54, 0x42, 0x72, 0x78, 0x45, 0x4c, 0x1c, - }, +const uint8_t kAltGameImages1xA[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x40, 0xcc, 0xc1, 0x2f, + 0xc8, 0x25, 0x29, 0x6e, 0xe, 0x12, 0x32, 0xe9, 0xe3, 0xad, 0xfa, 0xdf, + 0x55, 0x8a, 0x6, 0x12, 0xa2, 0x4e, 0xa6, 0x2e, 0xbd, 0x3, 0xeb, 0xdc, + 0x54, 0x29, 0xf4, 0x22, 0x7f, 0xdc, 0x80, 0xb3, 0xe1, 0xe2, 0xa5, 0xcf, + 0xa7, 0x7f, 0x7, 0x8a, 0xe, 0xa, 0x50, 0x50, 0xf7, 0x45, 0xa9, 0x9, + 0xee, 0xea, 0x93, 0xdb, 0xb2, 0xe5, 0x41, 0xfd, 0xc2, 0xf9, 0x2f, 0xf2, + 0x41, 0x0, 0x6d, 0x68, 0x2, 0x9e, 0x20, 0xe7, 0x90, 0x73, 0x6b, 0x57, + 0x44, 0x54, 0xcd, 0xd2, 0x90, 0x0, 0x2d, 0x58, 0xe8, 0x9d, 0x53, 0x59, + 0x32, 0xee, 0xca, 0xf0, 0xd4, 0xa6, 0x3c, 0x3, 0x52, 0x75, 0x7d, 0x83, + 0x97, 0x4e, 0x44, 0x79, 0xf2, 0xb6, 0x2, 0xab, 0xcc, 0xc9, 0xa8, 0x3, + 0xb9, 0x11, 0x2f, 0xe2, 0x1e, 0x16, 0xc6, 0x6c, 0x5b, 0x8c, 0xfb, 0xbb, + 0xe2, 0xd3, 0x86, 0xe9, 0x1b, 0xfa, 0xcc, 0x4c, 0xf8, 0xa, 0xd7, 0x1c, + 0xa1, 0x7, 0xd6, 0xf9, 0x13, 0x1, 0xb, 0x3c, 0x18, 0x1f, 0x1e, 0x6f, + 0x7d, 0xdf, 0xb8, 0xd6, 0xbd, 0xb3, 0x36, 0x8f, 0xef, 0xd3, 0x5, 0x17, + 0x2d, 0xf, 0x57, 0xcf, 0xa5, 0x73, 0x14, 0xc8, 0xee, 0x4e, 0xc2, 0x22, + 0x71, 0x8d, 0x29, 0x4b, 0xc2, 0xd5, 0xa0, 0x37, 0xe6, 0xad, 0xa4, 0xc1, + 0x8a, 0x72, 0xc1, 0x29, 0x87, 0x16, 0xb1, 0xad, 0xd3, 0xc7, 0x0, 0xa0, + 0x14, 0x5c, 0x2a, 0x10, 0x4f, 0xff, 0xe2, 0xb0, 0x3a, 0x93, 0xa8, 0xd5, + 0x43, 0xb, 0xa3, 0x78, 0x87, 0xbf, 0xf5, 0x79, 0x37, 0x34, 0xa8, 0xb2, + 0x1b, 0xab, 0x44, 0x86, 0x9c, 0x23, 0xc4, 0x76, 0x89, 0x6, 0x2e, 0x6c, + 0x8f, 0x5a, 0xfe, 0x96, 0xd4, 0xbf, 0x8, 0x3c, 0x3b, 0xd6, 0x34, 0xb4, + 0xc7, 0xb1, 0xa0, 0x38, 0x8f, 0x4b, 0xb4, 0xc6, 0x16, 0xaf, 0xc9, 0x28, + 0x8, 0xf1, 0x6a, 0xaa, 0x72, 0xf0, 0x53, 0xa8, 0x4b, 0x7, 0x22, 0x4b, + 0xa6, 0xa0, 0x65, 0xfc, 0xa8, 0xcd, 0x98, 0x26, 0x3c, 0xe6, 0xa6, 0x64, + 0x0, 0x3d, 0xd9, 0xa2, 0x77, 0xe1, 0x75, 0x5f, 0xf0, 0x1f, 0x69, 0xee, + 0x5b, 0x2f, 0x47, 0xdb, 0x75, 0x73, 0xed, 0xe4, 0x9f, 0x41, 0xd8, 0xb1, + 0x58, 0x6e, 0x5f, 0x45, 0xe1, 0x39, 0xae, 0xd1, 0xc, 0x78, 0x62, 0xb, + 0xef, 0x40, 0xd4, 0x15, 0xea, 0x7f, 0xa3, 0xb1, 0x5b, 0x44, 0xc0, 0xd, + 0x7f, 0x69, 0xb, 0x43, 0xbe, 0x11, 0xd, 0x7d, 0xaa, 0xd9, 0xaf, 0x78, + 0x99, 0xad, 0x1c, 0x25, 0xd2, 0x88, 0xb5, 0x5c, 0xf0, 0x27, 0xd9, 0x31, + 0xf0, 0x84, 0xbb, 0xf4, 0x66, 0x9f, 0x8b, 0xc, 0x18, 0x6e, 0xf7, 0x4d, + 0x3, 0xb5, 0x66, 0xb2, 0xdf, 0xf2, 0xd4, 0x8e, 0xef, 0xca, 0x99, 0xdd, + 0xd, 0x47, 0x86, 0xa, 0xc, 0xba, 0xce, 0xab, 0x7f, 0xae, 0x2f, 0xa9, + 0x49, 0x2b, 0x20, 0xe1, 0x80, 0x73, 0x0, 0xa9, 0x91, 0xe5, 0xce, 0x34, + 0x2c, 0xdb, 0x3c, 0xe3, 0x13, 0xdb, 0x65, 0x80, 0x90, 0xe4, 0x10, 0x8f, + 0x9b, 0xa5, 0xaa, 0xfe, 0x87, 0x6a, 0x73, 0x3, 0x64, 0x32, 0xe, 0xc4, + 0x3b, 0x8b, 0xb7, 0x2b, 0x42, 0x79, 0x60, 0x9d, 0x83, 0x12, 0xe3, 0x6a, + 0x65, 0x1f, 0x47, 0x3e, 0x6c, 0xa5, 0xe9, 0xda, 0x1e, 0x21, 0xe7, 0x44, + 0xdb, 0x72, 0x3c, 0xd4, 0x25, 0x39, 0x5a, 0x2, 0xb6, 0x53, 0xbe, 0x18, + 0x9a, 0x99, 0x26, 0xc6, 0x86, 0xfb, 0x2e, 0x79, 0xe2, 0x21, 0xaa, 0x56, + 0x52, 0x2b, 0xa0, 0xd9, 0x1f, 0x75, 0x99, 0x4c, 0xe2, 0x3f, 0x87, 0x90, + 0xc1, 0x29, 0x99, 0x78, 0xab, 0x15, 0x27, 0x55, 0xa2, 0x4f, 0x5c, 0x72, + 0x49, 0x4e, 0xc2, 0xd6, 0xaa, 0xe1, 0x0, 0x8, 0x70, 0x50, 0x64, 0x13, + 0xf0, 0x97, 0x38, 0x0, 0x95, 0x8f, 0x87, 0x4a, 0x46, 0x3f, 0xba, 0x83, + 0x96, 0x20, 0x29, 0x11, 0x19, 0xe5, 0x5b, 0x31, 0x8, 0xf1, 0x4a, 0x97, + 0xdd, 0x52, 0x1c, 0x6a, 0xc, 0xc, 0x6a, 0x13, 0x5b, 0x23, 0x49, 0xdf, + 0x95, 0x86, 0x82, 0x43, 0xde, 0x4a, 0x35, 0x88, 0x9a, 0x83, 0x2, 0xcc, + 0xc3, 0x16, 0x48, 0x0, 0x46, 0xeb, 0xde, 0x87, 0x98, 0xbd, 0xf7, 0x81, + 0xb9, 0xc6, 0xfc, 0xf4, 0x46, 0x98, 0x1, 0xd5, 0x7a, 0xf6, 0x1b, 0x3f, + 0xdb, 0x98, 0xf3, 0x22, 0x37, 0x5b, 0x7c, 0x3c, 0xd2, 0x41, 0x19, 0x11, }; +const uint8_t kAltGameImages1xB[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, + 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, + 0x13, 0x4a, 0xf5, 0xa0, 0x9b, 0x79, 0xc7, 0xcb, 0x4c, 0x57, 0xce, 0xbc, + 0x34, 0x95, 0x4e, 0xd9, 0xb6, 0x68, 0x9e, 0xf3, 0xaa, 0xea, 0xa3, 0x5a, + 0x57, 0x58, 0x30, 0x2c, 0xc8, 0x4b, 0x68, 0xd7, 0x11, 0x8a, 0x36, 0xdb, + 0x60, 0xb4, 0x3e, 0xca, 0xa, 0xba, 0x12, 0x36, 0x38, 0x56, 0xc0, 0x61, + 0xbc, 0xd3, 0x4b, 0x95, 0x3, 0x9a, 0x8e, 0x7b, 0xd2, 0x62, 0x81, 0x7, + 0x56, 0x42, 0x88, 0xbe, 0xea, 0x2c, 0xdd, 0x7e, 0xf2, 0x5a, 0xb5, 0x5a, + 0xc7, 0x35, 0x4d, 0xe8, 0x8f, 0xd2, 0x4a, 0x3, 0x5c, 0xb7, 0xcf, 0x23, + 0x5f, 0xd1, 0x11, 0x13, 0x7a, 0xc1, 0x46, 0x26, 0x6c, 0x4d, 0xa2, 0x56, + 0x30, 0xf6, 0x5d, 0x27, 0xa, 0x35, 0x50, 0x2f, 0xee, 0xe1, 0x3, 0x9d, + 0xdd, 0xa5, 0x85, 0xb, 0xcc, 0x46, 0xbc, 0x95, 0x40, 0x97, 0xd, 0xba, + 0x9d, 0x24, 0x47, 0xe0, 0xd1, 0xca, 0x4b, 0x30, 0x87, 0x23, 0x3c, 0xe1, + 0xc8, 0x50, 0x29, 0x56, 0x9b, 0xee, 0x4c, 0xb8, 0x1c, 0x26, 0xce, 0xb, + 0x8a, 0xd5, 0xb5, 0x75, 0xbc, 0x76, 0xad, 0x87, 0xc, 0x47, 0x62, 0xf5, + 0x57, 0xf4, 0x0, 0xa1, 0xad, 0xfa, 0xc6, 0xc3, 0xf7, 0x83, 0xfe, 0x9d, + 0x25, 0xdd, 0x35, 0x81, 0xf5, 0x1a, 0x82, 0x1b, 0x93, 0xa5, 0x40, 0x11, + 0xe9, 0xe5, 0x6e, 0xac, 0x36, 0x33, 0xcc, 0x99, 0x7e, 0x11, 0x85, 0x79, + 0x24, 0x22, 0x74, 0xf7, 0x8d, 0xfb, 0x40, 0x80, 0x9a, 0xca, 0xb5, 0xbe, + 0x3a, 0x58, 0x6f, 0xa9, 0x76, 0xd4, 0xe8, 0x29, 0x80, 0xc7, 0xe, 0xdd, + 0xe, 0x75, 0xf6, 0xc8, 0x11, 0x21, 0x81, 0xce, 0x3f, 0x41, 0x4d, 0xd8, + 0x4c, 0x4b, 0x2e, 0xeb, 0x9f, 0xb3, 0x1a, 0xa4, 0x2f, 0xa5, 0x44, 0xbb, + 0xcd, 0x46, 0xe6, 0x1f, 0xd, 0xd0, 0xc3, 0x27, 0x8b, 0x3a, 0xbf, 0xda, + 0x8f, 0xaa, 0xfd, 0xc2, 0x49, 0xd, 0x5c, 0xb7, 0xbc, 0x23, 0x57, 0x2f, + 0x83, 0xd4, 0x8, 0xee, 0x1, 0x56, 0x78, 0xee, 0x90, 0xb8, 0x5a, 0x64, + 0x51, 0xad, 0xad, 0xfe, 0xe9, 0xae, 0x8e, 0xae, 0xe9, 0x26, 0x57, 0xf0, + 0x77, 0xe1, 0xc1, 0xd8, 0x9d, 0x49, 0x8e, 0x8f, 0x7, 0x8, 0xcc, 0x45, + 0x6a, 0x3c, 0xf2, 0xbf, 0xee, 0x4f, 0xb, 0xe9, 0x5a, 0xaf, 0xd4, 0x12, + 0xb0, 0xcd, 0x3, 0x3c, 0x96, 0x1e, 0xa9, 0x24, 0xab, 0x1d, 0x16, 0xea, + 0x1a, 0x41, 0x56, 0xc6, 0xc1, 0xb7, 0x96, 0x36, 0xec, 0x20, 0xeb, 0xc2, + 0x19, 0x37, 0x55, 0x66, 0x12, 0xf5, 0x3, 0x55, 0x2d, 0x27, 0x28, 0x65, + 0xdb, 0x64, 0xc5, 0x71, 0xfc, 0x76, 0x2f, 0xc0, 0x7b, 0x49, 0x90, 0x5f, + 0x5d, 0x4d, 0x6a, 0x66, 0x7d, 0xfb, 0xe2, 0x16, 0x72, 0x84, 0xb6, 0xcb, + 0x65, 0x2d, 0x8b, 0x22, 0x4b, 0x1d, 0x4a, 0xde, 0x6b, 0x8c, 0x2c, 0x45, + 0x6, 0xe6, 0x92, 0x2e, 0xaf, 0x55, 0x66, 0xb, 0xae, 0xe9, 0xd7, 0xd2, + 0x3e, 0xc1, 0xdc, 0xe4, 0x4, 0x58, 0x4a, 0x64, 0x30, 0x20, 0xc6, 0x2f, + 0xa9, 0xee, 0xed, 0xb3, 0xe4, 0xc9, 0xca, 0x34, 0x71, 0xfc, 0x2, 0x95, + 0x51, 0xe4, 0xd2, 0x3, 0x4d, 0x3d, 0x10, 0xa5, 0xdc, 0xc6, 0x5e, 0x5c, + 0x1f, 0x27, 0xc4, 0x7c, 0xd, 0xfc, 0xdb, 0xd6, 0xd5, 0x2b, 0xaa, 0xbc, + 0x22, 0x61, 0x56, 0x10, 0xc2, 0xfc, 0x58, 0x53, 0xea, 0x12, 0x9d, 0x49, + 0xbd, 0x7e, 0xf7, 0x8d, 0x16, 0x25, 0x86, 0x84, 0x92, 0x70, 0x5f, 0xdd, + 0x73, 0xc1, 0x7, 0xfa, 0xd3, 0xc1, 0xdc, 0x61, 0x36, 0x1c, 0x74, 0xa2, + 0x9, 0x3f, 0x66, 0x90, 0x47, 0x9e, 0x27, 0x39, 0x44, 0xde, 0x48, 0xa8, + 0x5b, 0xdc, 0x42, 0xc1, 0x49, 0x87, 0x64, 0xa, 0xea, 0x5, 0x7e, 0x48, + 0xf9, 0x42, 0xf0, 0xf6, 0x5a, 0x4c, 0xc2, 0xd2, 0xb2, 0x4f, 0x16, 0x63, + 0xce, 0x10, 0x13, 0xce, 0xf7, 0x6a, 0xa4, 0xe8, 0x3, 0xe3, 0xd6, 0x10, + 0x6f, 0xbd, 0xf4, 0x24, 0x3, 0x16, 0x1f, 0x51, 0x2f, 0x85, 0x5f, 0x5d, + 0xd6, 0xc4, 0xd2, 0x3f, 0xd2, 0xab, 0x6b, 0x89, 0x52, 0xdb, 0x6c, 0x7a, + 0xa1, 0xf8, 0xe3, 0x19, 0x47, 0x2e, 0x64, 0xe3, 0xf0, 0x4e, 0x6d, 0x5e, + 0xbc, 0x54, 0x54, 0x5d, 0x9a, 0xdf, 0xed, 0xa7, 0xcf, 0xa0, 0x6f, 0x5e, + 0x23, 0x6f, 0x52, 0x90, 0x50, 0x35, 0x68, 0x45, 0xd8, 0xc2, 0x9a, 0x9e, + 0xae, 0x13, 0x8a, 0xc1, 0x60, 0x72, 0xb7, 0x6d, 0xd, 0x61, 0xe9, 0x3c, + 0xe1, 0xbe, 0x22, 0xc5, 0xa2, 0x7d, 0x8a, 0x8b, 0x43, 0x14, 0xef, 0x5c, + 0xa4, 0x10, 0xb7, 0x7, 0x73, 0xad, 0xb4, 0x86, 0xae, 0xc0, 0x1c, 0xf4, + 0xd2, 0x6, 0xda, 0x1, 0x35, 0x17, 0xcd, 0xa6, 0x28, 0x44, 0xc9, 0xbf, + 0x97, 0xe5, 0x41, 0x37, 0xe5, 0xcf, 0x3f, 0x96, 0xb5, 0x67, 0xcc, 0xea, + 0x69, 0x8e, 0xfd, 0xd6, 0x92, 0x5d, 0x72, 0xf5, 0xfd, 0x57, 0xb8, 0x4e, + 0x1b, 0x2d, 0x31, 0x3b, 0x99, 0x1a, 0x3e, 0xd4, 0x54, 0x77, 0x2e, 0x4b, + 0x2e, 0x5f, 0xcd, 0x56, 0xd4, 0xf7, 0xfc, 0x7, 0x92, 0x28, 0x3f, 0xdb, + 0x4f, 0x41, 0x1e, 0x43, 0xbc, 0x37, 0x81, 0xda, 0xe4, 0xeb, 0x9c, 0xf3, + 0xa5, 0x5b, 0xf7, 0x11, 0xf6, 0x5b, 0x12, 0x85, 0x57, 0xdb, 0xf, 0x1, + 0xc5, 0xfb, 0x33, 0x65, 0xa6, 0x51, 0xfa, 0x43, 0x8d, 0x9d, 0x42, 0xe2, + 0xe, 0x61, 0x9d, 0xcb, 0x6b, 0xe2, 0xa0, 0x60, 0x67, 0xba, 0x7e, 0x55, + 0xaf, 0x24, 0x7d, 0x32, 0xb0, 0x27, 0xa8, 0xa1, 0xad, 0xa, 0xd, 0xed, + 0xed, 0x2c, 0xeb, 0x98, 0xd9, 0x49, 0xcb, 0xd5, 0x2e, 0x7, 0x32, 0x87, + 0x37, 0xa4, 0x2a, 0x1c, 0xf2, 0xce, 0xfb, 0xa8, 0x6a, 0xf2, 0xf7, 0x70, + 0x20, 0xbd, 0xca, 0x48, 0x76, 0xc9, 0x49, 0x58, 0x15, 0xbb, 0xcc, 0x21, + 0x60, 0x37, 0x31, 0xee, 0xbb, 0xff, 0xde, 0xd8, 0x6c, 0xeb, 0x55, 0x12, + 0xf8, 0xbb, 0x36, 0x11, 0xa4, 0x6f, 0x1d, 0x81, 0xd, 0xc3, 0xd9, 0xa7, + 0xee, 0xc2, 0x9c, 0x45, 0x78, 0x12, 0xd, 0x73, 0x11, 0x69, 0x14, 0x7d, + 0x23, 0xdb, 0x69, 0xdf, 0xc2, 0xc8, 0x5b, 0x4, 0xd5, 0x4f, 0xa, 0xfb, + 0x4f, 0x2d, 0x52, 0x3c, 0x99, 0x15, 0xec, 0xf8, 0x2b, 0x98, 0x3c, 0x2a, + 0xd5, 0x59, 0x57, 0xbb, 0xa0, 0x14, 0x5f, 0x9, 0x7e, 0xd5, 0xbe, 0x0, + 0x99, 0x61, 0x7c, 0x8b, 0xdb, 0x94, 0xc6, 0x43, 0x7c, 0x13, 0xee, 0x1c, + 0xfa, 0x61, 0x2b, 0xd2, 0xc6, 0xa, 0xba, 0x30, 0x55, 0x50, 0x9a, 0xa1, + 0x14, 0x78, 0x97, 0x46, 0x6f, 0xe0, 0xa8, 0xd4, 0x3f, 0xf5, 0x39, 0xc8, + 0x1e, 0x4f, 0x3f, 0xc8, 0x67, 0x10, 0x25, 0x36, 0x8a, 0x8, 0x2, 0x67, + 0x6a, 0x73, 0x93, 0x76, 0x74, 0x54, 0x9, 0x87, 0xac, 0x9f, 0x90, 0x3, + 0xb6, 0xb4, 0x79, 0xa7, 0x56, 0x7f, 0x71, 0x9a, 0x41, 0xb0, 0xf4, 0xc7, + 0xbb, 0xd8, 0x68, 0xa7, 0xa, 0xfe, 0xe, 0x15, 0xe2, 0xcf, 0x2d, 0xd4, + 0x3, 0xee, 0x12, 0xa9, 0xef, 0x81, 0xa1, 0xa6, 0x12, 0x38, 0x6c, 0x37, + 0xd3, 0x11, 0xaa, 0x7, 0x8f, 0xfe, 0xb4, 0xf0, 0x92, 0x66, 0xfc, 0xa, + 0xc2, 0x21, 0xa3, 0x62, 0xec, 0xec, 0xda, 0x4f, 0xb3, 0xeb, 0x1d, 0x8c, + 0x1a, 0x7c, 0x58, 0x12, 0x30, 0x52, 0x1f, 0xf3, 0x90, 0xcf, 0x8e, 0xc5, + 0xd5, 0x5d, 0xe3, 0x92, 0xf3, 0x66, 0x7a, 0x1d, 0xea, 0x9c, 0x95, 0x91, + 0xe9, 0x13, 0x82, 0xe6, 0xea, 0x66, 0x3f, 0x31, 0xab, 0xb7, 0x46, 0x87, + 0x4d, 0xc4, 0x1a, 0x4a, 0x34, 0xfb, 0x0, 0x85, 0xd2, 0xa5, 0x18, 0xf3, + 0x50, 0x3f, 0x79, 0x5c, 0xe5, 0x5b, 0xc2, 0xcb, 0xd5, 0xa3, 0x63, 0x6f, + 0x11, 0xae, 0xf1, 0x5, 0xb1, 0x53, 0x8b, 0x65, 0x80, 0x8d, 0xd3, 0x98, + 0x1e, 0xba, 0xe4, 0xe1, 0x4f, 0xd0, 0x9c, 0x2, 0x6c, 0xd1, 0x6e, 0x18, + 0xce, 0xec, 0x10, 0x28, 0x29, 0xd8, 0xd2, 0xfa, 0x38, 0xb0, 0x3, 0xb7, + 0xc4, 0x99, 0xa7, 0x56, 0x24, 0xba, 0x70, 0xf3, 0x8, 0xae, 0x7f, 0xf4, + 0xb1, 0x84, 0xb5, 0xa8, 0xd7, 0x7a, 0xd8, 0x53, 0xde, 0x2d, 0xc9, 0xd3, + 0x27, 0x95, 0xe3, 0x5a, 0x11, 0xcc, 0xdf, 0x5b, 0x13, 0x36, 0x25, 0x92, + 0x49, 0x31, 0x1d, 0x83, 0x87, 0x61, 0x91, 0x9b, 0x18, 0xb, 0xc0, 0x6e, + 0xab, 0xfc, 0x73, 0x76, 0x92, 0xbc, 0x27, 0xc4, 0x37, 0x83, 0xb0, 0x80, + 0x71, 0x82, 0x17, 0x8c, 0x8f, 0x9e, 0x32, 0xb, 0x5a, 0x3d, 0x4d, 0xb1, + 0x24, 0x7, 0x91, 0x2a, 0x42, 0x43, 0xcc, 0xba, 0xbc, 0xee, 0x7f, 0x41, + 0x46, 0xcf, 0x5e, 0x85, 0xd7, 0x4d, 0xbc, 0x9, 0xe7, 0xbe, 0xab, 0x4d, + 0x63, 0x5c, 0xc7, 0x1a, 0x7f, 0x57, 0xf8, 0xd7, 0xbe, 0x50, 0x1, 0xa1, + 0xe, 0x27, 0x9a, 0xb2, 0x3f, 0x2a, 0xbc, 0x8f, 0x1b, 0x6a, 0xe0, 0x3e, + 0x5b, 0x97, 0x3f, 0x2b, 0xdb, 0x1e, 0x4f, 0x7, 0xbf, 0x29, 0x7b, 0x8e, + 0x2a, 0x64, 0x30, 0xbd, 0x1f, 0x53, 0xaa, 0x63, 0xad, 0x1d, 0x3e, 0xfd, + 0xd6, 0x6b, 0x32, 0x94, 0x84, 0xbe, 0x7e, 0x49, 0x72, 0x20, 0xec, 0xd4, + 0x63, 0xe7, 0xd, 0xbb, 0x3f, 0x70, 0x70, 0x43, 0x3a, 0xab, 0x6f, 0xb7, + 0x5b, 0x23, 0x7f, 0x23, 0xe, 0x36, 0xa2, 0xee, 0x72, 0xf9, 0x5d, 0x63, + 0x78, 0xfc, 0x19, 0x1e, 0x9c, 0x64, 0x87, 0xdb, 0xe6, 0x70, 0xd6, 0x60, + 0x1c, 0x3e, 0x38, 0x31, 0x94, 0xf4, 0xd9, 0x3f, 0xa1, 0x9c, 0x16, 0xae, + 0x80, 0x7b, 0x8d, 0x20, 0xa6, 0xf6, 0xd4, 0x37, 0x74, 0x44, 0x94, 0xaf, + 0x3c, 0x89, 0x8c, 0xdb, 0x3b, 0x96, 0x79, 0x15, 0xa, 0x2f, 0x1, 0xd, + 0x74, 0x99, 0x82, 0x51, 0x17, 0x97, 0x47, 0x68, 0x80, 0x55, 0x2d, 0x6c, + 0x11, 0x45, 0x5a, 0xee, 0x4a, 0xd6, 0x84, 0x76, 0x97, 0xad, 0x58, 0x40, + 0xf7, 0x15, 0x2f, 0xdc, 0x5c, 0x4a, 0x7b, 0x65, 0xc6, 0x20, 0x5a, 0x24, + 0xc5, 0xf4, 0xb0, 0x36, 0xb9, 0x61, 0xd, 0xbf, 0xe, 0x9f, 0x2d, 0x97, + 0xbb, 0x86, 0x5c, 0x40, 0x70, 0x86, 0x0, 0x4, 0x70, 0x66, 0x70, 0x65, + 0xdb, 0x39, 0x1d, 0x78, 0xd5, 0x7d, 0x92, 0xae, 0x0, 0x19, 0xef, 0x90, + 0x21, 0x92, 0x4, 0xcd, 0x22, 0x19, 0xa7, 0xc8, 0x3f, 0xa0, 0x38, 0x5b, + 0xfb, 0x46, 0x56, 0xd2, 0x11, 0xf1, 0xf9, 0x37, 0x53, 0xc, 0x98, 0x38, + 0x87, 0xc4, 0xed, 0x88, 0xf9, 0xc3, 0x6, 0x50, 0x19, 0x4b, 0xa8, 0x43, + 0x5f, 0xe5, 0xf, 0x79, 0x5f, 0x59, 0x22, 0x3c, 0x76, 0xdc, 0x51, 0x6d, + 0xb0, 0x2b, 0xf0, 0x95, 0x5c, 0xe4, 0x33, 0xb0, 0xff, 0xa3, 0xc8, 0xe0, + 0x85, 0xe0, 0x8a, 0xfe, 0xf, 0x63, 0x2d, 0x2b, 0x4a, 0x1a, 0xf9, 0xcb, + 0xb4, 0x86, 0x1, 0x1, 0xd4, 0x8f, 0x57, 0x82, 0xb0, 0xac, 0x52, 0x5d, + 0x5a, 0x79, 0x2c, 0x2d, 0x18, 0x1, 0x78, 0x3f, 0xb8, 0x31, 0x66, 0x9, + 0x61, 0x0, 0x8f, 0x4c, 0x4f, 0x18, 0x57, 0xc8, 0x39, 0x7, 0x44, 0x15, + 0xe4, 0x64, 0xed, 0x3c, 0xa2, 0x59, 0x38, 0x88, 0x13, 0xd0, 0x4c, 0xef, + 0xc6, 0x7, 0x37, 0x3, 0x81, 0xb1, 0x9, 0xce, 0xa6, 0x8e, 0x3b, 0x70, + 0x25, 0x87, 0xc4, 0x46, 0x60, 0x9a, 0xb5, 0xa8, 0xd3, 0x39, 0xd7, 0xa1, + 0xc8, 0x84, 0xa, 0x96, 0xe8, 0x73, 0x9, 0x1e, 0xb9, 0xde, 0x38, 0xc4, + 0x5, 0x60, 0x26, 0xc6, 0x51, 0x1b, 0x65, 0x66, 0x53, 0xd6, 0xa2, 0x2d, + 0x97, 0x5a, 0xb0, 0x9a, 0xb9, 0xf0, 0xcb, 0x7a, 0x94, 0xac, 0x9b, 0x9d, + 0xc3, 0x22, 0xf3, 0x44, 0x59, 0x13, 0x88, 0x18, 0x76, 0x26, 0x16, 0x67, + 0x85, 0x2a, 0x3d, 0x11, 0xc3, 0x69, 0x81, 0x9e, 0x96, 0x1e, 0x8, 0x23, + 0x9, 0x1a, 0x39, 0x44, 0xf2, 0x21, 0xd7, 0xa0, 0xc2, 0xb3, 0x6d, 0x42, + 0x6, 0xee, 0x6e, 0xf9, 0xad, 0x9c, 0x8c, 0x1, 0x6, 0xe6, 0x6, 0x19, + 0x7, 0xb1, 0x18, 0xdf, 0xe2, 0xa2, 0x97, 0x25, 0x32, 0x27, 0x1, 0x50, + 0xfc, 0xef, 0xa, 0x84, 0xd7, 0x43, 0x1b, 0xa2, 0xa0, 0x1e, 0x7e, 0x72, + 0x84, 0xce, 0xee, 0x25, 0x90, 0xcb, 0x47, 0xe3, 0xa0, 0xd1, 0x96, 0xbb, + 0xec, 0x95, 0x95, 0x73, 0xe7, 0xbc, 0x9c, 0xc5, 0x49, 0x8e, 0x71, 0x85, + 0x52, 0xf4, 0x27, 0x35, 0x89, 0xbb, 0x73, 0x78, 0xe2, 0xdb, 0xd8, 0xd2, + 0xe7, 0x92, 0xa3, 0x31, 0x22, 0x28, 0xf9, 0x56, 0x72, 0x9f, 0x3c, 0x72, + 0xda, 0x77, 0x5a, 0xd8, 0x9f, 0xc5, 0x75, 0xc6, 0xc5, 0xae, 0xb2, 0x33, + 0x40, 0x35, 0x71, 0x88, 0x11, 0xb0, 0xf1, 0xeb, 0xa0, 0x4d, 0xed, 0x46, + 0xd9, 0x6b, 0x8a, 0xf1, 0xcc, 0x36, 0x6d, 0x90, 0x58, 0x79, 0x7b, 0xad, + 0x81, 0xef, 0xd6, 0x39, 0xa3, 0xeb, 0x14, 0xd4, 0x82, 0x3a, 0x5a, 0x51, + 0x53, 0xf9, 0x9a, 0x54, 0x52, 0x76, 0xd, 0xa, 0xc3, 0x15, 0x87, 0x65, + 0x11, 0x38, 0x61, 0x83, 0x67, 0xd6, 0x6a, 0x9b, 0xbf, 0xf2, 0x1c, 0x65, + 0x7c, 0x58, 0xd9, 0x7f, 0x49, 0xa1, 0x63, 0x61, 0x17, 0xc9, 0x3d, 0x9a, + 0x26, 0xc0, 0xd3, 0x6a, 0x71, 0x95, 0xeb, 0x62, 0x26, 0xca, 0x14, 0x60, + 0x49, 0x32, 0xa, 0x5a, 0x8f, 0x29, 0x80, 0xc8, 0xfb, 0x6, 0xff, 0x1a, + 0x7e, 0x55, 0x65, 0x5c, 0x44, 0xc4, 0xa0, 0x72, 0xf0, 0xa1, 0xad, 0x4d, + 0xad, 0x3, 0xbe, 0x6e, 0xdb, 0x75, 0xd5, 0x6c, 0x5f, 0xaf, 0xa3, 0xaf, + 0xef, 0x62, 0x15, 0x49, 0x73, 0x87, 0x1, 0x78, 0xbc, 0xe, 0x85, 0xa2, + 0x81, 0xb4, 0xb5, 0xea, 0x65, 0xc0, 0x8c, 0xf2, 0x9b, 0x5a, 0x2c, 0x2f, + 0xcf, 0xd6, 0x9c, 0xdf, 0x74, 0x62, 0x68, 0x40, 0xf7, 0x30, 0xff, 0x96, + 0x9d, 0x66, 0x6c, 0x2d, 0x11, 0x7f, 0x90, 0x28, 0x16, 0xc7, 0xa5, 0x4a, + 0xe2, 0xd6, 0x5c, 0xdb, 0x97, 0xe7, 0xc6, 0x37, 0xe1, 0x5b, 0x7d, 0x4e, + 0xaa, 0x2b, 0x7f, 0xf5, 0x77, 0x20, 0x71, 0xec, 0xa9, 0x2f, 0x57, 0x6f, + 0xea, 0xb4, 0x43, 0x57, 0xc5, 0xee, 0xd8, 0xf6, 0xef, 0xf, 0xc, 0x6c, + 0x3c, 0xb2, 0x77, 0x83, 0x81, 0xaa, 0x8a, 0x2a, 0xc9, 0x9f, 0x2, 0xab, + 0xcc, 0x58, 0x3c, 0xb0, 0x42, 0x4, 0x1e, 0xe0, 0xf0, 0xf9, 0xa9, 0x2c, + 0xe8, 0x76, 0x5e, 0x39, 0xa0, 0xd6, 0xa8, 0x1, 0x56, 0x32, 0xc1, 0x27, + 0x96, 0xbe, 0x27, 0x5b, 0x74, 0xa7, 0x77, 0xf0, 0x6e, 0x2, 0xdf, 0x4a, + 0x5, 0x50, 0x2b, 0xf8, 0x73, 0xb0, 0x73, 0xce, 0xb8, 0xfa, 0xaf, 0xd2, + 0x9a, 0x2, 0x6d, 0xe0, 0x5d, 0x5e, 0x3, 0xff, 0x2d, 0x6a, 0xb0, 0xd6, + 0xa0, 0x1a, 0xd7, 0x77, 0x7, 0x27, 0xf8, 0x3f, 0xe0, 0x5, 0xe4, 0x42, + 0x18, 0xa4, 0xe9, 0xf0, 0xd7, 0xb4, 0xf1, 0x2b, 0x92, 0x76, 0x39, 0xb1, + 0x48, 0x62, 0xa3, 0xf, 0x95, 0x1c, 0x8a, 0xd, 0x79, 0xf6, 0x3d, 0x35, + 0x64, 0xa1, 0x66, 0x61, 0xa1, 0x38, 0xdd, 0x48, 0x5, 0xa4, 0x73, 0x59, + 0xca, 0x80, 0x57, 0x4a, 0x65, 0x73, 0x64, 0x5e, 0x9b, 0x7c, 0x85, 0x97, + 0x52, 0x89, 0x74, 0x79, 0x6f, 0x66, 0xe2, 0x3e, 0x69, 0x89, 0x78, 0xe3, + 0xee, 0x0, 0xae, 0x8e, 0xbd, 0x91, 0x76, 0xfe, 0x12, 0x7c, 0x2, 0x1d, + 0x55, 0x62, 0xba, 0x38, 0xf4, 0xba, 0x83, 0x18, 0xba, 0x9e, 0xa1, 0x15, + 0xdb, 0x7c, 0x56, 0xdb, 0x4f, 0xf3, 0x7a, 0xbe, 0xbd, 0x63, 0x61, 0x72, + 0xf2, 0x9d, 0x78, 0x4e, 0xa4, 0x22, 0xec, 0xfa, 0xa5, 0xf4, 0x3a, 0x5d, + 0xd9, 0x30, 0x3a, 0xd9, 0x3c, 0x88, 0xd8, 0x56, 0x59, 0xfb, 0xbd, 0xa6, + 0xe2, 0x37, 0x47, 0x7b, 0xf3, 0x6f, 0x3b, 0x8f, 0x81, 0xab, 0xbd, 0x95, + 0xe9, 0xaa, 0xfc, 0x33, 0xe4, 0x5e, 0x3, 0x9c, 0xb2, 0xfe, 0x6a, 0x7d, + 0xc, 0xcb, 0x17, 0x82, 0xfa, 0xb6, 0xf1, 0xa1, 0x6, 0x95, 0xda, 0x75, + 0xb8, 0x3f, 0x1, 0x49, 0x7d, 0x9, 0x8d, 0x7e, 0x8b, 0xa0, 0x73, 0xfc, + 0x37, 0x95, 0xa0, 0x4f, 0x2c, 0x37, 0x98, 0xd5, 0x76, 0xed, 0xd4, 0xc9, + 0xbd, 0x11, 0x63, 0x67, 0x5e, 0x8f, 0x85, 0x32, 0x57, 0x59, 0xd7, 0xaa, + 0xc8, 0x66, 0x61, 0xf, 0xea, 0x2b, 0x68, 0x57, 0xa8, 0x90, 0x29, 0x50, + 0xed, 0x78, 0xb6, 0xe, 0x5a, 0x6b, 0x15, 0x8d, 0xb7, 0xd5, 0x7d, 0x9, + 0x22, 0x54, 0x43, 0x96, 0x58, 0xa1, 0x2b, 0xe8, 0x89, 0x77, 0x3, 0xa6, + 0x18, 0xd7, 0xe7, 0x34, 0xe6, 0xe7, 0xbf, 0xae, 0x17, 0x27, 0x63, 0x10, + 0x1e, 0x4f, 0x97, 0x51, 0x28, 0x90, 0x11, 0x44, 0x8c, 0xe5, 0x15, 0xcb, + 0x3e, 0xa3, 0x6c, 0xc4, 0xfc, 0xa7, 0x5e, 0x54, 0x4a, 0x70, 0xc1, 0x31, + 0xf7, 0xd5, 0xed, 0xb0, 0xd1, 0x36, 0x1f, 0xfc, 0x49, 0x60, 0xe9, 0x88, + 0x3, 0x3d, 0xae, 0x7d, 0x4d, 0x55, 0x69, 0x62, 0xed, 0x16, 0x9a, 0xcc, + 0xf1, 0x8e, 0xf5, 0x86, 0xec, 0x60, 0x8c, 0x88, 0xa4, 0x6, 0xe4, 0xb8, + 0xdc, 0x35, 0xad, 0x2e, 0x13, 0xe, 0x7e, 0x90, 0x8c, 0x9f, 0xe5, 0xb1, + 0xa1, 0x9d, 0x1d, 0xa7, 0x4f, 0x94, 0x44, 0xc6, 0xe6, 0x45, 0xc2, 0x6, + 0x50, 0x96, 0xa0, 0x84, 0xca, 0x99, 0xc, 0xbf, 0x3c, 0x11, 0xf8, 0xb, + 0x74, 0x25, 0xf2, 0x91, 0xc9, 0x63, 0xe, 0xe4, 0x3c, 0x3b, 0xfd, 0xe8, + 0xe, 0xfb, 0x19, 0xe, 0x4b, 0x3c, 0x5d, 0x3f, 0x96, 0xa1, 0x76, 0x20, + 0x4c, 0x8d, 0x2a, 0x5f, 0xd2, 0x7c, 0x43, 0xf8, 0xb8, 0x49, 0x95, 0xad, + 0x6, 0xfa, 0x44, 0x4f, 0x72, 0x9, 0xa, 0x85, 0x3e, 0xca, 0xc0, 0x20, + 0x34, 0x6b, 0xc9, 0x3c, 0xa6, 0xad, 0xbe, 0xe4, 0x80, 0x40, 0x89, 0xee, + 0x87, 0x34, 0x22, 0xd1, 0xd0, 0x53, 0xb0, 0xb8, 0x65, 0xe6, 0x0, 0xb5, + 0x41, 0xfb, 0x6b, 0xeb, 0x6, 0x56, 0xd1, 0x83, 0x85, 0x1, 0x46, 0x6e, + 0x31, 0x43, 0xa2, 0x91, 0xe4, 0xcd, 0xa4, 0x43, 0x43, 0x8c, 0x26, 0xc, + 0xcb, 0x9b, 0xe1, 0x38, 0x42, 0xf1, 0xcd, 0x8f, 0x64, 0x3d, 0xd9, 0x4e, + 0x82, 0x80, 0x3, 0x16, 0xb5, 0x25, 0xc6, 0x6b, 0x5e, 0xfc, 0x5a, 0x97, + 0xe9, 0xa2, 0x24, 0x1e, 0xcd, 0x2d, 0xae, 0xca, 0x8, 0x4b, 0x29, 0x61, + 0xd1, 0xe6, 0xd, 0xc3, 0x98, 0x12, 0xf5, 0x23, 0xf8, 0x54, 0xcd, 0x51, + 0xec, 0x2e, 0x6c, 0x61, 0xdb, 0xa5, 0xaf, 0xf7, 0x48, 0x47, 0x27, 0x70, + 0xb3, 0xf6, 0xa3, 0x6e, 0x9c, 0xfb, 0x32, 0xd1, 0x23, 0x29, 0xe7, 0x43, + 0xa1, 0xa, 0x1, 0x3, 0xce, 0x45, 0x8d, 0x63, 0xd7, 0x23, 0x1d, 0xdb, + 0x3c, 0x66, 0xf9, 0x1e, 0x4b, 0x7f, 0x7, 0x3e, 0xd2, 0xd6, 0xf4, 0xcb, + 0xa2, 0x3a, 0xb2, 0x99, 0xd5, 0xc3, 0x53, 0x19, 0x79, 0xd9, 0x24, 0xe2, + 0x3e, 0xbd, 0x9e, 0x5, 0x3a, 0xa9, 0x67, 0x2c, 0x85, 0xdb, 0xd7, 0x17, + 0x9c, 0x59, 0xaa, 0xe6, 0x9f, 0x10, 0xb0, 0x2e, 0x20, 0x61, 0xcc, 0xf2, + 0x18, 0x88, 0xd0, 0x1c, 0x52, 0xc8, 0xab, 0x8c, 0x7a, 0x49, 0xee, 0x97, + 0x55, 0xf5, 0x48, 0x54, 0x4b, 0xbb, 0x11, 0xde, 0x8d, 0x26, 0x3f, 0x18, + 0x68, 0x15, 0xa7, 0x4c, 0x5c, 0x23, 0xf2, 0x74, 0x59, 0x4e, 0xca, 0x61, + 0x4c, 0x93, 0x7d, 0x84, 0x26, 0xf9, 0x13, 0x67, 0xc3, 0x76, 0xe5, 0x59, + 0x96, 0xab, 0xb, 0x23, 0x53, 0xef, 0x5, 0xae, 0x1, 0x2f, 0xe, 0xe5, + 0xc6, 0x2b, 0xc7, 0x73, 0xaa, 0x14, 0x48, 0xfe, 0x16, 0x97, 0xd5, 0xc8, + 0xbb, 0xd1, 0xb7, 0x5f, 0x70, 0xcc, 0xce, 0x49, 0x1b, 0x5d, 0x1a, 0xbb, + 0x6b, 0x93, 0xde, 0xdf, 0x98, 0x37, 0x9b, 0xcc, 0x4b, 0x35, 0xe0, 0xce, + 0xcb, 0x77, 0x29, 0x1e, 0x4d, 0x23, 0x42, 0x97, 0xa0, 0x4f, 0x7b, 0x95, + 0x44, 0x3d, 0x4f, 0x98, 0x32, 0x8, 0x77, 0xcd, 0xc5, 0x3f, 0xe5, 0xb6, + 0xc5, 0xf4, 0x50, 0x29, 0x71, 0x79, 0xca, 0x65, 0x80, 0x8c, 0xa7, 0xdc, + 0xcd, 0xbe, 0x57, 0x3a, 0xab, 0x75, 0x73, 0x38, 0x32, 0x20, 0x4b, 0xd8, + 0xe8, 0xed, 0xf, 0x6f, 0x8b, 0x47, 0xb4, 0x1a, 0xc3, 0x4e, 0x3c, 0x27, + 0xfc, 0x4a, 0x8a, 0xbd, 0x56, 0xe5, 0xc5, 0x6f, 0x47, 0x2e, 0xc1, 0x3e, + 0xf5, 0x82, 0x9a, 0x36, 0xc, 0xd0, 0x68, 0x17, 0x43, 0x93, 0xb1, 0xb2, + 0x11, 0xa0, 0x8f, 0xed, 0xc0, 0xca, 0x6c, 0x52, 0x92, 0x2e, 0x96, 0x86, + 0x90, 0x0, 0x37, 0x18, 0xf5, 0x66, 0xee, 0xa1, 0x3, 0x95, 0x1e, 0x16, + 0xa9, 0xe8, 0xce, 0xb4, 0x50, 0x16, 0x5b, 0xb0, 0x75, 0x8a, 0x99, 0xb0, + 0x29, 0x52, 0x9d, 0x1d, 0xe2, 0xa5, 0xfe, 0x38, 0x56, 0x61, 0x22, 0xb5, + 0x77, 0x9, 0xfc, 0x5f, 0x31, 0x2b, 0xa2, 0x83, +}; +const uint8_t kAltGameImages1xC[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, + 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, + 0xda, 0x49, 0x65, 0xea, 0xd, 0xbe, 0xe2, 0x3e, 0xad, 0x5e, 0x7d, 0xf9, + 0x74, 0xac, 0xe9, 0xfd, 0xf3, 0x6f, 0x3, 0x3f, 0xaf, 0x80, 0xf8, 0x6a, + 0xdb, 0xcf, 0x1c, 0xc7, 0x93, 0x4, 0x9c, 0x1c, 0x66, 0xb8, 0xf2, 0x38, + 0x54, 0xa3, 0x3f, 0x85, 0xf4, 0x6e, 0x2f, 0xa9, 0x3d, 0xe2, 0xd7, 0x3, + 0xcc, 0x46, 0x13, 0x89, 0x85, 0xd1, 0xc6, 0xa2, 0xd4, 0x58, 0xb5, 0x4c, + 0x2c, 0xfc, 0x76, 0x2c, 0x7a, 0x51, 0xb3, 0xc9, 0xd7, 0x33, 0xe0, 0x64, + 0xd6, 0xfe, 0xab, 0xae, 0xaa, 0x72, 0x52, 0x91, 0xf1, 0x67, 0xfe, 0xd8, + 0x63, 0xb4, 0xec, 0x50, 0xbd, 0xe1, 0xe7, 0x61, 0xfd, 0xfb, 0x69, 0x9d, + 0x2d, 0xf2, 0xc1, 0x35, 0xed, 0x7a, 0x8e, 0x3b, 0x2e, 0xd9, 0x56, 0xf8, + 0xf2, 0xd2, 0x4f, 0x10, 0x0, 0x57, 0x75, 0x96, 0xce, 0x4e, 0x70, 0x71, + 0x7b, 0x98, 0x80, 0x7d, 0xe8, 0x51, 0xde, 0x79, 0xa0, 0xd9, 0xaa, 0xf3, + 0x2, 0x20, 0xee, 0x9c, 0x75, 0x8, 0x44, 0x79, 0xf, 0xd9, 0x29, 0xba, + 0x89, 0x2e, 0xac, 0x6f, 0xdf, 0xdd, 0x2d, 0x1a, 0xde, 0xf4, 0x7b, 0x52, + 0x0, 0xc1, 0x19, 0x6d, 0xae, 0x93, 0x22, 0x53, 0x6d, 0xe0, 0xe1, 0x96, + 0x8c, 0x6, 0xcb, 0x84, 0x73, 0xde, 0x37, 0xf7, 0x2d, 0xb, 0x8a, 0xca, + 0x15, 0xd0, 0x46, 0xa7, 0x33, 0x32, 0xea, 0xfe, 0x64, 0x11, 0x6e, 0x90, + 0x3b, 0xa, 0x81, 0x4, 0xbe, 0x1b, 0x13, 0x7a, 0xb3, 0xbe, 0x98, 0x35, + 0x22, 0x99, 0x66, 0x75, 0x75, 0x87, 0x66, 0x4, 0x1c, 0xec, 0x8d, 0x90, + 0xc3, 0xe4, 0x8c, 0x7f, 0x1e, 0x60, 0x18, 0xff, 0x2, 0x80, 0xdf, 0x21, + 0x87, 0x32, 0x8, 0x71, 0xd3, 0xf5, 0xfa, 0x21, 0x10, 0x15, 0x38, 0x9a, + 0xd9, 0x1a, 0x28, 0xae, 0xd5, 0xaf, 0xba, 0x40, 0xe9, 0xa5, 0x73, 0x48, + 0xbf, 0xc, 0xf0, 0x60, 0xc0, 0x1f, 0x88, 0xa, 0x7d, 0x22, 0x57, 0x68, + 0xff, 0x4e, 0xb, 0x4, 0x86, 0x80, 0x4d, 0x5a, 0x88, 0x4c, 0x54, 0xb7, + 0x5b, 0x6d, 0x1c, 0xe5, 0xe8, 0xeb, 0x74, 0x20, 0xf6, 0x7e, 0x51, 0x44, + 0x16, 0x1a, 0x9a, 0xe8, 0x11, 0x5c, 0xd0, 0xa, 0xf9, 0x58, 0xa0, 0xcf, + 0x41, 0x98, 0x6a, 0x4d, 0x5b, 0x6b, 0xca, 0x9a, 0xe3, 0x2a, 0xd1, 0xe5, + 0x74, 0xb6, 0xe1, 0x9b, 0xb9, 0x45, 0xdb, 0xeb, 0x15, 0x71, 0xdb, 0x29, + 0x92, 0xc3, 0x9f, 0xdf, 0xb9, 0x7, 0x3f, 0x4f, 0xe9, 0x96, 0x11, 0x94, + 0x5e, 0x40, 0x4b, 0x74, 0x2c, 0x9c, 0x8a, 0x5c, 0x44, 0x4d, 0x1c, 0x54, + 0x47, 0x40, 0x4a, 0xa6, 0xdf, 0x43, 0x6b, 0xa1, 0x6a, 0x4d, 0xe4, 0x84, + 0x7b, 0x18, 0x7f, 0x84, 0x76, 0x2f, 0xd6, 0x57, 0x70, 0xe1, 0xa, 0xf6, + 0xb5, 0xc6, 0xe2, 0xf7, 0x31, 0x4f, 0xde, 0xa4, 0x2c, 0x35, 0x33, 0xb1, + 0x77, 0x39, 0xb7, 0xac, 0xe5, 0xf6, 0x59, 0x74, 0x7, 0xb9, 0x8, 0xf9, + 0x5c, 0x9e, 0x13, 0x7, 0x23, 0x81, 0x60, 0xf9, 0xa, 0xf3, 0x41, 0xbb, + 0x8a, 0x72, 0xdb, 0x99, 0x47, 0x4a, 0x86, 0xc0, 0x9, 0x8f, 0xf9, 0x8a, + 0xf5, 0xdf, 0x73, 0x34, 0xa9, 0x88, 0xf6, 0x79, 0x12, 0xbe, 0x50, 0xc5, + 0x4, 0x79, 0x35, 0x24, 0xe9, 0x71, 0x4f, 0xef, 0x13, 0xeb, 0x54, 0x94, + 0x9c, 0x20, 0x68, 0x81, 0xa9, 0x33, 0xac, 0xe6, 0xa7, 0x4b, 0x3f, 0x52, + 0x67, 0xab, 0x1a, 0xd6, 0x78, 0x2b, 0xd0, 0x8d, 0x98, 0x2f, 0x90, 0xaa, + 0xe5, 0x80, 0x5d, 0x1f, 0xa9, 0x33, 0x7, 0x5a, 0xe5, 0x2d, 0x5a, 0xa2, + 0x28, 0x84, 0x83, 0x7, 0xb7, 0xfd, 0x84, 0xc7, 0x6d, 0x53, 0xd4, 0x46, + 0xc2, 0xc6, 0x24, 0xbe, 0xe2, 0x25, 0xcf, 0x24, 0x5b, 0x3e, 0x39, 0xcb, + 0xbb, 0x7a, 0x3b, 0x2e, 0xc, 0x92, 0x68, 0x30, 0xa6, 0xe0, 0x69, 0xd5, + 0x1d, 0x6c, 0x95, 0x7b, 0xe2, 0x48, 0x10, 0xed, 0x1e, 0xbd, 0x10, 0x14, + 0x25, 0x41, 0xd7, 0x1b, 0xf2, 0x74, 0x12, 0x2c, 0x17, 0xd6, 0x36, 0x65, + 0x1, 0x3e, 0x87, 0x11, 0x90, 0x8e, 0x12, 0x71, 0xb2, 0xd1, 0x37, 0xda, + 0xa2, 0x5d, 0x80, 0x64, 0x32, 0x8e, 0x37, 0x3a, 0x8e, 0x4c, 0xbb, 0x40, + 0xe3, 0x1a, 0x73, 0x83, 0xb0, 0x82, 0x2d, 0x5e, 0x48, 0x20, 0xd2, 0xaf, + 0x0, 0x55, 0xff, 0x56, 0x7e, 0x8e, 0xb3, 0x6b, 0xc4, 0x11, 0x40, 0x17, + 0x25, 0x76, 0x35, 0xc, 0x9d, 0x3d, 0xe2, 0xea, 0x7, 0xec, 0xe2, 0xe3, + 0xd4, 0x10, 0xda, 0xf6, 0xb5, 0xe8, 0xf6, 0x7a, 0xb7, 0xe1, 0x38, 0x65, + 0x27, 0x97, 0x2b, 0x5a, 0x4, 0x1b, 0xd2, 0x21, 0xea, 0x5b, 0x9f, 0x5b, + 0xdf, 0xca, 0xd1, 0xad, 0x47, 0x25, 0xd, 0xed, 0xbb, 0xca, 0x6d, 0x45, + 0x29, 0x6d, 0xb7, 0xef, 0x70, 0x2b, 0x79, 0xc2, 0x29, 0x83, 0x75, 0xdb, + 0xa5, 0x60, 0xcd, 0x6f, 0x1a, 0xd4, 0xad, 0x6f, 0x8a, 0x51, 0xfb, 0x92, + 0x62, 0xd4, 0x97, 0x41, 0x8a, 0xb8, 0x79, 0x2a, 0x95, 0x14, 0x9, 0x95, + 0x6b, 0x7f, 0xf, 0xfb, 0xf5, 0x0, 0xf, 0x25, 0xc3, 0x81, 0xb, 0x81, + 0xa3, 0x5e, 0x29, 0xc5, 0x9c, 0xd1, 0x45, 0xff, 0xfc, 0x80, 0x24, 0x75, + 0xa1, 0x33, 0xd5, 0x6e, 0x8b, 0x85, 0x39, 0x93, 0x8f, 0x7c, 0xd0, 0x7e, + 0x39, 0xde, 0xdf, 0x93, 0x28, 0x4f, 0xf3, 0xe6, 0x41, 0xcf, 0x85, 0x32, + 0x82, 0xe5, 0x65, 0x52, 0xff, 0x37, 0x79, 0x54, 0x2, 0x47, 0x63, 0x1a, + 0xd4, 0xf0, 0xcf, 0x5, 0x11, 0xbd, 0x8c, 0x4, 0x47, 0xfe, 0xa2, 0x34, + 0x32, 0xda, 0x82, 0xfd, 0xe6, 0x3f, 0x7a, 0x1c, 0x5c, 0x43, 0x6d, 0x4c, + 0xa2, 0xad, 0x33, 0x15, 0x2d, 0xd4, 0xbd, 0xdf, 0x97, 0xa2, 0x1a, 0x3b, + 0x89, 0x3c, 0xd5, 0x19, 0x7d, 0x24, 0x13, 0xa, 0xeb, 0xd7, 0x66, 0x79, + 0xc5, 0x61, 0xea, 0x4c, 0x2d, 0x6d, 0xca, 0xea, 0x81, 0x81, 0x29, 0x88, + 0xaf, 0xcd, 0x3b, 0xff, 0xba, 0x1a, 0xe6, 0x60, 0x8, 0xdb, 0x17, 0x3e, + 0x37, 0xc2, 0xb8, 0x39, 0x91, 0x18, 0x74, 0xa4, 0xe0, 0x5f, 0xf1, 0x8d, + 0x7d, 0x30, 0x7d, 0xac, 0x3a, 0x2b, 0x80, 0x4e, 0x7e, 0xe0, 0x25, 0x39, + 0xeb, 0x0, 0xe1, 0x52, 0xe1, 0xa1, 0x31, 0x2d, 0x3c, 0xf1, 0xe3, 0xfd, + 0xa3, 0xf6, 0x3, 0xec, 0xf3, 0x0, 0x7a, 0x55, 0xe3, 0x21, 0x19, 0xea, + 0x5a, 0xb5, 0x7b, 0xc9, 0xdb, 0xa5, 0x3b, 0x9e, 0x62, 0xd5, 0x2f, 0x2a, + 0xbb, 0xae, 0x86, 0x61, 0xff, 0x45, 0x91, 0xce, 0x92, 0x51, 0x24, 0x8b, + 0x9c, 0x49, 0x2a, 0xbd, 0xa4, 0x54, 0x80, 0xa6, 0xe6, 0x88, 0xe, 0x40, + 0x95, 0xe4, 0x9e, 0xd0, 0xd3, 0x42, 0x3b, 0xda, 0xe5, 0xf, 0x11, 0x0, + 0x55, 0x69, 0xe1, 0xba, 0x65, 0x1a, 0x6f, 0x9f, 0x64, 0x76, 0xdc, 0xa5, + 0xc6, 0x32, 0xe8, 0x80, 0x6d, 0x10, 0xa7, 0x21, 0xdf, 0x35, 0xb1, 0xbe, + 0x2c, 0xf9, 0xa6, 0xcc, 0x2e, 0xe5, 0xeb, 0x6c, 0x10, 0xf7, 0x85, 0xd9, + 0xac, 0xd3, 0x4c, 0x5c, 0xe5, 0xc0, 0x3b, 0xcf, 0x27, 0x8f, 0xde, 0xc2, + 0x4e, 0xd6, 0x94, 0x58, 0xea, 0x37, 0xaa, 0x3b, 0x21, 0x38, 0x1e, 0x5d, + 0x3d, 0xa7, 0xe3, 0x3c, 0x5e, 0x2b, 0x45, 0x81, 0x22, 0x55, 0x66, 0xcf, + 0xfd, 0x5b, 0xec, 0xc6, 0xd1, 0x9f, 0xa9, 0x4c, 0x4, 0xe4, 0x33, 0x36, + 0xa3, 0xd6, 0x4d, 0x8c, 0xd3, 0xe9, 0xe9, 0x5c, 0xc2, 0xff, 0x75, 0x2c, + 0x4c, 0x87, 0x4f, 0x6b, 0xb9, 0x96, 0xa, 0x8c, 0x4d, 0x44, 0x8, 0x9e, + 0x3d, 0x2f, 0x8, 0xca, 0x84, 0x33, 0x38, 0x2a, 0xcf, 0xf, 0x69, 0xe, + 0x2d, 0xd3, 0xad, 0x2d, 0xe, 0xdb, 0x79, 0x6c, 0x85, 0xf2, 0x13, 0xc8, + 0xf2, 0x97, 0x7e, 0x8d, 0x40, 0xb6, 0x10, 0x52, 0x58, 0xd0, 0xec, 0x50, + 0xc7, 0x38, 0x68, 0xad, 0xfb, 0x27, 0xb6, 0xde, 0x96, 0x8c, 0x4, 0x97, + 0xb1, 0x39, 0x6c, 0x1b, 0xe8, 0xfb, 0x4b, 0x37, 0xc2, 0xa4, 0x61, 0xc8, + 0x71, 0xee, 0x49, 0x8c, 0x12, 0x59, 0xbf, 0x46, 0x78, 0xe, 0x8d, 0x4d, + 0xd5, 0x1c, 0x57, 0x1c, 0x38, 0x2, 0xd2, 0x1b, 0x8a, 0xe3, 0x7b, 0x65, + 0x1e, 0xf8, 0x77, 0xa0, 0xb4, 0xbd, 0x1a, 0x29, 0xee, 0x8b, 0xc2, 0xa5, + 0x34, 0x82, 0x44, 0x9c, 0x4a, 0x7f, 0xc1, 0x28, 0x9e, 0xc6, 0x42, 0xca, + 0xaf, 0xeb, 0x19, 0xd7, 0x77, 0xf1, 0x60, 0xfa, 0x17, 0xf, 0x82, 0x97, + 0xcd, 0xe0, 0x11, 0x56, 0xe0, 0x85, 0x8a, 0x5f, 0xc, 0x1d, 0xe6, 0x66, + 0x2b, 0xfe, 0x3f, 0x42, 0x45, 0x91, 0x1c, 0xda, 0xf3, 0xe2, 0xea, 0x4b, + 0xe5, 0x18, 0x3a, 0xb2, 0x2b, 0x5f, 0x3e, 0x74, 0x97, 0xff, 0x4e, 0x95, + 0xbc, 0xa6, 0x66, 0x24, 0xb5, 0x15, 0x18, 0xd8, 0x2e, 0x33, 0x12, 0x27, + 0x16, 0xa2, 0xe5, 0x3d, 0xf, 0x38, 0xc3, 0x75, 0x40, 0xc, 0x94, 0x67, + 0x65, 0xf, 0x6b, 0x78, 0x69, 0xa1, 0x61, 0xb7, 0xf, 0xf2, 0x61, 0x29, + 0x83, 0x4e, 0x34, 0xc6, 0xc0, 0x3b, 0xe8, 0x5d, 0x8c, 0x81, 0xe4, 0x81, + 0x18, 0xdf, 0x3c, 0xd1, 0x6e, 0x7e, 0x7c, 0xf3, 0x76, 0xb4, 0x79, 0x49, + 0x7, 0xc1, 0x83, 0xb6, 0x86, 0x26, 0x70, 0x57, 0x2, 0xfc, 0xa1, 0xcc, + 0xa6, 0x4b, 0xac, 0x7e, 0x9e, 0x3c, 0xf, 0xa7, 0xe4, 0xb, 0x58, 0xcb, + 0x13, 0xb7, 0x4, 0xec, 0xd2, 0xa8, 0xb2, 0x53, 0x32, 0x2c, 0x8a, 0x70, + 0xfb, 0xec, 0xa4, 0xde, 0xf3, 0xbd, 0x4b, 0xbd, 0x86, 0x72, 0x96, 0x4b, + 0x94, 0x8c, 0x5a, 0x47, 0x4a, 0x46, 0xda, 0xb9, 0xe, 0x16, 0x63, 0x85, + 0x9f, 0xdf, 0xa4, 0xef, 0x82, 0x78, 0x68, 0x0, 0xd7, 0x4f, 0x2, 0x37, + 0x67, 0x7a, 0x33, 0x51, 0x3f, 0xd6, 0x29, 0x99, 0xa3, 0x63, 0x7, 0x82, + 0x2b, 0x12, 0xe5, 0xa0, 0xb6, 0x2a, 0xc4, 0x28, 0xee, 0xac, 0xd2, 0xd2, + 0x39, 0x62, 0x37, 0xf6, 0x3e, 0x91, 0xd1, 0x14, 0x89, 0xea, 0x52, 0xc8, + 0x62, 0xc7, 0xb, 0x9f, 0x9b, 0x81, 0x9d, 0x18, 0x1e, 0x3f, 0x70, 0x5b, + 0x6c, 0x34, 0x33, 0x21, 0x23, 0xba, 0x6f, 0xed, 0x28, 0x63, 0x53, 0x4, + 0x72, 0x85, 0xa3, 0x16, 0xc0, 0xd2, 0x81, 0xfe, 0x67, 0x22, 0x3, 0x9, + 0xd8, 0xbf, 0x94, 0x4, 0x6c, 0xc4, 0x43, 0x27, 0x5d, 0x36, 0xe0, 0x6d, + 0x4e, 0xec, 0xa5, 0x54, 0xb4, 0x7d, 0xd4, 0xb0, 0xce, 0x47, 0x67, 0x8c, + 0x81, 0x19, 0x42, 0x48, 0x83, 0x43, 0x3c, 0x14, 0xe8, 0x41, 0xd, 0xe, + 0xa7, 0xdc, 0xa7, 0x7e, 0x78, 0x6d, 0xe3, 0xc3, 0x9c, 0xf0, 0xb8, 0xf6, + 0x16, 0xc7, 0xfd, 0xef, 0xe2, 0x59, 0xc, 0xda, 0x46, 0x58, 0x6a, 0x33, + 0xdf, 0x4d, 0xc7, 0x1b, 0x89, 0xca, 0xd3, 0xe1, 0xc6, 0x24, 0xcf, 0x83, + 0x99, 0xa4, 0xf4, 0xd2, 0x55, 0xff, 0x47, 0x94, 0xfe, 0xb2, 0xdc, 0x6f, + 0xb7, 0x47, 0x3b, 0xfc, 0xdc, 0xa2, 0x92, 0x87, 0xbc, 0xc0, 0x15, 0x6, + 0xbf, 0xd0, 0x99, 0xa4, 0x2b, 0x38, 0xdb, 0xae, 0xe, 0x77, 0x9c, 0xa1, + 0xc, 0x76, 0xec, 0xbf, 0x34, 0x9f, 0x8f, 0x11, 0xc8, 0xb9, 0x6e, 0xf5, + 0xdf, 0xf0, 0x47, 0x1e, 0xf0, 0x8e, 0x41, 0x1b, 0xb5, 0x85, 0xdd, 0x50, + 0xf6, 0xdf, 0x84, 0x8e, 0x8c, 0x4, 0x9e, 0x1c, 0x7, 0xe3, 0x70, 0x37, + 0xc2, 0xb2, 0x6f, 0x9a, 0x4f, 0xb7, 0x92, 0xcf, 0xc2, 0x51, 0x5f, 0xd4, + 0x7, 0xc, 0xc5, 0x61, 0x1b, 0x6a, 0x2e, 0x4c, 0x76, 0x78, 0x69, 0x47, + 0x97, 0x0, 0xa, 0x5, 0x3e, 0xef, 0xeb, 0x25, 0xd9, 0x3e, 0x17, 0xf7, + 0x98, 0xea, 0xc, 0xa7, 0x14, 0x5, 0x1f, 0x21, 0x4a, 0x21, 0xef, 0x36, + 0x95, 0xcd, 0xed, 0xda, 0x95, 0x69, 0x7f, 0x62, 0x7e, 0x6c, 0xb4, 0x89, + 0x54, 0xe9, 0x95, 0x0, 0x1d, 0xa4, 0xa1, 0x18, 0xfb, 0x35, 0xf6, 0x3b, + 0xe0, 0x2a, 0x3f, 0x86, 0x6e, 0x21, 0xc7, 0xb5, 0x2c, 0xa4, 0x8c, 0xc, + 0x87, 0xb6, 0xb7, 0x1c, 0xa, 0xf6, 0x4a, 0x47, 0x88, 0x18, 0x88, 0x5, + 0x1e, 0x40, 0xee, 0xe9, 0xc3, 0x10, 0x9c, 0x9a, 0xd5, 0xdb, 0x8b, 0x13, + 0xa8, 0x24, 0x5c, 0xd0, 0xc9, 0x29, 0x3f, 0xa, 0x90, 0x6d, 0x92, 0x7d, + 0x24, 0xad, 0x64, 0x7f, 0xf1, 0x6, 0x7e, 0x31, 0xb8, 0x7, 0xac, 0x8d, + 0xf7, 0x50, 0x46, 0x79, 0x63, 0x50, 0xa4, 0x66, 0xb3, 0x86, 0xa0, 0xb2, + 0xa4, 0x29, 0x66, 0x13, 0x1f, 0xea, 0x9b, 0x12, 0xf1, 0x13, 0x31, 0x18, + 0x3c, 0x4c, 0x2d, 0xff, 0x29, 0xe5, 0x27, 0xb3, 0xcf, 0xcc, 0xfe, 0x21, + 0xde, 0x54, 0xc5, 0xcf, 0xdd, 0x4f, 0x28, 0x7e, 0x7a, 0xcb, 0x8, 0x4f, + 0x84, 0x9b, 0xb4, 0x91, 0x28, 0x2c, 0x67, 0xee, 0xfd, 0xed, 0x58, 0xc0, + 0xda, 0xc5, 0x23, 0xed, 0xd7, 0xa0, 0x68, 0xf4, 0xc7, 0xd0, 0xd9, 0x33, + 0xa2, 0xd5, 0x78, 0x94, 0x91, 0x1f, 0x12, 0x12, 0xef, 0x8f, 0xdd, 0xd0, + 0x77, 0x6c, 0x50, 0xd7, 0xd5, 0x1b, 0xde, 0x2, 0xaf, 0x63, 0x91, 0xb5, + 0xce, 0xa2, 0x2c, 0x35, 0xf0, 0x21, 0xf3, 0xca, 0x3a, 0xe2, 0xc8, 0xa3, + 0x8d, 0x10, 0x95, 0x40, 0xfb, 0x2f, 0xbd, 0x50, 0x93, 0x8b, 0xa2, 0x75, + 0x82, 0xcd, 0xf8, 0x8f, 0x42, 0x64, 0x1a, 0xed, 0x59, 0x8c, 0xb1, 0x86, + 0xb6, 0xc8, 0x99, 0xed, 0x13, 0x86, 0x9, 0xfd, 0x2d, 0x21, 0x51, 0x90, + 0xac, 0x34, 0x2f, 0xe5, 0x2d, 0xb, 0xbc, 0xec, 0x99, 0x45, 0xde, 0xef, + 0xb2, 0xfd, 0xca, 0xc5, 0xdc, 0x47, 0xb2, 0xd6, 0xf6, 0x13, 0x4, 0x16, + 0x50, 0x1c, 0xf7, 0x24, 0xc7, 0xb4, 0x75, 0xdf, 0x21, 0x26, 0xbb, 0x41, + 0x8c, 0x4f, 0xe, 0xaa, 0x5c, 0x3a, 0x5f, 0xa4, 0x31, 0x58, 0xab, 0x58, + 0xb9, 0xce, 0x8, 0x32, 0xa0, 0xbc, 0xbc, 0x7f, 0x6, 0x75, 0x65, 0xed, + 0x2d, 0x9, 0x9b, 0xbe, 0xea, 0xf9, 0x21, 0x5d, 0xca, 0x1d, 0x98, 0x8c, + 0xc0, 0x50, 0xf4, 0x91, 0xec, 0x54, 0xf, 0xe7, 0x34, 0x67, 0x5f, 0x41, + 0xbf, 0x60, 0xd8, 0xcf, 0x37, 0xc0, 0x5f, 0x46, 0x9e, 0x2b, 0x3c, 0xda, + 0xcf, 0x1, 0x24, 0xd3, 0xe9, 0x49, 0x3f, 0x64, 0x5b, 0x41, 0xe4, 0x3f, + 0x7c, 0xb0, 0xad, 0xf, 0xe7, 0x90, 0x32, 0x65, 0xd0, 0x46, 0xb9, 0x55, + 0x22, 0xdb, 0xc0, 0xdf, 0xce, 0x63, 0x9b, 0xbe, 0xc9, 0xf9, 0x6b, 0x35, + 0x63, 0x75, 0xc3, 0x80, 0x6d, 0x66, 0xaf, 0x3b, 0x8a, 0x1e, 0x55, 0x74, + 0x23, 0xbc, 0xb9, 0x6b, 0x72, 0x8, 0x19, 0xa, 0x8b, 0x73, 0xc1, 0x92, + 0x34, 0x1, 0xba, 0x3b, 0xa4, 0xa2, 0x76, 0x2a, 0x35, 0xd6, 0xe0, 0x16, + 0xa8, 0x7f, 0xa8, 0xdc, 0xf, 0x93, 0x85, 0x8b, 0xc9, 0xa7, 0x98, 0x2a, + 0xf9, 0x91, 0x9a, 0x2a, 0x50, 0x2, 0x7e, 0x44, 0xa8, 0x10, 0xc5, 0x93, + 0x1b, 0xbe, 0xb1, 0xa7, 0x45, 0x3c, 0xb4, 0x5e, 0xe0, 0x4f, 0x39, 0x48, + 0xa3, 0x74, 0x2, 0x6d, 0xc7, 0x1a, 0x79, 0xb5, 0x8b, 0xb7, 0x14, 0x88, + 0x4c, 0xaf, 0x64, 0x3f, 0x70, 0xf8, 0xb6, 0xa0, 0xcc, 0x2, 0xd6, 0x75, + 0xfc, 0x75, 0x72, 0x12, 0x9d, 0x27, 0x1d, 0x75, 0x33, 0x25, 0xb1, 0x14, + 0xc, 0x66, 0xc6, 0x7a, 0x9e, 0xde, 0x26, 0xbb, 0x6e, 0xe, 0x25, 0xd2, + 0xf1, 0xe6, 0x8d, 0x85, 0x64, 0x75, 0xb7, 0xe8, 0x96, 0x84, 0xe, 0x8f, + 0x25, 0x24, 0x12, 0x41, 0x52, 0xdb, 0xa6, 0x7, 0x44, 0x60, 0x91, 0xd1, + 0xee, 0x9e, 0x19, 0x4c, 0xfc, 0x4a, 0x69, 0x97, 0x27, 0xc1, 0x7c, 0x32, + 0x19, 0x4b, 0x21, 0xe5, 0xc7, 0x38, 0x42, 0x86, 0x90, 0x47, 0x5c, 0xdc, + 0x73, 0xff, 0x5f, 0xba, 0xc1, 0xf4, 0x26, 0xa0, 0x38, 0xa5, 0xdb, 0x41, + 0x76, 0x49, 0x5, 0x58, 0xa8, 0xe8, 0xf9, 0x6, 0x57, 0x6d, 0xd4, 0x8e, + 0x86, 0x5a, 0xc1, 0xd8, 0x8f, 0x7b, 0xa6, 0x4b, 0xe5, 0xff, 0xd7, 0x6c, + 0x4d, 0x9f, 0x51, 0xa9, 0xdf, 0xe9, 0xe6, 0x91, 0xf, 0xe9, 0x13, 0xd1, + 0x7e, 0x28, 0x67, 0x1b, 0xb0, 0xac, 0x88, 0x25, 0xc3, 0x17, 0x6c, 0xde, + 0x6e, 0x88, 0xa8, 0x65, 0xb8, 0xd5, 0xf0, 0x40, 0x85, 0xc4, 0x52, 0x79, + 0x8c, 0x19, 0xe7, 0x33, 0x3a, 0x76, 0x34, 0x2d, 0x4c, 0x77, 0xc1, 0x3, + 0xc0, 0x11, 0xc1, 0x2f, 0x9c, 0xa0, 0x19, 0x51, 0x5f, 0x5, 0x9e, 0xfe, + 0x3b, 0x88, 0x5f, 0x59, 0x24, 0xb9, 0x8, 0x97, 0x44, 0xee, 0x56, 0xa8, + 0x12, 0xd6, 0x80, 0x9c, 0x51, 0xa3, 0x12, 0xaf, 0x47, 0xc4, 0x73, 0x8b, + 0x55, 0xc0, 0x4b, 0xe7, 0xf0, 0x4, 0x47, 0xeb, 0x5e, 0xad, 0xee, 0x64, + 0x83, 0xcd, 0xaa, 0x9, 0x57, 0x8f, 0x9, 0xae, 0x31, 0x70, 0x90, 0x49, + 0x61, 0xd7, 0x7, 0xf4, 0x8, 0xb0, 0xe9, 0xff, 0xfe, 0x8f, 0x9c, 0x6f, + 0xf7, 0x3, 0x11, 0xf5, 0x74, 0xe4, 0xd3, 0x84, 0xf6, 0x10, 0x58, 0xdf, + 0x17, 0xc9, 0x2e, 0x30, 0xcd, 0x1b, 0xe4, 0xab, 0x53, 0x43, 0x13, 0xb8, + 0x49, 0x54, 0x7a, 0xd9, 0xe7, 0xc8, 0xe7, 0xa9, 0xe1, 0xb6, 0x87, 0xa6, + 0x45, 0xcb, 0x5d, 0x21, 0xd7, 0xa4, 0x37, 0xc, 0x95, 0x70, 0xd8, 0x11, + 0x15, 0x41, 0x3a, 0xee, 0x92, 0xe7, 0xfc, 0x9, 0x19, 0x18, 0xcc, 0xe0, + 0x85, 0x2f, 0x55, 0xe5, 0x7d, 0x5e, 0x33, 0x3a, 0x21, 0x2c, 0xa5, 0x95, + 0x95, 0xc8, 0x55, 0xe4, 0x21, 0x18, 0x43, 0xb7, 0x98, 0x4, 0x6d, 0xb4, + 0x3a, 0x87, 0x5f, 0xc9, 0xc0, 0x6c, 0xf5, 0x2a, 0x7c, 0xb4, 0xd5, 0x16, + 0x63, 0x5c, 0xed, 0xb3, 0x82, 0xf6, 0x71, 0x2d, 0xd5, 0x82, 0x28, 0x5c, + 0x7f, 0x2e, 0x1a, 0xdd, 0xa5, 0x22, 0x89, 0x77, 0x3a, 0xba, 0x30, 0xa6, + 0x1c, 0xb3, 0x2, 0x64, 0x52, 0xf8, 0xd9, 0x6f, 0xd0, 0xab, 0xbe, 0x39, + 0x65, 0xb6, 0x5e, 0x51, 0x28, 0xec, 0x4, 0xc, 0x66, 0x7, 0x73, 0xc4, + 0x74, 0xe3, 0xc4, 0xb0, 0x7e, 0x97, 0x4d, 0xe4, 0x4c, 0x83, 0x5a, 0x61, +}; +const uint8_t kAltGameImages1xD[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, + 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, + 0x94, 0x23, 0x34, 0xaa, 0x29, 0xa0, 0x98, 0xd7, 0xc3, 0x15, 0xf2, 0xab, + 0xe, 0xc2, 0x5c, 0xff, 0x19, 0xeb, 0xa6, 0x5a, 0x79, 0x8d, 0xd7, 0x68, + 0xd2, 0x75, 0xc2, 0x4a, 0xc3, 0x9d, 0xd1, 0xba, 0xaf, 0x15, 0x12, 0xeb, + 0x87, 0xab, 0xc2, 0xaf, 0x45, 0xa3, 0x15, 0x8f, 0x47, 0x85, 0x13, 0xfc, + 0xb2, 0x90, 0x5, 0xac, 0x30, 0xa0, 0x6b, 0x93, 0xb5, 0x93, 0xcb, 0x4b, + 0x8c, 0xb9, 0x30, 0x56, 0x57, 0xa0, 0xfb, 0xba, 0x1e, 0xfb, 0x46, 0xac, + 0xe5, 0xa1, 0x7b, 0xf1, 0xf4, 0xfd, 0xf7, 0x92, 0xa3, 0x38, 0x5, 0x4a, + 0x2b, 0x67, 0x91, 0xd, 0x48, 0xf6, 0x5a, 0xf, 0x68, 0xeb, 0xb4, 0xfa, + 0x12, 0xd, 0x6d, 0x62, 0x3c, 0xcc, 0x92, 0x40, 0x5a, 0x74, 0x2f, 0xad, + 0xf0, 0x18, 0x66, 0x71, 0xc7, 0xcd, 0xd3, 0xde, 0x7b, 0x56, 0x53, 0x95, + 0x5, 0xae, 0x8, 0x44, 0xe2, 0xe0, 0xfd, 0x6c, 0x6f, 0xa0, 0xc1, 0x81, + 0xcf, 0x45, 0x41, 0x90, 0x7, 0x1, 0xd9, 0x74, 0x2c, 0x5, 0x56, 0x98, + 0x2e, 0x82, 0x89, 0xeb, 0xfc, 0xe, 0xd3, 0x14, 0x96, 0x38, 0xe0, 0x85, + 0xac, 0x77, 0xf, 0x2e, 0xdc, 0xaf, 0x8f, 0x19, 0xa2, 0x31, 0x72, 0xe9, + 0xe3, 0xc1, 0x8e, 0xb9, 0xff, 0x7d, 0xb9, 0x28, 0x8d, 0x3d, 0x51, 0xeb, + 0x43, 0xef, 0x4c, 0x0, 0xde, 0xb8, 0x36, 0xe8, 0x2e, 0xcb, 0x39, 0xba, + 0xcd, 0x93, 0x8d, 0x5, 0xf, 0x6f, 0xab, 0xe6, 0xbe, 0xaf, 0x40, 0xab, + 0xf8, 0x7b, 0x7e, 0x4, 0x90, 0x8, 0xbd, 0x2e, 0x13, 0x3d, 0x8a, 0x8, + 0xf, 0x96, 0x8f, 0xfd, 0x20, 0xc7, 0x21, 0x36, 0x66, 0x4c, 0x67, 0x66, + 0xa1, 0x88, 0x80, 0x14, 0x8b, 0xb4, 0x4a, 0x8, 0x6c, 0x5c, 0x84, 0xa8, + 0x5c, 0x22, 0x0, 0x31, 0x60, 0x77, 0x96, 0xda, 0x99, 0xe4, 0x24, 0x6f, + 0xd2, 0xb4, 0x2a, 0xe, 0x69, 0xa8, 0x13, 0x13, 0x4e, 0x7f, 0xed, 0xdb, + 0x26, 0x35, 0xaa, 0x34, 0x38, 0x16, 0xbb, 0x1, 0x7c, 0x25, 0x28, 0x13, + 0xbb, 0x28, 0x8a, 0xdd, 0x9b, 0xfc, 0x71, 0xa9, 0xb6, 0x92, 0xc5, 0x3b, + 0x14, 0xae, 0xdc, 0xf0, 0x7, 0x14, 0x70, 0xaf, 0xd6, 0xf7, 0xb4, 0x22, + 0x4a, 0x7e, 0x16, 0x76, 0x63, 0x48, 0xb5, 0xdd, 0xec, 0x1, 0xa, 0x97, + 0xab, 0xb, 0x52, 0x7e, 0xeb, 0x76, 0x3e, 0xbb, 0xd5, 0x9e, 0x4f, 0xe1, + 0x84, 0x6d, 0x31, 0xcc, 0x10, 0x2a, 0xd5, 0x8a, 0xea, 0x43, 0x1e, 0xe5, + 0x8f, 0xa7, 0x3f, 0x9c, 0xfb, 0x1e, 0xc2, 0xd2, 0xb4, 0xa1, 0x4a, 0x42, + 0xdf, 0x82, 0x5, 0x76, 0xbb, 0xd5, 0x14, 0x10, 0xf2, 0xd9, 0x6f, 0xca, + 0x7f, 0x61, 0x78, 0x2d, 0xf2, 0x75, 0xbb, 0x47, 0x6e, 0x1d, 0xe4, 0xc, + 0xe7, 0xdf, 0x5, 0x1c, 0x68, 0x51, 0xf, 0xc6, 0x8, 0xcc, 0xbd, 0xe7, + 0x82, 0x26, 0xc3, 0x8b, 0xa2, 0x3a, 0xda, 0x12, 0x8, 0xef, 0xdd, 0x89, + 0x48, 0xb9, 0x59, 0xca, 0x91, 0xd4, 0xe0, 0x53, 0xff, 0xb8, 0xb6, 0x2e, + 0xc5, 0xa7, 0x35, 0x8d, 0x24, 0x30, 0xe3, 0x81, 0x94, 0x1a, 0xe8, 0xe6, + 0x30, 0x56, 0x1, 0xe1, 0x22, 0x8e, 0x10, 0x78, 0x2e, 0x9c, 0x79, 0x6f, + 0x6c, 0xa7, 0xa1, 0x50, 0xfe, 0xe8, 0xc4, 0x31, 0x1a, 0xa7, 0xb5, 0x62, + 0x9c, 0xff, 0xf, 0x1e, 0x3c, 0x5c, 0x3a, 0x2a, 0xce, 0x3e, 0xb, 0xcf, + 0x2b, 0xfa, 0xfa, 0x40, 0x7b, 0x86, 0xbd, 0xf1, 0xed, 0xa7, 0x6f, 0x9e, + 0xde, 0xc8, 0xaf, 0xd6, 0x5f, 0x1c, 0x75, 0xb7, 0xb8, 0x27, 0xca, 0x67, + 0xe1, 0xee, 0x52, 0x73, 0x48, 0xb7, 0xd5, 0x4a, 0xa7, 0x9b, 0x1f, 0x3, + 0xbf, 0x6e, 0x17, 0x18, 0xb9, 0xed, 0xa3, 0x28, 0xf9, 0x1d, 0x42, 0x97, + 0x5, 0x9a, 0x1b, 0x7c, 0xc2, 0x55, 0xa9, 0xdc, 0x16, 0x1a, 0xdb, 0x81, + 0x4e, 0x21, 0xa5, 0x66, 0x69, 0x1d, 0xcf, 0x7c, 0x43, 0x66, 0xc5, 0x96, + 0xcd, 0xd, 0xf8, 0x25, 0x19, 0x90, 0xfe, 0x1d, 0x99, 0x22, 0x93, 0x9, + 0x54, 0xe8, 0xa2, 0x36, 0x1d, 0x4d, 0xe9, 0x86, 0xe1, 0xa8, 0x45, 0x3b, + 0xb6, 0x17, 0x38, 0x39, 0xbd, 0xc7, 0xed, 0x87, 0xcf, 0xa4, 0xec, 0x4e, + 0x12, 0x7c, 0xe, 0x36, 0x1a, 0x95, 0xd7, 0xe3, 0xe8, 0xd4, 0xb5, 0x83, + 0x50, 0xfd, 0x7d, 0xfd, 0x22, 0xcd, 0x72, 0x26, 0x55, 0x75, 0x86, 0x70, + 0xdb, 0xd6, 0x18, 0x10, 0x6b, 0x12, 0x27, 0xce, 0xa4, 0x92, 0x69, 0xdf, + 0xa2, 0xcb, 0xaa, 0x48, 0x99, 0xd6, 0xd2, 0xe1, 0x7b, 0xd6, 0xf5, 0x97, + 0x54, 0x26, 0xc1, 0xe5, 0xba, 0xb9, 0x5e, 0x15, 0x26, 0xd6, 0x1d, 0x84, + 0xa6, 0xdf, 0x54, 0xb6, 0x9f, 0x9c, 0x2, 0x7, 0x5e, 0x12, 0xad, 0x9a, + 0x68, 0x22, 0x52, 0xec, 0xcd, 0xc8, 0x11, 0x62, 0xf7, 0x1a, 0xb8, 0x7c, + 0x58, 0x67, 0x2f, 0xa1, 0xb, 0xdd, 0xb, 0xaf, 0x62, 0x4, 0x1d, 0x4a, + 0x31, 0x3, 0xa, 0xc8, 0xb1, 0x56, 0x1, 0x1f, 0x8d, 0xc0, 0x65, 0x5a, + 0x84, 0x7b, 0x55, 0xda, 0x88, 0x32, 0xac, 0x52, 0x3b, 0xd, 0x10, 0x48, + 0x64, 0x51, 0xa9, 0xa5, 0xbb, 0xe7, 0xd8, 0xee, 0xc6, 0xd0, 0x4e, 0x71, + 0xe9, 0x8f, 0xdf, 0x5c, 0x87, 0xa4, 0x5d, 0x38, 0x1e, 0xbf, 0xd5, 0xe7, + 0xc9, 0xb0, 0x4, 0xd4, 0xdf, 0xde, 0xd7, 0x64, 0xe9, 0x2, 0xce, 0x31, + 0x4e, 0x56, 0xc0, 0x90, 0xb0, 0xc5, 0x46, 0x36, 0x5a, 0xb8, 0x9e, 0x44, + 0xc3, 0x76, 0x5d, 0xfa, 0x79, 0xe6, 0x67, 0x16, 0x17, 0xde, 0x31, 0xb2, + 0x74, 0x21, 0x1c, 0xf3, 0x26, 0x4c, 0xd6, 0xf7, 0x4b, 0x73, 0x52, 0x5e, + 0x4d, 0xdd, 0xc0, 0x5b, 0x6b, 0xd8, 0x75, 0x83, 0x60, 0x3, 0x9e, 0xcb, + 0xac, 0x9f, 0x39, 0xc8, 0x66, 0x47, 0x4a, 0x2f, 0x72, 0x2c, 0x93, 0x16, + 0xb4, 0xb8, 0x73, 0xc1, 0x2c, 0xbe, 0xe6, 0x6e, 0xaf, 0x71, 0x66, 0xcd, + 0xc5, 0x91, 0xdd, 0x13, 0xf3, 0x70, 0x3, 0xc9, 0x63, 0xf6, 0x20, 0xed, + 0x62, 0x13, 0x40, 0xe9, 0x68, 0x3f, 0xc8, 0x74, 0xa7, 0x29, 0x51, 0xa2, + 0xa5, 0xa9, 0x3d, 0x67, 0x6b, 0xa7, 0x43, 0xa4, 0x97, 0x66, 0x57, 0x54, + 0x6a, 0xe2, 0xae, 0xe0, 0xff, 0xed, 0xbd, 0xe, 0x71, 0x78, 0xf, 0xf9, + 0xdf, 0x82, 0x5, 0x1a, 0x8f, 0xc9, 0x69, 0x23, 0x90, 0xd1, 0x85, 0x96, + 0x70, 0xa4, 0x92, 0xaf, 0xec, 0x82, 0x98, 0xbc, 0x12, 0x48, 0xd3, 0x20, + 0x88, 0x80, 0xbd, 0xc5, 0xc4, 0xca, 0x1c, 0x72, 0xa8, 0xe1, 0xc, 0x31, + 0xa3, 0x5a, 0x85, 0x66, 0x18, 0xed, 0x93, 0x58, 0xae, 0x53, 0x33, 0x76, + 0xfa, 0xc0, 0x52, 0x51, 0x59, 0xf4, 0xf, 0xc9, 0xc0, 0x62, 0xfe, 0x30, + 0xdf, 0x4d, 0xdb, 0x4c, 0x61, 0xde, 0x3d, 0x84, 0x7b, 0x82, 0x2b, 0x29, + 0xc0, 0xab, 0x1a, 0x94, 0x30, 0xf, 0x6b, 0xb2, 0xd8, 0x7e, 0x54, 0x38, + 0xdd, 0xfd, 0x8, 0xaf, 0x1, 0x62, 0xef, 0x2f, 0x43, 0x56, 0xc5, 0x5e, + 0x9a, 0x78, 0x62, 0xe7, 0x67, 0x2, 0xbe, 0xa7, 0xcc, 0x9c, 0x3d, 0x72, + 0xbb, 0xff, 0x37, 0x6a, 0xe4, 0xb2, 0x36, 0x27, 0x6d, 0x35, 0xcd, 0x60, + 0xd4, 0x93, 0xc2, 0x34, 0xbe, 0x6c, 0x16, 0x46, 0x97, 0x4c, 0x6d, 0x99, + 0xd5, 0xb3, 0x5a, 0x68, 0xdf, 0x4f, 0x8, 0x93, 0x28, 0xe2, 0x76, 0x66, + 0x1d, 0x50, 0xfb, 0xec, 0x63, 0x14, 0x36, 0xc8, 0x68, 0xd6, 0xcf, 0xa1, + 0x2d, 0x4e, 0x41, 0x25, 0x3f, 0xe0, 0x25, 0x40, 0xdb, 0xe1, 0xff, 0x7b, + 0xf0, 0x5b, 0x69, 0x4a, 0x31, 0xf5, 0xd0, 0xf4, 0x1d, 0xc4, 0x78, 0x3d, + 0xa7, 0x78, 0xea, 0xa9, 0x72, 0x22, 0xae, 0x67, 0x65, 0x82, 0x63, 0x2d, + 0x91, 0x5d, 0xed, 0xad, 0xb, 0xc3, 0xd2, 0xa7, 0xaf, 0xae, 0x8e, 0xb5, + 0x78, 0xf8, 0xca, 0x68, 0x67, 0xfe, 0x91, 0x3, 0x49, 0xa7, 0x35, 0x6a, + 0x87, 0x9d, 0x2d, 0x3a, 0x9f, 0x63, 0xf1, 0x68, 0x72, 0xb9, 0x35, 0xc3, + 0xd5, 0xe4, 0x7c, 0x5a, 0x5d, 0x9e, 0x3f, 0xc1, 0xc1, 0xed, 0xaa, 0x1e, + 0x88, 0xe5, 0xad, 0x27, 0x79, 0x80, 0x4, 0x1f, 0xec, 0xb1, 0x3c, 0x5f, + 0x15, 0x3c, 0x20, 0xce, 0x4e, 0xc6, 0xda, 0x39, 0x88, 0xef, 0xb5, 0xf2, + 0x39, 0x96, 0xb8, 0xbe, 0xc7, 0x3, 0x32, 0xcf, 0xe4, 0x33, 0x5b, 0x1, + 0xc, 0xfc, 0x3e, 0x63, 0xec, 0x67, 0x24, 0xec, 0x24, 0x97, 0xdf, 0xff, + 0x0, 0xcb, 0xa, 0x14, 0xbf, 0x5c, 0x10, 0xa6, 0x52, 0x29, 0xee, 0xc2, + 0x56, 0xe5, 0x25, 0x67, 0xe5, 0xf9, 0xd0, 0xb, 0x8b, 0xee, 0xd6, 0x19, + 0x8, 0x6f, 0x2a, 0xcc, 0xc7, 0x7a, 0xcd, 0xec, 0xc3, 0xbd, 0xdd, 0xd4, + 0x54, 0xa2, 0x76, 0xe1, 0x9f, 0x21, 0xa5, 0xde, 0x6, 0x7, 0x4d, 0x56, + 0xa7, 0x71, 0x93, 0x8, 0xd8, 0x56, 0xea, 0xbe, 0x78, 0xe4, 0x8d, 0xce, + 0x7a, 0xda, 0xc6, 0xb6, 0xb6, 0xc0, 0xce, 0x30, 0x18, 0xbd, 0x6e, 0x20, + 0xc6, 0xa0, 0x96, 0x26, 0x7e, 0xef, 0x6b, 0x1f, 0xe5, 0xc9, 0x15, 0x77, + 0xa7, 0xe9, 0xda, 0x9f, 0x53, 0x24, 0xe1, 0x2f, 0x70, 0x68, 0x62, 0x99, + 0xcb, 0xcd, 0xa0, 0xe1, 0xef, 0xe2, 0x38, 0x17, 0x9d, 0xfd, 0x5c, 0x41, + 0xee, 0x4d, 0x3b, 0xeb, 0x7d, 0x72, 0x45, 0x6e, 0x1b, 0x75, 0x46, 0x9d, + 0x75, 0x9f, 0xf4, 0xff, 0x31, 0x0, 0xaa, 0x2, 0xcc, 0x93, 0xa4, 0xbe, + 0x84, 0x8d, 0xd7, 0xb0, 0x42, 0x80, 0x8e, 0x29, 0xfb, 0x6, 0x32, 0x26, + 0xc, 0xe9, 0x67, 0x3a, 0xff, 0x9, 0xa2, 0x30, 0x70, 0xe2, 0xcc, 0x73, + 0xe8, 0x94, 0xf, 0xdb, 0xbb, 0x53, 0x43, 0x68, 0x15, 0x56, 0x9c, 0x75, + 0x61, 0xae, 0x59, 0xa4, 0x42, 0xcd, 0xe0, 0xbc, 0x5e, 0xc, 0x8c, 0xd1, + 0x3e, 0x8d, 0x8d, 0xf3, 0x2f, 0x2b, 0xbc, 0x98, 0x3, 0xec, 0xd9, 0xd3, + 0x38, 0x59, 0x9f, 0xde, 0x15, 0x6b, 0x55, 0x8, 0xef, 0xf, 0x5c, 0x9f, + 0xe, 0x74, 0xf9, 0x10, 0xde, 0xdc, 0x3d, 0x1d, 0xcf, 0xc9, 0xfd, 0x1, + 0xd7, 0x84, 0x44, 0xa0, 0xc4, 0x5e, 0xda, 0x6f, 0x6a, 0x97, 0x7e, 0x17, + 0x8d, 0x77, 0x62, 0x5b, 0x87, 0xd7, 0xa7, 0x31, 0x38, 0x41, 0xbf, 0x2b, + 0x7b, 0x5c, 0x72, 0x96, 0x6f, 0xe5, 0xa2, 0x99, 0xe, 0xdc, 0x69, 0x54, + 0xf0, 0x35, 0x78, 0xc6, 0xbc, 0x7e, 0x9d, 0x67, 0x73, 0xa6, 0x14, 0xf6, + 0xde, 0x6e, 0x91, 0x8e, 0x16, 0x2e, 0x18, 0xdd, 0xd, 0x16, 0x3, 0xbc, + 0x6f, 0x4, 0xfa, 0x20, 0xbf, 0xc1, 0x7c, 0x47, 0x45, 0x59, 0xc9, 0x5a, + 0xf7, 0xbd, 0x6, 0xa, 0x50, 0xf, 0x29, 0xa3, 0x12, 0x67, 0x58, 0x88, + 0xeb, 0x8d, 0x37, 0x8f, 0x6b, 0xef, 0xf, 0xc6, 0x13, 0xde, 0x8f, 0xe4, + 0xd, 0x2b, 0x93, 0x34, 0x48, 0x5e, 0x27, 0xf1, 0xaa, 0xc3, 0x7c, 0x79, + 0x7d, 0xc3, 0x89, 0xca, 0xce, 0xb3, 0x7a, 0x5a, 0xfe, 0xef, 0x83, 0x1f, + 0x43, 0xd5, 0xe4, 0x2b, 0x59, 0x2c, 0x44, 0x96, 0xba, 0xbc, 0x25, 0xe5, + 0x13, 0x7b, 0xbb, 0x78, 0x86, 0xef, 0x4d, 0x33, 0xf9, 0x95, 0xc5, 0x26, + 0x46, 0x80, 0x3f, 0xed, 0xf9, 0x9f, 0x76, 0x7f, 0xe6, 0x72, 0xa, 0xf6, + 0xc7, 0x55, 0x81, 0x43, 0x72, 0x41, 0xe9, 0x7e, 0x35, 0x3f, 0x8d, 0xf1, + 0x4b, 0x21, 0xdb, 0x58, 0xb4, 0x3a, 0xf2, 0x0, 0xab, 0x5c, 0xfd, 0x4e, + 0xe5, 0x30, 0x14, 0xe6, 0x5c, 0xa0, 0x15, 0x50, 0x2b, 0xb4, 0xd8, 0xe7, + 0x99, 0xb4, 0xd3, 0x98, 0x1c, 0x8, 0x4, 0xbc, 0x38, 0x88, 0x36, 0x51, + 0x94, 0x2f, 0xdc, 0x5e, 0x95, 0xa3, 0xf6, 0xde, 0x39, 0x90, 0x8c, 0x7c, + 0xfd, 0x3b, 0xbd, 0x23, 0xf4, 0x15, 0x74, 0x7c, 0x6f, 0xc0, 0x37, 0x48, + 0x85, 0xce, 0xa9, 0xd8, 0x67, 0xae, 0x1c, 0x22, 0x7d, 0x75, 0x5c, 0x61, + 0xb6, 0x96, 0x1a, 0xec, 0x91, 0xd8, 0x54, 0xe3, 0xdc, 0xf5, 0x4a, 0xf3, + 0x3a, 0xda, 0x48, 0xdc, 0xfa, 0x3d, 0xcc, 0xe7, 0xad, 0x4c, 0x8d, 0x49, + 0xdc, 0xa9, 0xd7, 0x1f, 0xf3, 0xef, 0xa8, 0x28, 0x2, 0x68, 0x79, 0x82, + 0x27, 0x81, 0x32, 0x5f, 0x55, 0x9, 0x28, 0xf6, 0xc9, 0x6e, 0xe5, 0x4b, + 0xa9, 0x3c, 0x46, 0xb4, 0xec, 0xd3, 0x77, 0xda, 0x62, 0x3d, 0x1f, 0xe6, + 0x3a, 0xc5, 0x8d, 0x32, 0xdb, 0xf8, 0x53, 0xb4, 0xca, 0xd6, 0xd5, 0x40, + 0xaf, 0x3e, 0x4f, 0x3e, 0x64, 0x21, 0xc2, 0xa9, 0x6a, 0x3a, 0x86, 0xd1, + 0x29, 0x18, 0xfb, 0xb8, 0xe1, 0x39, 0xd1, 0xb1, 0x18, 0xf3, 0x58, 0x6f, + 0x32, 0xf9, 0x28, 0x42, 0xbe, 0x9, 0x9d, 0xef, 0xb5, 0x7b, 0xa8, 0x12, + 0x7d, 0xc8, 0x4c, 0x32, 0x24, 0xca, 0x62, 0x6a, 0xd7, 0x23, 0xfc, 0x3d, + 0xc, 0xcb, 0x55, 0x75, 0x75, 0x1e, 0x84, 0x8d, 0xa4, 0x8f, 0x7d, 0x14, + 0x79, 0xe1, 0x2e, 0xf9, 0xaa, 0x7a, 0x13, 0x83, 0x30, 0xa4, 0x41, 0x56, + 0x2a, 0x13, 0xcc, 0x38, 0x5e, 0xfa, 0xbd, 0x1b, 0xba, 0x3d, 0xf6, 0xcc, + 0x68, 0x4a, 0x6b, 0xa9, 0x3b, 0xe5, 0x87, 0x43, 0xb3, 0xd2, 0x78, 0xcb, + 0x3e, 0x3, 0xd7, 0x8e, 0x49, 0xc7, 0x7b, 0xd5, 0x44, 0x61, 0x56, 0xd2, + 0x8e, 0x0, 0xd2, 0xde, 0x5c, 0xae, 0xbf, 0x35, 0x4, 0x11, 0xc4, 0x5, + 0x9, 0x50, 0x31, 0xf4, 0x4f, 0x1c, 0x5e, 0x1b, 0xf3, 0x91, 0x99, 0x1, + 0x7f, 0x69, 0xcc, 0xba, 0x91, 0xba, 0xb6, 0x2d, 0xc7, 0x99, 0x7e, 0xf2, + 0x1b, 0x68, 0x8, 0x7, 0x11, 0xe2, 0x31, 0x29, 0xd1, 0xc6, 0x68, 0x45, + 0x17, 0x7e, 0xf9, 0x0, 0x27, 0x23, 0x18, 0xa4, 0xb2, 0x61, 0xd5, 0x24, + 0xe8, 0x8, 0xb7, 0xb2, 0xb1, 0x14, 0x6f, 0xb, 0x3e, 0xe7, 0x37, 0x64, + 0xdb, 0x2f, 0x5e, 0x93, 0xf0, 0xa9, 0xf6, 0xad, 0x83, 0xa3, 0xba, 0xcc, + 0x92, 0x65, 0x15, 0x60, 0x11, 0x6c, 0x88, 0x2f, 0xf5, 0x52, 0x98, 0x2d, + 0xd0, 0x6e, 0x5d, 0x68, 0x24, 0xf6, 0xcf, 0xea, 0x33, 0xb9, 0x4d, 0xc8, + 0xa0, 0x87, 0x65, 0xfa, 0xc7, 0x6a, 0x7f, 0xae, 0xa9, 0x44, 0x19, 0x92, + 0xc3, 0x36, 0x1f, 0xf1, 0xf1, 0x4f, 0x9e, 0x1f, 0x2b, 0x4c, 0x2c, 0x94, + 0x34, 0x52, 0x70, 0x43, 0x73, 0x90, 0xfe, 0x24, 0x7a, 0x2d, 0x3b, 0x8a, + 0x24, 0x1d, 0xbd, 0xf5, 0xc6, 0x58, 0x65, 0x89, 0x9, 0xcc, 0x26, 0x46, + 0xeb, 0x8b, 0x1b, 0x6a, 0x80, 0x31, 0xf, 0xc2, 0xd4, 0xf3, 0x63, 0x75, + 0x1c, 0x77, 0x14, 0xe2, 0xcc, 0xc9, 0x94, 0x2c, 0x74, 0x7d, 0x29, 0x86, + 0x7f, 0x81, 0x5, 0xa9, 0x18, 0x3d, 0x1d, 0xa4, 0x50, 0xea, 0x86, 0x3, + 0x1f, 0xb, 0x49, 0xfd, 0x43, 0xf4, 0xa1, 0xe3, 0xbb, 0x17, 0x7c, 0x63, + 0x57, 0xbb, 0x5d, 0x5d, 0x3c, 0xca, 0xf2, 0x7b, 0x49, 0xd0, 0x30, 0x77, + 0x71, 0x71, 0x44, 0x9c, 0xc2, 0xfc, 0x2b, 0x4c, 0x1c, 0xc8, 0xe7, 0x35, + 0x6b, 0x1a, 0x72, 0xfe, 0xf4, 0xc1, 0x67, 0x18, 0x49, 0x32, 0x64, 0xef, + 0x85, 0x46, 0xfc, 0x5a, 0x94, 0xe7, 0x98, 0x6f, 0xb5, 0xbc, 0xb, 0x0, + 0x87, 0x3, 0x7f, 0x8a, 0x99, 0xc2, 0x60, 0x9a, 0xc7, 0x50, 0x80, 0x66, + 0x20, 0x55, 0x18, 0x89, 0xde, 0xf0, 0x2e, 0x32, 0x6b, 0xc5, 0xc1, 0x5b, + 0x70, 0x1f, 0xbb, 0xde, 0x87, 0xa1, 0x22, 0x4c, 0x8d, 0x6e, 0x95, 0x6f, + 0x9e, 0x71, 0x21, 0xdc, 0x5d, 0x55, 0xa2, 0xb1, 0xd4, 0x6, 0x61, 0x7, + 0x3c, 0x52, 0xa, 0xf4, 0x93, 0x21, 0xd7, 0x6f, 0xa4, 0xf3, 0x4f, 0xd0, + 0xda, 0x9, 0xf0, 0x31, 0x8b, 0xc, 0xb2, 0x8b, 0x2d, 0x33, 0xc4, 0x72, + 0xdc, 0xf, 0x2c, 0xd0, 0x2d, 0xd5, 0xf4, 0xff, 0x62, 0xaf, 0x85, 0xf7, + 0x10, 0xc8, 0x40, 0xba, 0x8b, 0x8a, 0xad, 0xcf, 0xc0, 0x24, 0xa5, 0xa3, + 0x64, 0x5d, 0x71, 0x2b, 0xba, 0xc1, 0x13, 0xea, 0x32, 0x2a, 0xb7, 0x6d, + 0x5d, 0xa5, 0x32, 0x12, 0x92, 0x71, 0xaf, 0xda, 0x3e, 0x0, 0xae, 0x13, + 0x37, 0x50, 0x44, 0xb4, 0x4c, 0xfb, 0xa0, 0x79, 0x6d, 0x97, 0x52, 0x9b, + 0x1b, 0x8d, 0xdf, 0x98, 0x78, 0xd9, 0xed, 0x90, 0x2, 0xb8, 0x1f, 0x4f, + 0xeb, 0xbf, 0x97, 0x19, 0x9c, 0x3f, 0x1a, 0x58, 0x1e, 0x77, 0x53, 0x5f, + 0xa2, 0xce, 0xf6, 0x36, 0x28, 0x8f, 0xbc, 0x7c, 0x39, 0x8f, 0x2, 0x6, + 0x29, 0x84, 0x37, 0x96, 0x86, 0x8a, 0x90, 0x6d, 0xcd, 0x72, 0xbf, 0xf0, + 0xc0, 0x51, 0xcf, 0xda, 0x7f, 0xd0, 0x42, 0x30, 0xe9, 0x83, 0xb2, 0x7d, + 0xbd, 0xd2, 0xe2, 0x47, 0x96, 0xd6, 0xc0, 0x34, 0xdc, 0x90, 0x45, 0x29, + 0x11, 0x11, 0xb0, 0x65, 0x44, 0xec, 0xe, 0xe4, 0x20, 0xba, 0x9a, 0xe0, + 0x85, 0x78, 0xa8, 0x37, 0x53, 0x8b, 0x2a, 0x1, 0x19, 0x84, 0xad, 0xa, + 0x5c, 0xba, 0x10, 0x38, 0xe1, 0x88, 0xdc, 0x52, 0x41, 0x19, 0xf4, 0x4c, + 0xad, 0x97, 0xa8, 0xa, 0xfc, 0x29, 0x3e, 0x9a, 0xd8, 0x34, 0x4f, 0xe7, + 0x17, 0xfb, 0x4a, 0x1c, 0x7d, 0x39, 0x8f, 0xc0, 0xb8, 0xf4, 0xcd, 0x9a, + 0xe2, 0x83, 0x76, 0x61, 0xc6, 0x30, 0x54, 0xa6, 0x2, 0xb0, 0x11, 0x8f, + 0xae, 0x90, 0x7c, 0x66, 0x9e, 0x3e, 0xb7, 0x82, 0xc2, 0x22, 0xaa, 0x53, + 0xca, 0x26, 0x5e, 0x94, 0x15, 0x68, 0xcd, 0xc1, 0x1e, 0x3a, 0x2, 0xec, + 0xfb, 0x48, 0xb6, 0x61, 0x15, 0x3b, 0x26, 0x8a, 0x1d, 0xfd, 0xb, 0x48, + 0xa0, 0x81, 0x2e, 0xd0, 0xc6, 0x24, 0x9e, 0x37, 0x90, 0xc5, 0x80, 0xaa, + 0xcf, 0x96, 0xee, 0xc5, 0x1d, 0xa9, 0xbe, 0x20, 0xc4, 0xb8, 0x59, 0x5f, + 0x95, 0x2b, 0x3a, 0x58, 0xe3, 0xe8, 0xe0, 0x3d, 0x43, 0x5b, 0x4b, 0x2a, + 0xf5, 0x8c, 0x36, 0x43, 0xaf, 0x8, 0x84, 0xbb, 0xa2, 0x2f, 0xd2, 0xac, + 0x6f, 0x55, 0x34, 0x45, 0x4, 0xbd, 0xa7, 0x53, 0x4f, 0x92, 0x9c, 0xba, + 0xf7, 0x50, 0x17, 0x5a, 0x47, 0x69, 0x96, 0x8f, 0x87, 0xb0, 0xd6, 0x4c, + 0xd6, 0xe3, 0x93, 0x7a, 0x9, 0xe4, 0x35, 0x18, 0xea, 0x83, 0xe4, 0x71, + 0xb2, 0xed, 0x94, 0x31, 0x20, 0xab, 0xdf, 0xb8, 0xab, 0xe0, 0x33, 0xcf, + 0x4d, 0x68, 0x15, 0x87, 0x5c, 0xbf, 0x97, 0x7f, 0xbc, 0xa3, 0xa1, 0x99, + 0x54, 0x3, 0x60, 0xc9, 0xb6, 0xe6, 0x82, 0xc6, 0x38, 0xab, 0x5b, 0xf0, + 0xe5, 0x2d, 0x51, 0x53, 0x91, 0x72, 0xf4, 0x14, 0xfc, 0x45, 0x66, 0xed, + 0x8, 0x24, 0x8d, 0xf0, 0x35, 0x14, 0xb9, 0xb4, 0xa7, 0xe, 0xa2, 0x45, + 0x20, 0xe5, 0x70, 0x2d, 0x46, 0xd2, 0x6b, 0x8f, 0xf1, 0xa4, 0xc6, 0x25, + 0xa0, 0x75, 0xcf, 0x5a, 0xce, 0xee, 0x33, 0xda, 0xf4, 0x46, 0x33, 0x1c, + 0x95, 0x87, 0xe1, 0xbe, 0x62, 0x88, 0x75, 0x40, 0x1d, 0xcb, 0x92, 0x86, + 0x98, 0xc3, 0x61, 0x6b, 0xd9, 0x46, 0x2d, 0xbb, 0x74, 0xb6, 0x57, 0xc4, + 0xea, 0xc, 0x53, 0x5c, 0x3, 0x39, 0x9e, 0x93, 0x70, 0x1b, 0xcb, 0x21, + 0xac, 0x87, 0xa4, 0x91, 0x37, 0xa1, 0x61, 0xed, 0xbe, 0xb3, 0x85, 0x75, + 0x35, 0x98, 0xf, 0x89, 0x1a, 0xcb, 0x5a, 0x54, 0xad, 0x5b, 0x6b, 0x1a, + 0x3d, 0x77, 0xab, 0x2d, 0x4e, 0x23, 0xef, 0x9c, 0x74, 0x46, 0x15, 0x4a, + 0x0, 0xe2, 0xfd, 0xfe, 0xe4, 0x3d, 0x73, 0xc6, 0x4f, 0x29, 0xe6, 0x89, + 0xd9, 0xb6, 0x9f, 0x8c, 0x37, 0x96, 0xc1, 0x8f, 0x55, 0x6b, 0x6a, 0x33, + 0xc3, 0x6c, 0xa5, 0x5b, 0x2f, 0x34, 0x25, 0xa4, 0x74, 0x3c, 0x3f, 0x4e, + 0xf4, 0xcf, 0xe9, 0x15, 0x57, 0xba, 0x65, 0x55, 0x2e, 0x3f, 0x1c, 0xc9, + 0x3c, 0x20, 0x99, 0xd1, 0x3d, 0x86, 0x5c, 0x9c, 0xd5, 0x93, 0x86, 0x39, + 0x6f, 0x6c, 0xd1, 0xe2, 0x26, 0xf8, 0xae, 0xed, 0x59, 0x6e, 0x15, 0xde, + 0xc9, 0xc7, 0x3f, 0xc6, 0x5c, 0x6c, 0x5b, 0x34, 0xce, 0x97, 0xe2, 0xfd, + 0xb8, 0xc8, 0xff, 0xd0, 0x4d, 0x7b, 0xbb, 0x59, 0x64, 0xc5, 0x2a, 0x70, + 0x37, 0x9d, 0xc5, 0x8d, 0xe4, 0xf, 0x16, 0x37, 0x98, 0x5c, 0xe2, 0x14, + 0xcb, 0x3f, 0x69, 0x46, 0xcf, 0xf1, 0xa8, 0x61, 0x8d, 0xcd, 0x99, 0x20, + 0x3, 0x53, 0xf7, 0xca, 0x4f, 0x2d, 0x23, 0x4c, 0xab, 0x94, 0xf5, 0xd9, + 0x4c, 0x32, 0xfa, 0xc3, 0x3, 0x21, 0x7a, 0x5e, 0x8b, 0xd4, 0x1c, 0xc0, + 0x1d, 0x85, 0x28, 0x36, 0xeb, 0x40, 0xac, 0xae, 0xb6, 0x13, 0x2e, 0x77, + 0xc2, 0xf5, 0xbe, 0x84, 0x47, 0xa0, 0xe3, 0x28, 0x4a, 0xf8, 0x17, 0x9e, + 0x3c, 0x29, 0x51, 0x86, 0xf9, 0x12, 0x7a, 0x5b, 0xdf, 0x75, 0x1e, 0x87, + 0x6f, 0xff, 0x3d, 0x32, 0x48, 0x79, 0x6e, 0x58, 0xa2, 0xc7, 0x9a, 0xc4, + 0xf3, 0x2, 0x1c, 0xf1, 0x7f, 0xb, 0x31, 0xb7, 0x19, 0xd, 0x62, 0xcf, + 0x3e, 0xa8, 0x59, 0x92, 0xfb, 0x61, 0xea, 0x8c, 0xca, 0x76, 0x1, 0x15, + 0xa6, 0xf, 0xff, 0x8a, 0xc7, 0xb3, 0xed, 0xee, 0xa4, 0x8d, 0x8d, 0x7, + 0xce, 0xb2, 0xc, 0x1c, 0xbc, 0x48, 0xad, 0xcb, 0x17, 0x9a, 0x61, 0x99, + 0x38, 0x4b, 0x40, 0xc9, 0xed, 0x21, 0x4, 0x9e, 0xd0, 0x4f, 0xc7, 0x71, + 0xb9, 0xf1, 0x11, 0x0, 0x7d, 0x4, 0xe3, 0xd5, 0xb7, 0xd9, 0x3, 0xe0, + 0xf9, 0x87, 0xdb, 0xf7, 0x96, 0x7d, 0x93, 0x24, 0x70, 0x8d, 0xbc, 0x17, + 0x41, 0x1a, 0x4d, 0x6b, 0x9e, 0x9b, 0x83, 0x67, 0x96, 0x67, 0x5a, 0x60, + 0xa8, 0xa8, 0xbe, 0x8e, 0x27, 0xa1, 0x2c, 0xfa, 0xc0, 0xe1, 0xd6, 0x69, + 0xea, 0x65, 0x58, 0x56, 0x9b, 0x3c, 0x92, 0x10, 0x76, 0xaf, 0x6b, 0x97, + 0xe1, 0x64, 0x19, 0x14, 0x1b, 0xc4, 0xe9, 0xc, 0xd0, 0x1a, 0x9c, 0x8, + 0x74, 0x3b, 0xd2, 0x48, 0x92, 0xa8, 0x5e, 0xbf, 0xc9, 0x5a, 0x2b, 0xe0, + 0x3, 0xbc, 0x62, 0x9e, 0xe9, 0x5d, 0x23, 0xd4, 0xdb, 0xf6, 0x8, 0x6d, + 0x67, 0x6f, 0x38, 0xe6, 0xb0, 0x83, 0xae, 0x82, 0xe4, 0xa9, 0xd8, 0xaf, + 0x7f, 0xd2, 0x45, 0xa4, 0x49, 0xc3, 0x68, 0xcc, 0x79, 0x65, 0xad, 0xfa, + 0x1b, 0x9f, 0x89, 0xd6, 0xe3, 0xbc, 0xe8, 0x7a, 0x7, 0xf9, 0x2d, 0x58, + 0xa3, 0x50, 0xe4, 0xc2, 0x0, 0xe1, 0x8b, 0xfe, 0x2d, 0x46, 0x1, 0xaa, + 0xa0, 0x1, 0x20, 0xef, 0x6a, 0x9, 0x69, 0x88, 0xf2, 0x4, 0xf5, 0xe1, + 0x15, 0x54, 0x5a, 0x26, 0x14, 0x6b, 0x9, 0xf5, 0x90, 0x9e, 0x44, 0x55, + 0x2d, 0x7e, 0xd5, 0xa9, 0xc1, 0x2a, 0xa2, 0x49, 0xec, 0x5c, 0xf8, 0x39, + 0x81, 0xe3, 0x86, 0xb7, 0xa3, 0x2a, 0xfd, 0xb2, 0x61, 0xa8, 0xb2, 0x80, + 0x9c, 0xb4, 0x48, 0x79, 0x17, 0x36, 0xe1, 0x30, 0x7d, 0xad, 0xde, 0x32, + 0x85, 0xbd, 0x54, 0xa1, 0x9, 0xf2, 0x74, 0xa0, 0x5f, 0xf6, 0xcd, 0x96, + 0xc4, 0x1c, 0x7a, 0x18, 0x8d, 0xae, 0xc1, 0x96, 0xbb, 0xdd, 0x8, 0x4e, + 0x2d, 0x86, 0xc, 0x89, 0xe, 0xf0, 0xd0, 0xae, 0x31, 0x96, 0xda, 0xa4, + 0x4e, 0x81, 0xaf, 0x27, 0x98, 0x53, 0xaf, 0x39, 0x9a, 0x2d, 0x92, 0x97, + 0x20, 0x5e, 0xfb, 0x4f, 0x6f, 0x4f, 0xa6, 0x7f, 0x2f, 0x92, 0x8b, 0xc6, + 0x51, 0x31, 0x2, 0x92, 0xbc, 0xdb, 0x48, 0x22, 0x7c, 0x8f, 0x84, 0x50, + 0x21, 0x43, 0x65, 0x2d, 0x6, 0xdd, 0xe0, 0x9f, 0x8a, 0x7c, 0x2f, 0xa9, + 0xc3, 0x1b, 0xde, 0x7a, 0x81, 0x7e, 0x1c, 0xb2, 0x2a, 0x53, 0xa0, 0xf7, + 0xc4, 0xb9, 0xfe, 0xce, 0x18, 0xba, 0xf2, 0x10, 0xfb, 0x54, 0x68, 0xa1, + 0x26, 0xb0, 0x0, 0x6b, 0x2e, 0x2f, 0x9e, 0xb2, 0x68, 0xea, 0x20, 0xe5, + 0x76, 0xf3, 0xe2, 0xe6, 0x4f, 0x40, 0x7d, 0x5e, 0x20, 0x96, 0xdf, 0x45, + 0x77, 0xb6, 0xd8, 0xf0, 0x5, 0x31, 0xf7, 0x86, 0xd3, 0x70, 0x12, 0x80, + 0x3a, 0xde, 0x75, 0x4a, 0x82, 0x1c, 0x9d, 0xe8, 0xc0, 0xed, 0xd7, 0x7, + 0xd5, 0x79, 0x24, 0x75, 0x5a, 0xac, 0x64, 0x8e, 0xb8, 0xc1, 0x19, 0xe, + 0xe4, 0xa9, 0xca, 0xc6, 0x27, 0xcc, 0x8c, 0xe8, 0xd8, 0xf4, 0xda, 0x4c, + 0x14, 0x88, 0x16, 0xe8, 0xae, 0x84, 0x71, 0xc5, 0x54, 0x21, 0x12, 0x98, + 0xa6, 0x43, 0x44, 0x48, 0x1, 0xf, 0x57, 0xf4, 0x4, 0x33, 0x50, 0x8c, + 0xe0, 0xbf, 0x3d, 0x36, 0x76, 0xfe, 0x72, 0x41, 0xe2, 0xfb, 0x4c, 0x35, + 0x1c, 0x65, 0x16, 0xaa, 0xb7, 0x1d, 0x13, 0xcb, 0x5f, 0x5a, 0x3f, 0x1c, + 0xaa, 0x1d, 0x6a, 0xe3, 0x54, 0x77, 0xd8, 0x15, 0x51, 0xe9, 0x7d, 0x50, +}; +const uint8_t kAltGameImages1xE[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, + 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, + 0x71, 0x24, 0xa1, 0xbd, 0x1f, 0x3f, 0x12, 0x23, 0x43, 0x2, 0x1e, 0x8e, + 0x36, 0xe5, 0x4e, 0xb8, 0x69, 0xf1, 0xd0, 0x12, 0xbe, 0x32, 0x17, 0x2f, + 0xd9, 0x54, 0x88, 0xf7, 0x67, 0x6e, 0xb, 0xdf, 0x39, 0x9e, 0xeb, 0x79, + 0x18, 0x2a, 0x16, 0x50, 0x90, 0x55, 0xc0, 0x2a, 0xc0, 0xbf, 0x77, 0xa3, + 0x47, 0xa4, 0xf3, 0x3f, 0xb, 0x74, 0xa9, 0x83, 0x4f, 0x2f, 0x4e, 0x73, + 0x84, 0x2c, 0x73, 0x7e, 0xd3, 0xc1, 0xc0, 0x2d, 0x36, 0xb5, 0x60, 0xb, + 0xc6, 0xd5, 0x50, 0x10, 0x1a, 0x2f, 0xa5, 0xa0, 0x17, 0x49, 0xaf, 0xcf, + 0xd9, 0xb7, 0xde, 0xeb, 0xc0, 0x9a, 0x4c, 0xf7, 0xf4, 0x96, 0xe1, 0x1, + 0x68, 0xe3, 0x26, 0xa3, 0xd3, 0x45, 0x7b, 0x57, 0xac, 0xc2, 0xa9, 0x88, + 0x8d, 0xdb, 0x4, 0x56, 0x34, 0xf5, 0x97, 0xd1, 0x7a, 0x60, 0xf8, 0x46, + 0xa, 0xf1, 0x19, 0x92, 0x2d, 0x7, 0x66, 0xec, 0x6f, 0x86, 0xc4, 0x3b, + 0x4b, 0xc8, 0xa8, 0x39, 0xe3, 0x94, 0x63, 0xb4, 0x5e, 0x9b, 0x5e, 0xd, + 0x9a, 0x32, 0xa8, 0x4e, 0xc5, 0x58, 0x39, 0x1b, 0x83, 0x74, 0x4e, 0x6d, + 0xa9, 0xf7, 0x14, 0x94, 0xbd, 0xa2, 0xd2, 0xe2, 0xa2, 0x66, 0x7, 0xc9, + 0x2b, 0xe0, 0x43, 0x8d, 0x6d, 0x28, 0x0, 0x9f, 0x3f, 0x94, 0x4b, 0xe5, + 0x68, 0xf8, 0x4d, 0x27, 0xcd, 0x33, 0x1d, 0xee, 0x11, 0x11, 0xe4, 0x2d, + 0x36, 0x64, 0xd4, 0xd0, 0xce, 0xa9, 0xa, 0x91, 0x7c, 0x1d, 0x6e, 0xe2, + 0xcb, 0x8, 0x65, 0x8b, 0x6f, 0xe1, 0x1b, 0x3c, 0xed, 0xa7, 0x42, 0x32, + 0x28, 0xa8, 0xbc, 0x8d, 0x1, 0x9b, 0x3b, 0x7e, 0xa3, 0xcf, 0x7d, 0x8e, + 0x6, 0x23, 0x42, 0xe9, 0xda, 0xa6, 0xf2, 0xa3, 0x15, 0x4a, 0x7c, 0xa5, + 0xba, 0xd3, 0xd5, 0x89, 0x44, 0x82, 0x86, 0xa, 0x3d, 0x9c, 0xfc, 0x64, + 0x43, 0x2e, 0xc5, 0x17, 0xe2, 0x24, 0x65, 0xc5, 0x73, 0x9c, 0x12, 0x37, + 0x7, 0x58, 0x7b, 0x12, 0xc, 0x82, 0x7, 0xad, 0x52, 0x7c, 0x43, 0x15, + 0xb5, 0xc0, 0x67, 0x99, 0x3, 0x2a, 0x5a, 0xf3, 0x66, 0xcf, 0xd7, 0x23, + 0xec, 0xb8, 0xf, 0x66, 0x48, 0x60, 0x74, 0x10, 0xe4, 0x61, 0xb2, 0x51, + 0x52, 0xbf, 0x87, 0xd5, 0x20, 0x5b, 0x5c, 0x63, 0xe5, 0x45, 0x18, 0x43, + 0xb4, 0xfe, 0x50, 0x6e, 0x57, 0xe0, 0x34, 0xe5, 0x12, 0x2d, 0xbf, 0x38, + 0xa5, 0x15, 0x1d, 0x8e, 0xf5, 0xfe, 0x4d, 0x59, 0x14, 0xde, 0xc1, 0xd1, + 0xf7, 0x34, 0x11, 0xac, 0xb5, 0xef, 0x76, 0xee, 0xb6, 0x2c, 0x1f, 0x23, + 0x0, 0xa3, 0x93, 0x9d, 0x77, 0xa9, 0x8f, 0x32, 0x16, 0x4, 0x6f, 0xe3, + 0xa8, 0x21, 0x45, 0xd4, 0x5a, 0x6d, 0xc, 0xb9, 0x7, 0x29, 0x2b, 0x17, + 0x6c, 0x3c, 0x58, 0xb7, 0x8, 0x4b, 0xb3, 0x20, 0x83, 0xf1, 0x60, 0xaa, + 0xfe, 0xf1, 0x38, 0xd7, 0xf5, 0x59, 0x5, 0x76, 0x74, 0xd, 0x5, 0xf4, + 0x8c, 0x8f, 0xbb, 0xb9, 0x32, 0x41, 0xb7, 0x7e, 0x14, 0xdc, 0xf1, 0xe2, + 0x39, 0xf4, 0xf9, 0x25, 0x4d, 0xc5, 0xb2, 0xa8, 0x9f, 0x77, 0x31, 0xe4, + 0x75, 0xf4, 0x6b, 0x73, 0xc8, 0xed, 0x8b, 0x1c, 0xe3, 0xfa, 0x5d, 0x30, + 0xbc, 0x71, 0x64, 0xe8, 0xde, 0x98, 0x11, 0xe6, 0x4b, 0xd6, 0x70, 0x72, + 0x45, 0xe3, 0x6b, 0xd6, 0x8c, 0x4f, 0xff, 0xec, 0x81, 0x34, 0x14, 0x26, + 0xed, 0xee, 0x8d, 0x53, 0x5d, 0xe0, 0x52, 0xdd, 0x9c, 0x31, 0x14, 0x51, + 0xbc, 0x1f, 0x6d, 0xfc, 0x91, 0xd4, 0xa3, 0xe6, 0xaf, 0x46, 0x9e, 0x41, + 0xe0, 0x2d, 0xa7, 0xfb, 0xd, 0x3b, 0x64, 0x3e, 0x67, 0x63, 0x96, 0xd4, + 0xe0, 0x40, 0xa5, 0x71, 0xbd, 0x67, 0xd1, 0xdb, 0xf5, 0x7d, 0xb0, 0x98, + 0x38, 0xc5, 0xe1, 0x13, 0x6e, 0x99, 0xb4, 0x92, 0x2c, 0x46, 0x40, 0x8, + 0x52, 0x9, 0xae, 0x70, 0x67, 0x1, 0x3f, 0xd2, 0x25, 0x61, 0x98, 0x9e, + 0xef, 0xcd, 0x1f, 0x37, 0x96, 0xce, 0xf1, 0x53, 0xff, 0xb8, 0x95, 0x2b, + 0xc6, 0x8d, 0xa2, 0xae, 0x9, 0xf8, 0x9b, 0xf4, 0x18, 0x17, 0x15, 0xed, + 0x98, 0xdf, 0x1c, 0xb8, 0xd5, 0x32, 0xf6, 0xbd, 0xdd, 0x8, 0xea, 0x38, + 0xb, 0x2b, 0x2f, 0x13, 0xab, 0x59, 0xcf, 0xce, 0xbe, 0x49, 0x39, 0xc, + 0x98, 0xe4, 0xbc, 0x1c, 0xe4, 0xf9, 0x88, 0x96, 0xe2, 0xf2, 0x8d, 0xac, + 0xa0, 0x31, 0xe9, 0x4a, 0x42, 0x37, 0x92, 0x7a, 0xcf, 0xb7, 0xee, 0x65, + 0xcd, 0xcd, 0x2f, 0xe8, 0x2f, 0xe2, 0x70, 0x8a, 0x7, 0xd5, 0x93, 0x3e, + 0xc4, 0xf1, 0x9, 0x19, 0x4a, 0xb1, 0x96, 0x4c, 0xb0, 0x9b, 0x41, 0x5a, + 0x1e, 0x52, 0x0, 0x2b, 0xa4, 0xc3, 0xd2, 0x9, 0xd8, 0x7f, 0x93, 0x53, + 0x25, 0x96, 0xe6, 0xbe, 0x41, 0x84, 0x6c, 0x3b, 0x72, 0x51, 0xec, 0x4e, + 0x91, 0xbd, 0x6c, 0x37, 0x34, 0xb7, 0x6f, 0xda, 0x3c, 0xac, 0xc, 0x1a, + 0xb, 0xdc, 0x4a, 0x55, 0xc8, 0x37, 0x4, 0x48, 0xd5, 0x1f, 0x27, 0x66, + 0xb9, 0x2c, 0x82, 0x9f, 0x62, 0xd, 0x1a, 0xdc, 0x7e, 0x44, 0x62, 0x51, + 0xf1, 0x30, 0x82, 0x90, 0x42, 0x4f, 0x3e, 0xda, 0x22, 0xca, 0xf4, 0x98, + 0x38, 0x46, 0xd0, 0x74, 0x2b, 0x71, 0x2d, 0x7d, 0x8e, 0x48, 0xae, 0xcb, + 0x19, 0xb6, 0x95, 0xf3, 0x53, 0xf6, 0x14, 0xff, 0xc, 0x56, 0xe1, 0x16, + 0x68, 0xb3, 0xc6, 0x59, 0xf5, 0x4e, 0x58, 0x7f, 0x42, 0x4a, 0xa4, 0xa4, + 0x7d, 0xc9, 0x1b, 0xd7, 0xa0, 0x5e, 0x1a, 0xec, 0xf9, 0xd7, 0xe3, 0x8b, + 0xbf, 0xde, 0x2, 0xab, 0x39, 0x6b, 0x8a, 0xf1, 0xe9, 0xc3, 0x4d, 0x3f, + 0x50, 0xd8, 0xa1, 0xed, 0x40, 0xb9, 0xb7, 0x42, 0xa7, 0x25, 0x78, 0xab, + 0x2, 0x3f, 0xd, 0x8e, 0x3c, 0x8a, 0x6b, 0xa7, 0xb2, 0x74, 0xf2, 0x0, + 0xd9, 0xaf, 0x8e, 0x1c, 0x8a, 0xd5, 0xd8, 0x2, 0x3a, 0xf3, 0x55, 0xbf, + 0x57, 0x31, 0x20, 0xf9, 0xa9, 0x2d, 0x62, 0x79, 0xac, 0xa0, 0xd4, 0xac, + 0x9b, 0x73, 0xc0, 0x6, 0x2d, 0x20, 0xa6, 0x49, 0x35, 0x3, 0x76, 0x81, + 0xec, 0x2f, 0xfc, 0x1e, 0x6d, 0x9d, 0x28, 0xfc, 0xe5, 0x27, 0x4d, 0x50, + 0x74, 0x41, 0xbf, 0x33, 0x51, 0x90, 0x41, 0x9, 0x6c, 0x8d, 0xe9, 0xff, + 0x48, 0xaf, 0x77, 0xe1, 0xfd, 0xe5, 0x45, 0x37, 0x45, 0x33, 0x6a, 0x8c, + 0xf3, 0x19, 0x31, 0x92, 0x4f, 0xbb, 0xd4, 0xc, 0x4c, 0x81, 0xd3, 0xab, + 0xde, 0x57, 0xb4, 0xc6, 0x31, 0xf5, 0xc6, 0x2c, 0xa, 0x7b, 0x98, 0xf7, + 0x13, 0x7d, 0x51, 0x77, 0x92, 0x71, 0xce, 0x1a, 0xb1, 0xf4, 0x44, 0xee, + 0xba, 0x8a, 0x66, 0x57, 0x16, 0x9a, 0x33, 0xca, 0xc3, 0xa4, 0x7a, 0xd8, + 0xcf, 0x3b, 0x89, 0x5e, 0x87, 0xa5, 0x52, 0x13, 0xa8, 0xc0, 0xab, 0xac, + 0xd2, 0xa7, 0xdd, 0xb3, 0xe8, 0x35, 0x69, 0xab, 0x44, 0xec, 0x4b, 0x1d, + 0x92, 0x36, 0x26, 0x5d, 0xdb, 0xa7, 0x32, 0x17, 0x56, 0x9a, 0x8f, 0x87, + 0xdd, 0x54, 0xba, 0x37, 0xd2, 0x4d, 0x2e, 0xfc, 0xc9, 0xc6, 0xb0, 0x34, + 0x20, 0x53, 0x71, 0xbb, 0x40, 0xc1, 0xd7, 0x6, 0x37, 0xc9, 0x26, 0x1b, + 0xd7, 0xb8, 0x69, 0x23, 0xab, 0xa3, 0xfc, 0xd1, 0xc, 0x0, 0x67, 0xb0, + 0xb3, 0x2c, 0xfc, 0xc2, 0xd4, 0x0, 0x16, 0xad, 0x65, 0x57, 0x4d, 0x4, + 0x5b, 0x9c, 0xa4, 0x80, 0xb2, 0xa, 0x92, 0xad, 0x60, 0x2f, 0x4e, 0xba, + 0x16, 0x36, 0x8f, 0xe7, 0x64, 0xf7, 0xfc, 0xa1, 0x68, 0xa4, 0x70, 0x26, + 0x67, 0x34, 0x6b, 0x1a, 0x9d, 0xf, 0x1d, 0xf4, 0x92, 0x9d, 0xc, 0x8b, + 0x3e, 0xdd, 0xcf, 0x5c, 0x52, 0x69, 0x98, 0x5c, 0x44, 0x47, 0x52, 0xc6, + 0x1d, 0xf5, 0xf9, 0xc3, 0x52, 0xd7, 0x88, 0x6d, 0x20, 0xf, 0x97, 0x28, + 0x36, 0x8d, 0x60, 0x18, 0x9e, 0x7a, 0xaf, 0xcc, 0x84, 0xc1, 0x50, 0x8f, + 0x7c, 0x59, 0x1f, 0x42, 0x20, 0x33, 0x59, 0x74, 0x20, 0x25, 0x67, 0xf8, + 0x17, 0x49, 0x6c, 0xf, 0x2e, 0x35, 0x6a, 0xd4, 0x53, 0x60, 0x80, 0x84, + 0x29, 0x85, 0x5c, 0x99, 0x87, 0x3, 0x22, 0xa5, 0xe5, 0xe5, 0x57, 0x4f, + 0xfc, 0x29, 0xcf, 0x4, 0x8b, 0x58, 0xe6, 0x21, 0x17, 0x9a, 0xc4, 0x13, + 0x22, 0x32, 0x46, 0x6f, 0x7f, 0xc4, 0xd8, 0x38, 0xc, 0xb1, 0xce, 0xe2, + 0xe0, 0x36, 0x4f, 0xcf, 0x6, 0xb, 0xa, 0xc1, 0x5e, 0x92, 0x3, 0x5c, + 0x73, 0x6, 0x54, 0x67, 0xe8, 0x52, 0x9f, 0xd8, 0x94, 0x48, 0x45, 0x65, + 0x54, 0xf, 0xa, 0x1d, 0x28, 0xd7, 0x72, 0x69, 0xbf, 0xe, 0xf1, 0xc8, + 0x50, 0x8e, 0x4a, 0xf1, 0x4e, 0x31, 0x92, 0xca, 0x48, 0x18, 0xc9, 0x53, + 0xfe, 0x92, 0xf5, 0xcf, 0x90, 0xe0, 0x66, 0x16, 0xf4, 0xc1, 0x33, 0x66, + 0xff, 0xf1, 0x3e, 0x33, 0x6f, 0xfe, 0xc5, 0xbf, 0x14, 0x70, 0xf3, 0xfc, + 0xc4, 0x2, 0xd3, 0x0, 0xd0, 0x78, 0x20, 0xbb, 0x71, 0x25, 0x7c, 0x47, + 0x33, 0xd7, 0xbb, 0x1e, 0xa8, 0x10, 0x5e, 0xe4, 0xcb, 0xcb, 0x5b, 0x2b, + 0x5f, 0xcb, 0x37, 0x87, 0x8f, 0xa3, 0x87, 0x37, 0x1, 0xa8, 0x8a, 0xf5, + 0x79, 0xae, 0xb0, 0x68, 0x80, 0x41, 0x1, 0x98, 0xf8, 0xbd, 0x7f, 0x59, + 0x65, 0xea, 0xc8, 0x92, 0xb5, 0x29, 0xa9, 0x38, 0xb0, 0x1a, 0x24, 0x36, + 0x48, 0xfc, 0xe9, 0x7e, 0xb2, 0x65, 0xb5, 0x18, 0x42, 0xc6, 0xe5, 0xa7, + 0xf, 0x5, 0x85, 0xff, 0x27, 0x52, 0xe7, 0x17, 0xf3, 0x27, 0xca, 0xf6, + 0xeb, 0x64, 0xf8, 0x52, 0x66, 0xa1, 0xe9, 0xc8, 0x7d, 0x6f, 0x1, 0x53, + 0x41, 0x64, 0xe9, 0x5, 0xd, 0x44, 0xf4, 0x81, 0x63, 0x25, 0xc6, 0xe8, + 0xb1, 0x83, 0x4f, 0x73, 0x5d, 0xbf, 0xa7, 0x27, 0x99, 0x7b, 0xbe, 0xa9, + 0x8d, 0x1, 0xe9, 0xd9, 0x3c, 0xb, 0x8d, 0xd5, 0x0, 0xf7, 0x49, 0xcf, + 0x14, 0x50, 0x4e, 0x26, 0x13, 0xd3, 0x80, 0x93, 0x6e, 0x3a, 0xde, 0x8d, + 0x1, 0xcd, 0x78, 0xf3, 0xe, 0x26, 0xe3, 0x1a, 0xe, 0xd6, 0xa7, 0xc0, + 0xac, 0xcb, 0x1d, 0x13, 0x6, 0xaf, 0xdb, 0x8f, 0x65, 0xd4, 0x5b, 0x19, + 0x48, 0xae, 0x6a, 0x63, 0x43, 0xa9, 0x86, 0x43, 0x93, 0x27, 0x1b, 0x41, + 0x68, 0x3a, 0xe9, 0xec, 0xdb, 0xe6, 0xa6, 0x6e, 0xd5, 0x6f, 0x30, 0xcc, + 0xda, 0x15, 0x2c, 0xb, 0x13, 0x6f, 0xf, 0xc7, 0xbd, 0x42, 0x6f, 0x3e, + 0x58, 0x95, 0xc6, 0x29, 0x30, 0x19, 0x9f, 0x50, 0x4f, 0x4c, 0x1, 0x48, + 0x69, 0xcb, 0x57, 0x14, 0xbc, 0xd0, 0x94, 0x9f, 0xe, 0x31, 0x16, 0xde, + 0x1e, 0x15, 0x18, 0x33, 0xc7, 0x8, 0x63, 0x9, 0xb2, 0x99, 0x31, 0x99, + 0xde, 0x7c, 0xaf, 0x15, 0x13, 0xf6, 0x32, 0x8f, 0x48, 0xe0, 0xd7, 0xc1, + 0xbe, 0x7e, 0x66, 0x98, 0xf3, 0x6, 0xe2, 0x99, 0x4, 0x9d, 0x23, 0x3f, + 0x44, 0xea, 0xbb, 0x2a, 0xf9, 0x33, 0xf0, 0xbc, 0xd, 0x23, 0x3e, 0x5e, + 0x89, 0xf4, 0x6, 0x1, 0xfe, 0x77, 0x2d, 0x9d, 0xd5, 0xfa, 0xc3, 0x39, + 0x3c, 0x41, 0x53, 0x40, 0xbb, 0x77, 0xc3, 0x56, 0x16, 0xd, 0x7c, 0x86, + 0x1c, 0x9, 0x2c, 0xad, 0x38, 0x59, 0x70, 0xdc, 0x38, 0x9e, 0x3b, 0x8a, + 0x34, 0xa5, 0x93, 0xcf, 0xc5, 0x34, 0x87, 0xe5, 0xca, 0x61, 0x96, 0x7d, + 0xa, 0x57, 0x8b, 0x8, 0x76, 0x8f, 0x4b, 0x8c, 0x96, 0xc8, 0xdf, 0x7e, + 0x5d, 0x51, 0x9a, 0x8c, 0x82, 0x8a, 0x8b, 0xa, 0x92, 0x87, 0xd5, 0x39, + 0xb, 0xac, 0xbf, 0x65, 0x62, 0x12, 0x71, 0x35, 0xda, 0x74, 0x2d, 0xdc, + 0xd0, 0x64, 0x25, 0xe9, 0x9f, 0xe9, 0x99, 0xf2, 0x46, 0xf9, 0x9d, 0xe6, + 0x4, 0xa3, 0x3e, 0x6c, 0x90, 0xd8, 0xa0, 0xc9, 0x11, 0xd1, 0xf4, 0x35, + 0xfc, 0x9e, 0xf, 0xb8, 0xca, 0x30, 0xd, 0xa4, 0x90, 0x61, 0x1e, 0x2a, + 0xca, 0x29, 0xbd, 0x72, 0x1f, 0xf6, 0x42, 0x14, 0x86, 0xbe, 0x69, 0x82, + 0x2b, 0xd5, 0xa4, 0x33, 0x62, 0x34, 0x3, 0x78, 0xa2, 0x92, 0x4b, 0x43, + 0x98, 0x84, 0xd3, 0x30, 0xba, 0x9, 0x22, 0xb2, 0xfd, 0xbd, 0x94, 0x63, + 0x1f, 0x38, 0x39, 0x0, 0x9e, 0x6b, 0xe8, 0x57, 0xb, 0xf5, 0x75, 0xec, + 0x73, 0xdf, 0x75, 0xba, 0x79, 0xe7, 0x4a, 0x88, 0xf0, 0xf0, 0xb0, 0x10, + 0xc3, 0xe3, 0x48, 0x4e, 0xc1, 0x2c, 0x9c, 0x5, 0x58, 0x7e, 0xd6, 0x2e, + 0xea, 0x99, 0xad, 0xa2, 0x6, 0xd6, 0xd7, 0xcc, 0x1c, 0x4c, 0x68, 0x64, + 0x59, 0xab, 0xcf, 0xdd, 0xc1, 0x1d, 0x70, 0xaf, 0x72, 0xe2, 0x61, 0x49, + 0xc7, 0x63, 0x40, 0x94, 0x1b, 0xae, 0xbd, 0xc0, 0xc0, 0xfd, 0x76, 0xa9, + 0x1b, 0x83, 0x91, 0x2, 0xe, 0xf2, 0xad, 0xd8, 0x0, 0x67, 0x1f, 0x6d, + 0xfc, 0xca, 0x77, 0x76, 0xe8, 0x59, 0xc, 0x51, 0x5d, 0x2d, 0xb1, 0x1e, + 0xb8, 0xc4, 0x0, 0x6a, 0xae, 0xd7, 0x3b, 0xe6, 0xb4, 0xe3, 0xb3, 0x59, + 0xf5, 0x5a, 0xde, 0x7d, 0x22, 0x45, 0x71, 0xe6, 0xdb, 0x23, 0x18, 0x35, + 0xaa, 0x0, 0x41, 0xfd, 0x56, 0xce, 0xd9, 0x2b, 0x5f, 0x2a, 0xa5, 0xa7, + 0xd5, 0x53, 0x34, 0x27, 0xbd, 0x26, 0x92, 0x2d, +}; +const uint8_t kAltGameImages1xF[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0xff, 0xe5, 0xb7, 0xbe, + 0x33, 0xdd, 0x84, 0x73, 0x82, 0xc, 0xa1, 0x47, 0x40, 0x9f, 0x40, 0x4c, + 0x48, 0x31, 0x55, 0x3a, 0xc9, 0x57, 0x30, 0x6a, 0x80, 0x88, 0xe8, 0x56, + 0xc4, 0x30, 0x4c, 0x85, 0x3a, 0x32, 0x5a, 0xd1, 0x44, 0xa4, 0x15, 0xa, + 0x2f, 0xac, 0xff, 0x9b, 0x25, 0x6c, 0x7, 0x68, 0x72, 0x79, 0x31, 0x4b, + 0xed, 0x2e, 0xdb, 0xf9, 0x82, 0xf4, 0xf, 0xf7, 0xf6, 0x7e, 0x64, 0xe7, + 0xa2, 0xef, 0xbd, 0x20, 0x71, 0x5b, 0xbc, 0xa7, 0xed, 0x70, 0x93, 0x1f, + 0xe9, 0x65, 0x1d, 0xb8, 0xd2, 0xfd, 0xc1, 0x4, 0x24, 0x56, 0xee, 0xf, + 0xca, 0x41, 0x77, 0xf7, 0x1c, 0x16, 0x39, 0x33, 0x66, 0x26, 0x81, 0x9c, + 0x3, 0xa2, 0x41, 0x8a, 0x71, 0x44, 0xb6, 0xc8, 0x2b, 0x31, 0xb6, 0x21, + 0xe2, 0x41, 0x92, 0xcd, 0x71, 0x98, 0x81, 0x75, 0x97, 0xdc, 0x0, 0x66, + 0x1c, 0xfc, 0x4a, 0xaa, 0x43, 0x75, 0x5d, 0x6c, 0xa7, 0xbe, 0x45, 0xa2, + 0x61, 0x47, 0x8b, 0x59, 0x4e, 0xe3, 0x0, 0x7, 0x3a, 0xb2, 0xc6, 0xdf, + 0x70, 0x28, 0xe6, 0xbd, 0x55, 0x20, 0x8b, 0x36, 0x72, 0xb9, 0x8a, 0x7d, + 0x6c, 0xbd, 0x73, 0x2d, 0x6, 0xe2, 0x9b, 0xc4, 0x3b, 0x1f, 0xdf, 0x1d, + 0xc8, 0x67, 0x87, 0x2c, 0x15, 0x22, 0xe1, 0xaf, 0x6f, 0x1a, 0x90, 0xb, + 0x25, 0x10, 0xd0, 0xdb, 0x5f, 0xd8, 0x69, 0x81, 0xf2, 0xf7, 0xf8, 0xca, + 0xfb, 0xa3, 0x76, 0x24, 0xc0, 0xd3, 0xc4, 0xfb, 0xa1, 0x94, 0xc2, 0x15, + 0x8d, 0x91, 0x6d, 0x3, 0x8e, 0x8d, 0xf, 0x46, 0xfd, 0x4a, 0x1, 0x95, + 0xf3, 0xf7, 0x6e, 0x45, 0x35, 0xb8, 0x3d, 0x4a, 0x19, 0xd3, 0x4a, 0x9b, + 0x6e, 0x81, 0x67, 0xe1, 0x5b, 0x25, 0xcd, 0x4e, 0x8e, 0x8d, 0x17, 0x1a, + 0x98, 0xb, 0xc2, 0xe6, 0x6e, 0x2a, 0x6b, 0x65, 0x30, 0x8a, 0x54, 0x21, + 0xd4, 0xbe, 0x1d, 0x2, 0x68, 0x7c, 0xee, 0x3c, 0x48, 0xba, 0xf7, 0xe7, + 0x46, 0xd6, 0x57, 0xf9, 0x1a, 0x63, 0x55, 0x70, 0x0, 0x87, 0x82, 0x42, + 0xc8, 0x5b, 0x7b, 0xf0, 0x88, 0x55, 0x4, 0xa6, 0x6d, 0x5c, 0x3a, 0x88, + 0xa0, 0xf4, 0xd3, 0x5f, 0xcd, 0x27, 0x8d, 0x2e, 0x1a, 0x76, 0xe8, 0x73, + 0x11, 0x32, 0xde, 0x4e, 0x44, 0x4e, 0x3e, 0x35, 0xfe, 0x8c, 0x90, 0x6, + 0x9c, 0x6b, 0x52, 0x73, 0xd0, 0x2a, 0x57, 0x77, 0x2c, 0xf1, 0xe6, 0x8a, + 0x7, 0x97, 0x9f, 0xae, 0x82, 0xa9, 0xfd, 0xe7, 0x25, 0x2f, 0xde, 0x2b, + 0xf1, 0x7e, 0x64, 0xcf, 0xd4, 0x1, 0xa5, 0x29, 0xe9, 0x2d, 0xde, 0x30, + 0x80, 0xe9, 0xdc, 0x9c, 0x20, 0x1d, 0x12, 0xd3, 0xa6, 0x74, 0x5d, 0xb0, + 0x25, 0x10, 0x7a, 0xa2, 0x65, 0x3, 0x8d, 0xfc, 0x9b, 0x2a, 0xfb, 0xa8, + 0xa0, 0x7e, 0x75, 0x10, 0x3f, 0xc2, 0x97, 0x4b, 0xd8, 0x19, 0x84, 0xd6, + 0xb1, 0x14, 0x39, 0xb8, 0x90, 0x29, 0x93, 0xaa, 0x3c, 0x62, 0x35, 0xa, + 0x11, 0x1a, 0x0, 0xf2, 0xf3, 0xb2, 0x4, 0xe, 0x6d, 0xa2, 0x14, 0x34, + 0xbd, 0x70, 0xb4, 0x8e, 0xa1, 0x92, 0x32, 0xc3, 0xa1, 0xdb, 0xdd, 0xac, + 0xa2, 0x4e, 0x35, 0x53, 0x16, 0xbb, 0xa7, 0x7b, 0x87, 0x7a, 0x37, 0x33, + 0xf6, 0x49, 0xa6, 0x36, 0xd8, 0xdd, 0x3f, 0x8, 0x5b, 0xe4, 0xcb, 0xe4, + 0xc7, 0x85, 0x8e, 0x17, 0x6d, 0xed, 0xe8, 0x8e, 0x6d, 0xa1, 0xb, 0x19, + 0x7c, 0x2c, 0xf9, 0xff, 0xb5, 0x77, 0x91, 0xa9, 0x59, 0x10, 0x16, 0x92, + 0x89, 0xcb, 0x8a, 0xb9, 0xa2, 0x28, 0x36, 0xf6, 0x36, 0x8b, 0xf1, 0xaa, + 0x5e, 0x3, 0x88, 0x76, 0xd9, 0x47, 0xa8, 0x67, 0x71, 0x7f, 0xeb, 0xd, + 0x84, 0x48, 0xa2, 0x90, 0x35, 0xe3, 0xbd, 0x8d, 0xe7, 0xeb, 0x7, 0xa6, + 0x2a, 0x9a, 0xe4, 0xb5, 0xab, 0x3e, 0xf2, 0x92, 0x84, 0x78, 0x42, 0x9, + 0xb0, 0xd7, 0x1c, 0x1c, 0x27, 0xd6, 0x78, 0x50, 0xad, 0x2a, 0xe8, 0x33, + 0x91, 0xa, 0xf9, 0x7c, 0xf, 0x5d, 0x75, 0x5c, 0xf8, 0x59, 0x7f, 0xa1, + 0x6f, 0x3d, 0xf9, 0xb8, 0x4b, 0x6a, 0x5, 0x54, 0xa0, 0x8a, 0xf1, 0xc, + 0x95, 0x25, 0x10, 0xb2, 0x1c, 0xfe, 0x36, 0x0, 0x83, 0xbe, 0x79, 0xd2, + 0x7e, 0xe9, 0x3f, 0x6c, 0x8a, 0xa7, 0x92, 0x86, 0xff, 0x56, 0xa9, 0x28, + 0x86, 0xf1, 0x94, 0xf1, 0xf7, 0x25, 0xd4, 0xe6, 0xd8, 0x71, 0xf8, 0xf5, + 0x7e, 0x20, 0x13, 0xb7, 0xa3, 0x38, 0xf0, 0x90, 0x17, 0x24, 0x45, 0xda, + 0x6e, 0xb4, 0xbd, 0x59, 0xba, 0x29, 0xba, 0x25, 0x78, 0xb8, 0xdd, 0x91, + 0x1c, 0x50, 0x8e, 0x5c, 0x2f, 0x57, 0x98, 0x5f, 0x61, 0xb0, 0x83, 0xeb, + 0x88, 0xe9, 0x42, 0x67, 0x51, 0x83, 0x9c, 0x4d, 0xd8, 0x5, 0x1d, 0x6c, + 0x7c, 0x83, 0xb7, 0xdb, 0x92, 0xa4, 0x3, 0xf8, 0x91, 0x90, 0xbb, 0xa5, + 0x64, 0xff, 0xb1, 0x1e, 0xf8, 0x46, 0x6f, 0x3b, 0xce, 0x9f, 0x70, 0x1d, + 0x5a, 0x64, 0x43, 0x8f, 0xcd, 0xcf, 0xa2, 0xa8, 0x38, 0x52, 0xcf, 0xf2, + 0x91, 0x1b, 0x32, 0xae, 0x32, 0xf7, 0x29, 0x36, 0x6f, 0xb3, 0x9d, 0x25, + 0x78, 0x3e, 0xbf, 0x41, 0x6b, 0xb4, 0x79, 0x5f, 0xf1, 0x92, 0x63, 0xd6, + 0xec, 0xbe, 0x4b, 0xef, 0x72, 0xca, 0x19, 0xca, 0x23, 0x98, 0xe2, 0xca, + 0x7d, 0x55, 0x87, 0xcc, 0xac, 0xb1, 0x33, 0xc4, 0xd6, 0x1e, 0xc6, 0xf8, + 0x82, 0x5, 0x23, 0x11, 0xe6, 0xf9, 0x85, 0x13, 0xa0, 0x81, 0xf1, 0x4, + 0x92, 0xbe, 0x43, 0xff, 0x3c, 0x96, 0xa0, 0x93, 0xe0, 0x72, 0xa, 0xee, + 0x4c, 0xf7, 0x25, 0x60, 0x74, 0xa2, 0xc7, 0xe8, 0xe4, 0xb9, 0x39, 0x6b, + 0xd5, 0xcb, 0x18, 0x71, 0x56, 0x53, 0xad, 0xe1, 0x7e, 0xa4, 0x33, 0x50, + 0x42, 0xd1, 0x2e, 0x12, 0x30, 0xd3, 0x32, 0xfd, 0xc8, 0x48, 0x86, 0x75, + 0xae, 0x37, 0xb2, 0x1b, 0x87, 0x3d, 0x9a, 0xd7, 0x10, 0xb0, 0xe1, 0x39, + 0xb9, 0xfb, 0xf5, 0xc6, 0x18, 0x9c, 0xb2, 0x6e, 0x6c, 0x64, 0x52, 0x5f, + 0x3e, 0xa7, 0x37, 0xb0, 0x9d, 0xc7, 0x85, 0x40, 0x71, 0xf3, 0xa6, 0xd6, + 0x80, 0x83, 0xa7, 0xc5, 0x46, 0x0, 0x9c, 0x88, 0x4e, 0x7d, 0x26, 0x87, + 0x7, 0x53, 0x1d, 0x27, 0x1f, 0xa5, 0x58, 0x6d, 0x73, 0xbb, 0x53, 0xa8, + 0xb1, 0x76, 0xc8, 0xe, 0xb7, 0x3a, 0x44, 0x87, 0x4a, 0x82, 0x1a, 0x25, + 0x2a, 0x96, 0x31, 0x16, 0xc8, 0xaf, 0x9a, 0x39, 0x9d, 0xf7, 0x2e, 0x79, + 0x70, 0x68, 0x2f, 0xdc, 0x6d, 0xe0, 0xb1, 0xee, 0x86, 0x2e, 0x24, 0xae, + 0x42, 0x95, 0xa3, 0xd8, 0xdf, 0xe0, 0xb6, 0xa3, 0x96, 0xf8, 0x4f, 0xfb, + 0x43, 0x9d, 0x50, 0x54, 0x41, 0x17, 0x75, 0xf4, 0xac, 0x8f, 0xcb, 0x9a, + 0x5b, 0x34, 0x75, 0x75, 0x50, 0xa7, 0x22, 0x4c, 0xae, 0x7, 0x46, 0xce, + 0x61, 0xa3, 0x53, 0xa7, 0xe9, 0x6b, 0x79, 0x32, 0xe0, 0xd1, 0xe8, 0xbf, + 0xf9, 0xce, 0x20, 0xae, 0xef, 0xc0, 0xf4, 0x4b, 0x95, 0x19, 0x13, 0xf0, + 0x89, 0x92, 0x12, 0xdc, 0x23, 0xa6, 0xb0, 0x2a, 0xc6, 0x47, 0xcc, 0xa9, + 0x4, 0x95, 0x69, 0x64, 0xb7, 0x21, 0x7f, 0xd, 0x4b, 0x60, 0x6d, 0x55, + 0xad, 0x11, 0xbe, 0xfe, 0x8a, 0x7e, 0x3, 0xa9, 0xc8, 0xc1, 0xbb, 0x12, + 0xd2, 0x3e, 0xfa, 0x8b, 0x53, 0xce, 0x54, 0x65, 0xfc, 0x79, 0xd3, 0x7b, + 0xdd, 0x6, 0xc3, 0x43, 0xc6, 0x5f, 0xe0, 0xe9, 0xfc, 0xca, 0xda, 0x1b, + 0xd6, 0xf4, 0xe4, 0x86, 0x1b, 0x6b, 0xb2, 0x8c, 0x16, 0x26, 0x33, 0xe6, + 0xca, 0xa4, 0x36, 0x80, 0x13, 0xf0, 0x90, 0xf3, 0x5, 0xff, 0x0, 0x61, + 0x13, 0x71, 0xab, 0x35, 0x83, 0xa2, 0x35, 0x24, 0x61, 0x91, 0xb0, 0x0, + 0x6f, 0x74, 0xb0, 0xeb, 0x46, 0xb3, 0x94, 0x46, 0x78, 0x55, 0x2e, 0x1d, + 0x6e, 0x1, 0x39, 0xea, 0x73, 0x8e, 0xcf, 0x97, 0x7b, 0xb3, 0xa9, 0x2f, + 0xc9, 0xfa, 0x74, 0x0, 0x35, 0x44, 0x58, 0x2f, 0x70, 0x3a, 0x1b, 0x44, + 0x56, 0x8b, 0xca, 0x34, 0x7f, 0x72, 0xd5, 0x77, 0x60, 0x7b, 0xce, 0x90, + 0x33, 0x7d, 0xd1, 0x39, 0x6d, 0x26, 0xa9, 0xc0, 0x51, 0x8c, 0x49, 0x24, + 0x16, 0xe6, 0xa5, 0x7d, 0x67, 0x40, 0x9a, 0xc9, 0xb4, 0x36, 0x3c, 0x6f, + 0x83, 0x65, 0xe2, 0x1a, 0xce, 0x95, 0xae, 0x58, 0xe0, 0x8a, 0x5d, 0xdc, + 0x70, 0xd2, 0xb9, 0x78, 0xb8, 0xc0, 0x12, 0xc1, 0xdd, 0x39, 0x52, 0x4c, + 0x8f, 0x19, 0xcf, 0x78, 0xf9, 0xcc, 0xc6, 0x44, 0xce, 0x95, 0x17, 0x8c, + 0x74, 0x7b, 0xfd, 0x73, 0x20, 0xe9, 0x3a, 0x5c, 0x51, 0x39, 0xc6, 0x99, + 0x1a, 0x57, 0x13, 0x37, 0xa7, 0x9a, 0x55, 0x20, 0x3f, 0x86, 0x27, 0x11, + 0xa5, 0x48, 0xc7, 0xee, 0xf3, 0xba, 0x1a, 0xc4, 0xce, 0x9, 0x14, 0xa8, + 0x90, 0x5, 0xe6, 0x96, 0xe4, 0x89, 0xc5, 0x42, 0x53, 0xdb, 0xce, 0xe5, + 0xf5, 0x36, 0x7c, 0x42, 0xb3, 0x1a, 0x43, 0xe, 0xcc, 0xbf, 0x98, 0x88, + 0x44, 0xc2, 0x4a, 0x2, 0xad, 0xc4, 0x46, 0xbc, 0x66, 0x8f, 0x18, 0x41, + 0xf9, 0xfa, 0x33, 0x86, 0x87, 0x4d, 0x94, 0x67, 0x79, 0x2a, 0x88, 0xbc, + 0xf6, 0x46, 0x7c, 0x8e, 0xb1, 0x35, 0xb1, 0xfd, 0xe7, 0xf, 0xec, 0x9b, + 0x90, 0xfe, 0x1e, 0x96, 0xf9, 0x91, 0xcc, 0x71, 0xca, 0xb8, 0x2d, 0x2b, + 0x9a, 0x5a, 0x19, 0xa9, 0x30, 0x3c, 0x64, 0xe, 0x84, 0xb4, 0x92, 0x7b, + 0xa6, 0x76, 0x35, 0xa4, 0xa, 0x39, 0x67, 0xdb, 0xf4, 0x1e, 0xda, 0x5, + 0xc8, 0x50, 0xff, 0xbc, 0xa0, 0x68, 0x66, 0x54, 0xf0, 0xcf, 0xb0, 0x39, + 0x77, 0x39, 0x23, 0xc8, 0x19, 0x27, 0xa, 0x2a, 0xf1, 0xd6, 0xe6, 0x55, + 0x38, 0x1e, 0xa8, 0xe3, 0x5e, 0x8f, 0xed, 0x90, 0xe1, 0x35, 0x1d, 0x8a, + 0x1, 0xac, 0xe7, 0x43, 0xc5, 0x43, 0xc7, 0x87, 0x5f, 0x35, 0xe0, 0x4c, + 0xfd, 0xef, 0x63, 0x1b, 0x70, 0xf2, 0x5c, 0x9f, 0x67, 0xe8, 0xe8, 0x1, + 0xe2, 0x89, 0x4c, 0x85, 0x2d, 0xf0, 0x91, 0x78, 0x8e, 0xe6, 0x7e, 0x9a, + 0x12, 0xa3, 0x99, 0x8, 0x3f, 0x93, 0x7f, 0x7e, 0x19, 0x95, 0x93, 0xf, + 0x43, 0x86, 0x1b, 0xe8, 0x74, 0xdf, 0xe6, 0x89, 0xa, 0xbd, 0x37, 0x82, + 0x5f, 0xa4, 0x84, 0xf1, 0x12, 0xc2, 0xbd, 0x45, 0x89, 0x17, 0xc9, 0x41, + 0x87, 0x77, 0x59, 0x1b, 0x72, 0x3f, 0x69, 0x90, 0xa0, 0x43, 0x8f, 0xad, + 0xc5, 0xa, 0x44, 0x33, 0x2b, 0xef, 0x7e, 0x81, 0x3a, 0x48, 0x43, 0x1a, + 0xf5, 0x3b, 0x2d, 0x15, 0x57, 0x41, 0x29, 0x5a, 0x25, 0x93, 0xb7, 0xdd, + 0x6, 0x9d, 0x96, 0xf7, 0x54, 0xd7, 0x9d, 0x1f, 0x96, 0x5f, 0xb4, 0xfb, + 0x43, 0x8f, 0xed, 0xbe, 0x82, 0x7d, 0xbb, 0x84, 0xb9, 0x58, 0x8e, 0x2d, + 0xc8, 0xff, 0x98, 0x2b, 0x8a, 0xe5, 0x2d, 0x38, 0xc7, 0x46, 0x63, 0x26, + 0x27, 0x70, 0x29, 0x99, 0x61, 0x5b, 0x72, 0xee, 0x7d, 0x3b, 0xd7, 0x56, + 0xfe, 0x96, 0xb0, 0xc0, 0x59, 0x91, 0x91, 0x43, 0xd6, 0x54, 0x7d, 0xce, + 0xf6, 0x76, 0x20, 0xb1, 0x24, 0x77, 0x66, 0x16, 0xd3, 0x1, 0xb4, 0x6b, + 0xdf, 0x3d, 0xc4, 0xab, 0xbf, 0xd1, 0x9d, 0xaa, 0x9f, 0xd0, 0x15, 0x2c, + 0x3b, 0x1d, 0x19, 0xa3, 0x8, 0x1f, 0xfb, 0xb6, 0xb4, 0x4c, 0x2e, 0x62, + 0x3f, 0x4e, 0x8, 0x55, 0x61, 0x17, 0xc, 0x60, 0xbe, 0xa, 0xf1, 0xf3, + 0xe7, 0xbd, 0x6a, 0x6d, 0xe2, 0x48, 0x74, 0x65, 0xd1, 0x3c, 0x39, 0x85, + 0xe3, 0xbc, 0x58, 0x59, 0x32, 0x49, 0x70, 0x8, 0xfd, 0x40, 0x76, 0xb7, + 0xdf, 0x61, 0xb7, 0x6e, 0xcc, 0x40, 0xc2, 0x2, 0xb0, 0x74, 0x59, 0x2d, + 0xf, 0xe, 0xd5, 0x56, 0x9b, 0x15, 0x1e, 0xcd, 0xdb, 0x27, 0xe5, 0x4c, + 0x3f, 0x86, 0x9a, 0x10, 0x47, 0x68, 0x7b, 0xa9, 0xca, 0xa2, 0x5d, 0xc1, + 0xd0, 0x26, 0x80, 0xb0, 0x14, 0x0, 0x33, 0xc4, 0xb7, 0x4d, 0x24, 0xcc, + 0x99, 0xe9, 0x62, 0xad, 0xc, 0xa5, 0x4e, 0x1f, 0x6c, 0x2f, 0xc7, 0xb0, + 0x62, 0xe7, 0xa6, 0xb9, 0x20, 0x44, 0x4a, 0xd8, 0xe3, 0x6, 0xbc, 0x26, + 0x84, 0xc9, 0x94, 0xfa, 0xc0, 0xa5, 0xc0, 0x3a, 0xaa, 0x58, 0x96, 0x56, + 0xe0, 0x6c, 0x4b, 0x75, 0xc3, 0x90, 0x46, 0xe0, 0xfd, 0x1d, 0xc5, 0x94, + 0xb7, 0xf0, 0x37, 0x5d, 0x42, 0x38, 0x20, 0x75, 0x90, 0x95, 0x6b, 0xff, + 0xcd, 0xf4, 0x56, 0xca, 0xf7, 0x26, 0xee, 0xaf, 0x75, 0x5f, 0x52, 0xdc, + 0x3b, 0xac, 0x98, 0x7, 0x72, 0xbb, 0xb9, 0xb3, 0x38, 0x21, 0xac, 0x2c, + 0xf9, 0xe9, 0xee, 0xbf, 0x93, 0x15, 0x75, 0xd6, 0xa7, 0xd, 0xae, 0x5e, + 0x22, 0x79, 0x8e, 0x84, 0x17, 0xb2, 0x49, 0x8, 0x2c, 0x13, 0x12, 0x72, + 0x70, 0x31, 0x4c, 0xba, 0x6c, 0x82, 0x10, 0x69, 0xf3, 0x43, 0x16, 0x47, + 0x96, 0xbd, 0xc6, 0x43, 0xbd, 0xe0, 0xf6, 0xa5, 0x2a, 0x64, 0x7a, 0xe0, + 0x4f, 0x91, 0xf2, 0x51, 0x42, 0x80, 0xba, 0x11, 0xf7, 0x61, 0x3f, 0xa9, + 0xb9, 0x62, 0x21, 0x78, 0xef, 0x99, 0x68, 0x2a, 0x82, 0xcf, 0x62, 0xb3, + 0xb7, 0xe9, 0x79, 0x69, 0x9c, 0x84, 0xcb, 0x3f, 0x59, 0x79, 0xc8, 0x17, + 0x5b, 0x7, 0x74, 0xf0, 0x8c, 0x65, 0x85, 0x3, 0x48, 0x7b, 0x80, 0x3c, + 0xcd, 0xe3, 0xf6, 0x50, 0xc1, 0x0, 0x3b, 0x14, 0xa, 0xfd, 0xcb, 0x46, + 0x99, 0x31, 0xb5, 0xa2, 0x72, 0x94, 0x25, 0x10, 0xd4, 0x7f, 0x2a, 0x2d, + 0x91, 0x47, 0xff, 0x55, 0xb3, 0x4f, 0x99, 0xfe, 0x9d, 0xbf, 0xb1, 0xf8, + 0xec, 0xac, 0x6d, 0xc, 0xe0, 0x94, 0x49, 0xe2, 0x1b, 0x73, 0xcc, 0x9a, + 0xc9, 0x95, 0xdb, 0x4b, 0x0, 0x86, 0xb9, 0x85, 0x42, 0xbc, 0xd5, 0xb8, + 0xc3, 0x2b, 0x39, 0xa2, 0x8, 0xc8, 0x2e, 0x1, 0xf0, 0x39, 0x6d, 0x7e, + 0xe1, 0x67, 0x42, 0xad, 0xc7, 0x3, 0x6f, 0x7a, 0x84, 0x5, 0xe0, 0x6a, + 0xbe, 0x24, 0x59, 0x87, 0x46, 0xcf, 0x1d, 0x3b, 0xa, 0x8c, 0xd9, 0x8e, + 0x60, 0xc1, 0x52, 0xb2, 0x18, 0xfc, 0x56, 0x1a, 0x20, 0x55, 0x8a, 0xa5, + 0x41, 0x2e, 0x4d, 0x4d, 0x0, 0x11, 0x93, 0xe3, 0x7f, 0xdc, 0x7f, 0x2d, + 0xde, 0xe3, 0x81, 0x1c, 0xf7, 0x11, 0xeb, 0x2a, 0xc3, 0x5f, 0x2c, 0xdb, + 0x45, 0xa3, 0x9a, 0x94, 0x6c, 0x5c, 0xd6, 0x38, 0xf, 0xe6, 0x91, 0x13, + 0xc4, 0xd7, 0xe2, 0x19, 0xfd, 0x90, 0x31, 0xc0, 0x9e, 0xeb, 0x2d, 0xfa, + 0x8c, 0xdc, 0xee, 0x27, 0xb9, 0x62, 0xb0, 0xa2, 0x4b, 0x4f, 0xb6, 0xd8, + 0x38, 0xe6, 0xb5, 0x39, 0xc0, 0xfa, 0x7, 0x62, 0xd2, 0xf0, 0x53, 0xa5, + 0x10, 0x9e, 0x5a, 0xe6, 0xdf, 0x89, 0x9f, 0x14, 0x1c, 0x1c, 0xd4, 0x59, + 0x85, 0x67, 0x90, 0xa2, 0xe6, 0xb0, 0xfa, 0x2d, 0x26, 0x7b, 0xcc, 0xab, + 0xde, 0xd5, 0xc7, 0x24, 0xfd, 0xfe, 0xa7, 0x5a, 0x77, 0x63, 0x1c, 0x8e, + 0xe8, 0x85, 0x83, 0x16, 0x77, 0x44, 0x34, 0xda, 0xd4, 0x98, 0x1d, 0x22, + 0xa5, 0xe6, 0x95, 0xe7, 0x7b, 0xd8, 0xfa, 0xde, 0xdf, 0x5, 0x27, 0x4b, + 0x29, 0x80, 0xbf, 0x5f, 0x87, 0x14, 0xe0, 0xa0, 0xa0, 0xe9, 0xc7, 0xc1, + 0xa1, 0x48, 0x22, 0x30, 0x37, 0xb3, 0x9, 0xd9, 0xa6, 0x18, 0x54, 0xe, + 0xb1, 0x3d, 0x48, 0xa4, 0x63, 0x70, 0x3e, 0xcb, 0x1d, 0x9b, 0x6f, 0x97, + 0xd2, 0xbf, 0x22, 0x93, 0xd0, 0x51, 0xdf, 0x9c, 0xf8, 0x47, 0x57, 0x74, + 0xc8, 0x40, 0x1b, 0x51, 0x3a, 0x14, 0x4b, 0x6e, 0xce, 0xd5, 0x38, 0x81, + 0x94, 0xda, 0x2f, 0x39, 0x84, 0x46, 0x8a, 0xf, 0x46, 0x6f, 0x7b, 0x5e, + 0x7d, 0x53, 0x30, 0x7, 0xea, 0xb, 0xaa, 0xd0, 0x7a, 0x98, 0xf4, 0xb8, + 0x51, 0x10, 0xca, 0x83, 0x72, 0x10, 0x86, 0x91, 0x81, 0x12, 0x53, 0x64, + 0x9a, 0xc8, 0xab, 0x9f, 0xd0, 0x82, 0x99, 0xb1, 0x43, 0x97, 0xc8, 0xa5, + 0x8, 0x7, 0xe, 0x23, 0xdb, 0xaf, 0x2d, 0x31, 0x3a, 0x87, 0xfa, 0x77, + 0x28, 0x49, 0x5e, 0x2c, 0x82, 0x40, 0x15, 0xa5, 0xb4, 0x46, 0x1, 0x93, + 0x5c, 0x19, 0x56, 0x67, 0x39, 0x23, 0x76, 0x67, 0x8d, 0xa9, 0xb4, 0x44, + 0x59, 0x1e, 0x5e, 0x93, 0x4c, 0x6e, 0xb0, 0x30, 0xd3, 0x87, 0x57, 0xfa, + 0xa5, 0xee, 0x42, 0xa0, 0xe5, 0x8d, 0x15, 0x8b, 0xd4, 0x12, 0x1c, 0x60, + 0xdf, 0xc, 0x27, 0xdf, 0x8f, 0x1, 0x7c, 0x31, 0xae, 0xd9, 0xd0, 0xad, + 0x3, 0x27, 0x32, 0x28, 0xbb, 0xd8, 0xb, 0x3b, 0xd, 0x3e, 0x9c, 0x3a, + 0x73, 0x8b, 0xd, 0x52, 0x8d, 0x4, 0x11, 0xe6, 0x65, 0x61, 0xcb, 0x9b, + 0x89, 0xe2, 0x1d, 0x43, 0xb3, 0xd5, 0x1, 0x1b, 0x0, 0xe0, 0xd1, 0x10, + 0x26, 0xf0, 0xda, 0x2, 0x56, 0xf4, 0x10, 0x39, 0xab, 0xc, 0x2f, 0x57, + 0x66, 0x54, 0x42, 0x72, 0x78, 0x45, 0x4c, 0x1c, +}; +const uint8_t* kAltGameImages1x[] = { + kAltGameImages1xA, kAltGameImages1xB, kAltGameImages1xC, + kAltGameImages1xD, kAltGameImages1xE, kAltGameImages1xF, +}; +constexpr int kAltGameImagesCount = base::size(kAltGameImages1x); const size_t kAltGameImages1xLength[] = { - 624, 2816, 2448, 3312, 1808, 2288, + base::size(kAltGameImages1xA), base::size(kAltGameImages1xB), + base::size(kAltGameImages1xC), base::size(kAltGameImages1xD), + base::size(kAltGameImages1xE), base::size(kAltGameImages1xF), }; -const char* kAltGameImages2x[] = { - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x9b, 0xf6, 0x93, 0x5e, - 0xf4, 0xc1, 0x6b, 0xa3, 0x71, 0x3b, 0xf3, 0x64, 0x61, 0xb5, 0xd1, 0x1d, - 0xb, 0xe5, 0xb6, 0x81, 0x61, 0x56, 0xd0, 0xa3, 0xd7, 0x75, 0xaa, 0x55, - 0x2e, 0x56, 0xf9, 0xf2, 0x1a, 0xe2, 0x93, 0x19, 0x47, 0xf4, 0x1d, 0x20, - 0xad, 0x83, 0x41, 0xa, 0x31, 0x36, 0x5b, 0x1e, 0x5e, 0xfe, 0x5e, 0x37, - 0x96, 0x3e, 0x1c, 0x34, 0xc4, 0xcd, 0x13, 0x3a, 0xc5, 0xc, 0xc5, 0x21, - 0xaf, 0x58, 0x9c, 0x5a, 0xc9, 0x90, 0xfc, 0x2b, 0x4b, 0xbc, 0x27, 0x96, - 0x57, 0xb5, 0x17, 0x99, 0x6, 0x48, 0x29, 0x67, 0x16, 0x28, 0xd6, 0xfd, - 0xb0, 0xe7, 0x59, 0x41, 0xa3, 0xbf, 0x5, 0xce, 0x26, 0xc4, 0x61, 0x2b, - 0xf1, 0xd, 0x2b, 0x39, 0x5a, 0x99, 0xb6, 0x62, 0x30, 0x4, 0xd2, 0x4d, - 0x68, 0x23, 0x9a, 0x5b, 0xd9, 0x7d, 0xe6, 0xeb, 0xba, 0x96, 0x91, 0xb6, - 0x3d, 0x9a, 0x54, 0xaa, 0xe7, 0x9c, 0xd3, 0x78, 0x11, 0x70, 0xd4, 0xdc, - 0xcd, 0x39, 0xbb, 0x98, 0x38, 0xb0, 0x82, 0x3c, 0x1, 0xed, 0x6c, 0xc2, - 0x82, 0x2, 0xc8, 0x6a, 0xcb, 0x26, 0x7a, 0x12, 0xd0, 0x10, 0xc3, 0xaa, - 0x95, 0x2f, 0x5c, 0x80, 0xc, 0xba, 0xaf, 0xf2, 0x75, 0x51, 0x95, 0xf9, - 0xba, 0xa7, 0x71, 0x2f, 0x38, 0x9a, 0x23, 0xfd, 0xf6, 0x7b, 0x1a, 0xcd, - 0xdb, 0xda, 0xf4, 0x4d, 0x54, 0xc5, 0x7, 0xfa, 0x53, 0x4f, 0x7e, 0x8, - 0x4f, 0x20, 0x69, 0x20, 0x8d, 0xc8, 0xb6, 0x1a, 0x80, 0x79, 0x5e, 0x86, - 0x8b, 0xb, 0xc0, 0x2a, 0x40, 0x58, 0x2d, 0x6b, 0x31, 0x5d, 0xee, 0x24, - 0x9, 0xa1, 0x14, 0x9c, 0x40, 0x44, 0x36, 0x3a, 0x62, 0x7, 0xe4, 0x2f, - 0x38, 0xa2, 0x3, 0x72, 0x95, 0xf1, 0xa3, 0x86, 0x6d, 0x56, 0x4c, 0x80, - 0xf6, 0xa4, 0x4d, 0xb6, 0x1c, 0xad, 0x7c, 0x24, 0x2f, 0x57, 0x12, 0xf, - 0x26, 0x18, 0xef, 0xa5, 0xa2, 0xe8, 0x5e, 0xc5, 0x81, 0x1f, 0x29, 0x85, - 0x5a, 0x3c, 0x39, 0x2c, 0x4d, 0x23, 0x5b, 0x92, 0xf5, 0xe4, 0xf3, 0xc6, - 0x56, 0xde, 0xc0, 0x6b, 0x54, 0x18, 0x8b, 0xa8, 0x45, 0x5, 0xde, 0xf8, - 0x60, 0xa6, 0x75, 0x30, 0x5d, 0x3b, 0x7b, 0x99, 0xfc, 0x61, 0xd9, 0xe7, - 0xc4, 0x13, 0xd8, 0x54, 0xde, 0x1c, 0xe4, 0xf1, 0x5c, 0xf6, 0x67, 0x51, - 0x33, 0x79, 0xcd, 0x10, 0xaa, 0xc7, 0xb4, 0xdf, 0xa3, 0x4a, 0x3b, 0xc1, - 0x5e, 0x14, 0x6c, 0xca, 0x4c, 0xbe, 0xef, 0x4b, 0x70, 0x6, 0xbb, 0xc1, - 0xc8, 0x4, 0xf9, 0x1d, 0x93, 0xb5, 0x8c, 0x0, 0xda, 0x73, 0xc7, 0x7a, - 0xc8, 0xdc, 0xec, 0x92, 0xe0, 0x94, 0x41, 0x1a, 0xab, 0xce, 0x60, 0x42, - 0x8e, 0x7c, 0xb6, 0x93, 0xdb, 0xc2, 0xe5, 0x50, 0xc1, 0x52, 0x46, 0x2d, - 0xf6, 0xa2, 0x22, 0x26, 0x2d, 0xcd, 0x4b, 0x1f, 0x86, 0x22, 0xe5, 0x95, - 0x1, 0x57, 0xe4, 0x1f, 0x3f, 0xd2, 0xb3, 0xcb, 0xf0, 0x44, 0x9e, 0x5a, - 0xbb, 0xc7, 0x27, 0x88, 0x92, 0x81, 0x7d, 0x50, 0xfc, 0xf2, 0x18, 0x21, - 0x66, 0x2c, 0x9b, 0xb5, 0x42, 0x8a, 0x3, 0xf9, 0x6b, 0x77, 0x6b, 0xc8, - 0x8a, 0xf8, 0xa, 0x51, 0xa8, 0xbc, 0x12, 0xe, 0x6b, 0xbc, 0x57, 0xa3, - 0x49, 0xe2, 0xee, 0x2e, 0xe5, 0x5e, 0x12, 0xfa, 0xe1, 0x59, 0xee, 0x8b, - 0x2, 0xad, 0xac, 0xd9, 0x3b, 0x2e, 0xf6, 0x16, 0xee, 0x98, 0x8b, 0x1d, - 0xd6, 0x14, 0x6b, 0x61, 0x60, 0x88, 0x96, 0x89, 0x2b, 0xaf, 0x23, 0xde, - 0xb9, 0xba, 0x6b, 0xc4, 0x82, 0xe5, 0x24, 0x9, 0x3d, 0x32, 0x65, 0x8e, - 0x68, 0x8d, 0xec, 0x94, 0x3d, 0x5, 0xc1, 0xbd, 0x87, 0x87, 0xaa, 0x53, - 0x27, 0xfe, 0xf9, 0x12, 0x74, 0xc7, 0xaf, 0x42, 0x7d, 0x1b, 0x23, 0xbc, - 0x41, 0xa1, 0xba, 0xa6, 0x1f, 0x62, 0x49, 0x32, 0x90, 0x38, 0xa8, 0xec, - 0x83, 0xa4, 0xd1, 0x34, 0x2, 0x63, 0xb1, 0xaf, 0xd9, 0x78, 0x55, 0x90, - 0x3d, 0x1, 0x74, 0xf1, 0x2a, 0x37, 0x2f, 0x46, 0x16, 0xb9, 0xa6, 0x4f, - 0xf6, 0x37, 0xc6, 0xe5, 0x7e, 0x50, 0x4e, 0x49, 0x31, 0x31, 0x61, 0x1f, - 0x8a, 0xe7, 0xf1, 0x7a, 0xd6, 0xd3, 0x4a, 0xbf, 0xc1, 0xd9, 0x7b, 0x68, - 0xa6, 0x9f, 0xd3, 0x69, 0xec, 0x9d, 0xe5, 0x9d, 0xe9, 0x35, 0xdc, 0x55, - 0x21, 0xe3, 0xd2, 0x63, 0x71, 0xf, 0xb6, 0xbd, 0x9c, 0x47, 0x46, 0x61, - 0x1f, 0xf0, 0x44, 0x77, 0x7d, 0xfa, 0xf9, 0x32, 0x5f, 0x71, 0x21, 0xdb, - 0x55, 0x41, 0x64, 0xe2, 0xe6, 0xc4, 0x5, 0xbd, 0x76, 0xfc, 0x44, 0x6e, - 0xef, 0xd7, 0x5, 0x61, 0x94, 0x58, 0xec, 0xcc, 0xdc, 0xd3, 0x1c, 0x4f, - 0x38, 0xa1, 0x28, 0xc, 0xf2, 0x18, 0xa8, 0xf6, 0xb0, 0x4f, 0x29, 0x10, - 0x4b, 0x52, 0x76, 0xb1, 0xc1, 0x6b, 0xb9, 0xe2, 0xd1, 0xd7, 0x4e, 0x82, - 0x48, 0xb6, 0xc8, 0xb3, 0x42, 0x2f, 0xdb, 0xd3, 0x7, 0x6, 0x60, 0xb9, - 0x48, 0x55, 0xdc, 0x27, 0xa3, 0x9d, 0xfa, 0xc2, 0x43, 0xfc, 0xd2, 0xfd, - 0x60, 0x65, 0xd5, 0x50, 0xc, 0x6c, 0x3c, 0x71, 0xdd, 0x19, 0x97, 0xba, - 0xc3, 0x5, 0x2b, 0xcd, 0xd2, 0xf1, 0x0, 0x35, 0x5a, 0x29, 0xc6, 0xf0, - 0x93, 0xd9, 0x2a, 0xf0, 0x22, 0x9f, 0xc0, 0x33, 0x9b, 0xd0, 0x46, 0xae, - 0x1d, 0xe9, 0x65, 0x3d, 0x66, 0xf0, 0xc0, 0xcc, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, - 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, - 0x44, 0x59, 0x55, 0xf7, 0x6, 0x26, 0x3c, 0x46, 0xcf, 0x87, 0xd, 0xfa, - 0xc, 0x4, 0xb8, 0xd1, 0x9a, 0x96, 0x2, 0x3f, 0xa3, 0x31, 0xdd, 0x26, - 0xc5, 0xb4, 0x97, 0xd9, 0xf6, 0x1a, 0xc8, 0xe9, 0x38, 0x9f, 0x52, 0xc3, - 0xb7, 0x9b, 0x4a, 0x4a, 0xc1, 0x8c, 0x27, 0x79, 0x5b, 0xc, 0x95, 0xe6, - 0xa0, 0x4b, 0xa7, 0x70, 0x6d, 0x54, 0xdb, 0x20, 0x56, 0x5f, 0xa4, 0x13, - 0x4d, 0x97, 0xff, 0x3d, 0xf4, 0x48, 0x3e, 0x74, 0x41, 0x9a, 0x6c, 0x72, - 0x4c, 0xc1, 0x89, 0xcd, 0xf, 0xdb, 0x7a, 0x47, 0xf, 0x2d, 0x3d, 0xaf, - 0xff, 0x20, 0x6, 0x55, 0x78, 0x3b, 0xe3, 0xbc, 0xd1, 0x56, 0xd4, 0xbc, - 0x0, 0x4a, 0x9b, 0x48, 0x7b, 0xbd, 0x18, 0x10, 0x6e, 0xe0, 0xbb, 0xcf, - 0xe7, 0xb0, 0x82, 0xd5, 0x50, 0x6c, 0x90, 0xdd, 0x32, 0xc6, 0xd, 0xc2, - 0x64, 0x13, 0xae, 0xa1, 0x74, 0xde, 0x23, 0x78, 0xdd, 0xd, 0x4f, 0x8b, - 0xe4, 0xa3, 0x31, 0x95, 0xde, 0x86, 0xd3, 0x9a, 0x73, 0x3d, 0x44, 0x23, - 0xaa, 0xbb, 0xf9, 0x34, 0x8f, 0xba, 0x53, 0x50, 0xa4, 0x50, 0x8b, 0x51, - 0x63, 0xe3, 0xd0, 0x1e, 0x9c, 0x1c, 0x93, 0x12, 0x67, 0xe0, 0xf1, 0xf9, - 0x57, 0x26, 0x97, 0x16, 0x84, 0xe5, 0x14, 0xd1, 0x18, 0x65, 0xb0, 0x2c, - 0xab, 0x80, 0xd7, 0x76, 0xd3, 0xed, 0x15, 0xe3, 0xc5, 0xbc, 0x0, 0xf5, - 0x48, 0x63, 0x25, 0xb3, 0x23, 0x30, 0x17, 0x2a, 0x1f, 0x13, 0x43, 0x1a, - 0x6f, 0x52, 0xb7, 0x49, 0x47, 0x1b, 0xaf, 0x41, 0xeb, 0x6e, 0x8e, 0x4c, - 0xe6, 0x20, 0xfb, 0x63, 0xd4, 0x98, 0xe, 0xff, 0xb9, 0xbb, 0x91, 0x17, - 0x10, 0x9f, 0x7f, 0xb2, 0xf0, 0xae, 0x57, 0xba, 0x96, 0x1, 0xbb, 0x4b, - 0x7e, 0xd7, 0xc4, 0xc, 0xdb, 0xa9, 0x36, 0x23, 0x6b, 0xaa, 0x3d, 0x8b, - 0x11, 0x7a, 0x17, 0xe4, 0x52, 0x84, 0xc4, 0x5f, 0x95, 0xf7, 0xc5, 0x9, - 0x9b, 0xb, 0xc2, 0x8c, 0x4, 0xd3, 0x32, 0xb7, 0xa9, 0x86, 0x1e, 0x19, - 0xf0, 0xf3, 0xb9, 0x9b, 0xee, 0x17, 0x9f, 0xa, 0x35, 0xd6, 0x5e, 0xb1, - 0x72, 0x92, 0xf, 0x7, 0x50, 0x41, 0x9a, 0xef, 0x35, 0xca, 0xbf, 0xd4, - 0x3e, 0x90, 0x83, 0xfa, 0xa7, 0x52, 0x18, 0x7b, 0xb4, 0x8a, 0x1d, 0x62, - 0x8b, 0xfd, 0x36, 0xda, 0x20, 0x40, 0x33, 0x14, 0x50, 0xb2, 0xfd, 0xc8, - 0xc6, 0x76, 0x82, 0x81, 0xda, 0xb6, 0xd7, 0x47, 0xda, 0x4b, 0xc9, 0xac, - 0x13, 0x87, 0xa2, 0x53, 0xc, 0xbb, 0x32, 0x1, 0xba, 0x24, 0xcb, 0x76, - 0xea, 0xa0, 0x9c, 0x70, 0xd8, 0x3b, 0x52, 0x75, 0xdc, 0x5, 0x40, 0x0, - 0xa2, 0xe3, 0x4c, 0xc5, 0x5f, 0x64, 0xaa, 0xfa, 0x64, 0x9, 0x58, 0x4c, - 0x4a, 0x35, 0xf0, 0x99, 0xd, 0x44, 0xe9, 0x9b, 0x32, 0x9b, 0xa0, 0x84, - 0x81, 0x2, 0xef, 0x65, 0x3b, 0x6b, 0x7f, 0x1b, 0x89, 0x59, 0x9a, 0xd5, - 0x90, 0x44, 0xb9, 0xe7, 0x55, 0xd2, 0x3d, 0x16, 0x68, 0xdd, 0x38, 0xf0, - 0xb2, 0xc6, 0x3c, 0x49, 0xe6, 0xf8, 0x7f, 0xc5, 0x87, 0x67, 0x1c, 0x36, - 0x87, 0xf7, 0x4e, 0xa5, 0x6f, 0x2, 0xab, 0x44, 0xf9, 0xc, 0xee, 0x7d, - 0x82, 0xe7, 0xbf, 0xff, 0x69, 0xf8, 0xa6, 0xbb, 0xf6, 0x91, 0x11, 0x40, - 0x68, 0xc9, 0x94, 0x7b, 0xd4, 0x31, 0xf2, 0x70, 0x49, 0x43, 0x55, 0xa9, - 0xac, 0xce, 0x7d, 0xbf, 0xed, 0x2, 0x9b, 0x57, 0x4c, 0xc, 0x1f, 0xcb, - 0xc5, 0xc7, 0xa3, 0xc0, 0xe7, 0xd8, 0xf4, 0x21, 0xe6, 0xa4, 0x95, 0x27, - 0x1a, 0x52, 0xe5, 0xd7, 0xf, 0x45, 0x2d, 0xd2, 0x85, 0x3c, 0xbb, 0xa0, - 0x3, 0xab, 0x7c, 0xfb, 0xc8, 0x4c, 0x42, 0x2a, 0x68, 0x4e, 0xc9, 0xdc, - 0xbd, 0x11, 0xf2, 0xe2, 0xf1, 0x5b, 0x9, 0x81, 0x28, 0xe3, 0xb0, 0x4a, - 0x38, 0xbc, 0xb3, 0x14, 0xcc, 0x76, 0x24, 0x44, 0x99, 0x4a, 0x8f, 0x8f, - 0x89, 0x54, 0xc, 0x7b, 0xdd, 0x2e, 0xbf, 0xc7, 0xa4, 0x44, 0xec, 0x22, - 0x8c, 0xa4, 0x3b, 0xce, 0x94, 0x64, 0xc6, 0x8e, 0xde, 0xa6, 0x6c, 0x67, - 0xd2, 0x3d, 0xc9, 0xf3, 0x41, 0x58, 0xf7, 0x3f, 0x15, 0xa2, 0xdb, 0x97, - 0xa8, 0x9, 0x60, 0x28, 0x62, 0xbd, 0xe0, 0xa9, 0x4f, 0x9b, 0x66, 0x30, - 0x51, 0x6e, 0x84, 0xf2, 0xdd, 0xab, 0x5a, 0x48, 0x1b, 0x7, 0x87, 0x2f, - 0xfc, 0x3c, 0x6b, 0x49, 0x34, 0x71, 0xd8, 0x32, 0x2a, 0x20, 0x38, 0xdb, - 0xb7, 0x20, 0xba, 0x87, 0xcd, 0x1a, 0x19, 0xf6, 0x7b, 0x91, 0x70, 0x3d, - 0x3a, 0xff, 0xd3, 0xa4, 0x7f, 0x32, 0x62, 0xad, 0x2c, 0x29, 0xae, 0x6, - 0xe5, 0x90, 0x88, 0x76, 0x92, 0x64, 0x57, 0xe6, 0x37, 0x68, 0x2a, 0xb9, - 0x12, 0x4c, 0xd6, 0xc, 0x4, 0xd9, 0x9f, 0x68, 0xac, 0x32, 0x1a, 0x33, - 0xbc, 0x83, 0x32, 0x45, 0xd3, 0x2d, 0x16, 0x8e, 0xaa, 0xcc, 0x85, 0x8c, - 0xd3, 0xda, 0xa1, 0x82, 0xfa, 0x8d, 0x0, 0x1b, 0xad, 0x83, 0xd1, 0xa2, - 0xb9, 0x4f, 0x41, 0x1e, 0xe3, 0x1f, 0x1a, 0x18, 0x9a, 0x91, 0x2c, 0x52, - 0xa5, 0x14, 0xc4, 0xaa, 0x33, 0x20, 0xfc, 0xd5, 0x2b, 0xe0, 0x38, 0x21, - 0x9d, 0xeb, 0x21, 0x16, 0x34, 0xd5, 0x4d, 0x84, 0x95, 0x46, 0x3a, 0xa3, - 0xe8, 0xf5, 0xe6, 0xde, 0x9e, 0x88, 0x1f, 0xdd, 0x25, 0x6b, 0x30, 0x2f, - 0x32, 0xe3, 0x60, 0x1a, 0xc6, 0x6c, 0xe6, 0x63, 0x5c, 0xa7, 0x1d, 0xa2, - 0x43, 0x6d, 0x0, 0x1b, 0x64, 0xce, 0xb3, 0x38, 0xe, 0xae, 0x5b, 0x2b, - 0x1, 0xa7, 0x4c, 0x8b, 0x9e, 0xbc, 0x5a, 0x8a, 0x46, 0x4, 0xa4, 0xb2, - 0xfb, 0x12, 0x61, 0xe5, 0x84, 0x63, 0x1e, 0x13, 0x9c, 0xc7, 0x19, 0x37, - 0x9, 0xb9, 0x6e, 0xcf, 0x64, 0xed, 0x41, 0xb1, 0x8, 0x82, 0x31, 0xc9, - 0xda, 0x2, 0x80, 0x67, 0xf9, 0x85, 0xcf, 0x9f, 0x26, 0xae, 0xfb, 0x3b, - 0x2f, 0x80, 0x38, 0x33, 0x22, 0x34, 0x4, 0xec, 0x5b, 0xc8, 0x55, 0xd6, - 0xa6, 0xef, 0x1d, 0x68, 0x39, 0x70, 0xc4, 0xdc, 0x7e, 0xba, 0x33, 0x9f, - 0xd1, 0xb2, 0xd5, 0x56, 0x95, 0xde, 0x38, 0xd5, 0x26, 0x5d, 0x23, 0xd8, - 0xca, 0xd, 0xe2, 0xdc, 0x3c, 0x61, 0xcb, 0x1d, 0x51, 0xfc, 0x5e, 0x42, - 0x97, 0x83, 0x72, 0xc5, 0xa5, 0x6c, 0xb6, 0x90, 0xa3, 0xe7, 0xda, 0xb2, - 0x8, 0xfc, 0x7e, 0x41, 0x3b, 0xa2, 0x4a, 0xa9, 0x1b, 0x6b, 0x42, 0x1, - 0x5, 0x5b, 0x86, 0xa5, 0x9f, 0x40, 0x4f, 0x87, 0x2e, 0x5f, 0xda, 0x39, - 0x9a, 0xdc, 0x67, 0xff, 0xf8, 0x9d, 0xcb, 0x49, 0xd4, 0x9, 0x41, 0x2d, - 0xf7, 0x2e, 0x44, 0xe, 0x93, 0x96, 0xf2, 0x76, 0xb5, 0xa5, 0x61, 0x3a, - 0x51, 0x9a, 0xa9, 0xb, 0xc2, 0xc1, 0x7d, 0x3d, 0xfb, 0xf4, 0xd9, 0x5f, - 0xbe, 0xa, 0xa2, 0x95, 0xaf, 0x42, 0xf6, 0x5e, 0xc4, 0x1d, 0x34, 0x26, - 0x1, 0x37, 0xbc, 0xa0, 0x4e, 0x4c, 0x1a, 0xd4, 0x10, 0x5f, 0x5a, 0xe4, - 0x69, 0x3e, 0x49, 0xdc, 0x57, 0x56, 0x7e, 0x51, 0x1b, 0x86, 0x6e, 0x87, - 0x4e, 0x40, 0xa4, 0x94, 0x5, 0xbc, 0xf0, 0xaa, 0xf0, 0xef, 0x2d, 0x39, - 0xf1, 0x42, 0x73, 0x4, 0xe4, 0x17, 0x23, 0xec, 0xdd, 0x84, 0x3, 0x2, - 0x4, 0x6b, 0x8c, 0x5a, 0x78, 0xbe, 0x38, 0x61, 0x53, 0x17, 0xc3, 0xcc, - 0xb9, 0x68, 0xc9, 0x1d, 0x6d, 0x37, 0xfb, 0xe3, 0xce, 0xa7, 0x1, 0xb7, - 0xe4, 0x2d, 0xc1, 0xcc, 0xae, 0xb4, 0xf9, 0xfb, 0x53, 0x19, 0x6f, 0xdd, - 0x30, 0xed, 0x54, 0x74, 0xc2, 0x70, 0xec, 0xf8, 0xde, 0xd3, 0x5e, 0x22, - 0xe5, 0xab, 0xc2, 0x19, 0xec, 0x7, 0xcf, 0x28, 0x8, 0xdb, 0xe0, 0x69, - 0x82, 0x58, 0xf6, 0x8d, 0xe9, 0xe5, 0xab, 0x50, 0xa0, 0x63, 0xd, 0x8a, - 0x23, 0x7c, 0xc6, 0x46, 0x4a, 0x18, 0x1e, 0xad, 0x76, 0xfb, 0xb7, 0xc5, - 0x20, 0xa0, 0xa1, 0xfb, 0xa0, 0x11, 0x4a, 0xdf, 0xd2, 0xb3, 0x4b, 0xc2, - 0xce, 0xa9, 0x34, 0xdc, 0xaa, 0x3, 0xcc, 0x45, 0x3a, 0xe9, 0xa5, 0x9a, - 0xc3, 0xaf, 0xc6, 0xb7, 0x7e, 0x73, 0x4c, 0x0, 0x3e, 0x26, 0x35, 0x50, - 0x6a, 0x1f, 0x24, 0x6e, 0xd2, 0x1a, 0x50, 0xb3, 0xa6, 0x4c, 0xfe, 0xd2, - 0xc7, 0x9d, 0xa4, 0xc, 0x5d, 0xc4, 0x36, 0xf6, 0xe9, 0xc5, 0xfe, 0x4d, - 0x87, 0xe3, 0x74, 0xb5, 0xd6, 0x96, 0x6f, 0x6, 0x2c, 0x34, 0x2d, 0x4, - 0xc8, 0xfe, 0xbb, 0x9, 0xa7, 0x32, 0xd3, 0x2d, 0xfd, 0xb1, 0x9, 0xe6, - 0x64, 0x47, 0x5e, 0x5d, 0x9e, 0xe, 0xaf, 0x2, 0x9d, 0xbc, 0x20, 0x21, - 0xa1, 0x75, 0x67, 0x4e, 0x19, 0x7a, 0xa, 0x3b, 0x65, 0xe1, 0xec, 0x6e, - 0xbe, 0xc3, 0x1d, 0x77, 0x3b, 0x97, 0xb5, 0xf1, 0x4a, 0xaf, 0x9e, 0x2e, - 0xdb, 0xb, 0x49, 0xac, 0x11, 0xda, 0x60, 0x83, 0x23, 0xb7, 0xd9, 0x92, - 0x8f, 0x6c, 0x6f, 0xaf, 0xea, 0x18, 0xb0, 0x53, 0x11, 0x84, 0x14, 0x31, - 0x78, 0x6d, 0x9, 0x25, 0x4c, 0x90, 0x8e, 0xe4, 0x7b, 0x79, 0x1f, 0x17, - 0x64, 0x40, 0x78, 0x8e, 0x7f, 0x27, 0x5b, 0x10, 0x75, 0x13, 0xce, 0xd2, - 0x5b, 0xe2, 0xca, 0x16, 0x23, 0xee, 0x92, 0xd6, 0xea, 0x7e, 0xde, 0x68, - 0x98, 0x73, 0x3f, 0x1c, 0x9c, 0x1e, 0x67, 0xfb, 0x92, 0x10, 0x51, 0xe1, - 0x97, 0x15, 0x5d, 0xbb, 0x26, 0x7f, 0xee, 0xb, 0x7d, 0xf6, 0xc6, 0x81, - 0x23, 0xd5, 0x55, 0xae, 0x86, 0x60, 0x5d, 0x8c, 0x0, 0x55, 0x1e, 0xb7, - 0x4b, 0x1c, 0xc5, 0x3e, 0x5b, 0x1f, 0x89, 0x47, 0x17, 0x28, 0x2b, 0x46, - 0x2b, 0xc3, 0x21, 0xdf, 0x1c, 0x20, 0x22, 0x49, 0xea, 0xe8, 0xb5, 0xff, - 0xfd, 0xd0, 0x91, 0x27, 0xe0, 0x15, 0x3f, 0x15, 0xca, 0xd4, 0xe1, 0x28, - 0xa0, 0x7a, 0xf1, 0xb0, 0xa5, 0x6a, 0x62, 0x90, 0x4e, 0xdc, 0x9d, 0xe, - 0x94, 0x31, 0x5f, 0x8f, 0xbf, 0x15, 0xa5, 0xec, 0x9f, 0x66, 0x6, 0xf1, - 0xe8, 0x97, 0x8f, 0xe1, 0xc6, 0xd3, 0xea, 0xc9, 0xa5, 0x50, 0xe1, 0xdc, - 0x91, 0x18, 0xfb, 0xf1, 0x48, 0xe4, 0x91, 0x1a, 0xc, 0xeb, 0xf4, 0xd, - 0xc3, 0x20, 0x3a, 0xac, 0xf7, 0x4b, 0x4c, 0xa2, 0xab, 0x4a, 0x4a, 0x92, - 0xe3, 0x57, 0x94, 0xf7, 0x92, 0x90, 0xb2, 0xa2, 0xd1, 0x9d, 0xcc, 0x4e, - 0x6a, 0x28, 0x83, 0xd3, 0xb8, 0x40, 0x38, 0x1b, 0x4f, 0x8a, 0x25, 0x95, - 0x2d, 0xde, 0xca, 0xc0, 0xc6, 0x15, 0xe7, 0xc9, 0x7f, 0x89, 0xbf, 0x57, - 0xc3, 0x3a, 0x9c, 0xd9, 0x88, 0x97, 0x58, 0xa7, 0xe5, 0x2d, 0xec, 0x47, - 0x87, 0x9, 0x88, 0x21, 0x87, 0x39, 0xc7, 0xbe, 0x40, 0xa, 0x2b, 0x17, - 0x8b, 0x82, 0x4f, 0xa3, 0x31, 0x5, 0x63, 0xfa, 0x36, 0x83, 0x33, 0x28, - 0x51, 0x38, 0xfd, 0xd7, 0xa3, 0x3b, 0xb3, 0xe8, 0x27, 0x3, 0xda, 0xf8, - 0x35, 0x24, 0x78, 0xcd, 0x20, 0xf6, 0xcd, 0x34, 0xca, 0xf2, 0x66, 0xa3, - 0xaf, 0xd0, 0x29, 0xab, 0xf0, 0x76, 0x5e, 0x23, 0x35, 0xf7, 0x91, 0xa6, - 0x13, 0x2a, 0x91, 0xe8, 0x56, 0x38, 0x1d, 0x8a, 0x2c, 0xad, 0xe9, 0x6f, - 0x50, 0x7, 0x83, 0x64, 0xd5, 0x40, 0xd8, 0x9, 0x2c, 0x7d, 0x14, 0x47, - 0xaa, 0xf5, 0xdb, 0x62, 0x5e, 0x14, 0xa7, 0x78, 0xa6, 0x1b, 0x8c, 0x5b, - 0xc5, 0xef, 0x79, 0x69, 0xfd, 0x78, 0xa9, 0x31, 0xb9, 0xf, 0x51, 0xb3, - 0xe8, 0x2b, 0x51, 0x28, 0x49, 0x8e, 0x86, 0x36, 0x9d, 0x57, 0x45, 0x68, - 0xd4, 0xe1, 0xe, 0x12, 0x76, 0x39, 0x77, 0x6f, 0x5a, 0x1f, 0x2f, 0xad, - 0x60, 0x4e, 0x93, 0xdf, 0x73, 0xdd, 0x49, 0x7d, 0xdb, 0x23, 0x8b, 0xaf, - 0xfa, 0xef, 0xf0, 0xee, 0x30, 0xf6, 0x25, 0x71, 0xa, 0x24, 0x78, 0xe9, - 0xaa, 0x2f, 0x12, 0x44, 0x8f, 0x97, 0x6c, 0x7, 0x21, 0xb0, 0x2f, 0x9b, - 0xd, 0x19, 0x6b, 0xc3, 0xb7, 0x31, 0x85, 0x1c, 0xe9, 0xc2, 0xdd, 0x78, - 0xef, 0xf7, 0xed, 0x31, 0xa2, 0x2d, 0x64, 0xcf, 0xcf, 0xa6, 0x42, 0x28, - 0x62, 0x22, 0xb8, 0x2e, 0xf8, 0xfc, 0xd0, 0xe5, 0xcf, 0x27, 0x7d, 0x2b, - 0x37, 0xbe, 0xd4, 0xb5, 0x6e, 0xd5, 0xbc, 0xfe, 0x77, 0x19, 0x7f, 0xa4, - 0x19, 0xcb, 0xcb, 0x63, 0x9c, 0x7c, 0x5, 0xfd, 0xf4, 0xe7, 0x43, 0x83, - 0xca, 0xbd, 0x72, 0x48, 0x18, 0xb4, 0xe3, 0xa, 0xe, 0x71, 0x8b, 0xa8, - 0x2d, 0xed, 0xd, 0x94, 0xea, 0x3a, 0xe, 0xc0, 0xe9, 0x82, 0x93, 0xad, - 0xa0, 0x6, 0x4c, 0x61, 0xf1, 0x9, 0x15, 0x42, 0x2d, 0xc9, 0x9, 0xb, - 0xb6, 0xc, 0x22, 0x6f, 0x84, 0x29, 0xbe, 0x8e, 0x18, 0xe4, 0x9d, 0xb7, - 0xc1, 0x1e, 0xc, 0x5b, 0x2, 0xc2, 0x40, 0xb4, 0xe2, 0xb8, 0xd7, 0x55, - 0x2, 0xd3, 0x81, 0x3a, 0xd7, 0xca, 0x4b, 0x2f, 0x4b, 0x1c, 0x5d, 0xa2, - 0x4d, 0xba, 0x9e, 0xa6, 0xa3, 0xd5, 0xc8, 0x87, 0x48, 0xd2, 0xdf, 0xa1, - 0x41, 0x5, 0x2, 0xa4, 0xee, 0x36, 0x23, 0x1e, 0x41, 0xd0, 0x60, 0x2e, - 0x29, 0x33, 0xb5, 0x50, 0xc5, 0xae, 0x97, 0xe9, 0xbc, 0x15, 0xa5, 0x2d, - 0x4a, 0xae, 0x50, 0xa7, 0xde, 0x1d, 0x6a, 0x4e, 0xe, 0xbc, 0x99, 0xc6, - 0x9, 0x72, 0x1d, 0xb7, 0xf9, 0xbd, 0x61, 0xce, 0x21, 0xc1, 0x29, 0x60, - 0xda, 0xa5, 0x83, 0x4f, 0x9d, 0xff, 0x14, 0xf9, 0x8, 0xbd, 0x3a, 0x85, - 0xc0, 0x5, 0xf2, 0xff, 0x76, 0xeb, 0x1d, 0x5c, 0xb7, 0x41, 0xc4, 0x55, - 0xaa, 0x3f, 0x20, 0x59, 0x9d, 0x9c, 0xc, 0x64, 0xb7, 0x40, 0xd5, 0xfd, - 0xab, 0xd, 0xd6, 0x84, 0xe0, 0x4d, 0x33, 0xd7, 0xdc, 0xfb, 0xde, 0xd3, - 0xa4, 0x94, 0x1f, 0xee, 0x75, 0x60, 0x7d, 0x90, 0xb2, 0xa3, 0xab, 0xcc, - 0xe4, 0xf0, 0x40, 0xaf, 0xce, 0x73, 0xfb, 0x14, 0x9d, 0x43, 0xe4, 0x91, - 0x31, 0xbf, 0x97, 0x8d, 0xa1, 0x0, 0x51, 0x59, 0xe6, 0x7, 0xad, 0x13, - 0x2e, 0x21, 0xd1, 0x37, 0x1e, 0x6, 0xdc, 0xf6, 0xa3, 0xae, 0x9f, 0x14, - 0x97, 0x7b, 0xea, 0x92, 0xfb, 0x93, 0xa4, 0xd4, 0x8a, 0x94, 0xa0, 0x19, - 0x22, 0xfb, 0x3b, 0xce, 0x2, 0x7e, 0x2, 0x40, 0xd0, 0x9b, 0x91, 0x12, - 0xc3, 0x29, 0xd1, 0xf2, 0x85, 0xd8, 0x86, 0xf0, 0x34, 0xda, 0x9b, 0xcb, - 0x17, 0xef, 0xe, 0x29, 0xcb, 0x26, 0xc5, 0xfe, 0x1d, 0xd6, 0x86, 0x43, - 0x5d, 0x8d, 0xec, 0x81, 0x13, 0x89, 0x1a, 0xb6, 0x2a, 0x25, 0x6c, 0x6a, - 0x95, 0x88, 0xd3, 0x69, 0x6e, 0x1f, 0xa3, 0x63, 0x5, 0xf8, 0x1d, 0x8a, - 0xab, 0xcb, 0x63, 0xb9, 0xb9, 0xbc, 0xea, 0x20, 0xdb, 0x81, 0x2c, 0xf9, - 0x81, 0x78, 0x6, 0x91, 0xa6, 0xe0, 0xb7, 0x73, 0x39, 0x43, 0x87, 0xb, - 0x66, 0xb2, 0xc, 0x83, 0xd2, 0x21, 0xeb, 0xfa, 0xc1, 0x99, 0xa2, 0xfb, - 0x8b, 0x41, 0x91, 0x36, 0xdc, 0x95, 0xa2, 0x2e, 0xe0, 0xb6, 0x6e, 0xdc, - 0x6f, 0x76, 0xe0, 0xd0, 0x93, 0x1d, 0x87, 0xdb, 0x4, 0xe, 0x33, 0x83, - 0xf, 0xd, 0x7f, 0xae, 0x5, 0x71, 0x45, 0x11, 0x79, 0xb0, 0xd0, 0x56, - 0x2b, 0x69, 0x7d, 0xe4, 0x6f, 0x2a, 0xc9, 0x7b, 0xe4, 0xb, 0xb4, 0x3e, - 0x73, 0x13, 0x9c, 0xf5, 0xe2, 0xea, 0xd3, 0xbb, 0xed, 0xc4, 0x49, 0xa5, - 0xbb, 0x31, 0x22, 0x29, 0xb8, 0xa6, 0xdb, 0xb1, 0xb0, 0xc, 0x6f, 0x7b, - 0x8a, 0xe6, 0x73, 0x7, 0xb6, 0x12, 0xc3, 0xdd, 0x6e, 0xa9, 0x30, 0xb9, - 0xe9, 0xd1, 0x3a, 0x81, 0x65, 0xd, 0x8a, 0x77, 0x33, 0xab, 0xcf, 0x8, - 0x39, 0x16, 0xca, 0x44, 0x93, 0xdf, 0xcb, 0xa8, 0x3f, 0x93, 0xc1, 0xd6, - 0x11, 0x37, 0x67, 0x9b, 0x6, 0x44, 0x36, 0x78, 0xbf, 0xc3, 0x9d, 0xd8, - 0x3e, 0x31, 0x56, 0x3, 0xc, 0x2f, 0xa4, 0xf0, 0x7b, 0xff, 0x10, 0x5a, - 0xed, 0x31, 0xff, 0xee, 0x22, 0x6c, 0xb6, 0xaa, 0x3b, 0xa7, 0x17, 0xe1, - 0xc1, 0x47, 0x45, 0x37, 0x90, 0xb7, 0x7a, 0xcf, 0x7c, 0xdb, 0x0, 0xbe, - 0xca, 0xc5, 0xe9, 0xfe, 0x1c, 0xa3, 0x58, 0x89, 0xd8, 0xea, 0xff, 0xc2, - 0xa5, 0x8f, 0xe7, 0x42, 0x28, 0x5f, 0x2, 0x68, 0xc6, 0x88, 0x89, 0x29, - 0x56, 0x38, 0x53, 0xd3, 0x27, 0xf8, 0x77, 0xb4, 0x99, 0x55, 0xe9, 0xa4, - 0xfa, 0xfb, 0xad, 0xe0, 0x99, 0xf4, 0xc0, 0xef, 0xe5, 0x63, 0x6b, 0x36, - 0x90, 0xb8, 0x9c, 0x1a, 0xe7, 0x12, 0xad, 0xab, 0xd9, 0x51, 0xbe, 0x5, - 0x95, 0xe4, 0x1e, 0xda, 0x95, 0xd1, 0xd4, 0x51, 0xc5, 0x80, 0x64, 0x17, - 0xeb, 0xf1, 0xee, 0xe0, 0xe0, 0x8c, 0x8a, 0x32, 0xa6, 0xfc, 0x55, 0xa9, - 0x2d, 0xe1, 0xbe, 0xc3, 0x76, 0x78, 0x5f, 0xba, 0xf0, 0x8e, 0x16, 0x5, - 0x1a, 0xc, 0x78, 0xfa, 0xc4, 0x21, 0xcd, 0xaf, 0xc6, 0x8f, 0x84, 0xf5, - 0x16, 0xf8, 0x48, 0xab, 0x5a, 0x68, 0xb0, 0xd4, 0x75, 0xd8, 0x91, 0x69, - 0x4f, 0x93, 0xd1, 0xee, 0xf0, 0x4c, 0x4d, 0x17, 0xc3, 0x89, 0xa0, 0x7b, - 0x56, 0x38, 0xf4, 0xd7, 0x12, 0xa7, 0x7d, 0x39, 0x81, 0x48, 0xb3, 0x67, - 0xe1, 0x15, 0xa0, 0xa4, 0x2a, 0x60, 0x56, 0xa5, 0xed, 0x9c, 0x76, 0x8b, - 0xa7, 0x14, 0x73, 0x33, 0x9f, 0x55, 0x16, 0x6b, 0x5, 0x40, 0x3b, 0xfe, - 0x93, 0x58, 0x7e, 0xee, 0x2d, 0x61, 0xc5, 0x19, 0x6b, 0x6, 0x71, 0x69, - 0x39, 0x21, 0x0, 0x8, 0x39, 0xb7, 0x76, 0xe, 0x81, 0xe5, 0xe3, 0x77, - 0xff, 0x4b, 0x9b, 0x3, 0x8e, 0xc5, 0xe0, 0xb1, 0x8b, 0x16, 0xbd, 0x71, - 0xbc, 0xc6, 0x62, 0x19, 0xaa, 0x6e, 0x54, 0xb6, 0x7a, 0x17, 0xdb, 0xe5, - 0xd9, 0x2, 0xaa, 0x57, 0x78, 0x2f, 0xd2, 0x85, 0xfb, 0x36, 0xb5, 0xdd, - 0x17, 0xbd, 0x4c, 0x8, 0x3c, 0x6b, 0x79, 0x3e, 0x28, 0xab, 0x38, 0xc3, - 0xe9, 0xdb, 0xf1, 0x28, 0xc3, 0x2a, 0xba, 0x51, 0x1a, 0xf, 0x78, 0xec, - 0x25, 0xa8, 0xf5, 0xed, 0xe4, 0x9f, 0xb, 0xa5, 0x66, 0x58, 0x18, 0xb0, - 0xe4, 0x40, 0xb9, 0xf, 0xce, 0x78, 0xc9, 0x49, 0x4d, 0x2e, 0x29, 0xd9, - 0xbb, 0x59, 0x99, 0xef, 0x3d, 0x44, 0x99, 0x75, 0x8f, 0xe1, 0x1d, 0x5, - 0x70, 0xeb, 0x65, 0x93, 0xeb, 0x3f, 0x76, 0x4f, 0xae, 0xa0, 0x12, 0x5b, - 0x18, 0x28, 0xe6, 0x2a, 0x26, 0xae, 0xe0, 0xd3, 0x26, 0xd2, 0x5f, 0xf5, - 0x89, 0xec, 0x1e, 0xc6, 0x1, 0xe9, 0xe1, 0x7c, 0x30, 0x6a, 0x65, 0x4d, - 0x7c, 0x82, 0xb4, 0xd, 0x92, 0xde, 0x2f, 0xe8, 0x9, 0xde, 0x6f, 0x15, - 0x21, 0x78, 0x91, 0xb2, 0x39, 0xab, 0x20, 0xbb, 0x96, 0xf6, 0xc0, 0xba, - 0xeb, 0x8b, 0x63, 0x97, 0xab, 0xc7, 0x21, 0xd2, 0x85, 0xb, 0x66, 0x91, - 0x31, 0xeb, 0x17, 0x18, 0x4e, 0x12, 0x3e, 0xa5, 0x57, 0x6e, 0xe5, 0x95, - 0x70, 0x3c, 0x25, 0x1b, 0x53, 0x4a, 0xde, 0x29, 0x20, 0x13, 0x90, 0xd9, - 0xc7, 0x3f, 0x15, 0xcf, 0x98, 0x94, 0x43, 0xe6, 0x98, 0xee, 0x33, 0xa0, - 0x8a, 0xc6, 0xfb, 0x71, 0x73, 0xfe, 0xd1, 0xf5, 0xd, 0x71, 0xfe, 0x15, - 0xdb, 0x7e, 0xaf, 0x36, 0x5a, 0x59, 0xab, 0xaf, 0x96, 0xa0, 0x3b, 0x5, - 0xda, 0xa, 0x46, 0x76, 0xa0, 0x55, 0x93, 0xd9, 0xf0, 0x63, 0xc9, 0x8c, - 0x40, 0x2d, 0x97, 0x1b, 0x6e, 0x54, 0x0, 0x78, 0xfb, 0x88, 0xc2, 0x46, - 0xef, 0xf, 0x45, 0xba, 0xa0, 0xc7, 0x99, 0xa2, 0xcf, 0x88, 0x9e, 0x96, - 0x27, 0x15, 0x24, 0x28, 0xf8, 0xa0, 0xa4, 0xbb, 0x57, 0x7c, 0xc7, 0xef, - 0x2b, 0x50, 0xa, 0x78, 0x92, 0x82, 0x6e, 0x6e, 0x75, 0x4a, 0x29, 0x20, - 0xab, 0xef, 0x9e, 0x85, 0x7f, 0x33, 0x2c, 0x5, 0xfa, 0xd, 0x6e, 0xab, - 0xc8, 0xb9, 0xee, 0xd0, 0x22, 0xd6, 0xd9, 0xc9, 0x90, 0xe4, 0xea, 0x42, - 0x9, 0x72, 0x15, 0x3c, 0xbe, 0x6f, 0x6e, 0x85, 0x18, 0x2e, 0xb0, 0xc8, - 0xac, 0xe2, 0xc, 0xd3, 0xa3, 0x6, 0xbf, 0xdc, 0x93, 0x2a, 0xb8, 0xa0, - 0x21, 0x3c, 0x7f, 0x8c, 0xbe, 0xda, 0x8e, 0xf3, 0xf7, 0xfe, 0x83, 0x4a, - 0x35, 0x5, 0x80, 0x39, 0x66, 0xab, 0x38, 0x3a, 0x8a, 0xc6, 0x5e, 0xca, - 0xb0, 0x74, 0x39, 0xfd, 0x23, 0xa0, 0x4f, 0x5, 0xb3, 0x23, 0xe9, 0xfd, - 0xb5, 0xe, 0x47, 0x20, 0x14, 0x27, 0x6, 0x33, 0x60, 0xbc, 0xd4, 0xb0, - 0x84, 0x17, 0x87, 0xcf, 0x24, 0x79, 0xa0, 0x26, 0x91, 0x81, 0xe3, 0x4c, - 0x73, 0x7c, 0xa3, 0xc2, 0xc6, 0x4b, 0xb8, 0xda, 0xff, 0xaa, 0x89, 0x38, - 0x84, 0xea, 0xfe, 0x58, 0xd9, 0x11, 0x82, 0x30, 0x90, 0x39, 0x39, 0x88, - 0x10, 0xec, 0xf8, 0xc0, 0x1, 0x16, 0xb6, 0xc1, 0x74, 0xf6, 0xb2, 0xb3, - 0x6d, 0x8d, 0xf8, 0x76, 0xa0, 0x7f, 0x12, 0x26, 0xba, 0x9d, 0xed, 0x45, - 0x27, 0x5d, 0x3f, 0x4b, 0xe7, 0xd2, 0xc5, 0xf9, 0xf8, 0xde, 0x95, 0x74, - 0xb1, 0x2a, 0x3f, 0xed, 0x1f, 0x73, 0x15, 0x18, 0xc4, 0xb1, 0x32, 0x90, - 0x52, 0xc4, 0x11, 0x78, 0x21, 0x25, 0x61, 0x2c, 0x8f, 0x78, 0x7f, 0xee, - 0x31, 0x92, 0x4f, 0x36, 0xbc, 0xd5, 0x70, 0x84, 0x4c, 0xb4, 0x39, 0xa3, - 0x73, 0x53, 0xbb, 0x48, 0x3d, 0xff, 0x3, 0x74, 0xea, 0x2f, 0x7, 0xf3, - 0xaa, 0xeb, 0x1b, 0x69, 0xa3, 0x28, 0x56, 0x45, 0x6d, 0xb2, 0xb2, 0x12, - 0xc1, 0xf7, 0x21, 0x35, 0x5, 0x14, 0x9c, 0x6, 0xf9, 0x1c, 0x9e, 0x8e, - 0xda, 0x19, 0xa8, 0x6, 0x5f, 0xa1, 0x21, 0x1e, 0x1e, 0x96, 0x38, 0x2, - 0x29, 0xd5, 0x6d, 0x8e, 0x24, 0x4e, 0x94, 0x79, 0x22, 0xc7, 0x67, 0xe8, - 0xc2, 0x12, 0xdf, 0xed, 0x82, 0x22, 0xdb, 0x80, 0x52, 0xc, 0x60, 0xdf, - 0x84, 0x92, 0x55, 0xc2, 0xce, 0xfc, 0x7, 0x69, 0x9f, 0xd2, 0xd0, 0x37, - 0xbf, 0x1d, 0x11, 0x8a, 0xab, 0x26, 0x92, 0x6b, 0xe, 0xbc, 0x1c, 0x6f, - 0xdf, 0x78, 0x8f, 0x8a, 0xce, 0x16, 0x70, 0x90, 0x2a, 0x66, 0x13, 0x9a, - 0x57, 0xda, 0x5f, 0x93, 0xcd, 0xef, 0x8f, 0x76, 0x1e, 0x8e, 0x59, 0xdf, - 0x7, 0x49, 0x35, 0x81, 0xa4, 0x7d, 0x1b, 0xe0, 0x61, 0x6f, 0x10, 0xc1, - 0x1c, 0xf2, 0xc6, 0x7f, 0x1, 0x92, 0xa0, 0x4d, 0x58, 0x2a, 0xe0, 0x27, - 0xbf, 0x3a, 0x8f, 0xb0, 0x2a, 0xfd, 0x6, 0xb, 0x35, 0xfd, 0x49, 0x2, - 0x2, 0xf6, 0x52, 0x35, 0x15, 0x78, 0x3d, 0xa0, 0x99, 0x98, 0x5f, 0xf3, - 0xce, 0x38, 0xfd, 0xd6, 0x81, 0xb1, 0xed, 0xb1, 0x89, 0x2d, 0x7c, 0xee, - 0x1c, 0x65, 0x36, 0x24, 0xc2, 0xd, 0xbe, 0xa6, 0xf1, 0xa2, 0x95, 0xb8, - 0x9d, 0xc9, 0xaf, 0x5, 0xb2, 0xe5, 0x95, 0x45, 0xe5, 0x9b, 0x82, 0x3d, - 0xbb, 0x65, 0x0, 0xfe, 0x24, 0xb9, 0xc8, 0x43, 0x57, 0xd6, 0x2d, 0x9e, - 0xa4, 0xfa, 0x99, 0x1a, 0xc9, 0xb0, 0xdb, 0x70, 0xd9, 0x28, 0x85, 0x4c, - 0x33, 0x33, 0xa7, 0x37, 0x86, 0xa7, 0x62, 0x8a, 0xca, 0xbc, 0xfd, 0x25, - 0x43, 0x4c, 0xbe, 0x3e, 0xb7, 0xfb, 0x99, 0x5e, 0xe4, 0x9, 0x9a, 0x92, - 0xdd, 0xec, 0x6f, 0xab, 0x39, 0x65, 0x75, 0x6e, 0x98, 0xbd, 0xd0, 0xd9, - 0x87, 0x46, 0xa3, 0x9c, 0xfe, 0x41, 0x4f, 0x20, 0x3d, 0x68, 0x32, 0x21, - 0x94, 0x5a, 0xbd, 0x67, 0x9f, 0x79, 0x51, 0x8a, 0xe9, 0x16, 0xa3, 0xc0, - 0x33, 0x69, 0x21, 0x45, 0x62, 0xa2, 0x45, 0x36, 0xaa, 0xd1, 0x80, 0x3a, - 0x6a, 0x51, 0x86, 0xb4, 0x49, 0x56, 0xd6, 0x65, 0xdd, 0x87, 0x9e, 0xb0, - 0x4a, 0xbe, 0x80, 0x42, 0x13, 0x44, 0xc4, 0x5d, 0x8a, 0x54, 0x37, 0x11, - 0xfc, 0xe6, 0xa5, 0xd, 0x59, 0xd7, 0x11, 0xa6, 0x61, 0x44, 0x87, 0xf0, - 0x93, 0x36, 0x57, 0x15, 0x6c, 0xe2, 0x8f, 0x37, 0x27, 0x87, 0x96, 0x1, - 0xe0, 0x98, 0xc4, 0xda, 0x1, 0xf4, 0x21, 0x3, 0x97, 0x28, 0x71, 0xdc, - 0xd2, 0xf3, 0xb0, 0x24, 0x10, 0xb9, 0x89, 0xd5, 0x97, 0x34, 0x60, 0xcb, - 0x39, 0x6, 0xb3, 0x59, 0xeb, 0x3b, 0x86, 0xd0, 0x1b, 0x51, 0x6d, 0x46, - 0xa8, 0xb6, 0xcd, 0xec, 0xf7, 0xe1, 0xf6, 0xc8, 0x9, 0xe0, 0xfa, 0x29, - 0xf4, 0x96, 0x53, 0x9f, 0x3, 0xe1, 0x3e, 0x72, 0x23, 0x32, 0x8f, 0xa7, - 0xb, 0x94, 0x55, 0x71, 0x4f, 0x41, 0x6d, 0xcf, 0xf, 0x87, 0xd, 0x45, - 0xcd, 0x33, 0x63, 0x10, 0x7, 0xff, 0x95, 0x58, 0xb6, 0xc1, 0x2, 0x0, - 0x8d, 0xbb, 0x4e, 0x16, 0x9f, 0x5d, 0x3f, 0xbe, 0x44, 0x16, 0x4, 0x73, - 0x6e, 0xf5, 0xb8, 0x72, 0x5b, 0xed, 0x36, 0x4e, 0xf8, 0x86, 0xb9, 0x71, - 0x63, 0x10, 0x7f, 0x4e, 0x69, 0xc8, 0xa, 0xc0, 0x75, 0xdd, 0xd3, 0xe0, - 0xa5, 0x2c, 0xd2, 0xf4, 0xc1, 0x9a, 0x72, 0xe3, 0xf2, 0xb1, 0x46, 0x56, - 0x6b, 0x3f, 0x3, 0x87, 0x53, 0x75, 0x7d, 0xce, 0x1b, 0x31, 0xd6, 0x29, - 0x99, 0xcf, 0xc0, 0x5f, 0xb5, 0x7b, 0x3a, 0xa0, 0x7d, 0x66, 0xda, 0x86, - 0x5f, 0x74, 0x29, 0x8f, 0x37, 0x90, 0x65, 0xec, 0xef, 0x1c, 0xb0, 0xf6, - 0x68, 0xe, 0x34, 0x78, 0xd5, 0xae, 0x4, 0x5d, 0x6, 0xa, 0x5c, 0xb8, - 0x74, 0x67, 0xbc, 0xa8, 0x97, 0x3d, 0x2a, 0xbe, 0xd3, 0x74, 0x5, 0xdc, - 0x3d, 0x61, 0x22, 0x5a, 0x84, 0x98, 0xe1, 0xae, 0x59, 0x20, 0x6a, 0xe0, - 0xb6, 0x78, 0xc, 0x8, 0xfa, 0x75, 0xb4, 0xb7, 0xd2, 0x14, 0x1e, 0x8a, - 0x3c, 0x58, 0x7c, 0x95, 0x91, 0x5d, 0x56, 0xbf, 0xfe, 0xbe, 0x7f, 0xb1, - 0x2e, 0x81, 0x7b, 0x4e, 0x1e, 0xd1, 0x2a, 0x25, 0x30, 0x87, 0xf5, 0x40, - 0xd7, 0xcc, 0x1d, 0xd8, 0x9d, 0x77, 0x37, 0x3, 0x6, 0x91, 0x6c, 0x1d, - 0xa3, 0xaa, 0xa9, 0x9b, 0xa9, 0xf5, 0x92, 0x31, 0x44, 0xdc, 0x7b, 0xcf, - 0xe8, 0x9a, 0xa5, 0x46, 0x9a, 0xac, 0x20, 0x56, 0x8, 0x56, 0x7d, 0x82, - 0xba, 0x4b, 0x3, 0x3e, 0xa3, 0x62, 0xe2, 0xcc, 0x19, 0x48, 0xc7, 0xfe, - 0xde, 0x2, 0xa4, 0x59, 0x6e, 0xf0, 0x19, 0x40, 0xd7, 0x35, 0x64, 0x8b, - 0x40, 0xb, 0x3d, 0x87, 0xb8, 0xd9, 0x11, 0xed, 0xae, 0x2c, 0x8b, 0x6c, - 0x45, 0x91, 0x81, 0x27, 0xc, 0xea, 0xb2, 0x9f, 0xb7, 0x27, 0x90, 0x32, - 0xd4, 0x19, 0xb1, 0xff, 0x48, 0xa, 0xac, 0x55, 0x8d, 0x1b, 0x22, 0xef, - 0x51, 0xcc, 0x9, 0xff, 0xab, 0x1e, 0x70, 0xa8, 0x49, 0xf2, 0x68, 0xc4, - 0xdf, 0xd, 0xee, 0x3, 0x67, 0xb3, 0xa, 0x39, 0x8b, 0x59, 0x1a, 0x8a, - 0x95, 0xba, 0xc8, 0xde, 0x6, 0xf6, 0xb7, 0xa5, 0xbc, 0xa0, 0x4d, 0xb2, - 0xd2, 0x58, 0x6e, 0xcc, 0x94, 0xa1, 0xaf, 0xf1, 0xf4, 0x73, 0x64, 0xc3, - 0x90, 0xdd, 0xd7, 0x4f, 0xb7, 0xbc, 0x65, 0x11, 0xdd, 0x40, 0xd6, 0xf, - 0x73, 0xeb, 0xef, 0x4e, 0x57, 0x72, 0xd7, 0xe6, 0xe6, 0xe1, 0xb1, 0x2d, - 0x80, 0xb2, 0x59, 0x95, 0xa9, 0xca, 0x85, 0x3f, 0x5e, 0x9c, 0x7d, 0xa9, - 0x9d, 0x22, 0x7b, 0xcc, 0x89, 0xda, 0xe0, 0x7e, 0x56, 0x42, 0x69, 0x28, - 0x76, 0x12, 0x2a, 0xa, 0xa1, 0xc9, 0x19, 0x2c, 0x46, 0xd3, 0xe8, 0x22, - 0xd4, 0x9, 0x92, 0x9f, 0x75, 0x53, 0x82, 0xfb, 0xf0, 0x2f, 0x96, 0x4, - 0xc6, 0xf4, 0xc3, 0xdf, 0x2, 0x31, 0xfd, 0x74, 0x24, 0xda, 0xe5, 0xdf, - 0x4d, 0x68, 0xe4, 0x5e, 0x20, 0xd5, 0x55, 0x9b, 0x9d, 0xe3, 0xc6, 0x70, - 0x10, 0x70, 0x56, 0xe4, 0x4d, 0x7e, 0x78, 0x69, 0xb3, 0x7f, 0xc0, 0x8c, - 0xea, 0xc, 0xf0, 0xdc, 0x3a, 0x87, 0x34, 0xa8, 0x9f, 0x6a, 0x4d, 0xae, - 0x49, 0x9e, 0x35, 0x66, 0xc8, 0x6f, 0xaa, 0xa7, 0xfb, 0x4c, 0xf6, 0xb, - 0x58, 0x11, 0x26, 0xa7, 0x45, 0xef, 0x3c, 0xdb, 0x5e, 0xce, 0xf8, 0xb4, - 0x6d, 0x7c, 0x85, 0x93, 0xb1, 0x27, 0x56, 0x60, 0x3a, 0x1b, 0xd0, 0x96, - 0xba, 0x8b, 0xf4, 0x65, 0xa4, 0xda, 0x8f, 0x71, 0xc, 0xa6, 0x81, 0x8c, - 0x8a, 0x3c, 0xb4, 0x27, 0x6a, 0xcf, 0x16, 0x7, 0x81, 0x2e, 0xa0, 0xb, - 0xf6, 0xd1, 0xec, 0x1d, 0x85, 0x0, 0xf7, 0x49, 0xeb, 0x19, 0xd3, 0xa7, - 0xc0, 0xec, 0x79, 0xf7, 0xa3, 0x91, 0x27, 0x9a, 0xe3, 0x16, 0x60, 0x52, - 0xe7, 0xfe, 0xe5, 0x7, 0x16, 0x88, 0xf4, 0x27, 0x69, 0x47, 0x5, 0x1e, - 0x76, 0xe6, 0x16, 0x5d, 0x32, 0x5a, 0x92, 0x41, 0x5, 0x97, 0x3e, 0xcf, - 0x3f, 0x22, 0x63, 0xa1, 0xa7, 0x8f, 0xac, 0xa9, 0x56, 0x82, 0x7, 0xbc, - 0x79, 0xbc, 0x4f, 0xe5, 0x84, 0xa4, 0xe8, 0xde, 0xd3, 0xe7, 0x96, 0x5f, - 0x0, 0xde, 0xba, 0x27, 0xa4, 0x23, 0x57, 0xc6, 0x4a, 0x69, 0xab, 0xbf, - 0x3d, 0x34, 0xe7, 0xec, 0xc4, 0xe9, 0xee, 0xd6, 0xc8, 0x2d, 0x52, 0x47, - 0x11, 0x19, 0xd8, 0xc6, 0x4e, 0x2c, 0xf2, 0x68, 0x9a, 0xd5, 0xb, 0x25, - 0xe8, 0x77, 0xa1, 0x38, 0x7e, 0x15, 0xf, 0xc6, 0x85, 0x7d, 0x14, 0x2a, - 0x41, 0x55, 0xb, 0xe7, 0x83, 0xcc, 0x6b, 0x4f, 0xbe, 0xde, 0xec, 0x38, - 0xd1, 0xf4, 0x32, 0x4c, 0x36, 0xe1, 0xf3, 0x70, 0x1b, 0xbb, 0x82, 0xd9, - 0x80, 0x19, 0x67, 0x25, 0xa0, 0x1c, 0xdd, 0x63, 0xb2, 0x80, 0xf8, 0xef, - 0xd, 0xa9, 0xde, 0x77, 0x4c, 0x53, 0x17, 0x9d, 0x2f, 0x3d, 0x91, 0x80, - 0x6b, 0xcc, 0x55, 0x5d, 0xbc, 0x14, 0x8f, 0xfa, 0x6e, 0xfd, 0xf5, 0xf1, - 0x22, 0x33, 0xf5, 0x39, 0x6f, 0xe0, 0xc, 0x69, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, - 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, - 0x9c, 0xe5, 0x73, 0xd9, 0x39, 0xba, 0x2, 0x36, 0xe2, 0x8a, 0xd1, 0x1, - 0xb, 0x82, 0x86, 0x7e, 0x6, 0xa9, 0xae, 0xfd, 0x76, 0x74, 0xfb, 0x7b, - 0xea, 0xea, 0x4a, 0xd4, 0x8c, 0xd2, 0xec, 0x68, 0xf5, 0xd2, 0xfe, 0x7e, - 0xc6, 0x5f, 0xa7, 0x53, 0x22, 0xe7, 0xed, 0x68, 0x22, 0xf7, 0x1d, 0x8b, - 0xcb, 0x84, 0xfd, 0x82, 0xf9, 0x48, 0xe6, 0x91, 0xc9, 0x81, 0x2c, 0x40, - 0x53, 0x7b, 0x7f, 0x85, 0x83, 0xab, 0x99, 0xf6, 0xbb, 0xc2, 0x20, 0xaf, - 0x40, 0xd9, 0xb, 0xc8, 0x7d, 0x55, 0x68, 0xda, 0x6d, 0xe6, 0x8c, 0xd9, - 0x20, 0xaf, 0xd, 0x7e, 0x8b, 0x66, 0xe1, 0x43, 0x3a, 0x6e, 0xb8, 0x97, - 0x50, 0xbe, 0xd1, 0x33, 0xb7, 0x18, 0xe3, 0x68, 0xa, 0x4, 0x4b, 0x76, - 0x1e, 0xd6, 0x6e, 0x6c, 0x68, 0x43, 0xd7, 0x14, 0xff, 0xc6, 0xee, 0xfb, - 0xe7, 0xab, 0x36, 0x81, 0x85, 0x58, 0xe, 0x4b, 0xdd, 0x24, 0x7, 0x8b, - 0xa7, 0x3a, 0x8f, 0xc0, 0x58, 0xad, 0x68, 0x32, 0xaf, 0xf6, 0xdf, 0x2a, - 0x86, 0xd1, 0x47, 0xa7, 0x76, 0xe1, 0x2b, 0xcb, 0xf7, 0xfc, 0x75, 0x35, - 0x2c, 0x1a, 0x24, 0xd, 0x6d, 0x91, 0x27, 0x4, 0x4d, 0x2b, 0xad, 0xa7, - 0x8f, 0x48, 0xf4, 0xa4, 0xfe, 0x92, 0x75, 0xc3, 0x10, 0x82, 0xb2, 0xd0, - 0x2d, 0xf4, 0x89, 0xda, 0x25, 0xb3, 0x85, 0x1, 0x50, 0xd5, 0x27, 0x27, - 0x81, 0x5, 0x4e, 0x9, 0x1a, 0x36, 0x87, 0xd3, 0xe2, 0x32, 0xb7, 0x43, - 0x4d, 0x4c, 0x15, 0x83, 0xe1, 0x1b, 0xd8, 0xae, 0xe8, 0x10, 0x44, 0x78, - 0x11, 0x9f, 0x52, 0xc0, 0xa6, 0x70, 0x23, 0xe4, 0xa9, 0xbc, 0xdd, 0x44, - 0x61, 0x42, 0xc5, 0x30, 0xd3, 0xe8, 0x1, 0x24, 0x61, 0x2b, 0x9, 0x1, - 0xe2, 0x8e, 0xca, 0x2, 0x1b, 0x52, 0xc5, 0xe2, 0xd8, 0x1b, 0x25, 0x49, - 0xed, 0x29, 0x85, 0x56, 0xef, 0xa4, 0xce, 0x32, 0x9, 0xcd, 0x94, 0x6b, - 0x7d, 0x9, 0x7d, 0xf1, 0xcc, 0x4c, 0xc7, 0x42, 0x98, 0xd3, 0x70, 0xd2, - 0xf2, 0xee, 0xa3, 0xac, 0x6b, 0x7c, 0x52, 0xfe, 0x26, 0x1d, 0x9b, 0x6d, - 0x53, 0xb3, 0x33, 0xa6, 0x9f, 0x8d, 0xb1, 0xd3, 0x8a, 0x87, 0x52, 0xf5, - 0x42, 0xff, 0xf3, 0x81, 0x0, 0x5f, 0xf0, 0x2f, 0x25, 0xf2, 0xf6, 0xc1, - 0xe1, 0x8c, 0x41, 0x10, 0x74, 0xd6, 0x3c, 0x2e, 0x5b, 0x2c, 0x93, 0xd6, - 0xcb, 0x67, 0x15, 0x4, 0x1f, 0x27, 0x28, 0xf9, 0xe9, 0x4d, 0x4, 0x47, - 0x49, 0x77, 0xeb, 0x8c, 0x3c, 0x96, 0x1b, 0x7f, 0xf3, 0x31, 0xf5, 0xff, - 0x20, 0x9d, 0x18, 0x94, 0xdf, 0x6f, 0x77, 0x9c, 0x63, 0x7c, 0xcf, 0x4f, - 0x3e, 0x55, 0x32, 0xc8, 0xe9, 0xd5, 0x37, 0x8f, 0x3e, 0x9c, 0x4b, 0x12, - 0x6, 0xcf, 0xf4, 0xfb, 0x1a, 0x9a, 0x58, 0x2, 0xb0, 0xc1, 0xf5, 0x32, - 0x91, 0xfd, 0xec, 0xa5, 0xb2, 0x79, 0x99, 0x64, 0xbb, 0xb8, 0x8b, 0xf9, - 0xe4, 0xb2, 0xa2, 0x84, 0xdf, 0x92, 0x71, 0x87, 0xbb, 0x75, 0x3, 0xfc, - 0x37, 0x72, 0x13, 0x31, 0xd, 0xec, 0xdd, 0x6e, 0xa6, 0x3f, 0xef, 0xbf, - 0xe2, 0xdd, 0x20, 0x98, 0x24, 0x7c, 0x57, 0xfd, 0x4b, 0x77, 0x6, 0x73, - 0xbd, 0xb2, 0xa1, 0xb0, 0x6e, 0x8c, 0x28, 0x71, 0x11, 0x92, 0x1d, 0x7b, - 0x2b, 0x28, 0x1, 0x85, 0x73, 0x1b, 0xff, 0xf3, 0xdc, 0x31, 0xbb, 0x14, - 0x2c, 0x6e, 0x77, 0x19, 0x67, 0xf7, 0x1c, 0xc4, 0xba, 0x1c, 0xaa, 0x4d, - 0x9f, 0xa6, 0x33, 0xa0, 0x7d, 0xc4, 0x70, 0xd7, 0xeb, 0x93, 0x7c, 0x64, - 0x18, 0xf7, 0x77, 0xc, 0x1b, 0x1, 0x91, 0x70, 0x90, 0x3f, 0x92, 0x5e, - 0xc2, 0xe7, 0xc9, 0x3e, 0x0, 0xab, 0x3a, 0x75, 0x8a, 0x42, 0x39, 0x47, - 0x26, 0x51, 0x91, 0x20, 0xbb, 0x96, 0xac, 0xfb, 0xa6, 0x9c, 0x5f, 0xa8, - 0x58, 0x3c, 0x4e, 0x1e, 0xe0, 0xd0, 0xf1, 0x84, 0x7e, 0xe8, 0x83, 0xa5, - 0x54, 0x3e, 0xae, 0xdf, 0xd9, 0x75, 0xf8, 0x7a, 0xed, 0xb7, 0x28, 0xfb, - 0x11, 0xb7, 0xd, 0x67, 0xf, 0xea, 0x3b, 0xbd, 0x97, 0xc0, 0x43, 0x41, - 0x26, 0xaf, 0xfb, 0x5c, 0xb7, 0x56, 0xb1, 0x7d, 0xcb, 0x8, 0xa8, 0x63, - 0xfc, 0xfb, 0x61, 0x1b, 0xc1, 0x77, 0xee, 0xd, 0x2e, 0xdd, 0xc6, 0x74, - 0x14, 0x9f, 0x90, 0x5d, 0x50, 0xe4, 0x96, 0xc, 0xb3, 0x5c, 0x5e, 0x6c, - 0xec, 0x63, 0x43, 0xf4, 0xa5, 0xc0, 0xf1, 0x18, 0xc0, 0x25, 0x76, 0x80, - 0x8a, 0x51, 0x38, 0xb9, 0x29, 0x2b, 0x8e, 0x5, 0x63, 0xb1, 0x4f, 0x3e, - 0x92, 0xc0, 0xc1, 0xf7, 0x94, 0x4a, 0xd8, 0x9d, 0xba, 0xc1, 0x8e, 0xc9, - 0x16, 0x4c, 0xe4, 0xd4, 0x6f, 0x78, 0x4d, 0xa3, 0x79, 0x44, 0x63, 0x66, - 0x9d, 0x28, 0xee, 0xae, 0x8e, 0x1d, 0xa0, 0x45, 0x1b, 0xf, 0x13, 0x87, - 0x45, 0x48, 0x47, 0xf9, 0xe7, 0x90, 0x4e, 0x47, 0xce, 0xcf, 0xca, 0x26, - 0xb3, 0x5d, 0xa3, 0xb9, 0xa0, 0x97, 0x1e, 0x57, 0x7d, 0x11, 0xa7, 0xfc, - 0x1c, 0xe8, 0x93, 0x47, 0xc9, 0x1f, 0x60, 0x1f, 0x15, 0x9f, 0x61, 0xc5, - 0x2c, 0xc6, 0xaa, 0xa2, 0xc2, 0xaa, 0x25, 0xdc, 0xfe, 0x74, 0x2, 0xb6, - 0xd0, 0x5, 0x63, 0xe7, 0x4, 0xa8, 0xe, 0x3e, 0x3d, 0x80, 0x45, 0x95, - 0xa7, 0xc6, 0x53, 0xd7, 0xed, 0xb, 0x1c, 0x1d, 0x21, 0x8, 0x8f, 0x3e, - 0xec, 0xf, 0x71, 0x14, 0x3e, 0xc0, 0x88, 0x15, 0xfd, 0x18, 0x7f, 0x7b, - 0x8, 0x5c, 0xfd, 0x27, 0xa2, 0x82, 0xfd, 0xb8, 0x4, 0xed, 0xe1, 0x10, - 0x33, 0xdd, 0x43, 0x6d, 0x75, 0xd5, 0x26, 0x50, 0xb, 0xc1, 0xa0, 0x14, - 0xa1, 0x6b, 0xad, 0xc8, 0x1f, 0xe0, 0x25, 0x2c, 0x3e, 0x1f, 0x58, 0xf9, - 0x3f, 0x18, 0x5f, 0xb7, 0xa4, 0x56, 0x90, 0x4d, 0x66, 0xab, 0x77, 0x66, - 0x54, 0xbd, 0x7d, 0xff, 0x1f, 0x3a, 0x6c, 0x7, 0x6e, 0x5a, 0x64, 0xf0, - 0x5b, 0x75, 0x20, 0xc4, 0x30, 0x1d, 0x3e, 0xd0, 0xf3, 0x31, 0x14, 0xe5, - 0x6d, 0xd0, 0x35, 0xa0, 0x62, 0x7, 0x14, 0x25, 0x14, 0x45, 0x19, 0xfb, - 0x7a, 0x93, 0x69, 0xbc, 0x1, 0xd2, 0x17, 0x92, 0xc4, 0x53, 0xa2, 0xcf, - 0xa5, 0xa, 0xde, 0xc5, 0x3d, 0x25, 0x91, 0x62, 0x4e, 0x0, 0xdd, 0xc5, - 0x2b, 0xc9, 0x39, 0x80, 0x3a, 0xc8, 0x4a, 0x15, 0xe5, 0x62, 0x2a, 0x25, - 0xfc, 0x3d, 0xaf, 0x4b, 0x72, 0x74, 0x12, 0x1c, 0xdc, 0xbb, 0x79, 0x34, - 0xfb, 0x4, 0xeb, 0xd4, 0x87, 0xf6, 0x60, 0x3a, 0x84, 0x97, 0x17, 0x58, - 0x44, 0x8f, 0xd4, 0xbf, 0x27, 0x27, 0x6a, 0x7a, 0x7a, 0x1a, 0x4a, 0x38, - 0xfe, 0xa8, 0xde, 0xcf, 0xd0, 0x23, 0xcd, 0x7a, 0x56, 0x7f, 0x76, 0x62, - 0x3f, 0xaf, 0xb6, 0xde, 0x47, 0x4c, 0xea, 0xb4, 0x6, 0x7c, 0xb0, 0x8, - 0x2d, 0x4b, 0xfe, 0x6b, 0x1e, 0x94, 0x91, 0x72, 0xb9, 0x13, 0x67, 0x71, - 0x21, 0xeb, 0x8e, 0xd4, 0xf5, 0x3c, 0xe8, 0xc8, 0x7c, 0xcb, 0x1d, 0xcf, - 0x82, 0x8b, 0xa7, 0x60, 0x81, 0x9f, 0xb, 0xce, 0x4e, 0x22, 0x23, 0x11, - 0x72, 0x5e, 0xeb, 0xd, 0xca, 0x31, 0xdb, 0x18, 0x9d, 0x1d, 0x3f, 0xa3, - 0xe5, 0x25, 0xdc, 0xc2, 0xd3, 0x99, 0xad, 0xaa, 0xd6, 0x89, 0xc4, 0x2d, - 0x3f, 0x54, 0x3, 0x90, 0x75, 0xfb, 0xc7, 0x73, 0xc3, 0xbc, 0x4e, 0xe7, - 0xaf, 0x9, 0x6a, 0x67, 0xec, 0xb5, 0x9c, 0x6b, 0x3a, 0xc6, 0x24, 0xa8, - 0x12, 0xd, 0xbe, 0xf8, 0xec, 0x3d, 0xe7, 0x76, 0x2b, 0xb9, 0x1e, 0xed, - 0x65, 0xf6, 0xb3, 0x7e, 0x54, 0x58, 0xbf, 0x60, 0x78, 0x74, 0x0, 0xe1, - 0x93, 0x18, 0xd, 0x64, 0xc0, 0x89, 0xfb, 0x5a, 0x1b, 0x1b, 0x30, 0x4c, - 0x9a, 0xa5, 0x6e, 0x72, 0x1f, 0x77, 0x60, 0xb8, 0x36, 0x63, 0x5a, 0x35, - 0x4, 0xd6, 0x19, 0xbb, 0x84, 0x11, 0xbd, 0x8d, 0x10, 0x8e, 0xe5, 0xee, - 0xa7, 0x7e, 0xc2, 0xf8, 0x4f, 0xf4, 0x48, 0x63, 0xd3, 0x5c, 0xdc, 0x63, - 0x71, 0x2f, 0xdf, 0xe, 0xbf, 0x6c, 0x6a, 0x54, 0x25, 0xe4, 0xea, 0xd7, - 0x6e, 0x25, 0x36, 0x84, 0xf0, 0xcf, 0x2d, 0x5f, 0x4c, 0x49, 0x1b, 0x19, - 0xdd, 0x38, 0xb, 0x69, 0xa, 0x2c, 0x51, 0xfe, 0x4, 0xf5, 0x57, 0xa7, - 0xf0, 0xd6, 0x8c, 0x54, 0x78, 0x50, 0x11, 0x88, 0xd3, 0x5c, 0xdc, 0x1a, - 0x3d, 0x6b, 0xb1, 0x3a, 0x1, 0x66, 0xf0, 0xb4, 0x11, 0x5, 0x14, 0x38, - 0x34, 0x72, 0xbb, 0xde, 0xec, 0x26, 0xdb, 0x8b, 0x4c, 0xdf, 0xa7, 0xb6, - 0x52, 0xfe, 0x30, 0x46, 0xf3, 0x10, 0x7c, 0xc6, 0xa1, 0x97, 0x13, 0xdc, - 0xd6, 0xa1, 0x20, 0x45, 0x5e, 0x47, 0x98, 0x77, 0xf6, 0x57, 0xd2, 0x81, - 0x44, 0x2b, 0x4, 0x7f, 0x19, 0x80, 0x38, 0xc6, 0xfd, 0xcf, 0xa8, 0xa0, - 0x80, 0x10, 0xfb, 0xb0, 0x8b, 0x48, 0x52, 0xf8, 0x5c, 0x24, 0x20, 0x42, - 0x50, 0xfc, 0x6c, 0x76, 0x76, 0x5, 0x3d, 0x9f, 0xd4, 0xa7, 0xa8, 0x38, - 0x1c, 0xa3, 0xd1, 0xe8, 0x3f, 0xfd, 0x4b, 0xb5, 0x7, 0x3f, 0xe7, 0x9c, - 0x4a, 0xa4, 0x7d, 0xd6, 0x7c, 0x3e, 0xfb, 0x9c, 0x3d, 0xf2, 0xa9, 0x2e, - 0x82, 0x1b, 0x51, 0xb0, 0x94, 0x3f, 0x37, 0xc8, 0x1c, 0x6c, 0xff, 0xcb, - 0xe0, 0x87, 0xd3, 0xab, 0x56, 0x41, 0xd7, 0xc1, 0xee, 0x6d, 0x9d, 0xab, - 0xd8, 0x29, 0x79, 0xec, 0xff, 0xa8, 0xaa, 0xf4, 0xd9, 0xfc, 0xa0, 0xe4, - 0xf7, 0x22, 0x79, 0xe4, 0xcf, 0x5, 0x7e, 0x59, 0x94, 0x4d, 0x2f, 0x18, - 0xeb, 0x4c, 0xab, 0x78, 0xb3, 0x58, 0x69, 0x73, 0x8e, 0x7b, 0xc1, 0xc9, - 0x7f, 0x90, 0x63, 0xe, 0x48, 0x7c, 0x40, 0x49, 0x2c, 0xb9, 0xf0, 0x50, - 0xed, 0x82, 0x15, 0x14, 0x8f, 0xac, 0xab, 0x46, 0xf2, 0x46, 0x59, 0x9c, - 0x5f, 0x7b, 0xf7, 0x42, 0xc8, 0x31, 0x90, 0xa0, 0x39, 0xe8, 0x69, 0xd2, - 0xd4, 0xe6, 0x96, 0x5e, 0xe4, 0x57, 0x32, 0xa3, 0x39, 0x7f, 0x67, 0xb, - 0xfd, 0xf1, 0x54, 0x45, 0xe1, 0xa0, 0xe, 0x69, 0xa7, 0x31, 0x2, 0xf3, - 0xd1, 0x57, 0xea, 0x2, 0x93, 0xdc, 0xb6, 0x6, 0x74, 0x3, 0xae, 0xd7, - 0x18, 0x51, 0x6c, 0xf4, 0x96, 0x16, 0x59, 0x90, 0x3a, 0xe, 0x23, 0xf4, - 0x41, 0xc4, 0x43, 0xa2, 0x22, 0xa2, 0xaa, 0xf7, 0x68, 0x72, 0x98, 0x69, - 0x95, 0xc1, 0xc8, 0xf3, 0xc6, 0xb2, 0x9d, 0xc4, 0x5e, 0xbd, 0x56, 0xd8, - 0xc5, 0x21, 0x76, 0x3f, 0x83, 0xbf, 0x4b, 0xb4, 0xd7, 0xc6, 0x67, 0xf5, - 0x49, 0x9, 0x7d, 0x99, 0xee, 0x72, 0x22, 0x6c, 0xc0, 0x6b, 0xe3, 0x3c, - 0x38, 0xb7, 0x37, 0xe2, 0x3c, 0x44, 0x5e, 0x67, 0xbd, 0xff, 0xd3, 0xfa, - 0xe3, 0x56, 0x50, 0x26, 0xc6, 0xbe, 0x2a, 0x4f, 0xba, 0x50, 0xe5, 0x43, - 0xb5, 0x4a, 0xc4, 0xe, 0xe3, 0x67, 0xa5, 0xa9, 0xf, 0x2d, 0xbc, 0x9a, - 0x34, 0xba, 0xed, 0xa1, 0x4f, 0xd9, 0xd, 0x81, 0xf6, 0x44, 0x4c, 0xa2, - 0x4a, 0x69, 0x4c, 0xe2, 0x77, 0xb3, 0x91, 0x9c, 0xa5, 0x9b, 0xe9, 0xa4, - 0xba, 0xbd, 0x84, 0xc9, 0x45, 0x60, 0xdd, 0x5d, 0x27, 0x95, 0x16, 0xa1, - 0x95, 0xfa, 0xf, 0x3c, 0x92, 0xc0, 0xee, 0xc8, 0x6b, 0x25, 0x30, 0xf2, - 0x64, 0x5f, 0x8d, 0x84, 0xd9, 0x34, 0x41, 0x62, 0xdf, 0x4e, 0x5, 0x4f, - 0x8d, 0xa8, 0x90, 0x1b, 0xe, 0xc8, 0xc7, 0xe, 0xdd, 0xd3, 0x47, 0x88, - 0x9a, 0xc5, 0xf8, 0xbf, 0x34, 0x1d, 0x84, 0xd1, 0x67, 0xd3, 0xee, 0x4e, - 0x62, 0x60, 0x66, 0x5a, 0x8f, 0x5c, 0xe4, 0x88, 0xc9, 0xd8, 0x9e, 0xb9, - 0x15, 0xd1, 0x4, 0x70, 0x62, 0x7, 0x4e, 0x4d, 0xfd, 0x25, 0x83, 0xc9, - 0xa4, 0xa7, 0x97, 0xd7, 0xf7, 0x5, 0xca, 0x14, 0x5f, 0xc1, 0x38, 0x34, - 0x4a, 0xc9, 0x7e, 0x2d, 0xdb, 0x1b, 0x4f, 0x3d, 0xab, 0xd3, 0x6a, 0x64, - 0xe9, 0xbf, 0x5a, 0x84, 0xa7, 0xc1, 0x31, 0xf5, 0x45, 0xec, 0x1e, 0x29, - 0x98, 0x1f, 0xc5, 0xab, 0x37, 0xd, 0xcc, 0xf, 0xc4, 0x56, 0x3, 0x6d, - 0xdb, 0xd1, 0x57, 0x4e, 0x9e, 0x9c, 0x64, 0x29, 0x87, 0x95, 0x8c, 0x6d, - 0x3c, 0x4e, 0x68, 0x24, 0xd6, 0x4, 0xc7, 0xed, 0xc1, 0x5f, 0x43, 0x4e, - 0x1c, 0x59, 0x1c, 0x84, 0x58, 0x97, 0xa9, 0xf3, 0x49, 0x90, 0x22, 0x6e, - 0x51, 0xae, 0x96, 0x9f, 0xb3, 0x55, 0x59, 0xf4, 0xc3, 0xfe, 0x87, 0x97, - 0xa8, 0xa6, 0xee, 0x0, 0xae, 0xf2, 0x7e, 0x28, 0xe1, 0xca, 0x83, 0xcc, - 0x1b, 0xf0, 0x56, 0xee, 0xba, 0x25, 0xf6, 0x7e, 0xf4, 0xb6, 0x2e, 0xaf, - 0xbf, 0x6f, 0x3b, 0xac, 0xf0, 0xc5, 0x8d, 0xe7, 0x4b, 0x61, 0x2c, 0x11, - 0xcd, 0x85, 0x5c, 0xe6, 0x3b, 0xbe, 0xa4, 0x3c, 0x5e, 0x15, 0x1f, 0x51, - 0x65, 0xe2, 0xcb, 0xbe, 0x34, 0x27, 0x97, 0x6, 0x7e, 0x35, 0xc8, 0x19, - 0x99, 0xe0, 0x54, 0x64, 0x12, 0x52, 0x1e, 0x97, 0x9f, 0x1, 0x1f, 0x96, - 0x35, 0xdc, 0x56, 0xc6, 0x95, 0xa3, 0x54, 0x1f, 0xc8, 0x20, 0x1e, 0xcc, - 0xe9, 0xf8, 0x7b, 0xf, 0x63, 0x18, 0xd2, 0xfd, 0x64, 0x84, 0x0, 0xdf, - 0x13, 0x33, 0x27, 0x47, 0x6f, 0xb9, 0x92, 0xe, 0x1e, 0xec, 0x25, 0xe5, - 0x77, 0x36, 0xd6, 0x70, 0x91, 0x2e, 0x2a, 0xd7, 0x5c, 0x38, 0xfa, 0x53, - 0xc, 0x1e, 0xae, 0xef, 0x54, 0xbd, 0x91, 0x76, 0x99, 0x2c, 0xbb, 0xa2, - 0xdc, 0xa8, 0x2e, 0xc7, 0x25, 0x4b, 0x66, 0xe3, 0xa5, 0x54, 0x56, 0xa8, - 0x53, 0xc2, 0xe, 0xe8, 0x0, 0xaf, 0xcf, 0x8b, 0xc5, 0x77, 0x74, 0x31, - 0x75, 0xe1, 0x22, 0x24, 0x31, 0xb2, 0x69, 0xec, 0x3, 0x69, 0xa3, 0xf7, - 0x14, 0x69, 0x2e, 0x3d, 0x75, 0x69, 0x9c, 0xaa, 0x52, 0x1, 0xb1, 0x91, - 0x16, 0x9b, 0x95, 0xd4, 0x11, 0x6d, 0x73, 0x1e, 0xb1, 0x5c, 0x5f, 0x9b, - 0xb7, 0x42, 0xf2, 0x3a, 0xc5, 0xc8, 0xad, 0xa7, 0xd, 0x5f, 0x65, 0xe7, - 0x42, 0x86, 0xd, 0x5b, 0x8a, 0x40, 0x15, 0x7a, 0x5c, 0xa1, 0x59, 0x7d, - 0xe7, 0xf6, 0xff, 0xa2, 0x33, 0xb1, 0x6d, 0x97, 0x4b, 0x22, 0xb6, 0x79, - 0xf0, 0xd1, 0x5a, 0x25, 0x6, 0x9c, 0x72, 0xf, 0x95, 0xc6, 0x2e, 0x29, - 0xc8, 0x5, 0x9d, 0x79, 0x1e, 0xc7, 0x10, 0x4a, 0x96, 0xe5, 0xa9, 0x1, - 0x81, 0xc7, 0x87, 0x5a, 0x62, 0xed, 0x4f, 0xa9, 0x24, 0xe6, 0x76, 0x85, - 0x95, 0xf9, 0xf1, 0x73, 0x30, 0xad, 0xd4, 0xbc, 0xeb, 0x91, 0x6a, 0xcc, - 0xfc, 0xb6, 0x18, 0xc2, 0xcb, 0x20, 0x32, 0x7f, 0xd0, 0x4d, 0x55, 0x1c, - 0x91, 0xd5, 0xd4, 0x2, 0x3a, 0xab, 0xcd, 0x61, 0x7, 0x92, 0x31, 0x4e, - 0xc6, 0xdb, 0xed, 0x5, 0x76, 0x2d, 0x2, 0x9a, 0xd8, 0xd2, 0x54, 0x40, - 0x98, 0x79, 0xd2, 0x95, 0xfd, 0xda, 0x1d, 0x8e, 0xf4, 0xc8, 0xd1, 0xe0, - 0x24, 0x8b, 0x7d, 0x5a, 0x7b, 0xfa, 0xa2, 0xc7, 0xe0, 0x14, 0xbc, 0x9, - 0x7e, 0xe8, 0x19, 0x16, 0x93, 0x3a, 0xc6, 0x26, 0x9d, 0x3d, 0x6e, 0xec, - 0x4a, 0x9a, 0x61, 0xc9, 0xc, 0x74, 0x93, 0xd1, 0x41, 0x97, 0x17, 0x88, - 0x40, 0x8e, 0x60, 0x76, 0xdd, 0xb0, 0x46, 0x3e, 0x25, 0xad, 0xa4, 0x5f, - 0x8b, 0x26, 0x81, 0x92, 0x51, 0x77, 0xe, 0x85, 0xa6, 0xb, 0xac, 0x8b, - 0x8c, 0x30, 0x24, 0x88, 0xf1, 0xc5, 0xf2, 0x3a, 0x9d, 0x49, 0x54, 0xe8, - 0x52, 0xe1, 0x20, 0xc8, 0x41, 0xee, 0x46, 0xee, 0x6, 0x40, 0x74, 0x3, - 0x14, 0xe7, 0x96, 0xe4, 0x44, 0xcf, 0xa2, 0xae, 0xf8, 0x9b, 0xcd, 0x5f, - 0x48, 0xc8, 0xb4, 0x27, 0x85, 0x9d, 0x51, 0x8f, 0x73, 0x64, 0x56, 0x9a, - 0xef, 0x87, 0xbf, 0x94, 0x8a, 0x54, 0x1b, 0xd1, 0xc7, 0x7a, 0xd5, 0x2c, - 0xbd, 0xba, 0x3d, 0x1, 0xb4, 0xfa, 0x82, 0x84, 0x88, 0x4c, 0x0, 0x29, - 0x37, 0x4e, 0xc0, 0x23, 0xf2, 0x75, 0x27, 0x55, 0xd5, 0xa8, 0x83, 0xea, - 0x7a, 0xab, 0xd5, 0x5f, 0x79, 0xa6, 0x4f, 0xf2, 0x9b, 0xc0, 0x32, 0x94, - 0xcb, 0x8, 0xa9, 0x92, 0xf7, 0x36, 0xef, 0x9, 0xb9, 0x63, 0x6a, 0xe0, - 0x75, 0x3, 0x26, 0x53, 0xf, 0xda, 0x36, 0x10, 0x29, 0x4c, 0xaf, 0xa9, - 0x75, 0xb0, 0xc0, 0xd7, 0xef, 0xd5, 0xf9, 0x2b, 0xb9, 0x5a, 0xe7, 0xfb, - 0xc1, 0xc7, 0x34, 0x7b, 0x33, 0x55, 0x8, 0xc4, 0x19, 0xf8, 0x7c, 0xa1, - 0x61, 0x0, 0x43, 0x68, 0xf0, 0xf, 0xbc, 0x41, 0xce, 0x78, 0xc9, 0x61, - 0xbb, 0xa3, 0x8e, 0xc1, 0xac, 0x7, 0x8b, 0x80, 0xf9, 0x34, 0x14, 0xe8, - 0xee, 0x2e, 0xb6, 0xb2, 0x82, 0x74, 0x78, 0x96, 0xf0, 0xf2, 0xd5, 0x4f, - 0xaf, 0x16, 0x5f, 0x8c, 0x50, 0xe9, 0xb2, 0x92, 0xbc, 0xe5, 0x68, 0x26, - 0x11, 0xf9, 0xbc, 0xa5, 0xd8, 0xe1, 0xd4, 0xad, 0xc, 0x0, 0xde, 0x3a, - 0x57, 0xfe, 0x4b, 0x63, 0x9a, 0x5b, 0x32, 0xd0, 0x52, 0xc3, 0x88, 0x2b, - 0x26, 0xc2, 0x73, 0x4, 0x1a, 0xf5, 0x92, 0x54, 0x42, 0x35, 0x8e, 0x11, - 0x60, 0xb0, 0x10, 0x6c, 0xb4, 0xe2, 0x3a, 0xdc, 0xec, 0x13, 0xa2, 0x44, - 0xac, 0x95, 0xe5, 0x2c, 0xed, 0x15, 0xe3, 0xdd, 0x52, 0x8, 0x78, 0x21, - 0x76, 0xfa, 0xab, 0x8d, 0x38, 0x28, 0xda, 0x28, 0x2b, 0x55, 0xe2, 0x95, - 0x51, 0xeb, 0x51, 0x20, 0xa3, 0x7e, 0xe9, 0x5a, 0x26, 0xd9, 0x5, 0x7d, - 0x76, 0x55, 0xb6, 0xd8, 0x5b, 0x37, 0x8e, 0xda, 0x2f, 0x71, 0x12, 0xc9, - 0x9b, 0xdf, 0x3d, 0x6e, 0x8c, 0xf0, 0xe4, 0xb1, 0x9, 0xe4, 0x5, 0x54, - 0x56, 0x23, 0xf3, 0x7e, 0x6, 0x23, 0xc6, 0xf4, 0x7f, 0x7f, 0x7f, 0xe7, - 0x7c, 0x23, 0x9c, 0xc4, 0x55, 0x38, 0x3b, 0x59, 0xe3, 0x37, 0x9f, 0xfc, - 0x6e, 0x89, 0x6d, 0x8d, 0x33, 0xfc, 0x15, 0x68, 0xda, 0x56, 0x8e, 0x14, - 0x57, 0x3e, 0x8b, 0x7, 0xa3, 0xce, 0xe2, 0x8e, 0x43, 0xef, 0x94, 0xaf, - 0x2d, 0x10, 0xa3, 0x45, 0xb2, 0x68, 0x8e, 0xd7, 0xf4, 0xe0, 0x2c, 0x62, - 0x7d, 0x98, 0x7c, 0xe3, 0xc9, 0x8a, 0x99, 0x7a, 0xdb, 0x63, 0xe, 0xb1, - 0x6f, 0x81, 0xfd, 0x60, 0x8d, 0xaa, 0x9e, 0x53, 0x7a, 0xa3, 0x31, 0x7f, - 0x1c, 0xbf, 0x0, 0xe9, 0x4c, 0xd, 0x2b, 0xa5, 0x49, 0x23, 0xff, 0x20, - 0x62, 0xcf, 0xc9, 0x4e, 0x2e, 0xd3, 0x26, 0xaf, 0xdf, 0xe7, 0xef, 0xbf, - 0xad, 0x3f, 0xa7, 0xb, 0x47, 0x8, 0xc9, 0x59, 0xb1, 0x59, 0xfa, 0xc6, - 0x39, 0xb9, 0x27, 0xdf, 0x7a, 0xbb, 0x6c, 0xde, 0x9d, 0x81, 0x9a, 0xee, - 0x4a, 0x9e, 0x8a, 0xc6, 0xd4, 0x48, 0xe9, 0xc9, 0x94, 0x57, 0x6e, 0x84, - 0x46, 0x69, 0x62, 0x9f, 0x89, 0x94, 0x38, 0x4a, 0xc1, 0xa9, 0x5a, 0x22, - 0x91, 0x3e, 0xcf, 0x1d, 0x83, 0x7a, 0xe6, 0x7c, 0x8d, 0x74, 0x7, 0x7f, - 0xf8, 0x44, 0xb5, 0x3f, 0xda, 0x65, 0xe8, 0x2b, 0x9b, 0x1, 0x51, 0x1b, - 0x89, 0xb0, 0x5c, 0x27, 0x94, 0x1, 0x43, 0x1d, 0x2c, 0x19, 0xcd, 0xda, - 0xdd, 0x9d, 0x20, 0xe3, 0x24, 0x3, 0x88, 0x83, 0x5, 0xd6, 0x83, 0xee, - 0x3d, 0x3c, 0x77, 0x14, 0xfd, 0x82, 0x3b, 0x0, 0xbd, 0xb5, 0x0, 0x56, - 0x59, 0x6b, 0xfb, 0xeb, 0x69, 0xbc, 0xe1, 0xe2, 0x57, 0x53, 0x9f, 0xf6, - 0xdc, 0x1a, 0x5a, 0x96, 0xea, 0xc6, 0x61, 0x1b, 0xd9, 0x15, 0x14, 0xce, - 0xd2, 0x3c, 0x59, 0x9a, 0x78, 0x94, 0x5a, 0xe7, 0xd8, 0xea, 0x87, 0xee, - 0xcd, 0x9d, 0x54, 0xd6, 0xce, 0x9a, 0x91, 0xab, 0x49, 0x61, 0x9, 0xa4, - 0x5b, 0x9f, 0x78, 0x75, 0xdc, 0x45, 0x7a, 0x34, 0xd1, 0xfb, 0x5c, 0xc0, - 0x95, 0xe4, 0x49, 0x4f, 0x8a, 0xda, 0xcf, 0x4a, 0x27, 0x3, 0x1b, 0x59, - 0xcf, 0x23, 0x19, 0xcc, 0x75, 0xdf, 0x26, 0xa6, 0x3c, 0xfa, 0x7f, 0x6d, - 0x90, 0x8e, 0xcf, 0xc, 0x5e, 0x94, 0x38, 0x1e, 0xe4, 0x82, 0x78, 0xd1, - 0x4c, 0xcc, 0xac, 0xe8, 0x4d, 0x87, 0xf2, 0x95, 0x8, 0xa3, 0xd6, 0xf4, - 0x5a, 0x46, 0xde, 0x0, 0x4f, 0x86, 0x2f, 0xf4, 0x15, 0x2d, 0xe7, 0x90, - 0x11, 0x40, 0xb6, 0xa7, 0x5c, 0x4f, 0x3, 0x28, 0x4a, 0x8b, 0x1d, 0x47, - 0xfb, 0x49, 0x77, 0x65, 0x83, 0x1e, 0x18, 0xfd, 0xe7, 0x5e, 0x5c, 0x3a, - 0x21, 0x7f, 0xff, 0xf8, 0x2a, 0x5e, 0x6b, 0xba, 0x19, 0xf2, 0x6e, 0x2b, - 0x17, 0x80, 0xa7, 0x5b, 0xf7, 0xb2, 0xa3, 0xc3, 0x37, 0x2b, 0xd9, 0x29, - 0x25, 0x9c, 0x98, 0x6e, 0x5c, 0xed, 0x1d, 0x8f, 0xf4, 0xcb, 0xb6, 0x43, - 0x80, 0xf8, 0x4d, 0x7d, 0xe8, 0x94, 0xd1, 0x44, 0x2f, 0x7e, 0xb6, 0x80, - 0xc0, 0x1, 0xc5, 0xc6, 0xb, 0xfc, 0x1, 0xc7, 0x11, 0x13, 0x90, 0xcb, - 0x29, 0x64, 0xbf, 0xfa, 0x84, 0xde, 0x50, 0x91, 0xfa, 0x8d, 0x87, 0x8c, - 0xc, 0x19, 0x4b, 0x83, 0x4e, 0x8a, 0x83, 0xb8, 0xbc, 0x79, 0x5f, 0x8d, - 0xe3, 0x19, 0x9a, 0xae, 0xdd, 0xe6, 0x8f, 0xda, 0xb2, 0x11, 0x63, 0xe9, - 0x44, 0x4c, 0x20, 0x11, 0x1d, 0x27, 0x63, 0x10, 0xf9, 0x70, 0x1d, 0x42, - 0xf, 0x3f, 0x8b, 0x30, 0x92, 0x66, 0x7c, 0x20, 0x9e, 0xfc, 0xf6, 0x87, - 0x6b, 0x3b, 0xc4, 0x8f, 0x8, 0xdf, 0x74, 0x92, 0xb8, 0x7, 0xc4, 0x47, - 0x6b, 0xe9, 0xc0, 0x93, 0xc7, 0x27, 0x7f, 0xc4, 0x42, 0xaf, 0xde, 0x10, - 0xfb, 0x8d, 0x7b, 0x3f, 0xba, 0x5, 0x71, 0x43, 0xc3, 0xa7, 0xc1, 0x65, - 0x35, 0x52, 0xba, 0xb7, 0xe3, 0x4a, 0x9e, 0x7, 0xb4, 0x95, 0x74, 0x82, - 0x60, 0x9f, 0xbc, 0x84, 0xf4, 0xa4, 0x82, 0x37, 0xcf, 0x12, 0x44, 0x15, - 0xed, 0x68, 0x1f, 0x6b, 0x4c, 0xbc, 0xe8, 0xd8, 0x2e, 0x9e, 0x81, 0x87, - 0x4a, 0x40, 0xf2, 0x1e, 0xd0, 0x60, 0xee, 0xeb, 0x5e, 0x4d, 0x44, 0xc8, - 0x9, 0x11, 0x77, 0x5d, 0xa5, 0x1b, 0xf3, 0x1a, 0x31, 0xbe, 0xba, 0x7d, - 0x33, 0x97, 0x36, 0xcd, 0x91, 0xea, 0x1c, 0xc7, 0xbf, 0x1d, 0xd0, 0x3e, - 0x24, 0x7c, 0x10, 0x6c, 0xbb, 0x5c, 0xfd, 0xbe, 0xde, 0xdb, 0x48, 0x1a, - 0xbf, 0x91, 0x1b, 0xe7, 0x7e, 0xc2, 0xb, 0x7c, 0x36, 0x13, 0xb1, 0x18, - 0xad, 0x60, 0xf2, 0x1d, 0x2b, 0xb1, 0x88, 0xb1, 0x72, 0x7a, 0x7a, 0xa0, - 0xe6, 0x38, 0xde, 0xa4, 0x86, 0xfc, 0x43, 0xc4, 0xa1, 0xa6, 0xf5, 0x2f, - 0x9a, 0x9e, 0x5, 0xf1, 0xef, 0xaa, 0x42, 0x40, 0xe2, 0xba, 0x81, 0x3e, - 0xa, 0x5f, 0xa0, 0xa6, 0x37, 0x5a, 0xc8, 0x4b, 0x7, 0x60, 0x5f, 0xb6, - 0xf8, 0x70, 0xd6, 0x5c, 0x85, 0x97, 0x1a, 0x66, 0x7c, 0xae, 0x9d, 0xd7, - 0xb4, 0xfa, 0x94, 0x3a, 0x2f, 0x1e, 0x1f, 0xee, 0x2b, 0x45, 0xa6, 0xc6, - 0xd7, 0x9b, 0xec, 0x7b, 0x3e, 0xf8, 0xc, 0x4f, 0x6a, 0xad, 0x6e, 0xc7, - 0x9d, 0xee, 0xc, 0x29, 0x9, 0xfc, 0x86, 0x4b, 0xe4, 0x8, 0x44, 0x2a, - 0x6f, 0xbc, 0xea, 0x9f, 0xcf, 0x58, 0xb1, 0x36, 0x2f, 0xce, 0xb4, 0x93, - 0xae, 0x67, 0xca, 0xe5, 0x3b, 0xed, 0xe0, 0x6d, 0xaf, 0xc7, 0x9, 0xc8, - 0x42, 0x3d, 0x9a, 0x33, 0xc5, 0x80, 0x72, 0x1, 0xd3, 0x67, 0xbf, 0x2f, - 0x9c, 0xe1, 0xb9, 0x4d, 0x0, 0x58, 0x5e, 0x94, 0x9a, 0xda, 0x72, 0xc5, - 0x17, 0x81, 0xd8, 0xb6, 0xcd, 0xa8, 0xf6, 0xed, 0x91, 0x43, 0xa2, 0x82, - 0x80, 0x7d, 0xa, 0x75, 0xe4, 0xef, 0x2, 0xb9, 0x1, 0x5a, 0x6a, 0xd4, - 0x47, 0x70, 0x2c, 0x66, 0x2c, 0x39, 0xcb, 0xad, 0xd5, 0x89, 0x89, 0x4a, - 0x39, 0x59, 0x7d, 0xd6, 0x6a, 0x27, 0x2c, 0x7a, 0xcc, 0xc9, 0x85, 0xe2, - 0xc5, 0x50, 0xf7, 0x13, 0xfc, 0x41, 0x1a, 0xaa, 0x24, 0x66, 0x88, 0x54, - 0x99, 0xe1, 0x72, 0x2a, 0xd4, 0x42, 0x67, 0x4d, 0xa2, 0x81, 0x27, 0xce, - 0xd, 0x7e, 0x7f, 0x81, 0x44, 0xaa, 0x92, 0x69, 0x75, 0x3c, 0xb, 0x60, - 0xa5, 0xa3, 0xd0, 0x45, 0x56, 0x17, 0x58, 0xce, 0xdd, 0x9f, 0x4e, 0x32, - 0x25, 0x98, 0x4b, 0xfb, 0xd0, 0xf0, 0x4b, 0x24, 0x1a, 0xb2, 0xec, 0xca, - 0x16, 0x74, 0xdf, 0xf8, 0x4, 0x27, 0x64, 0xf3, 0x85, 0x9, 0x11, 0x2a, - 0xf6, 0x43, 0x40, 0x4c, 0x3a, 0xe1, 0x4d, 0xdb, 0x2, 0xd1, 0xb7, 0x29, - 0x2f, 0x9e, 0x38, 0x4f, 0xb0, 0x6, 0xb8, 0xe5, 0xc3, 0x18, 0x54, 0xb9, - 0x49, 0xcb, 0x4a, 0xc9, 0x47, 0xba, 0x3a, 0x67, 0x1, 0x10, 0x76, 0x1a, - 0xe8, 0xa7, 0xd6, 0x9b, 0x78, 0x9d, 0xf5, 0xb2, 0xf8, 0xb5, 0x24, 0x45, - 0xf, 0x92, 0x64, 0x19, 0xe7, 0x78, 0x1d, 0xdb, 0x43, 0x2a, 0x27, 0x6a, - 0x66, 0xdf, 0xc1, 0xc2, 0x59, 0xf8, 0x4f, 0x76, 0xd3, 0x87, 0x75, 0x46, - 0x9d, 0xd9, 0xd8, 0x4d, 0xd3, 0xcf, 0x92, 0x7d, 0x4f, 0x4e, 0x90, 0xc9, - 0x6c, 0x7a, 0x42, 0x71, 0x99, 0xc1, 0x2a, 0xb0, 0x31, 0x80, 0x33, 0x30, - 0x78, 0x5c, 0xac, 0x12, 0xa3, 0x8b, 0x7, 0x4a, 0x36, 0x1c, 0xf9, 0xcc, - 0xc, 0xb4, 0xec, 0x34, 0x68, 0xa6, 0x21, 0x81, 0xe4, 0x65, 0x2f, 0x2c, - 0x18, 0x20, 0x55, 0x4, 0xad, 0xf4, 0x21, 0x43, 0x3b, 0xb0, 0xfc, 0xe3, - 0xea, 0x39, 0x4f, 0x51, 0x77, 0x7e, 0xa8, 0xd, 0x8b, 0xb9, 0xef, 0x9c, - 0x2d, 0xfd, 0x4b, 0x2a, 0xac, 0x34, 0x4a, 0x60, 0xb7, 0xa6, 0xa5, 0x8c, - 0xd8, 0x2d, 0x45, 0x1b, 0x0, 0xe7, 0xdd, 0x2d, 0xeb, 0x9d, 0x7e, 0x4c, - 0x49, 0xa8, 0xe6, 0x8d, 0x48, 0xde, 0x8b, 0x98, 0xff, 0x4f, 0xd5, 0x16, - 0x8, 0x6, 0x36, 0x7a, 0xe1, 0x7d, 0x2a, 0x85, 0xc8, 0xb1, 0x6f, 0x3e, - 0xb2, 0x10, 0x90, 0x91, 0xdc, 0x56, 0xb, 0xbf, 0xe5, 0x46, 0xa6, 0x56, - 0x4e, 0x9c, 0x2d, 0xdd, 0x34, 0x0, 0xe1, 0xe9, 0xf7, 0xaf, 0x90, 0x63, - 0x32, 0x74, 0x35, 0xfd, 0xf5, 0x28, 0x73, 0x81, 0x32, 0x50, 0x42, 0x11, - 0xbe, 0x33, 0x77, 0x6a, 0xea, 0x29, 0xdf, 0x98, 0x6e, 0xeb, 0xc6, 0x2f, - 0x5a, 0x5a, 0x93, 0xd9, 0xdf, 0xc8, 0x41, 0x33, 0x3c, 0xae, 0xc7, 0x2f, - 0x35, 0x1c, 0xce, 0x5b, 0xa8, 0x68, 0x3e, 0x43, 0x73, 0x62, 0x30, 0xd3, - 0xa3, 0xfc, 0x61, 0x2c, 0x95, 0xe0, 0xdb, 0xf, 0x35, 0x96, 0x1c, 0x28, - 0xb9, 0x6e, 0xbb, 0xda, 0x96, 0xf2, 0x92, 0x5a, 0x7, 0xbf, 0x4c, 0xd1, - 0xe1, 0x77, 0x14, 0x90, 0xb6, 0x48, 0x2b, 0xc1, 0x3e, 0xe4, 0x9a, 0xfe, - 0x3c, 0xbc, 0xf4, 0xf1, 0x1f, 0x54, 0x17, 0xdd, 0x85, 0xf5, 0xc3, 0x7b, - 0xda, 0xca, 0x9e, 0xc8, 0x91, 0xe9, 0xbd, 0xc7, 0xa3, 0x51, 0x4e, 0x3d, - 0x55, 0xd9, 0xf7, 0x79, 0x1b, 0xbf, 0x69, 0xa3, 0x58, 0x4d, 0x96, 0xd8, - 0x57, 0x3a, 0x49, 0x71, 0x38, 0xe, 0xec, 0x68, 0x73, 0x8f, 0x2b, 0xbc, - 0xb9, 0x53, 0x43, 0x11, 0xc8, 0xff, 0x92, 0x81, 0x7d, 0xe6, 0x29, 0xdf, - 0x7a, 0xb0, 0xd3, 0x7f, 0x31, 0xa, 0xef, 0xce, 0xac, 0xdd, 0x57, 0xbb, - 0x3a, 0x0, 0x87, 0x57, 0x7, 0xce, 0x84, 0xa7, 0x5, 0x76, 0x10, 0xe0, - 0x69, 0xf3, 0xec, 0xa5, 0x12, 0x91, 0x97, 0x5d, 0x83, 0xd5, 0x35, 0xba, - 0x30, 0xe1, 0xf1, 0x1, 0x49, 0xe1, 0x86, 0x50, 0xd4, 0x52, 0x32, 0x73, - 0xc7, 0xab, 0x1a, 0xe6, 0xb2, 0xab, 0xff, 0x77, 0xc4, 0x14, 0x20, 0xad, - 0xd1, 0xbf, 0x69, 0xc6, 0x11, 0x4c, 0x24, 0x3e, 0x1d, 0xc9, 0x84, 0x9d, - 0xe2, 0xa6, 0xc8, 0x4d, 0xed, 0xf5, 0x84, 0x74, 0xae, 0x68, 0x17, 0x70, - 0x59, 0xe, 0xeb, 0xe2, 0xda, 0x83, 0x21, 0xfd, 0x81, 0x66, 0x21, 0x61, - 0x47, 0xb2, 0xb7, 0xa5, 0x9a, 0x95, 0xf8, 0x91, 0x51, 0x5c, 0xf8, 0x63, - 0x52, 0xe2, 0x5a, 0x5e, 0x58, 0xd3, 0xda, 0x74, 0x68, 0xba, 0xfe, 0xda, - 0xe7, 0x96, 0xd8, 0x61, 0x5c, 0xf6, 0x7c, 0xd, 0x1d, 0xb1, 0x80, 0x1b, - 0x7f, 0x5e, 0x85, 0x4a, 0xfe, 0xe, 0x62, 0x65, 0x77, 0x84, 0xe, 0x4e, - 0x59, 0xfc, 0x7d, 0xc2, 0xe4, 0x7d, 0x43, 0x27, 0x6d, 0xc7, 0x4, 0xb8, - 0x47, 0xe, 0x8c, 0x25, 0xec, 0x25, 0x9d, 0x88, 0x16, 0x73, 0x7d, 0x6f, - 0x46, 0x24, 0xd5, 0x16, 0x14, 0xde, 0x54, 0x94, 0xed, 0x1c, 0x9e, 0xe3, - 0x6d, 0xb3, 0xe1, 0x57, 0xab, 0xab, 0x87, 0xbb, 0xf7, 0x6c, 0x87, 0xcf, - 0x94, 0xde, 0x8d, 0x23, 0xe2, 0x9d, 0xbb, 0x93, 0xf8, 0x69, 0x43, 0x74, - 0x22, 0x31, 0x85, 0x8e, 0x6a, 0x91, 0x9, 0x9e, 0xac, 0xc9, 0xdb, 0xe6, - 0xec, 0x39, 0xe3, 0x86, 0x42, 0xd3, 0xfc, 0xbe, 0x57, 0xdb, 0x7c, 0xa7, - 0x9b, 0x5, 0xed, 0x8e, 0x26, 0xde, 0x5a, 0xc4, 0xe2, 0x4b, 0xa2, 0x13, - 0xd8, 0x59, 0x9d, 0x67, 0x3, 0x6a, 0x93, 0x68, 0x41, 0x34, 0x5, 0xfd, - 0x1e, 0x65, 0xdf, 0xac, 0xbe, 0xa6, 0x17, 0xf1, 0x56, 0x92, 0x7a, 0xfe, - 0x80, 0xbd, 0xd9, 0xfa, 0xb6, 0x37, 0x2d, 0x56, 0x23, 0xc9, 0x5d, 0x87, - 0x1c, 0xa9, 0x7, 0xbc, 0xf3, 0x3c, 0x28, 0xdc, 0x4d, 0x85, 0x29, 0x72, - 0x64, 0x7, 0x49, 0x6f, 0x96, 0xae, 0xb4, 0x55, 0xc8, 0x18, 0xfe, 0xb, - 0x36, 0x10, 0xc8, 0xbd, 0x5b, 0x66, 0xd, 0xef, 0xf5, 0x22, 0xe9, 0x5e, - 0x39, 0x2e, 0xb5, 0x2a, 0x36, 0x2a, 0x53, 0x8e, 0xda, 0x7c, 0x3d, 0xbb, - 0xc, 0x7d, 0x27, 0x5a, 0x21, 0x7a, 0xf8, 0xb3, 0xd2, 0x26, 0x1f, 0x0, - 0xe5, 0x13, 0xee, 0x70, 0x56, 0x6d, 0x85, 0x30, 0x24, 0x10, 0xe7, 0x49, - 0x11, 0x5c, 0xec, 0x3a, 0x5, 0x74, 0xc7, 0xe7, 0x51, 0x93, 0x5, 0x3a, - 0x7c, 0x96, 0x43, 0xe7, 0xd4, 0x5d, 0x32, 0x62, 0xf7, 0xff, 0x3a, 0xc7, - 0x72, 0xba, 0x91, 0x59, 0x86, 0xa, 0x7d, 0x84, 0xd4, 0xd4, 0x0, 0x1d, - 0xe3, 0xb9, 0x1a, 0xc5, 0xa2, 0xed, 0x67, 0xc2, 0x4f, 0xe3, 0xeb, 0xd0, - 0xae, 0x1a, 0x49, 0x55, 0x50, 0x57, 0xf0, 0x78, 0xc8, 0xbc, 0x20, 0x8, - 0x6a, 0x4, 0x1c, 0x21, 0xa1, 0xf, 0x5b, 0x9d, 0xad, 0xc1, 0x22, 0x26, - 0xe0, 0x50, 0x8, 0x1f, 0xfe, 0xe5, 0x8c, 0x9e, 0xf7, 0xd9, 0x3d, 0x92, - 0xed, 0xb3, 0x7d, 0x7e, 0xa6, 0xac, 0x3a, 0x57, 0xaa, 0x4c, 0xb3, 0xb, - 0xc0, 0x86, 0xd2, 0x9b, 0x2e, 0xbe, 0xbe, 0xfd, 0xc2, 0xc2, 0xd6, 0xe7, - 0xec, 0x53, 0x4, 0xe9, 0x21, 0x81, 0x1f, 0x37, 0xe4, 0xbe, 0xa9, 0x92, - 0x72, 0x7d, 0x9f, 0x9a, 0xe8, 0x80, 0x2d, 0xe5, 0x6f, 0xbb, 0x21, 0xbd, - 0x7d, 0xbe, 0xee, 0xac, 0x11, 0x3c, 0x7b, 0x15, 0x16, 0x27, 0xa7, 0x13, - 0x42, 0x40, 0xa3, 0x73, 0xf7, 0x3b, 0xd9, 0xf2, 0xc9, 0x69, 0x5f, 0xed, - 0xbf, 0x2e, 0xd6, 0x4e, 0xe5, 0x17, 0x95, 0x1c, 0xdd, 0x81, 0xae, 0x64, - 0x6a, 0x2c, 0x15, 0x6f, 0xe4, 0x37, 0x65, 0x26, 0xd6, 0xd0, 0x86, 0x48, - 0x4d, 0x3d, 0xa1, 0x2e, 0x9e, 0xd4, 0xd4, 0x8d, 0xd2, 0x33, 0x6c, 0x8b, - 0x1d, 0x50, 0x3e, 0x1e, 0xe0, 0xad, 0x9a, 0xe7, 0x45, 0x17, 0xa8, 0xbe, - 0x52, 0x13, 0xec, 0x5d, 0x8d, 0x10, 0x85, 0x1a, 0xf7, 0xbc, 0x98, 0xe8, - 0x57, 0xbd, 0x75, 0x1d, 0x7a, 0xb9, 0x7f, 0xf1, 0xa1, 0x83, 0x8f, 0x53, - 0x5f, 0xc7, 0x8, 0x31, 0x86, 0xb3, 0x33, 0x73, 0xa1, 0x6a, 0xce, 0x88, - 0x8b, 0x5d, 0xe4, 0x3f, 0x90, 0x1b, 0x4e, 0xb, 0x51, 0x2f, 0xb3, 0x4b, - 0x60, 0x9f, 0xf6, 0xc7, 0x90, 0xfb, 0x4c, 0x38, 0xd6, 0xaa, 0xc0, 0x78, - 0x52, 0x9a, 0x85, 0xf0, 0x1, 0xeb, 0xd0, 0x4c, 0xc8, 0x72, 0x39, 0x75, - 0x22, 0xae, 0xd1, 0x62, 0x9d, 0x4f, 0x4e, 0xf3, 0xdd, 0x1b, 0x89, 0x9f, - 0x1e, 0x4f, 0x8a, 0x45, 0xd6, 0x4e, 0x15, 0xef, 0xf2, 0x6b, 0x32, 0x15, - 0x5b, 0xf8, 0x94, 0xbb, 0x1, 0x25, 0xd2, 0xf1, 0x77, 0x7a, 0x9b, 0x73, - 0xc4, 0xe4, 0x2d, 0x3f, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, - 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, - 0x96, 0xf6, 0x93, 0xd, 0x9d, 0xce, 0xd2, 0xdd, 0x5e, 0x30, 0xaf, 0x79, - 0x5e, 0x2d, 0x5b, 0x8c, 0xac, 0x2, 0x2a, 0x7e, 0xbb, 0x7b, 0xb7, 0xb6, - 0xd6, 0x1d, 0xf0, 0x24, 0xd, 0x14, 0xd0, 0x5a, 0x22, 0xea, 0xda, 0x95, - 0x3a, 0xd1, 0x12, 0x93, 0xd3, 0xb2, 0xc8, 0xbd, 0x37, 0xbf, 0xc3, 0xfa, - 0x2d, 0x7c, 0x3, 0x7d, 0xab, 0xdc, 0xf6, 0x40, 0x5e, 0xad, 0x77, 0xa, - 0x21, 0xe3, 0xc0, 0xec, 0x42, 0x3b, 0x2b, 0xf3, 0xa6, 0x7d, 0x59, 0x5b, - 0xe8, 0xcf, 0x5, 0x5c, 0x75, 0xb5, 0x6f, 0x10, 0x7a, 0xa3, 0xb8, 0x71, - 0xaa, 0x39, 0xe0, 0x13, 0x5e, 0xa2, 0x7, 0xa5, 0x85, 0xd4, 0x4c, 0xb6, - 0x13, 0x94, 0xe0, 0x62, 0xc0, 0xb2, 0xa4, 0xbe, 0x96, 0xe5, 0x3, 0xf2, - 0xb5, 0xd7, 0x93, 0x69, 0xb5, 0x85, 0x4a, 0x84, 0x92, 0xc7, 0x45, 0xf5, - 0xec, 0x5b, 0x91, 0x6a, 0xf7, 0x64, 0xf7, 0x4, 0x70, 0x88, 0x5c, 0xca, - 0xf, 0xa1, 0x91, 0x12, 0x6d, 0x7a, 0xe9, 0x4b, 0xc, 0x7c, 0x1b, 0x1b, - 0x5e, 0xba, 0x13, 0xd6, 0x88, 0x9b, 0xc1, 0x19, 0x6a, 0x30, 0xa2, 0xc2, - 0x3a, 0x1e, 0x21, 0x5b, 0xc3, 0x2, 0x3f, 0xbb, 0xf6, 0x1c, 0x56, 0x60, - 0xf9, 0xb7, 0xad, 0xaa, 0x7, 0x62, 0x37, 0xbb, 0xcc, 0xd5, 0x1d, 0xeb, - 0x92, 0x12, 0x37, 0x75, 0xcb, 0x4f, 0xeb, 0x44, 0x7a, 0x3c, 0xd4, 0xc5, - 0x3e, 0x2f, 0x73, 0x9b, 0x50, 0x12, 0x8d, 0xa7, 0x7f, 0xe6, 0xe6, 0xc0, - 0xe, 0x47, 0x39, 0x60, 0x3a, 0x9b, 0x26, 0x93, 0x4d, 0xa3, 0xef, 0xc9, - 0x8a, 0xa7, 0x69, 0xfb, 0x8f, 0x68, 0x3a, 0x93, 0x6a, 0x44, 0x28, 0x33, - 0x15, 0xdd, 0xcb, 0x0, 0xe8, 0xcd, 0x43, 0xeb, 0xd0, 0x6b, 0xeb, 0x2b, - 0x10, 0x9a, 0x9f, 0x7a, 0x40, 0xf5, 0x62, 0xa3, 0x78, 0xb2, 0xfa, 0x29, - 0xcb, 0x21, 0xec, 0xcd, 0x4c, 0xd6, 0xd9, 0x75, 0xc0, 0xb8, 0x53, 0xa9, - 0x5f, 0xc2, 0x25, 0x1c, 0x29, 0xed, 0x9, 0x25, 0xf, 0xf7, 0xd5, 0xc1, - 0x4d, 0xd9, 0x97, 0x23, 0x38, 0xda, 0x78, 0x1c, 0x93, 0x6f, 0xca, 0x3c, - 0xd0, 0xa6, 0xbd, 0x17, 0xa6, 0xc4, 0xd5, 0xa4, 0x6c, 0x8a, 0x9e, 0xa3, - 0x94, 0x83, 0xb4, 0xbf, 0x20, 0x35, 0xbd, 0x68, 0xeb, 0x7e, 0x71, 0xc4, - 0xc0, 0x49, 0x47, 0xbd, 0x8b, 0xe9, 0x96, 0x74, 0x4d, 0xe7, 0xd1, 0xe9, - 0xcf, 0x7, 0x79, 0xf5, 0x7f, 0x21, 0x52, 0x9a, 0x50, 0x2, 0xdc, 0x8b, - 0xb0, 0x63, 0xb1, 0x34, 0xb8, 0x7b, 0x6b, 0x3f, 0xa3, 0xa7, 0xa0, 0x2f, - 0xfa, 0xb3, 0xd3, 0xbe, 0xd3, 0xd4, 0xa6, 0xde, 0x30, 0x7c, 0x1, 0x86, - 0x3e, 0xa1, 0xd, 0x11, 0x1d, 0xd8, 0xe1, 0x90, 0xd2, 0x6e, 0x2a, 0x81, - 0x2e, 0x43, 0xb5, 0x46, 0x45, 0xc6, 0x47, 0x80, 0xab, 0x8d, 0x6c, 0xc6, - 0xd2, 0xe1, 0xe4, 0x76, 0x6e, 0x2a, 0x3d, 0x1b, 0x73, 0x5b, 0x24, 0x36, - 0x61, 0xda, 0x6d, 0x30, 0xd3, 0x1a, 0x3, 0xf, 0x26, 0x67, 0x8f, 0x9f, - 0xbc, 0xc1, 0xed, 0x90, 0x8e, 0xaf, 0x6b, 0x9a, 0xc4, 0x1d, 0xad, 0x1e, - 0x4d, 0xbc, 0xe, 0xfa, 0x17, 0xde, 0xcc, 0x7b, 0xd0, 0x5a, 0xb2, 0x53, - 0x71, 0x8f, 0xf2, 0x45, 0x69, 0x38, 0xe0, 0xd3, 0xd4, 0xd2, 0xab, 0xad, - 0xe0, 0x3, 0x3, 0x58, 0xe, 0xcc, 0xe9, 0x65, 0x52, 0x1f, 0xe, 0xc3, - 0x9d, 0x68, 0x4a, 0xc3, 0x22, 0x71, 0x67, 0x22, 0x41, 0x50, 0x8, 0x28, - 0xb2, 0x26, 0x0, 0x8a, 0x52, 0xf3, 0x66, 0xa8, 0x6e, 0xa1, 0x33, 0x2c, - 0xab, 0x5a, 0x29, 0x69, 0x46, 0x73, 0xeb, 0x2c, 0xa8, 0xbe, 0x3f, 0xc6, - 0xd7, 0x32, 0x14, 0x3d, 0x56, 0xf6, 0xdf, 0x8c, 0x65, 0x68, 0x87, 0xfd, - 0xf2, 0xdc, 0xcc, 0x71, 0x21, 0xd0, 0x13, 0xe, 0x56, 0x94, 0xa0, 0x1a, - 0xf2, 0x11, 0x7a, 0xe, 0x2b, 0x87, 0x98, 0x48, 0xb8, 0x76, 0xda, 0xf3, - 0xeb, 0x30, 0xc, 0xa8, 0x87, 0x4a, 0x91, 0xb7, 0x95, 0xf0, 0x86, 0x5, - 0xe2, 0xd7, 0xd6, 0xf9, 0x5, 0xbd, 0x3, 0x62, 0x90, 0x32, 0x37, 0xb4, - 0xf, 0x29, 0xaf, 0x7, 0x6d, 0x82, 0x56, 0x97, 0xb3, 0x9c, 0x55, 0x33, - 0xd7, 0x24, 0x1d, 0x7, 0xc7, 0xf, 0x3e, 0x18, 0xd4, 0x69, 0xd4, 0x35, - 0xb4, 0x5, 0x13, 0xf3, 0xe, 0xe1, 0xf8, 0x19, 0x21, 0x7, 0x46, 0xa4, - 0x57, 0x93, 0x7, 0x2f, 0x49, 0x30, 0x3c, 0xa6, 0xde, 0x4, 0xee, 0x33, - 0xe3, 0x4d, 0x4, 0x46, 0xca, 0x6b, 0xe6, 0xda, 0x87, 0x44, 0x9f, 0xf5, - 0xc7, 0xce, 0x60, 0x66, 0x32, 0xde, 0x89, 0xc5, 0x23, 0xd, 0xe3, 0x53, - 0xdd, 0x99, 0xd1, 0x17, 0x81, 0x83, 0x7b, 0x7c, 0xb6, 0xed, 0x8c, 0xaa, - 0x6c, 0x5e, 0x7b, 0xba, 0x58, 0x89, 0x61, 0xea, 0x2f, 0x15, 0xa6, 0x67, - 0x6d, 0x2, 0x91, 0xd6, 0x7, 0x2f, 0x68, 0xaa, 0xf1, 0x7, 0x73, 0x1c, - 0xe1, 0xc9, 0x98, 0xc, 0x61, 0xfa, 0x52, 0x63, 0x8f, 0x14, 0xb0, 0x54, - 0x64, 0xd9, 0xfe, 0x2d, 0x74, 0x5c, 0x80, 0x36, 0x86, 0xb, 0xb9, 0xe2, - 0xf7, 0x45, 0xb3, 0x56, 0xb8, 0x49, 0x21, 0x39, 0x2f, 0x90, 0xf3, 0x3d, - 0x2f, 0xb8, 0xc8, 0x9c, 0x2a, 0x3b, 0xb5, 0x99, 0x35, 0xa5, 0x31, 0xaa, - 0x1d, 0x30, 0xf, 0x12, 0xe0, 0x43, 0xaa, 0xf9, 0xd5, 0x5f, 0x75, 0xcf, - 0xda, 0xd2, 0x92, 0x7a, 0x73, 0xc2, 0x93, 0x5a, 0xdf, 0x3d, 0x92, 0x3a, - 0x32, 0xa9, 0xd4, 0x4f, 0x88, 0xb0, 0x4d, 0xdf, 0xf4, 0xb7, 0xa9, 0x81, - 0xa8, 0x68, 0x1f, 0x3, 0xd4, 0x5f, 0xe6, 0xd0, 0x36, 0x8d, 0x6c, 0xa, - 0x2b, 0x32, 0x83, 0x75, 0xfa, 0x76, 0xd0, 0xc3, 0xc6, 0xcd, 0xd1, 0xb0, - 0x58, 0x7a, 0xa0, 0x28, 0xe8, 0xf1, 0x94, 0xcd, 0xb9, 0x97, 0x6d, 0xc0, - 0x8f, 0xd3, 0xc8, 0xd8, 0x11, 0xcf, 0xc8, 0x5f, 0xa6, 0x3e, 0xfd, 0x22, - 0x2, 0xcc, 0x7, 0xc9, 0x3f, 0xf9, 0x9e, 0x6d, 0x79, 0x5a, 0xa5, 0x7f, - 0x40, 0x58, 0x2c, 0x64, 0xa8, 0x9c, 0x26, 0x6c, 0xbe, 0x93, 0x9, 0xf7, - 0xf, 0x9e, 0x41, 0xef, 0x1d, 0x64, 0xed, 0x46, 0x76, 0x96, 0xb8, 0x47, - 0xa8, 0x2c, 0x30, 0xbf, 0xae, 0x31, 0xff, 0x2, 0x74, 0x4b, 0xb6, 0x72, - 0x43, 0x37, 0x3d, 0x28, 0x54, 0x8e, 0x98, 0xcb, 0x5d, 0xeb, 0xc6, 0x51, - 0x8, 0xc, 0xd9, 0xb5, 0xef, 0x5d, 0x78, 0xe3, 0x8a, 0xce, 0x99, 0xbe, - 0xb8, 0xc1, 0x16, 0x64, 0xad, 0x52, 0xc, 0x33, 0x7, 0xad, 0x7d, 0xbb, - 0xcb, 0x27, 0xb8, 0x20, 0x54, 0xab, 0x49, 0xa8, 0xf3, 0xbb, 0xfd, 0x7e, - 0xb3, 0x2, 0x40, 0xd8, 0x7, 0x43, 0xce, 0xa, 0xb5, 0xe5, 0xa4, 0x28, - 0xaa, 0xcd, 0x54, 0x5c, 0xc8, 0xd3, 0x13, 0x4, 0xda, 0x28, 0x15, 0xd8, - 0xb7, 0xea, 0x99, 0x6, 0x7, 0xad, 0x43, 0x50, 0xe4, 0xe0, 0xe9, 0xf3, - 0x31, 0x65, 0xd7, 0x4f, 0xd1, 0x27, 0xe3, 0x4d, 0x56, 0xd8, 0xfb, 0x67, - 0x2f, 0xed, 0x1c, 0xfd, 0xf7, 0xf0, 0xe9, 0x27, 0x1c, 0x8c, 0x93, 0xeb, - 0x59, 0x6f, 0x6b, 0x69, 0x6, 0x9f, 0x71, 0x7a, 0x2, 0x33, 0xf4, 0x95, - 0xfa, 0x61, 0x1, 0xfb, 0xc8, 0x7, 0x5d, 0x12, 0x46, 0x50, 0xef, 0xe9, - 0xa7, 0xd3, 0xe3, 0x33, 0x69, 0x59, 0xd0, 0x83, 0xad, 0xf0, 0x99, 0xdd, - 0x2d, 0xcd, 0x5e, 0xf7, 0x4, 0xac, 0xd4, 0x36, 0xcf, 0xc0, 0xdf, 0xd5, - 0xce, 0xbd, 0x3d, 0xc8, 0x40, 0x3d, 0xc2, 0x6b, 0xb8, 0x32, 0xff, 0x82, - 0xa2, 0x62, 0x94, 0x51, 0x9, 0xb6, 0x86, 0xa1, 0x71, 0xf7, 0xbf, 0x7, - 0x45, 0x2a, 0x63, 0xc3, 0xc3, 0x3a, 0xa4, 0x21, 0x39, 0x12, 0x6f, 0x49, - 0x53, 0x1b, 0xde, 0x53, 0xa3, 0xde, 0xbb, 0xa4, 0x6d, 0x65, 0x39, 0x7c, - 0x6d, 0x31, 0x5a, 0x8, 0x8c, 0x5a, 0x87, 0xee, 0x6f, 0xfb, 0x92, 0x4a, - 0xf9, 0x73, 0x56, 0x9a, 0xb8, 0x3f, 0x8d, 0xb6, 0x5b, 0x8, 0x80, 0xec, - 0x51, 0xbb, 0x6, 0x2f, 0x98, 0x80, 0x7c, 0x26, 0xab, 0xbb, 0x85, 0xfb, - 0x9e, 0xe6, 0x90, 0x16, 0xa2, 0xa5, 0x9b, 0xb3, 0x53, 0x40, 0x5c, 0x75, - 0x23, 0x3, 0xee, 0xe8, 0x8f, 0x4, 0xb2, 0x77, 0x3, 0x9, 0xd6, 0xa3, - 0xe5, 0xd8, 0xd, 0x11, 0xb3, 0x2d, 0x33, 0xf2, 0x39, 0x64, 0x8, 0x41, - 0x69, 0x38, 0xaa, 0xfb, 0xac, 0xaa, 0xd, 0x85, 0x82, 0x7a, 0x4b, 0x87, - 0x43, 0x95, 0xca, 0x43, 0x10, 0x69, 0x3d, 0x47, 0x6f, 0x28, 0x36, 0x52, - 0xcd, 0x9d, 0x61, 0xa9, 0x2e, 0x4a, 0x7c, 0xcb, 0x60, 0x4c, 0x80, 0xc1, - 0x8f, 0x61, 0x1d, 0xb6, 0xd2, 0x9f, 0x1a, 0x87, 0xd, 0x78, 0xe7, 0xb9, - 0x83, 0xaf, 0x48, 0xb0, 0x53, 0xe1, 0x22, 0x99, 0xa3, 0x80, 0xae, 0x8b, - 0xd0, 0x2f, 0x94, 0x2c, 0xbb, 0xf5, 0x84, 0x6a, 0x9, 0xb7, 0x28, 0xbe, - 0x3f, 0x4, 0xb7, 0xb8, 0x9c, 0x41, 0xe6, 0x61, 0x5, 0x13, 0x6e, 0x36, - 0xa1, 0x7e, 0x80, 0x95, 0x5f, 0x23, 0x73, 0xac, 0xe5, 0xd9, 0xb1, 0x82, - 0xb2, 0xd9, 0x3d, 0xe8, 0x28, 0x27, 0xcb, 0xb7, 0xfc, 0xe, 0xb4, 0x3e, - 0xc5, 0x14, 0x1d, 0x33, 0x63, 0xc3, 0x15, 0x79, 0x2e, 0xa8, 0xf4, 0xa5, - 0xbd, 0xd8, 0x3a, 0x61, 0xdf, 0x59, 0xff, 0x8a, 0xd7, 0xe9, 0xe3, 0x51, - 0xd2, 0xd2, 0x4e, 0x96, 0x2d, 0x7, 0xa, 0xe, 0xa5, 0x7b, 0x64, 0x68, - 0xcc, 0xc6, 0x40, 0x3a, 0x81, 0x73, 0x67, 0xbc, 0x6b, 0xaa, 0x41, 0x82, - 0xd5, 0xbd, 0xeb, 0xe9, 0xb8, 0x49, 0x8a, 0x1f, 0x9d, 0xbb, 0x36, 0x39, - 0x7a, 0xa6, 0xc1, 0xed, 0x42, 0x83, 0xe6, 0x77, 0xa7, 0x6, 0xaa, 0x32, - 0xdc, 0x2, 0x59, 0x11, 0x94, 0x3, 0xd5, 0xc3, 0x22, 0xb9, 0xf7, 0x8e, - 0x27, 0x44, 0xec, 0xfb, 0x1a, 0x25, 0x99, 0x47, 0x0, 0x7c, 0xa3, 0xc6, - 0x1d, 0x58, 0xbf, 0xcd, 0xa5, 0x13, 0x4d, 0xba, 0xc8, 0x2d, 0x7f, 0x97, - 0x9d, 0xc2, 0x57, 0x20, 0xf1, 0x9a, 0xa7, 0x6e, 0xc8, 0x44, 0x89, 0x53, - 0x94, 0xdd, 0x21, 0xd0, 0xd4, 0x54, 0x65, 0x20, 0x7f, 0x3d, 0x55, 0xfe, - 0x13, 0x4d, 0xa0, 0xe2, 0x39, 0x74, 0x1c, 0x18, 0xc5, 0x58, 0x56, 0x15, - 0x5e, 0x27, 0x6d, 0xca, 0x8a, 0x90, 0x24, 0x2, 0x7, 0xe9, 0xd1, 0x5d, - 0x6c, 0xc8, 0xe4, 0x6a, 0x5e, 0x17, 0x49, 0x0, 0x8f, 0xea, 0xcb, 0x3b, - 0x8b, 0x2f, 0x9e, 0xae, 0x8d, 0x8d, 0x65, 0x65, 0xb1, 0x28, 0xd1, 0x5c, - 0x7c, 0xd, 0x1c, 0x52, 0xb8, 0xb7, 0x4e, 0x3b, 0x33, 0x5, 0x5f, 0x6e, - 0x1d, 0x94, 0x3, 0xc6, 0x25, 0xd2, 0x53, 0x99, 0x35, 0xd9, 0xaf, 0xec, - 0x42, 0x90, 0x14, 0x94, 0x66, 0x6a, 0x3a, 0xa7, 0xf3, 0xa6, 0x7e, 0x7f, - 0x25, 0x57, 0xba, 0x94, 0xff, 0x50, 0x64, 0x4e, 0x63, 0x79, 0xc2, 0x76, - 0xd5, 0x32, 0x13, 0x22, 0xe0, 0x62, 0x64, 0x24, 0xe4, 0x35, 0x54, 0x99, - 0xa, 0xe8, 0x64, 0x75, 0xa0, 0x36, 0xbf, 0xa0, 0xc2, 0x82, 0xdf, 0xa3, - 0xbf, 0xc1, 0x6f, 0xbb, 0xe7, 0x20, 0x6e, 0xb3, 0x49, 0xcc, 0xb9, 0xdc, - 0xdb, 0xd2, 0x52, 0x2c, 0x1f, 0xbb, 0x6c, 0x21, 0xb, 0x8, 0xfa, 0x33, - 0x22, 0xa6, 0xaa, 0xe0, 0x4, 0x20, 0x5f, 0xaa, 0x29, 0xdd, 0x8b, 0xf2, - 0x15, 0x8a, 0x67, 0xdc, 0xc2, 0x95, 0xac, 0xbd, 0x3e, 0x72, 0x2a, 0x6c, - 0x11, 0x5d, 0x6e, 0xfc, 0x77, 0x94, 0xa7, 0x81, 0x93, 0xb9, 0x49, 0x2b, - 0x21, 0xb1, 0xd9, 0xa, 0xc5, 0x1f, 0xe8, 0x5c, 0xce, 0x11, 0xab, 0x65, - 0xe2, 0x32, 0xa5, 0x5, 0xc2, 0x8b, 0x9d, 0x1c, 0xae, 0x7d, 0x1, 0x6c, - 0x20, 0xed, 0xbe, 0xb8, 0x1e, 0xbd, 0xc7, 0xaa, 0x84, 0x87, 0xc4, 0xf1, - 0x8, 0x32, 0xe5, 0x27, 0xb1, 0xa7, 0x15, 0x86, 0xf9, 0x32, 0xf, 0x16, - 0x9c, 0x3f, 0xdd, 0xa4, 0xfb, 0x0, 0x65, 0xe8, 0xf5, 0x7e, 0xbc, 0x14, - 0x78, 0x82, 0x1b, 0xdc, 0x13, 0xd6, 0x98, 0xe6, 0x69, 0x6d, 0x4a, 0xc2, - 0xcd, 0x39, 0x7d, 0x71, 0xf1, 0xca, 0x26, 0x55, 0xcc, 0xe9, 0x99, 0xc5, - 0x50, 0x9a, 0xb8, 0x25, 0x4b, 0x11, 0xb5, 0x7, 0xa7, 0x7f, 0x75, 0x21, - 0x16, 0x24, 0xc5, 0xc, 0x69, 0xff, 0x59, 0x8d, 0xaa, 0xda, 0xc7, 0x57, - 0x1a, 0x6e, 0xc4, 0xcc, 0xc, 0x54, 0xfc, 0x81, 0x32, 0x74, 0x86, 0xeb, - 0xf9, 0xfa, 0x73, 0x60, 0x1e, 0xed, 0x93, 0x6, 0x99, 0xdb, 0xf, 0xbc, - 0x2c, 0x99, 0x6, 0xe6, 0x1a, 0xf5, 0x6d, 0xc7, 0x18, 0xc2, 0x6c, 0xc7, - 0x57, 0x48, 0x59, 0x9f, 0xed, 0x24, 0xb1, 0xb9, 0xb5, 0xe4, 0x8b, 0xc1, - 0x3e, 0x50, 0x20, 0x7d, 0x60, 0xba, 0x2b, 0xaa, 0x2b, 0x64, 0xe7, 0xac, - 0x6e, 0xce, 0x53, 0x84, 0xea, 0x79, 0x70, 0xe8, 0xfa, 0x14, 0xca, 0x4d, - 0x38, 0x9, 0x85, 0x28, 0xc7, 0xd3, 0x6e, 0xd, 0xe9, 0xbf, 0xff, 0x0, - 0xb9, 0x14, 0xff, 0x38, 0xb8, 0x92, 0x35, 0x63, 0xa1, 0xee, 0x4c, 0xb0, - 0x64, 0x90, 0x1, 0x84, 0xd, 0x89, 0xaa, 0x5c, 0xf0, 0x8, 0x99, 0xb3, - 0x8a, 0x72, 0x1, 0x62, 0x77, 0x73, 0x92, 0xbb, 0x5c, 0x71, 0x50, 0xa4, - 0xdf, 0x1c, 0x2a, 0xdd, 0x79, 0x1a, 0x7b, 0xb6, 0x36, 0xff, 0x7d, 0x8c, - 0xd0, 0x4f, 0x3f, 0x56, 0x5f, 0x95, 0x92, 0x58, 0xc, 0x3a, 0xe0, 0x10, - 0x48, 0x77, 0xd, 0x2, 0xfc, 0xba, 0x82, 0xff, 0x45, 0xd6, 0x19, 0xb5, - 0xaa, 0x1c, 0xab, 0xcd, 0x54, 0xf, 0x84, 0xe, 0xa3, 0xfb, 0xcd, 0xac, - 0x3b, 0xa0, 0x38, 0x4c, 0xf9, 0xb1, 0xf6, 0xa2, 0x21, 0xb8, 0x57, 0x45, - 0x3d, 0x4, 0x75, 0x5, 0xc8, 0x64, 0xd2, 0x6c, 0xfb, 0x28, 0xd1, 0x48, - 0x35, 0xde, 0x4a, 0x91, 0xe1, 0x9, 0xea, 0x3c, 0xa6, 0xa9, 0x15, 0xc8, - 0xa5, 0xf3, 0x3f, 0xa2, 0xae, 0x4a, 0xca, 0xe5, 0xb1, 0xfa, 0xeb, 0x9c, - 0xc7, 0xd6, 0x1, 0xbd, 0xb7, 0x3c, 0x8a, 0x24, 0x4b, 0x3, 0xc2, 0x36, - 0x38, 0x3a, 0x65, 0xd4, 0xbb, 0x7a, 0x87, 0xf8, 0x5f, 0x14, 0xdd, 0x94, - 0x74, 0xd9, 0xf0, 0x43, 0x35, 0xbc, 0x68, 0x39, 0x2b, 0x28, 0xb8, 0x39, - 0x40, 0x2, 0x51, 0x30, 0x8b, 0x90, 0xb5, 0xc2, 0xcb, 0x7d, 0x6, 0x2d, - 0xeb, 0xed, 0xc6, 0x47, 0x76, 0xcb, 0x2, 0x47, 0x85, 0xe0, 0xff, 0x77, - 0x6d, 0x1a, 0x24, 0xff, 0xbb, 0x5a, 0xf4, 0xdb, 0xa1, 0xea, 0x16, 0x11, - 0x50, 0x13, 0xc5, 0xe4, 0x66, 0xcb, 0xc7, 0x90, 0x10, 0xe4, 0xa7, 0x74, - 0x93, 0xde, 0x67, 0x16, 0x1e, 0x21, 0x28, 0x96, 0x93, 0x71, 0xdc, 0xb5, - 0x6d, 0x3e, 0x5f, 0x1e, 0x9b, 0xd4, 0x78, 0x5d, 0xdb, 0xce, 0xfe, 0x60, - 0x38, 0xed, 0xd7, 0xce, 0x12, 0x33, 0x1c, 0x34, 0x40, 0xeb, 0xfe, 0x69, - 0x5d, 0x3d, 0xd3, 0xf3, 0xd1, 0x3d, 0xd4, 0x1f, 0x4a, 0xd9, 0xab, 0xc5, - 0x94, 0x8b, 0x9a, 0x33, 0xe2, 0xf4, 0x92, 0xda, 0xe2, 0x8f, 0x75, 0x8f, - 0xb3, 0x23, 0x24, 0x3e, 0xd7, 0x53, 0x78, 0x4d, 0xf0, 0xa6, 0x1d, 0xb1, - 0x6a, 0xcc, 0x66, 0x21, 0x26, 0x43, 0x6d, 0xbe, 0x86, 0x12, 0x9, 0xed, - 0xf2, 0xd6, 0xd3, 0x90, 0x19, 0x10, 0xe1, 0x44, 0x11, 0x90, 0x6a, 0x86, - 0x30, 0x6d, 0x77, 0x0, 0x3, 0xae, 0x0, 0xdd, 0x51, 0x97, 0xa8, 0xc2, - 0x77, 0x77, 0x0, 0xdd, 0x62, 0x84, 0x1, 0x7e, 0xc6, 0xd6, 0x4c, 0x49, - 0x72, 0x8a, 0xdb, 0x4e, 0x7e, 0x1a, 0x4b, 0xfb, 0xd6, 0x40, 0xad, 0x64, - 0x64, 0x99, 0x9, 0x56, 0xec, 0xad, 0x3d, 0x88, 0x9a, 0xb4, 0x6c, 0x17, - 0x62, 0xf9, 0xd8, 0xb3, 0x2f, 0x8, 0x3e, 0xc, 0xc6, 0xc1, 0xee, 0x20, - 0x9f, 0xe6, 0xeb, 0xc6, 0xe6, 0xcc, 0xb4, 0xe7, 0xe6, 0xca, 0xf1, 0x2c, - 0x9, 0x73, 0xb2, 0xa, 0xd6, 0xf5, 0x40, 0x44, 0xfd, 0xa, 0x36, 0xb3, - 0xe6, 0xf, 0x84, 0xf8, 0x8a, 0x22, 0xc, 0x15, 0x99, 0xf1, 0xe1, 0x3f, - 0xe5, 0x73, 0x5f, 0x63, 0x1d, 0xdf, 0xb6, 0xf6, 0x2f, 0xa3, 0x7e, 0x2, - 0x7, 0xba, 0xc1, 0x0, 0x72, 0x38, 0x41, 0xe3, 0x33, 0x3, 0x16, 0x2f, - 0x2a, 0xd7, 0x54, 0x94, 0x78, 0xd2, 0x5e, 0xe4, 0x6e, 0x19, 0xa0, 0xe3, - 0xa, 0xc1, 0x8b, 0xd4, 0x6f, 0x1f, 0xc2, 0x5f, 0xca, 0x23, 0x30, 0x7b, - 0xd3, 0xe, 0x45, 0xf9, 0x2a, 0x1d, 0x6e, 0x8c, 0x8, 0xc8, 0x9c, 0x84, - 0xd2, 0x71, 0xe8, 0xfc, 0x68, 0x1b, 0xf5, 0xca, 0xb3, 0x98, 0xe3, 0xeb, - 0xb4, 0xb7, 0x88, 0x4f, 0xfb, 0x37, 0xdf, 0x4c, 0xf9, 0x3e, 0x71, 0x36, - 0xfa, 0xd0, 0x98, 0x38, 0x8, 0x77, 0xa8, 0xdb, 0x75, 0x8d, 0x1f, 0x25, - 0x92, 0x4c, 0xe, 0x47, 0x5c, 0x83, 0x91, 0x36, 0x57, 0x3a, 0x8e, 0xf, - 0x70, 0xb1, 0x2b, 0x15, 0x46, 0x92, 0x35, 0x16, 0x78, 0xca, 0xf, 0x37, - 0xa1, 0xce, 0x9c, 0x44, 0x29, 0xad, 0xdf, 0x28, 0x69, 0x27, 0x6d, 0x72, - 0x71, 0x62, 0x48, 0xe5, 0xdc, 0xe8, 0x64, 0x11, 0x47, 0x9b, 0x2d, 0xc, - 0xe4, 0x5, 0xd8, 0x72, 0x1f, 0xc6, 0x35, 0x14, 0x8e, 0x6a, 0x11, 0x90, - 0xa9, 0x1f, 0xd3, 0x8d, 0x7c, 0x28, 0x10, 0x22, 0x88, 0x2e, 0x15, 0xcb, - 0x3d, 0xf7, 0xef, 0x60, 0x4a, 0x83, 0xeb, 0x1a, 0x8, 0xd2, 0x43, 0xae, - 0x5e, 0xbe, 0xd6, 0x8e, 0x69, 0x9, 0x2f, 0x7f, 0x7f, 0x2a, 0xcd, 0x55, - 0x5d, 0x30, 0x8, 0x5, 0xe3, 0xd6, 0xc8, 0xb4, 0x7, 0x78, 0xc4, 0x69, - 0x0, 0x70, 0x4f, 0x92, 0x1b, 0x9c, 0x9d, 0xaa, 0x1a, 0x6a, 0x13, 0x54, - 0xa8, 0x3d, 0x66, 0xf4, 0xad, 0xc3, 0x8a, 0xb4, 0x48, 0x31, 0xc3, 0xe8, - 0x23, 0x48, 0x1b, 0xee, 0x32, 0x66, 0x23, 0xca, 0xe6, 0x97, 0x3c, 0x63, - 0xfc, 0xf, 0x4c, 0x45, 0xd1, 0xbf, 0x55, 0x78, 0xf2, 0x7b, 0x32, 0xd9, - 0x7d, 0xe4, 0xdb, 0x8, 0x2c, 0xdd, 0xa7, 0xf0, 0xae, 0xfb, 0x74, 0x6, - 0x5d, 0x62, 0xb1, 0x6f, 0xc6, 0x2b, 0x93, 0x82, 0xd7, 0x98, 0x4, 0x8f, - 0x9a, 0x9e, 0xa2, 0x88, 0x8d, 0xa2, 0xe, 0xc1, 0x8b, 0xdc, 0x1b, 0xb4, - 0xcc, 0xe6, 0x6f, 0xe, 0x23, 0x3f, 0xaf, 0x3b, 0x60, 0x4c, 0xaa, 0x1d, - 0xb0, 0xe6, 0x14, 0x0, 0x1b, 0x68, 0x4f, 0xcc, 0xdb, 0x16, 0xdd, 0x96, - 0x71, 0x6c, 0xbe, 0x1, 0x7b, 0x80, 0x2b, 0xb8, 0xc4, 0x85, 0xf9, 0x98, - 0x25, 0x3d, 0xa7, 0x28, 0x71, 0xab, 0xbe, 0x80, 0x3e, 0x45, 0x42, 0x14, - 0xa6, 0x5c, 0x84, 0x37, 0x49, 0x66, 0x2f, 0x2d, 0x4b, 0x3d, 0x22, 0x92, - 0x6a, 0x1a, 0x9e, 0x1d, 0xe6, 0xc7, 0x58, 0x16, 0x70, 0xb2, 0xe, 0x89, - 0xd1, 0xec, 0xc8, 0x47, 0xdf, 0x8b, 0xce, 0x5a, 0x31, 0x64, 0xa1, 0xa0, - 0xf1, 0xed, 0x51, 0x89, 0x86, 0x72, 0xd0, 0xa, 0x9b, 0x65, 0xbb, 0x57, - 0x35, 0x13, 0x21, 0x86, 0xbf, 0xb9, 0x49, 0x7c, 0x94, 0xfe, 0x40, 0xaf, - 0x3b, 0x27, 0xc3, 0x74, 0x2e, 0xcd, 0xea, 0x30, 0x60, 0xb8, 0x5c, 0x7c, - 0x21, 0x39, 0x30, 0xd9, 0x57, 0x5f, 0xd3, 0xc7, 0xd6, 0x6b, 0xb2, 0x88, - 0x7d, 0xb6, 0xa0, 0xca, 0x18, 0xf3, 0x9c, 0xf, 0xb0, 0xb6, 0x98, 0x20, - 0x33, 0xe9, 0xf5, 0x92, 0x7, 0xba, 0x1c, 0x6a, 0x59, 0x4c, 0xe6, 0xf0, - 0x43, 0xdf, 0x49, 0x72, 0x1a, 0x8a, 0x8f, 0x9a, 0x6b, 0x28, 0xef, 0xeb, - 0x5a, 0x96, 0x6d, 0xa5, 0x3a, 0xd4, 0xf9, 0x1e, 0x93, 0x8f, 0xef, 0xd2, - 0x1f, 0xbc, 0x2a, 0xd6, 0x21, 0xd0, 0x4b, 0x49, 0x5d, 0x6d, 0x45, 0xd0, - 0xc, 0xbf, 0xf7, 0x25, 0xe9, 0xca, 0x45, 0x8f, 0x22, 0xed, 0x48, 0x1a, - 0xa0, 0xc5, 0x73, 0xb5, 0x44, 0x96, 0x0, 0x8, 0x9b, 0xfd, 0xc0, 0xd0, - 0x7e, 0xd5, 0x1b, 0xb1, 0xe1, 0xf7, 0x19, 0x5c, 0x59, 0xbb, 0x86, 0xd5, - 0xb1, 0x17, 0x16, 0xbf, 0x10, 0x5b, 0xdc, 0x6f, 0xa9, 0x8f, 0xf9, 0x4a, - 0x11, 0xac, 0x2, 0xc1, 0x9e, 0x92, 0x23, 0xd8, 0xfb, 0x38, 0x95, 0xc9, - 0x70, 0x1f, 0x57, 0x5f, 0x7, 0xb2, 0xa1, 0xe2, 0xe2, 0xd5, 0x24, 0xe5, - 0xbb, 0x6a, 0x90, 0xf, 0xbe, 0x18, 0x90, 0xf3, 0x47, 0x95, 0xfa, 0xe8, - 0x13, 0xe2, 0x2c, 0x4f, 0xc5, 0xb9, 0x64, 0xb, 0x67, 0x1f, 0xbc, 0x34, - 0xb0, 0x66, 0xd2, 0xa3, 0x6, 0xfa, 0xae, 0x6, 0xff, 0x17, 0x96, 0xfe, - 0xa, 0xec, 0xf2, 0xe2, 0x7c, 0x3c, 0xe1, 0x16, 0xcc, 0x3c, 0x69, 0xf7, - 0x23, 0xaa, 0x51, 0x3f, 0x39, 0xb3, 0x94, 0xa0, 0x8c, 0x59, 0x21, 0xd3, - 0xb0, 0xac, 0x35, 0xa2, 0xa, 0x50, 0x89, 0x33, 0x34, 0x83, 0x45, 0xa1, - 0x9d, 0xf4, 0xec, 0xbe, 0x8d, 0x9, 0xda, 0xd7, 0x10, 0xee, 0xb3, 0x10, - 0xea, 0x85, 0x16, 0xc8, 0x89, 0x8e, 0xdf, 0x8b, 0xf1, 0x7a, 0x7, 0xb4, - 0xe7, 0xc9, 0x1f, 0x4c, 0x6a, 0x4a, 0xfe, 0x0, 0xd8, 0xd4, 0xd0, 0x1c, - 0xc4, 0xa4, 0x3, 0x4c, 0xf, 0xc3, 0x95, 0x2d, 0xb5, 0x80, 0x4, 0x61, - 0xdf, 0xac, 0x79, 0x10, 0xd3, 0xd8, 0x1d, 0xc5, 0x80, 0x10, 0xe6, 0x77, - 0x37, 0xec, 0x80, 0x44, 0x30, 0x5a, 0xad, 0x21, 0xa, 0x4f, 0xe6, 0x77, - 0x45, 0x6b, 0x5d, 0xc2, 0x10, 0x26, 0xaa, 0x9e, 0x5f, 0x4e, 0x31, 0x22, - 0x27, 0xa7, 0xef, 0x44, 0x17, 0x3b, 0xad, 0xea, 0xc7, 0x55, 0x32, 0x2, - 0x2a, 0x5b, 0xfc, 0xbd, 0x13, 0xe5, 0x7e, 0x96, 0x19, 0x89, 0xd3, 0xc9, - 0x7c, 0x23, 0x7d, 0x4c, 0x4d, 0x90, 0xc1, 0x46, 0x32, 0x21, 0xdb, 0xbd, - 0xdc, 0x65, 0x4, 0x4, 0x23, 0x8a, 0x24, 0xe4, 0xf0, 0x61, 0x8e, 0x9e, - 0x57, 0x8e, 0x99, 0x2b, 0xe6, 0xda, 0x10, 0xd6, 0x6d, 0xae, 0xb4, 0x4b, - 0xfa, 0x3a, 0x1e, 0x4, 0xb4, 0xd0, 0xd1, 0x8f, 0x97, 0x51, 0x82, 0x80, - 0x67, 0x56, 0x3b, 0xed, 0x6d, 0x86, 0x47, 0x34, 0x3c, 0x40, 0xd2, 0x9d, - 0xa9, 0x12, 0x77, 0x60, 0x94, 0x4f, 0x35, 0x85, 0x7e, 0x29, 0xb8, 0x50, - 0x1, 0x9f, 0x32, 0x95, 0x99, 0x6a, 0x7b, 0xf8, 0xf0, 0xc2, 0x4d, 0x4, - 0x7e, 0x8a, 0x88, 0x57, 0x67, 0x62, 0x98, 0x7c, 0x49, 0x7d, 0x3d, 0x49, - 0x98, 0x9, 0xd9, 0xff, 0x85, 0xdb, 0xfd, 0xc5, 0xa2, 0xdc, 0xc0, 0xa7, - 0xc0, 0xd7, 0x23, 0x19, 0x2b, 0x33, 0x1c, 0x2a, 0xb8, 0xe6, 0xef, 0xb9, - 0x41, 0x12, 0xea, 0xc, 0x20, 0x52, 0x7b, 0xd2, 0xc6, 0xfb, 0xea, 0xc1, - 0x30, 0x18, 0x67, 0xe9, 0x3e, 0x3e, 0x1, 0xb3, 0xf8, 0x72, 0xd2, 0x79, - 0xc6, 0x27, 0x62, 0xfd, 0x2c, 0xe1, 0xeb, 0xf4, 0x4e, 0xa6, 0x68, 0x6c, - 0x17, 0x3a, 0xbf, 0xfb, 0x4b, 0x6c, 0xe, 0x3a, 0x7a, 0xcc, 0x9a, 0xe4, - 0x45, 0xd2, 0x35, 0x8, 0x7c, 0xcc, 0x43, 0x91, 0x31, 0x1d, 0x40, 0x7d, - 0xd7, 0x62, 0xab, 0x5d, 0x30, 0xa2, 0x10, 0xea, 0x9c, 0xa9, 0xb2, 0x35, - 0xa, 0xb9, 0x84, 0xd8, 0xf4, 0xd3, 0x82, 0x96, 0xb4, 0xbb, 0x3c, 0x65, - 0xe8, 0xa4, 0x74, 0xc7, 0xa5, 0xde, 0x3b, 0xea, 0xf3, 0xf6, 0xf3, 0xf1, - 0xd9, 0xb1, 0xd5, 0x29, 0x68, 0x51, 0x1d, 0x1e, 0x7a, 0xd4, 0xab, 0x44, - 0x61, 0x49, 0xa5, 0x94, 0xd1, 0x7b, 0x77, 0x93, 0x24, 0x7d, 0x9f, 0xa1, - 0x6d, 0xf0, 0x10, 0xfc, 0x96, 0xfc, 0xc7, 0xa3, 0x2d, 0x43, 0x9, 0x56, - 0x23, 0x0, 0xaf, 0x4b, 0xb8, 0xe3, 0xc5, 0x3c, 0x1b, 0x7c, 0x6a, 0x25, - 0x2e, 0xa2, 0xdc, 0x2d, 0x6e, 0xb3, 0xa6, 0x63, 0xed, 0xb2, 0xa6, 0x12, - 0x33, 0x6e, 0xfa, 0x3a, 0x66, 0x83, 0xcd, 0x20, 0x39, 0xd7, 0xb7, 0xe, - 0x2b, 0x26, 0x69, 0xd9, 0x29, 0x35, 0x72, 0xc9, 0xee, 0x57, 0xef, 0x6c, - 0x6f, 0x7e, 0x57, 0xa9, 0x12, 0xd2, 0x8c, 0x6, 0xa8, 0x74, 0xe0, 0x2, - 0x28, 0xdf, 0x54, 0x6b, 0x32, 0x9c, 0x53, 0x64, 0x23, 0xd6, 0x9e, 0xf9, - 0x75, 0xe0, 0x56, 0x27, 0xf8, 0x56, 0xdb, 0x27, 0xd5, 0x39, 0x61, 0x4f, - 0x82, 0x79, 0x35, 0xa4, 0x1, 0x35, 0x74, 0x74, 0x47, 0x29, 0x98, 0xa4, - 0x19, 0x28, 0x95, 0x1e, 0xac, 0x0, 0x63, 0x40, 0xac, 0x2, 0x12, 0x86, - 0x86, 0xf0, 0x6c, 0x7f, 0xd9, 0xe9, 0xe4, 0x57, 0x96, 0x37, 0x77, 0xb9, - 0x4b, 0xda, 0x3c, 0x82, 0x86, 0x53, 0xf2, 0x89, 0x6b, 0x71, 0x5b, 0xef, - 0x46, 0xa9, 0x84, 0x99, 0xf7, 0x30, 0x5f, 0xbb, 0xf4, 0x90, 0x50, 0xbe, - 0xb7, 0x45, 0xec, 0x19, 0x62, 0xab, 0x8b, 0xdf, 0xa7, 0x54, 0x11, 0xc0, - 0xf7, 0x78, 0xe3, 0x80, 0x4b, 0xa2, 0x8c, 0x26, 0x49, 0x6d, 0x96, 0xb, - 0xca, 0x2a, 0xd1, 0xe2, 0x88, 0xd3, 0x9, 0xef, 0xef, 0x89, 0xca, 0xe, - 0xb8, 0x5d, 0x2f, 0xea, 0xc6, 0x26, 0x24, 0xc2, 0x96, 0xaf, 0xf9, 0x6e, - 0xd4, 0x1c, 0xae, 0x24, 0x68, 0x3b, 0xad, 0x24, 0x59, 0x80, 0xc3, 0x15, - 0x25, 0xb0, 0xd8, 0x65, 0x5b, 0x17, 0x93, 0xe7, 0x15, 0xc9, 0x39, 0xbf, - 0x81, 0xfd, 0xa8, 0x16, 0xf0, 0x1f, 0x43, 0xf0, 0xb, 0x1d, 0x63, 0xa8, - 0x50, 0x8e, 0x2e, 0xe9, 0x42, 0xec, 0x53, 0xa0, 0x5a, 0xa5, 0x2e, 0x93, - 0x19, 0xbf, 0x9a, 0xf7, 0x9c, 0x9, 0x44, 0x56, 0xf5, 0x68, 0xd6, 0x90, - 0xb3, 0xc3, 0x77, 0x9d, 0x7c, 0x85, 0x53, 0xcf, 0xb8, 0x53, 0x48, 0x88, - 0xa, 0xfa, 0x9c, 0xdb, 0x5a, 0xbe, 0xcd, 0xce, 0x81, 0xab, 0xb, 0x18, - 0x3d, 0xf4, 0xc9, 0xfb, 0xac, 0xf9, 0x68, 0xf6, 0x2b, 0xd9, 0x4a, 0xe, - 0x2d, 0x20, 0x3e, 0xd8, 0x29, 0x1a, 0xa, 0xe6, 0x9f, 0xf, 0xf, 0x13, - 0x48, 0x8c, 0xdd, 0x66, 0x2b, 0x4e, 0x70, 0x9b, 0x54, 0x8a, 0x9f, 0x83, - 0x71, 0x86, 0xc, 0xae, 0x6d, 0xd5, 0x2c, 0x13, 0xf1, 0x16, 0x9d, 0xe9, - 0xcc, 0xa2, 0xfc, 0x6c, 0xc3, 0xbf, 0x94, 0xfd, 0xd5, 0xac, 0xd8, 0x46, - 0x2f, 0xf5, 0xc6, 0x53, 0xe5, 0xdf, 0x90, 0x23, 0x20, 0x1d, 0xa5, 0x86, - 0x11, 0x63, 0xea, 0xe1, 0xc5, 0xf8, 0x31, 0x80, 0x27, 0xba, 0x71, 0x54, - 0x78, 0x12, 0xc1, 0xa9, 0x42, 0x6f, 0xba, 0xe8, 0x11, 0x34, 0x6e, 0xc7, - 0xca, 0x4c, 0x56, 0x23, 0x19, 0x8a, 0xa9, 0x43, 0x23, 0xab, 0xcb, 0x37, - 0xb5, 0xaf, 0xe4, 0xcd, 0x23, 0xcb, 0xf7, 0xcf, 0x64, 0x8a, 0x68, 0x87, - 0x84, 0x4f, 0x55, 0xde, 0x22, 0x3b, 0xca, 0x7c, 0x4c, 0x3, 0xf4, 0xd3, - 0x67, 0x3c, 0xf3, 0xd1, 0xeb, 0xf0, 0x90, 0xb1, 0xa7, 0xd9, 0x39, 0x19, - 0xd9, 0x40, 0xea, 0x55, 0x13, 0x56, 0xc7, 0x12, 0x9e, 0x34, 0x17, 0xcf, - 0xbf, 0xc7, 0x17, 0xb5, 0xe7, 0xfd, 0xdc, 0xd8, 0x51, 0x85, 0x75, 0x37, - 0xc4, 0xdc, 0xf3, 0x51, 0x2d, 0x62, 0xfc, 0x2a, 0x76, 0x84, 0x36, 0xc3, - 0x3a, 0xf3, 0xeb, 0x7f, 0x6f, 0x9f, 0xe0, 0xe8, 0x92, 0x37, 0xf7, 0x53, - 0xb2, 0x7d, 0x1d, 0xef, 0xe4, 0x8f, 0x72, 0xe9, 0xea, 0x8b, 0x2d, 0xf5, - 0x7, 0x12, 0xbf, 0xee, 0x89, 0xc3, 0xc0, 0x59, 0x7a, 0x91, 0xdd, 0x76, - 0x21, 0xb5, 0xeb, 0xda, 0x9a, 0xb4, 0x87, 0x29, 0xbd, 0x14, 0xa3, 0x3f, - 0xd0, 0x9b, 0xb, 0x12, 0xf6, 0x65, 0x1a, 0x43, 0x44, 0xed, 0x88, 0xb9, - 0xba, 0xef, 0xe1, 0xc5, 0x10, 0x7d, 0xe4, 0x55, 0x72, 0x90, 0xc4, 0xa5, - 0x7f, 0x2a, 0xee, 0x62, 0x7e, 0xfe, 0x21, 0x27, 0xac, 0x7c, 0x41, 0x75, - 0x2b, 0x46, 0xef, 0x3c, 0x37, 0x86, 0xbb, 0xeb, 0x4c, 0xf1, 0x21, 0x62, - 0xdd, 0x44, 0xca, 0xce, 0xf7, 0xbb, 0xf8, 0x3d, 0x44, 0x84, 0x47, 0x0, - 0x44, 0xf4, 0x26, 0xd7, 0x8a, 0x24, 0x14, 0x99, 0xaa, 0x93, 0x86, 0x48, - 0x86, 0x2, 0x39, 0x55, 0x26, 0x76, 0xbf, 0xdc, 0x99, 0x3, 0x3b, 0x93, - 0x7d, 0x50, 0x8d, 0x75, 0x3f, 0xd7, 0xfd, 0x25, 0xcf, 0x64, 0xaf, 0xcb, - 0x66, 0x24, 0xed, 0x13, 0xbc, 0x1d, 0xe3, 0x9e, 0x21, 0xd7, 0xcb, 0xc9, - 0x1f, 0x3b, 0xc0, 0x2e, 0xad, 0xcf, 0x96, 0x2, 0x26, 0x92, 0x61, 0xce, - 0xa9, 0xea, 0xd8, 0xec, 0x15, 0x9c, 0x65, 0x12, 0x26, 0x9c, 0xf5, 0x79, - 0x3e, 0x3c, 0xa5, 0x80, 0x4f, 0xf2, 0xb4, 0x95, 0x75, 0xf4, 0x57, 0x20, - 0xf0, 0xf5, 0x89, 0x58, 0x19, 0x92, 0x25, 0x86, 0x41, 0x82, 0x8c, 0x31, - 0x23, 0x71, 0xf4, 0xbf, 0x13, 0xd6, 0xcb, 0xc7, 0xff, 0x2f, 0x96, 0x7a, - 0x7c, 0xec, 0xcd, 0xa6, 0xba, 0x21, 0x14, 0xf, 0x4, 0x6f, 0xa7, 0x10, - 0xc4, 0x8f, 0xb4, 0xb9, 0xa9, 0x5c, 0x59, 0x94, 0xa0, 0xf1, 0xf9, 0x60, - 0xc3, 0xf0, 0xe4, 0xf5, 0x2f, 0xe4, 0x98, 0xf0, 0xe0, 0x88, 0x88, 0xa1, - 0xd5, 0xdf, 0x9b, 0xb4, 0x33, 0xa0, 0x29, 0xa3, 0xbb, 0xd5, 0x1c, 0x71, - 0x5d, 0xec, 0x60, 0x9f, 0x40, 0x20, 0x64, 0xf, 0x26, 0x18, 0x17, 0xdc, - 0x1f, 0x68, 0x8d, 0x1c, 0x57, 0xf0, 0x14, 0xbc, 0xb1, 0xec, 0x60, 0x5a, - 0x9a, 0xe8, 0x49, 0xfb, 0x64, 0x41, 0xbf, 0x14, 0x69, 0x40, 0x5c, 0xb8, - 0x8c, 0x96, 0x21, 0x5c, 0x4d, 0xae, 0x75, 0x22, 0x9c, 0x94, 0x1f, 0xf8, - 0xb, 0xab, 0xc0, 0x67, 0xd4, 0x58, 0x56, 0xfa, 0xb5, 0x23, 0xef, 0x1c, - 0x4d, 0x91, 0xde, 0x6a, 0x27, 0x69, 0x17, 0x54, 0x94, 0xbe, 0x32, 0x3f, - 0x8d, 0x13, 0x66, 0x45, 0x9c, 0xf0, 0x7, 0x16, 0x9, 0xf0, 0xe, 0x9a, - 0x6e, 0x8c, 0x28, 0x8a, 0xc9, 0x2b, 0x2b, 0x89, 0x30, 0x9f, 0xde, 0xf7, - 0xbd, 0x55, 0x4f, 0x1d, 0xf4, 0xeb, 0x80, 0xf3, 0x41, 0x5d, 0xe0, 0x1a, - 0x54, 0xb6, 0x44, 0x46, 0x71, 0xc8, 0xe2, 0xfa, 0x98, 0x20, 0xcd, 0x35, - 0x46, 0xb4, 0xd0, 0x5d, 0x94, 0xed, 0xd8, 0x9c, 0xda, 0x2a, 0x5c, 0xec, - 0x7, 0xb2, 0x22, 0xa3, 0xce, 0xa6, 0x43, 0x4d, 0x49, 0xf8, 0x78, 0x68, - 0xa7, 0x3, 0xed, 0xfb, 0x52, 0x9f, 0x92, 0x16, 0x84, 0x72, 0xd7, 0x94, - 0x53, 0x1a, 0x91, 0xb7, 0x1d, 0xbf, 0x91, 0x7c, 0x2d, 0x65, 0x28, 0x5f, - 0xff, 0xb0, 0xfb, 0xe4, 0xa3, 0xf5, 0x35, 0x74, 0x11, 0x59, 0x64, 0x45, - 0x44, 0xeb, 0x7a, 0xf7, 0xca, 0x2d, 0x73, 0x9d, 0x4, 0x25, 0xb5, 0xad, - 0xde, 0xd4, 0x17, 0xc5, 0x55, 0x66, 0x19, 0xb1, 0x61, 0x47, 0x45, 0x6c, - 0x99, 0x8, 0xe9, 0x83, 0x8e, 0x84, 0x5f, 0xf6, 0xca, 0x5, 0x42, 0x8, - 0x7d, 0x69, 0x8f, 0x69, 0x89, 0x6e, 0x84, 0x44, 0x44, 0x52, 0x98, 0xc3, - 0x90, 0xa9, 0xfa, 0xf, 0xd0, 0x2, 0xe2, 0x6f, 0xbb, 0x23, 0xe2, 0x5b, - 0x34, 0xb1, 0xfc, 0x48, 0xaf, 0xbe, 0x96, 0x1a, 0xe, 0x5c, 0x5e, 0xa, - 0xaf, 0x1a, 0xc4, 0x5f, 0x13, 0x65, 0x3f, 0x7c, 0xd6, 0x27, 0x9e, 0xfc, - 0x53, 0x37, 0x59, 0x40, 0x48, 0x9, 0x24, 0xfa, 0x59, 0x45, 0xf, 0xc0, - 0xae, 0xa1, 0x71, 0x9, 0xb, 0x77, 0x41, 0xe0, 0xdd, 0xaa, 0xfe, 0xc4, - 0x31, 0x2b, 0x90, 0xfa, 0x28, 0x5c, 0x88, 0x67, 0xd7, 0xcf, 0x40, 0x31, - 0x8c, 0x85, 0x6, 0xd, 0x8, 0x3e, 0x5e, 0x3c, 0x87, 0xf, 0x3f, 0x7b, - 0x22, 0x3d, 0x47, 0x3e, 0xdf, 0x9b, 0x72, 0x8c, 0x77, 0x29, 0xd5, 0xfe, - 0x5d, 0x16, 0x91, 0x87, 0x6d, 0x45, 0x92, 0x7d, 0xea, 0x13, 0x7c, 0xc9, - 0x94, 0xc3, 0xb, 0xf7, 0x49, 0xf3, 0x22, 0xd5, 0x5b, 0x60, 0xda, 0xc3, - 0x53, 0x6e, 0x70, 0x8d, 0x87, 0x79, 0x6e, 0x90, 0xd3, 0x6a, 0x7c, 0xae, - 0xc8, 0x28, 0xb, 0x9c, 0x6, 0xf6, 0xdb, 0x1e, 0x4b, 0x18, 0x34, 0x69, - 0x1c, 0x3c, 0x1a, 0xf4, 0xf8, 0x9c, 0xc8, 0x7f, 0xf9, 0x40, 0xf2, 0xb1, - 0x3f, 0xa, 0x56, 0xc7, 0xc5, 0x3c, 0x31, 0xdb, 0x8f, 0x1b, 0xc3, 0x5, - 0x0, 0xd4, 0x8c, 0x34, 0x73, 0xc, 0xa7, 0x3e, 0xd1, 0xca, 0x8b, 0x6e, - 0x42, 0x71, 0xfc, 0x62, 0x90, 0x4c, 0x33, 0xca, 0xdd, 0x4d, 0xc9, 0xe0, - 0x38, 0xb4, 0xa8, 0x50, 0xd4, 0x18, 0x7d, 0xd4, 0x59, 0x4d, 0x2, 0xdb, - 0xbd, 0x92, 0x60, 0xf1, 0x7e, 0x61, 0x36, 0xf5, 0x2a, 0x55, 0x8f, 0x32, - 0x3d, 0x21, 0xa7, 0xa, 0x23, 0x35, 0xe7, 0xb4, 0x35, 0x83, 0x6a, 0x35, - 0xbd, 0xe7, 0xfc, 0x55, 0x1a, 0x53, 0xc1, 0x63, 0xe4, 0x89, 0xa8, 0xce, - 0xc8, 0x23, 0x55, 0x17, 0xea, 0xa8, 0xe9, 0xf2, 0xe9, 0x4e, 0x6f, 0xf8, - 0x78, 0xa7, 0xdf, 0xe0, 0x75, 0xf4, 0x2e, 0x3, 0xb5, 0x57, 0x99, 0xb3, - 0x93, 0x1f, 0xf0, 0x7, 0x43, 0xc6, 0x3a, 0xf2, 0x5d, 0xae, 0xd7, 0xe6, - 0x1b, 0x4c, 0x8a, 0x5, 0x35, 0x12, 0x74, 0x25, 0x76, 0x8d, 0x83, 0xba, - 0xbe, 0x25, 0x4f, 0x10, 0x5e, 0xd2, 0xc8, 0xc5, 0xa8, 0xdc, 0x31, 0x2c, - 0xe9, 0x18, 0x40, 0x3d, 0x4a, 0x4a, 0x5f, 0xd7, 0xf0, 0xfa, 0xd9, 0xa0, - 0x6e, 0x0, 0x14, 0xf7, 0xa9, 0xe6, 0x6e, 0x43, 0xb3, 0x80, 0x95, 0x1f, - 0x2d, 0x72, 0x77, 0x3f, 0x2f, 0xbc, 0xc4, 0xea, 0x5f, 0xaa, 0xa1, 0x1f, - 0x55, 0x94, 0x94, 0xe8, 0x9f, 0x21, 0x28, 0xbd, 0xd, 0x4a, 0x39, 0x4c, - 0xac, 0x27, 0xd, 0xf3, 0x4c, 0x34, 0xc7, 0xc, 0xf8, 0x4f, 0x70, 0x7, - 0xa7, 0x49, 0x63, 0x1, 0xc7, 0xe9, 0xb9, 0xc6, 0xe6, 0x4a, 0x26, 0xec, - 0xfd, 0x73, 0xb3, 0x45, 0xe9, 0x69, 0xf4, 0x2c, 0x1e, 0xc5, 0xd7, 0xa, - 0x1d, 0x95, 0xd6, 0x9b, 0x4c, 0xb0, 0xa, 0x80, 0x45, 0x98, 0x70, 0x80, - 0xa7, 0x15, 0xc7, 0x8, 0x76, 0xa9, 0x87, 0x99, 0xcb, 0xeb, 0x44, 0xb2, - 0x36, 0xdd, 0x75, 0x60, 0x13, 0x75, 0x33, 0xe1, 0xb8, 0x3b, 0xde, 0xac, - 0xcc, 0xc, 0x15, 0x2c, 0x4a, 0xb5, 0x7b, 0x65, 0x49, 0x1f, 0x1, 0x4c, - 0x56, 0xcb, 0x5d, 0x8f, 0x99, 0xcc, 0xc4, 0x21, 0xe7, 0x6c, 0x84, 0x89, - 0xac, 0x9c, 0x50, 0x77, 0x32, 0xf9, 0xc8, 0xf2, 0x61, 0x87, 0x3f, 0xc7, - 0x69, 0xff, 0xb7, 0xbd, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, - 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, - 0xa2, 0x67, 0x30, 0xc1, 0x9a, 0x9b, 0x60, 0x1, 0x9e, 0x5f, 0xc3, 0xba, - 0xdb, 0xdc, 0x7, 0xf7, 0x41, 0x11, 0xf3, 0xe3, 0x98, 0x14, 0xfe, 0x57, - 0xa4, 0x20, 0x8e, 0xf5, 0x2, 0x52, 0xd0, 0xac, 0x81, 0xb2, 0x93, 0x5a, - 0x67, 0xee, 0x2e, 0x8d, 0x87, 0xf5, 0x49, 0x93, 0x75, 0x76, 0x34, 0x1a, - 0x3a, 0x76, 0xdd, 0x5f, 0x8f, 0xdf, 0x5, 0x5e, 0xea, 0xa8, 0xb9, 0xae, - 0xf9, 0xd, 0x87, 0xa0, 0x66, 0x68, 0x6, 0xfe, 0xad, 0xc7, 0xe2, 0x12, - 0x88, 0xd1, 0x3f, 0x6d, 0xd7, 0x6d, 0xb0, 0x7, 0x71, 0xe2, 0x75, 0x88, - 0x8b, 0xb6, 0xb5, 0xcd, 0x7d, 0x67, 0xe3, 0x80, 0x4f, 0xcc, 0x63, 0xd3, - 0x8f, 0x1a, 0x4, 0xd6, 0xe5, 0xf3, 0x56, 0xa, 0x21, 0x18, 0x56, 0x7b, - 0x1, 0x15, 0x46, 0x19, 0xb8, 0xd4, 0xe8, 0xad, 0xb9, 0x49, 0x13, 0x3e, - 0x8f, 0x27, 0xfd, 0x38, 0xe4, 0x85, 0x58, 0xae, 0x30, 0x2a, 0x8, 0x69, - 0xa4, 0x22, 0xef, 0xcc, 0x3b, 0x26, 0x9f, 0x57, 0xc4, 0x9b, 0x7e, 0x3b, - 0xf3, 0x72, 0xb3, 0x2a, 0x27, 0x18, 0xd9, 0xc4, 0xf3, 0x1e, 0x9a, 0xda, - 0x71, 0x29, 0x1d, 0xf3, 0xaf, 0x85, 0xc, 0x5e, 0x53, 0x90, 0xc0, 0x33, - 0x44, 0x88, 0x51, 0x59, 0xd8, 0x95, 0xbc, 0x31, 0xed, 0xed, 0x35, 0x7, - 0xf4, 0xb2, 0x8a, 0xe6, 0x84, 0x19, 0xab, 0xed, 0xab, 0xae, 0xce, 0x9, - 0x30, 0xee, 0xa9, 0x3d, 0xf0, 0xf8, 0x67, 0xfa, 0xaf, 0xeb, 0x7e, 0xb0, - 0x79, 0xe3, 0xfc, 0x2, 0xc3, 0x74, 0xf6, 0x69, 0xbd, 0x3c, 0xef, 0xf0, - 0x3c, 0x85, 0xc2, 0xf4, 0x7c, 0xe3, 0xef, 0x2f, 0x54, 0x8e, 0x1f, 0x95, - 0xbb, 0x40, 0x5d, 0x2f, 0x0, 0x5, 0xc3, 0x39, 0x8b, 0xbe, 0x51, 0x77, - 0xbe, 0xe8, 0x5b, 0x6e, 0x16, 0x27, 0x94, 0xda, 0xba, 0x3e, 0x2f, 0xb1, - 0x61, 0x77, 0x2d, 0xfe, 0x2a, 0x5a, 0x70, 0xd2, 0xab, 0xdb, 0x46, 0x7a, - 0xb6, 0x42, 0x86, 0xbf, 0x97, 0x9f, 0xa, 0xa3, 0xc1, 0x82, 0x2c, 0x58, - 0x21, 0xba, 0xad, 0x61, 0xab, 0x4d, 0x31, 0xe1, 0xd8, 0x81, 0x59, 0xfb, - 0x29, 0xe9, 0xaf, 0xef, 0x79, 0xfa, 0x9, 0x4a, 0x32, 0x3, 0xa9, 0xc, - 0x7d, 0xb5, 0x8b, 0x28, 0xbf, 0xfb, 0xae, 0xd7, 0x55, 0x5f, 0x10, 0x7d, - 0xc6, 0xe8, 0x87, 0x2d, 0x6e, 0xdb, 0x84, 0xa7, 0xbb, 0x2d, 0xb4, 0x8b, - 0x49, 0xf1, 0x3c, 0x7a, 0xdd, 0x7e, 0xcc, 0x4b, 0x1d, 0x5d, 0x1f, 0x3e, - 0x3c, 0xf3, 0xcd, 0x4f, 0xde, 0x17, 0xe2, 0xcc, 0x1d, 0x9b, 0x6e, 0x34, - 0xf3, 0xca, 0x4b, 0xda, 0x0, 0xb7, 0xc4, 0x82, 0x5e, 0x97, 0xbb, 0x59, - 0x7d, 0xe8, 0x76, 0x5c, 0x5b, 0x7d, 0x79, 0x41, 0x29, 0x32, 0xe1, 0xa7, - 0xce, 0x82, 0x51, 0xbe, 0x7, 0x81, 0x8, 0x79, 0xc1, 0x94, 0x65, 0xf9, - 0xfb, 0x6e, 0xa2, 0x52, 0xe5, 0xc, 0xa6, 0x9e, 0xe4, 0xcd, 0xa8, 0x76, - 0xb3, 0xb1, 0x97, 0xc6, 0x37, 0xb0, 0x59, 0xe2, 0x93, 0x9b, 0xc5, 0x9d, - 0x4b, 0xc7, 0xcf, 0x6b, 0xd2, 0x3d, 0x74, 0xda, 0x7e, 0xd1, 0x92, 0xf3, - 0xd2, 0xb7, 0x86, 0x53, 0x25, 0x2a, 0xdf, 0x6d, 0xe2, 0x6, 0x25, 0x38, - 0x36, 0xb2, 0x39, 0xe1, 0x2e, 0xa, 0xe9, 0x18, 0xfe, 0x37, 0xfe, 0x3f, - 0xcd, 0x1a, 0xcf, 0x9, 0xb6, 0xfd, 0x90, 0xc0, 0x8a, 0x28, 0xde, 0xa9, - 0x94, 0xa, 0x77, 0xf3, 0x22, 0xf8, 0xbc, 0xa6, 0xba, 0x1a, 0xb7, 0x3b, - 0x1f, 0x80, 0x4c, 0x1f, 0xa6, 0x59, 0xb9, 0x64, 0x73, 0xfa, 0x4c, 0xe8, - 0x1a, 0xd5, 0x9, 0xa5, 0x2e, 0x24, 0xb0, 0x68, 0xf0, 0x68, 0x12, 0xef, - 0x72, 0x2b, 0x1, 0x15, 0xfc, 0xd9, 0x70, 0x41, 0x1, 0xa6, 0x94, 0x89, - 0x3f, 0x76, 0x25, 0x79, 0xf8, 0x5d, 0x24, 0xe, 0x83, 0xdb, 0x8a, 0xfb, - 0x93, 0xeb, 0x61, 0x63, 0xc0, 0x4e, 0xf8, 0x7e, 0x55, 0xf0, 0xfe, 0x2c, - 0xf7, 0x18, 0xd7, 0x83, 0x29, 0x3, 0x68, 0xf5, 0xd9, 0xd0, 0x20, 0x52, - 0x63, 0x5, 0xbd, 0x74, 0x15, 0xe6, 0xab, 0xf2, 0x49, 0x34, 0xe7, 0x20, - 0xb1, 0x12, 0xbd, 0x87, 0x14, 0x82, 0xbc, 0xef, 0x79, 0x1c, 0x4e, 0xdd, - 0x62, 0x0, 0xba, 0x87, 0x4e, 0x64, 0xe5, 0x9b, 0x97, 0xf4, 0x2b, 0xc, - 0x22, 0x65, 0x35, 0x35, 0xa6, 0xb0, 0x80, 0x75, 0x14, 0x35, 0x2e, 0x9a, - 0xdb, 0x75, 0x92, 0x2, 0xec, 0x33, 0x53, 0x43, 0x57, 0x44, 0x19, 0x7e, - 0x5e, 0x2c, 0x3e, 0x49, 0xa9, 0xa8, 0xb1, 0x26, 0x5f, 0xa3, 0x21, 0x96, - 0xee, 0x66, 0x2d, 0x27, 0x8d, 0x36, 0xaf, 0xe3, 0x80, 0x15, 0xce, 0x8c, - 0xff, 0xa8, 0xd4, 0x7a, 0x7f, 0x28, 0x99, 0x8, 0xe9, 0x13, 0x3, 0x2e, - 0x83, 0x26, 0xa4, 0x36, 0x3d, 0x1f, 0xcf, 0x2, 0x5c, 0x7b, 0x0, 0x3c, - 0xb, 0x18, 0xa2, 0xe4, 0x1b, 0x13, 0xbf, 0x67, 0x61, 0x7d, 0x27, 0x6c, - 0xbf, 0xa, 0xfd, 0xcf, 0x74, 0xa8, 0x74, 0x3a, 0xdd, 0xe3, 0x81, 0xb9, - 0x2f, 0xda, 0x95, 0xd, 0xfa, 0xf7, 0x7c, 0xd7, 0xf6, 0xc6, 0xca, 0x7a, - 0x2d, 0xf2, 0xe1, 0xd9, 0xf5, 0xcd, 0xff, 0x75, 0x79, 0x32, 0xe7, 0xb1, - 0x6e, 0xf4, 0xa9, 0xe4, 0xbd, 0xdc, 0xf2, 0xcd, 0xa4, 0xaf, 0xa5, 0xa7, - 0xf2, 0x27, 0xc1, 0x1d, 0x70, 0x0, 0xa7, 0xa6, 0xf3, 0x6b, 0x2c, 0xef, - 0x84, 0x59, 0xba, 0xfc, 0x4e, 0x92, 0xe, 0x29, 0x5e, 0xfa, 0x96, 0x5f, - 0xde, 0x1b, 0x34, 0x1a, 0x58, 0x2f, 0xfd, 0x62, 0x22, 0xb9, 0xdd, 0x38, - 0xf0, 0x70, 0x9, 0x30, 0x47, 0x5b, 0x3a, 0x38, 0x49, 0x77, 0x44, 0xc, - 0x22, 0x5c, 0xb0, 0x5f, 0x17, 0x52, 0x50, 0xd8, 0x51, 0x7e, 0x96, 0xcc, - 0x3d, 0xea, 0x7f, 0x25, 0x6d, 0xdb, 0x39, 0x97, 0x71, 0xc3, 0xea, 0xbd, - 0x71, 0x92, 0x2f, 0x4d, 0xe9, 0x5d, 0xac, 0x26, 0x41, 0x71, 0x42, 0xfa, - 0xe3, 0x8c, 0x22, 0xfa, 0x85, 0xc5, 0x21, 0xca, 0x85, 0x70, 0xc9, 0x69, - 0xbf, 0x48, 0x95, 0x6, 0x7a, 0x33, 0x77, 0xf3, 0x76, 0x7a, 0x9b, 0x4e, - 0xf3, 0xd2, 0xd1, 0x8f, 0xbd, 0x3c, 0xe2, 0xa8, 0xe7, 0x7b, 0xde, 0xa, - 0xaf, 0x3e, 0x6e, 0x21, 0x96, 0xe, 0x52, 0x93, 0x75, 0x97, 0x6b, 0x6, - 0xbf, 0x9e, 0x50, 0x51, 0xa, 0xdc, 0x96, 0x15, 0x62, 0x1, 0x94, 0x2d, - 0x44, 0x2a, 0xc0, 0xc0, 0xf, 0x8c, 0xd6, 0x63, 0x74, 0x73, 0x99, 0xe5, - 0x49, 0xad, 0xf5, 0xb4, 0x41, 0x97, 0x6, 0xbc, 0x81, 0x6c, 0x40, 0xd7, - 0x45, 0x6f, 0x72, 0xa5, 0x51, 0xf8, 0xc0, 0xa1, 0x4e, 0xce, 0x75, 0x93, - 0x85, 0x5f, 0xe8, 0x8b, 0x5e, 0x6b, 0x48, 0xc1, 0xf8, 0x55, 0xea, 0xc6, - 0xc5, 0x7, 0x83, 0x33, 0xcc, 0x1f, 0x55, 0xe1, 0xc9, 0xe4, 0x6d, 0x31, - 0x3c, 0x41, 0x5c, 0xa8, 0xec, 0x82, 0xfa, 0x30, 0x87, 0xfa, 0x16, 0x90, - 0x16, 0x29, 0xb5, 0x4b, 0x7e, 0xb9, 0xc5, 0x32, 0xc8, 0xb2, 0xa6, 0x59, - 0xfa, 0x80, 0x26, 0x1, 0xfb, 0x3c, 0xe4, 0x3b, 0xb5, 0x2, 0x7b, 0xd, - 0xf7, 0x5a, 0xaa, 0x8, 0x51, 0xa0, 0x54, 0x7d, 0x1, 0x28, 0x31, 0x14, - 0x3b, 0x24, 0x1f, 0x25, 0x9e, 0xd5, 0x51, 0x2a, 0x1f, 0xad, 0xd7, 0x34, - 0x46, 0x95, 0x74, 0x48, 0xa4, 0x1e, 0x62, 0xd1, 0x29, 0x84, 0xfc, 0x7b, - 0x75, 0x36, 0xfe, 0xa1, 0x41, 0xda, 0x6c, 0xe9, 0x59, 0xf8, 0xd0, 0x68, - 0x7a, 0x4b, 0x93, 0x26, 0xb9, 0x28, 0xf5, 0xdd, 0x7a, 0xd7, 0xb6, 0x69, - 0xae, 0xd0, 0x4c, 0xc3, 0x98, 0xca, 0x12, 0xc, 0x55, 0x59, 0x96, 0x59, - 0xde, 0xad, 0xac, 0xbd, 0xe3, 0xb, 0x48, 0x3c, 0x13, 0x80, 0xbf, 0x49, - 0x59, 0xfa, 0x38, 0x82, 0x9b, 0x9, 0x33, 0xbc, 0x9c, 0x17, 0x93, 0x93, - 0xad, 0x8e, 0x58, 0x3f, 0x5, 0x40, 0x75, 0x3f, 0xf7, 0xcd, 0x54, 0x8d, - 0x52, 0x8d, 0xf6, 0xeb, 0xbc, 0x31, 0x4a, 0xce, 0xb2, 0x3f, 0xc8, 0x8e, - 0x52, 0x7a, 0xa4, 0x46, 0xea, 0x1e, 0x9a, 0xa, 0x69, 0x20, 0x98, 0x98, - 0x45, 0xb0, 0xed, 0xa2, 0x6b, 0x65, 0xec, 0x6d, 0x53, 0xba, 0xaf, 0xb1, - 0xe7, 0xf7, 0x41, 0xbf, 0x35, 0x97, 0xc1, 0xb7, 0xa2, 0xe4, 0x8e, 0x93, - 0xea, 0x1b, 0xb1, 0xb5, 0xe3, 0x65, 0xab, 0xd1, 0x28, 0xd8, 0x50, 0x86, - 0x33, 0x86, 0x60, 0x26, 0xf4, 0x56, 0x48, 0xe5, 0x54, 0x6a, 0x17, 0x44, - 0x46, 0x76, 0x55, 0x4f, 0x43, 0xaf, 0x28, 0x99, 0x7b, 0x96, 0x6e, 0x7c, - 0xcb, 0xb9, 0xcc, 0x1c, 0xf, 0x84, 0x4a, 0x80, 0x53, 0x4c, 0x42, 0xcd, - 0xf0, 0x23, 0x2d, 0x3f, 0x8d, 0x2, 0x79, 0xc0, 0x7d, 0xce, 0x7d, 0xe5, - 0xfb, 0xe4, 0x7b, 0x65, 0x65, 0x6, 0x30, 0x44, 0x4e, 0x36, 0x85, 0x44, - 0x5a, 0x32, 0x47, 0x23, 0xe5, 0x98, 0x80, 0xb2, 0xb8, 0x5a, 0x1c, 0x84, - 0x86, 0x2, 0x71, 0x6d, 0xbe, 0x99, 0x88, 0xd, 0x26, 0x2e, 0x95, 0x1d, - 0xde, 0xb8, 0x2d, 0x40, 0xd5, 0xec, 0x7a, 0xb1, 0x8b, 0x6b, 0x67, 0xf4, - 0x2a, 0x93, 0xb4, 0xcb, 0xef, 0xab, 0x24, 0x13, 0x2b, 0xa1, 0x34, 0x18, - 0xa0, 0x28, 0xfe, 0xb3, 0x5, 0x3, 0x92, 0x49, 0x9, 0xa, 0xf2, 0x63, - 0xde, 0xd1, 0xf9, 0xfb, 0x50, 0xc1, 0x4, 0x26, 0xc8, 0x8b, 0xf2, 0x20, - 0x8, 0xb4, 0xbb, 0x45, 0x15, 0x3a, 0x27, 0xb4, 0xd3, 0x27, 0x85, 0xbc, - 0x8, 0x8f, 0xf1, 0xa2, 0x42, 0x16, 0x19, 0xb6, 0xc6, 0x11, 0x6f, 0x39, - 0x6c, 0x69, 0x53, 0xc, 0x31, 0x9e, 0x57, 0x4, 0x71, 0xf5, 0xf7, 0xff, - 0x11, 0xc4, 0x65, 0xde, 0x22, 0x11, 0x37, 0x3, 0x4c, 0x56, 0x4d, 0xf8, - 0x40, 0x34, 0x32, 0x69, 0x2, 0x54, 0xaf, 0x96, 0x10, 0x18, 0xd9, 0x35, - 0xf, 0x53, 0x53, 0x69, 0x9c, 0x36, 0x95, 0x62, 0x57, 0xf9, 0xed, 0xf0, - 0x41, 0x97, 0x72, 0xdb, 0x1c, 0xb6, 0xda, 0xab, 0x7a, 0x24, 0xac, 0x89, - 0x97, 0x15, 0x37, 0x6e, 0xfe, 0xef, 0x3c, 0xfc, 0x16, 0x91, 0x4b, 0xf0, - 0x57, 0x4a, 0xbc, 0x48, 0xe, 0x8, 0xe, 0x81, 0xe8, 0x8e, 0x98, 0x29, - 0x6, 0x58, 0xfc, 0xc1, 0x80, 0x1c, 0x63, 0x3c, 0x6a, 0xa7, 0xe4, 0x78, - 0x13, 0x53, 0xb6, 0x4b, 0xb2, 0x67, 0xc9, 0xfd, 0x3b, 0x6e, 0xaf, 0xd0, - 0xd5, 0x2b, 0x38, 0xf9, 0xc0, 0x0, 0x4, 0xc4, 0x25, 0xf9, 0xd2, 0x2a, - 0x83, 0xec, 0x1d, 0x49, 0x27, 0xda, 0xf8, 0xd1, 0x9e, 0x8e, 0x37, 0x73, - 0x6e, 0xb6, 0x25, 0x65, 0x39, 0xf9, 0xef, 0x74, 0xb6, 0xd3, 0x16, 0x94, - 0x9c, 0x6e, 0xac, 0xc6, 0x8b, 0x13, 0xc, 0xcf, 0x28, 0x94, 0xe9, 0xed, - 0x2e, 0xe4, 0x75, 0xc4, 0xe7, 0x1e, 0xc9, 0xd3, 0xad, 0xa9, 0x35, 0x7f, - 0x23, 0x8a, 0x88, 0x6, 0x3b, 0x89, 0xcc, 0x6, 0xc0, 0xc1, 0x79, 0x5e, - 0x70, 0x6c, 0xc2, 0x9b, 0x76, 0x22, 0x99, 0x5c, 0xbe, 0xcf, 0x16, 0x2a, - 0x47, 0x98, 0xfb, 0xe6, 0x83, 0x83, 0x8c, 0xab, 0x27, 0xc6, 0xb2, 0x5e, - 0x76, 0x2, 0x85, 0xf, 0x91, 0x19, 0x38, 0x57, 0xbc, 0x6f, 0xd9, 0x5, - 0xac, 0xf3, 0x7e, 0xfc, 0x68, 0x3, 0xb3, 0x4f, 0x96, 0xab, 0x84, 0x71, - 0x58, 0xce, 0xd9, 0x61, 0xfe, 0xd6, 0x1c, 0xd1, 0xcc, 0xb2, 0x7e, 0xc8, - 0x3a, 0x41, 0x9d, 0x5b, 0x64, 0xc2, 0xf2, 0xd8, 0xa1, 0x9e, 0xfa, 0xec, - 0xea, 0xf9, 0x1c, 0x35, 0x71, 0xe5, 0x42, 0xec, 0x8e, 0x46, 0x17, 0x9b, - 0x8e, 0xdc, 0x7e, 0x81, 0x1, 0x1b, 0xab, 0x2e, 0x9d, 0xea, 0xe0, 0x28, - 0xe7, 0x70, 0xdd, 0x8d, 0xf7, 0x19, 0x4f, 0xb, 0x60, 0x2e, 0xca, 0x7d, - 0x7a, 0x11, 0x2d, 0x1e, 0xa2, 0xe, 0x9f, 0x15, 0x8b, 0x8a, 0x58, 0x9d, - 0xd0, 0x0, 0xe, 0xc9, 0x6b, 0xde, 0x94, 0x88, 0xcf, 0x1d, 0x71, 0x44, - 0x9c, 0x1, 0x74, 0x69, 0x71, 0x14, 0xf9, 0x62, 0x7, 0x9e, 0xa2, 0x87, - 0xa6, 0x4f, 0xa6, 0x5, 0xe, 0xfd, 0x1e, 0xf5, 0xa6, 0xe4, 0x30, 0x9b, - 0x39, 0x91, 0xe0, 0x3c, 0xbd, 0x72, 0x30, 0x84, 0x85, 0xb5, 0x67, 0xad, - 0xf, 0x87, 0x88, 0xf8, 0x83, 0x1, 0x3c, 0x14, 0x7f, 0x72, 0xee, 0x58, - 0x62, 0xa1, 0xf0, 0x46, 0x65, 0x7e, 0x74, 0xbf, 0xc6, 0xee, 0x74, 0x85, - 0x46, 0xe, 0x82, 0x8c, 0x48, 0x40, 0x66, 0x99, 0x6d, 0x97, 0x7d, 0x35, - 0x5b, 0x2a, 0x48, 0x77, 0xd2, 0xd2, 0x32, 0x35, 0x7e, 0xa1, 0x4c, 0xa8, - 0x64, 0x8d, 0x30, 0xa4, 0xe3, 0xe0, 0x9a, 0x4, 0x73, 0x9a, 0xef, 0x46, - 0x82, 0x38, 0x7b, 0x58, 0x6e, 0xaf, 0xe5, 0x38, 0x13, 0xa1, 0xe0, 0x65, - 0x6a, 0xda, 0x88, 0x47, 0xde, 0xf3, 0xc4, 0x4c, 0xca, 0xdb, 0xf9, 0x6e, - 0x4e, 0xe8, 0xd9, 0x8, 0x8a, 0x84, 0x90, 0x8f, 0x7b, 0xc0, 0x9e, 0x86, - 0x29, 0x38, 0xbc, 0xf0, 0x13, 0xb4, 0xee, 0xc8, 0xb2, 0xc6, 0xb4, 0xdf, - 0x22, 0x68, 0x27, 0x9d, 0x6, 0x76, 0x65, 0xfd, 0xe0, 0xbf, 0xe9, 0x0, - 0xe9, 0x17, 0x29, 0x7f, 0xf1, 0x8c, 0xf1, 0xc, 0x21, 0xe3, 0xa2, 0x8d, - 0xc8, 0xf1, 0x36, 0x62, 0x60, 0x98, 0xd9, 0x24, 0xc2, 0xba, 0x2c, 0x83, - 0x99, 0x1, 0xcc, 0x73, 0xd, 0x52, 0x14, 0x98, 0xd6, 0xf3, 0x6c, 0x48, - 0x44, 0x83, 0xe6, 0x5c, 0xfa, 0x41, 0x1d, 0xb8, 0x1c, 0xf6, 0xf6, 0x89, - 0xab, 0xbd, 0x7c, 0x45, 0x87, 0xed, 0xc6, 0x2b, 0x94, 0x22, 0x8b, 0xfd, - 0xa4, 0x7a, 0x64, 0xf7, 0xab, 0x29, 0xb7, 0x2, 0xb7, 0xc4, 0xba, 0xa2, - 0x15, 0x15, 0x26, 0x19, 0x82, 0x89, 0x52, 0x73, 0x32, 0xb4, 0xd6, 0xae, - 0x3b, 0x42, 0xb, 0xbe, 0x4c, 0xff, 0x3c, 0xe4, 0xa3, 0x98, 0x77, 0x32, - 0x3e, 0x3b, 0x7f, 0x98, 0x40, 0x7e, 0x5f, 0xa2, 0x24, 0x39, 0xfd, 0x25, - 0x93, 0x51, 0xe3, 0x1b, 0x47, 0xe2, 0xce, 0xc7, 0x3d, 0x8d, 0x4a, 0x96, - 0xd7, 0x13, 0xf0, 0x39, 0x28, 0xc7, 0xbd, 0xfd, 0x68, 0xee, 0x31, 0x4d, - 0x9e, 0xaa, 0xc2, 0x7, 0x7a, 0x6d, 0xfc, 0x66, 0x80, 0x7a, 0xca, 0xe5, - 0xff, 0x78, 0x28, 0xca, 0xe5, 0xa, 0x1, 0x52, 0x2, 0xf4, 0x3d, 0x37, - 0x3c, 0x3f, 0x72, 0xa5, 0x7f, 0x2a, 0xa2, 0x4d, 0x63, 0x65, 0x60, 0xe9, - 0x51, 0x18, 0xdb, 0x59, 0x3d, 0xb2, 0xe3, 0xb0, 0x3f, 0xf0, 0x97, 0x9b, - 0xc4, 0x51, 0x7f, 0x88, 0xfb, 0x85, 0x61, 0xea, 0xaa, 0xb3, 0x6e, 0xd6, - 0x8f, 0x1b, 0x1e, 0xb7, 0x8d, 0x25, 0xed, 0x7c, 0x59, 0xd4, 0xd5, 0x14, - 0x95, 0xc, 0x2f, 0x8e, 0xa5, 0x48, 0xfa, 0x14, 0xf1, 0x7b, 0x2a, 0x21, - 0xd5, 0xc4, 0x75, 0x2, 0xe4, 0x49, 0xd, 0x9b, 0x2e, 0x83, 0x13, 0x22, - 0xe6, 0xdf, 0xf2, 0xfc, 0xf8, 0xa7, 0x5a, 0xd2, 0xe1, 0x7a, 0x27, 0xe9, - 0x8b, 0x3, 0xa1, 0xde, 0xe1, 0x27, 0xd8, 0xfc, 0x2c, 0x6a, 0x67, 0x85, - 0xdc, 0x1d, 0x1f, 0x59, 0x10, 0x99, 0xce, 0x2e, 0x48, 0x86, 0xf6, 0x9c, - 0xf6, 0x79, 0x79, 0x7c, 0xdf, 0x8e, 0xa3, 0x14, 0x9a, 0xa3, 0xe5, 0xf3, - 0x74, 0x62, 0x62, 0x37, 0x83, 0x89, 0xf2, 0xd7, 0xda, 0xdd, 0x5, 0x11, - 0xaf, 0xc1, 0xe4, 0x2a, 0xaa, 0xa7, 0xc0, 0xa6, 0x2a, 0xc5, 0x17, 0xa7, - 0xea, 0x23, 0x56, 0xea, 0x3d, 0x52, 0x32, 0x31, 0x16, 0xb1, 0x4d, 0xa8, - 0x0, 0x44, 0x59, 0x7a, 0xf7, 0x6b, 0x5, 0x4d, 0x5c, 0xf8, 0xe, 0xa, - 0x48, 0x63, 0xe5, 0x94, 0xef, 0x74, 0x8e, 0x47, 0x3e, 0xd9, 0xb1, 0x2d, - 0x15, 0xaf, 0x52, 0x6e, 0x63, 0xe6, 0x88, 0x5d, 0xcd, 0xc0, 0x8a, 0xd2, - 0xa, 0x96, 0x24, 0x1, 0xe5, 0xe6, 0xad, 0xf1, 0xee, 0xe6, 0xbb, 0xa1, - 0x5f, 0x50, 0x63, 0x1d, 0xa, 0xec, 0xda, 0xb1, 0xff, 0x7a, 0x4d, 0x83, - 0x24, 0xcd, 0xde, 0x38, 0x31, 0x7f, 0xe5, 0x93, 0x2d, 0x3e, 0x3c, 0xa8, - 0x55, 0x81, 0x7b, 0xa2, 0x5f, 0xfb, 0xa7, 0xa7, 0x1b, 0x27, 0xd9, 0x22, - 0x19, 0xce, 0x66, 0xc6, 0x59, 0x60, 0xeb, 0xdc, 0x45, 0x6, 0xe2, 0xf3, - 0xfd, 0x43, 0x3d, 0x5e, 0x72, 0xd, 0x62, 0x70, 0xfd, 0x61, 0x43, 0xe4, - 0x2f, 0xc5, 0x58, 0x70, 0x18, 0xa2, 0xee, 0xb9, 0xaa, 0x20, 0x3c, 0x4d, - 0x7f, 0xf5, 0xc3, 0x29, 0x4d, 0x43, 0x20, 0xb1, 0x50, 0x84, 0x38, 0x56, - 0xb4, 0x94, 0xa2, 0x5, 0xa3, 0x84, 0xae, 0x41, 0x17, 0x53, 0x51, 0xe1, - 0x2f, 0x4a, 0xa6, 0xa7, 0x8b, 0x5, 0x4b, 0x2f, 0x50, 0xfd, 0xaa, 0xa0, - 0xe1, 0x59, 0xe6, 0x1b, 0x94, 0x46, 0x17, 0x29, 0x4f, 0xdc, 0x4e, 0x46, - 0xff, 0xd1, 0xa9, 0x6a, 0x3f, 0xa7, 0x33, 0x13, 0x85, 0x8, 0xd1, 0x40, - 0xdc, 0x95, 0xe0, 0x53, 0xdc, 0x6c, 0xf4, 0xee, 0xd4, 0x90, 0x76, 0x64, - 0xc, 0x43, 0x54, 0x44, 0x2d, 0x73, 0xed, 0x63, 0x99, 0xe3, 0x2, 0xad, - 0x4e, 0x10, 0xc, 0x8f, 0x31, 0x6b, 0x53, 0xeb, 0xc7, 0x6f, 0xfd, 0x3a, - 0xfe, 0xb2, 0x78, 0x35, 0xc, 0x2b, 0x34, 0xeb, 0x9a, 0x9d, 0xf9, 0x93, - 0x18, 0xcf, 0xeb, 0x43, 0xb5, 0xaa, 0x89, 0xdd, 0xec, 0x80, 0xd4, 0xbc, - 0x4a, 0x45, 0xea, 0x56, 0x2, 0xb2, 0xb5, 0xe9, 0xb3, 0x8a, 0x5e, 0x30, - 0xf7, 0x76, 0xeb, 0xf0, 0x25, 0x4c, 0x5d, 0xe9, 0x76, 0x9, 0x5f, 0x7f, - 0x54, 0xe5, 0xd0, 0xa0, 0xf, 0xb4, 0xcc, 0x27, 0x1, 0xa4, 0x95, 0x15, - 0x4, 0xc0, 0xc8, 0x0, 0x16, 0xb6, 0x78, 0xe7, 0x79, 0xd1, 0x1a, 0x5e, - 0xfc, 0xaa, 0x2a, 0xc4, 0xb3, 0xc3, 0x62, 0x39, 0xde, 0x4c, 0xb7, 0x4b, - 0x4f, 0x5c, 0xe1, 0x58, 0x7f, 0x4c, 0x7e, 0x81, 0x9a, 0xbc, 0x57, 0xbd, - 0x1d, 0xae, 0xc7, 0x5a, 0x6f, 0xf8, 0xa7, 0x8c, 0x64, 0xee, 0xb6, 0x88, - 0x7d, 0xaf, 0x96, 0xfb, 0xf2, 0x60, 0xae, 0xdc, - }, - (char[]){ - 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, - 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, - 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, - 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, - 0xc1, 0x94, 0xe1, 0xdb, 0x36, 0x75, 0xce, 0xc5, 0x42, 0xa6, 0x31, 0xb, - 0x5a, 0x1d, 0xfe, 0x74, 0x44, 0xeb, 0x75, 0xc4, 0xd, 0x40, 0x68, 0xe6, - 0x1, 0x76, 0xfa, 0x61, 0x5e, 0x9d, 0x1d, 0x1b, 0x84, 0xb6, 0xa4, 0x9, - 0x5, 0xe0, 0x92, 0x93, 0x79, 0xed, 0xa1, 0x37, 0x42, 0xdd, 0xeb, 0xbc, - 0x80, 0xaa, 0x2e, 0xe6, 0xa8, 0x5c, 0xa3, 0x9a, 0xaf, 0x14, 0x61, 0xaa, - 0xf4, 0x79, 0x1c, 0x2c, 0xd7, 0x1b, 0xcb, 0x22, 0x11, 0x3d, 0xd9, 0x41, - 0x9d, 0xb8, 0x56, 0xf3, 0x62, 0xd0, 0x6e, 0xef, 0xbb, 0xcd, 0x9d, 0xdf, - 0x9e, 0xaa, 0x38, 0xd3, 0x93, 0xaa, 0x92, 0xb2, 0x95, 0x7, 0x98, 0x8f, - 0xb6, 0x3f, 0x9a, 0xc7, 0x2b, 0x95, 0x4, 0x94, 0xbe, 0xe4, 0x9b, 0x1d, - 0x4e, 0x62, 0x2b, 0xb9, 0x39, 0x17, 0x6, 0xdb, 0x57, 0x86, 0xdd, 0x22, - 0x27, 0xa5, 0x82, 0x16, 0x7a, 0xd6, 0xc7, 0xa5, 0x56, 0x46, 0x44, 0xc8, - 0x68, 0xd8, 0x30, 0xe7, 0xbd, 0xea, 0xb5, 0x74, 0x3, 0x9d, 0x57, 0x1c, - 0x8e, 0xe2, 0x17, 0x4d, 0xa3, 0x2b, 0xb7, 0xab, 0x21, 0xe0, 0x33, 0xe, - 0x20, 0x2c, 0xb1, 0x2f, 0x1, 0x8e, 0xaf, 0x36, 0x4, 0x77, 0x42, 0x4, - 0xb0, 0x39, 0xc0, 0x11, 0x59, 0xd1, 0xba, 0x8d, 0xf0, 0xfd, 0x37, 0xcf, - 0xec, 0xe9, 0xb9, 0x87, 0xe, 0xda, 0xd4, 0xbf, 0xe1, 0x9e, 0xe9, 0xd1, - 0x29, 0xb0, 0xcf, 0xb0, 0xdf, 0xbe, 0x14, 0x7, 0xe5, 0xe0, 0x20, 0xe5, - 0x6f, 0x39, 0x6d, 0x53, 0x35, 0xa8, 0x4d, 0x4a, 0x30, 0x54, 0xfb, 0x96, - 0x80, 0x4d, 0x44, 0xb6, 0x87, 0x66, 0x72, 0xcd, 0x63, 0x61, 0xf1, 0x2d, - 0xb1, 0x9c, 0x7, 0x51, 0x48, 0xc1, 0x53, 0x40, 0x0, 0x4f, 0x42, 0x4b, - 0xbc, 0x3c, 0x7e, 0x3d, 0xc2, 0xaf, 0xe4, 0x36, 0x95, 0x3a, 0x7c, 0xf6, - 0x14, 0xa0, 0xd4, 0x3d, 0x89, 0xb7, 0xa0, 0x4d, 0x57, 0x41, 0x9e, 0xa4, - 0x33, 0x6f, 0x28, 0x5a, 0x76, 0x17, 0x0, 0xd2, 0xe0, 0x88, 0xc, 0x43, - 0x42, 0xc8, 0xb4, 0xdc, 0x24, 0xc3, 0xd7, 0x8, 0x48, 0xe1, 0x76, 0xb8, - 0x6c, 0xbd, 0x7c, 0x72, 0xb2, 0x9d, 0xf, 0x7, 0x62, 0x3a, 0xf4, 0xd7, - 0x7b, 0xee, 0x8e, 0xba, 0x1, 0x45, 0x15, 0xfa, 0x55, 0xbd, 0x25, 0xba, - 0x7a, 0xfe, 0x83, 0x22, 0x9c, 0xca, 0x7b, 0x46, 0xb8, 0xcf, 0xfa, 0x16, - 0x1c, 0x74, 0x57, 0x75, 0x43, 0x26, 0x10, 0xad, 0x57, 0xff, 0xd4, 0xa7, - 0xe9, 0xfa, 0xeb, 0x84, 0x9f, 0xdc, 0x34, 0x63, 0x5e, 0x5, 0x8d, 0xc2, - 0xa6, 0x2e, 0x13, 0x8d, 0x33, 0xcc, 0x25, 0x2f, 0x4, 0xfb, 0x95, 0xcd, - 0x8d, 0x29, 0xd5, 0x9e, 0xaa, 0x14, 0x7b, 0xa3, 0xda, 0x1b, 0xa3, 0xc4, - 0x24, 0x75, 0xf1, 0x95, 0xbd, 0xb8, 0x1f, 0x8c, 0xe9, 0xb0, 0x78, 0xee, - 0x6b, 0x3a, 0x9a, 0x70, 0x1, 0x8, 0xf, 0x5f, 0xde, 0xdf, 0xd5, 0x2c, - 0x22, 0xbf, 0xc2, 0xbf, 0xcf, 0x7b, 0x7f, 0x58, 0x5c, 0x1e, 0xdf, 0xcd, - 0xe7, 0x4a, 0x52, 0xf7, 0x3d, 0xba, 0x2f, 0x3f, 0x55, 0x45, 0x7b, 0x9b, - 0xfc, 0xd0, 0xd4, 0xd3, 0xe0, 0x92, 0xa5, 0x9c, 0x1f, 0xd1, 0xef, 0xbb, - 0x93, 0xd3, 0x6b, 0x48, 0x59, 0xf1, 0xba, 0xf3, 0xf1, 0x4a, 0x29, 0x83, - 0xa8, 0x65, 0x8f, 0x46, 0x60, 0xb0, 0x8c, 0x10, 0xaa, 0xd1, 0xf5, 0xa0, - 0x1, 0xd5, 0x38, 0xeb, 0x14, 0x88, 0x60, 0x95, 0x17, 0xdc, 0x1f, 0xb9, - 0x55, 0xff, 0x9a, 0x5d, 0x46, 0x67, 0xa2, 0xa0, 0x7b, 0xd9, 0x7b, 0xdb, - 0x8f, 0xac, 0x43, 0x94, 0xa8, 0xdf, 0xc2, 0xc2, 0xa1, 0xec, 0xf0, 0x8c, - 0x6e, 0x35, 0x3f, 0xd3, 0x39, 0xcf, 0xee, 0x80, 0x23, 0xa, 0x73, 0x74, - 0x78, 0x1f, 0x19, 0x5d, 0xb, 0x88, 0xae, 0x3c, 0x67, 0x60, 0x85, 0xdd, - 0x2, 0x46, 0x51, 0x5c, 0x55, 0xba, 0x15, 0x24, 0xd2, 0x98, 0x70, 0x14, - 0x19, 0xa, 0x31, 0x3f, 0x38, 0x80, 0x85, 0x48, 0xde, 0xc2, 0xd, 0x67, - 0xc1, 0x46, 0xd3, 0x93, 0x49, 0x22, 0xa0, 0x4, 0xfe, 0xe6, 0xaa, 0x6f, - 0xa0, 0x2f, 0x7c, 0x22, 0x5, 0x49, 0xdf, 0xee, 0x2, 0x4d, 0x35, 0x4c, - 0xd1, 0x5d, 0x6d, 0xe3, 0xe2, 0x5a, 0xc4, 0x5e, 0x43, 0x1e, 0x47, 0x41, - 0xf9, 0xb7, 0x0, 0x53, 0x3a, 0xc3, 0x5e, 0xa5, 0x81, 0x36, 0x22, 0xe9, - 0x25, 0x38, 0xfe, 0x3a, 0x7d, 0xf2, 0xee, 0x33, 0x30, 0x72, 0x6e, 0x81, - 0xa1, 0x7, 0x1b, 0xc4, 0x83, 0x68, 0xde, 0x8e, 0x90, 0xde, 0x43, 0x73, - 0xda, 0xb2, 0x75, 0x7a, 0xfd, 0x0, 0x21, 0xd2, 0x15, 0x58, 0x45, 0x65, - 0x10, 0x26, 0x7a, 0x68, 0xfe, 0x9b, 0x31, 0xb5, 0xaa, 0xad, 0x9a, 0x92, - 0x2e, 0x77, 0x68, 0xc5, 0x90, 0x4, 0xd6, 0x18, 0x6d, 0xf6, 0x99, 0x33, - 0x99, 0xcd, 0x2, 0xc7, 0x20, 0x4b, 0x1f, 0x18, 0xc0, 0x6d, 0x4f, 0xe3, - 0x41, 0x79, 0xcd, 0x7f, 0x11, 0xe, 0xdd, 0xee, 0x9a, 0x3f, 0x9, 0xa0, - 0xc, 0x1f, 0xe1, 0x83, 0x3d, 0xd6, 0x8f, 0xb, 0xb6, 0x12, 0x47, 0x9f, - 0x7e, 0x4b, 0xaa, 0x23, 0x13, 0xed, 0xee, 0xbb, 0x3d, 0x72, 0xab, 0xfe, - 0xd2, 0xed, 0x7b, 0xc7, 0xf9, 0xeb, 0xb3, 0x3f, 0x72, 0xd0, 0x15, 0xb8, - 0x98, 0xb8, 0x60, 0xd9, 0x5f, 0x3, 0x4d, 0x9, 0xfe, 0x28, 0x68, 0xdb, - 0x2, 0x4d, 0xd7, 0xc5, 0xbd, 0x7a, 0xf6, 0x16, 0x1a, 0xd0, 0xc5, 0x32, - 0x42, 0x17, 0x7f, 0x3b, 0x67, 0x1a, 0xa5, 0x44, 0x2a, 0xb3, 0x17, 0x81, - 0x94, 0x75, 0x38, 0x30, 0xa7, 0x31, 0xa2, 0xfa, 0x92, 0x25, 0xcb, 0x1a, - 0x39, 0x58, 0xdc, 0x3f, 0x5c, 0xb5, 0xa0, 0xbd, 0xdf, 0xa6, 0xe8, 0x8e, - 0x9f, 0x2e, 0x2d, 0xa2, 0x3e, 0x3e, 0x37, 0xcc, 0x8d, 0x4e, 0x82, 0x44, - 0xc, 0xac, 0x80, 0xf7, 0xd6, 0x19, 0x71, 0xf6, 0xcb, 0x28, 0x40, 0x68, - 0x98, 0xee, 0xec, 0x2b, 0x9e, 0x4, 0xcd, 0xa1, 0xbf, 0x4c, 0xa5, 0x1b, - 0x47, 0xea, 0x43, 0xf5, 0xb0, 0xc4, 0x64, 0xba, 0x54, 0x89, 0x1b, 0x67, - 0xd9, 0x12, 0x6f, 0x6d, 0x3, 0x42, 0xb4, 0xe4, 0x2d, 0x1f, 0x45, 0x50, - 0x87, 0x5d, 0x6a, 0xd6, 0xf9, 0xf8, 0xc1, 0xa6, 0xc5, 0x99, 0x8b, 0xc3, - 0x2d, 0xac, 0x29, 0xee, 0x31, 0x75, 0xcf, 0xd1, 0xb0, 0x4e, 0x67, 0xa2, - 0x56, 0x42, 0xc5, 0x3b, 0x42, 0x9b, 0x2b, 0xa7, 0xe3, 0x4e, 0x92, 0xa4, - 0xd3, 0xf8, 0xf9, 0x6c, 0x64, 0x64, 0x9e, 0xd7, 0x74, 0x67, 0xbb, 0xa3, - 0x4e, 0x24, 0xf, 0x90, 0xbf, 0x92, 0x24, 0xa0, 0xb0, 0x4c, 0x7b, 0xb7, - 0x9f, 0x8e, 0x76, 0x5e, 0x45, 0x51, 0xe2, 0xdc, 0x69, 0xb0, 0x4d, 0x9e, - 0xd6, 0xb0, 0x45, 0x48, 0x64, 0x17, 0x1e, 0xad, 0xbb, 0x24, 0xf8, 0x12, - 0xf5, 0x94, 0x3c, 0xdc, 0xf9, 0xf8, 0x7f, 0x51, 0x3b, 0x80, 0xad, 0x6f, - 0x1b, 0xe3, 0x98, 0x60, 0x6e, 0xf5, 0xd1, 0x4a, 0x6a, 0xf8, 0x66, 0x26, - 0xf8, 0xa, 0xb6, 0x3f, 0xd9, 0x91, 0x7c, 0x79, 0xb1, 0x2b, 0xa8, 0x2c, - 0x77, 0x7d, 0xa2, 0x2e, 0x85, 0x80, 0x9c, 0xcc, 0xb9, 0x67, 0xc7, 0x56, - 0xaf, 0xcc, 0x49, 0xee, 0x3c, 0x47, 0xf1, 0x6d, 0xb, 0xe4, 0x2c, 0xd3, - 0xbc, 0xfc, 0x6, 0xa7, 0x44, 0xc5, 0xbe, 0x87, 0x7f, 0xbc, 0x17, 0xb, - 0x41, 0x9e, 0x6b, 0x78, 0xeb, 0xeb, 0xae, 0x5a, 0x60, 0x8f, 0x6f, 0x7c, - 0x45, 0x4b, 0xd1, 0x99, 0x67, 0x6b, 0x43, 0x1d, 0xb9, 0x52, 0x95, 0x98, - 0x17, 0x2a, 0xd6, 0xdf, 0x40, 0x8d, 0x5c, 0x52, 0x13, 0x19, 0x57, 0xbf, - 0x10, 0x35, 0x9e, 0xda, 0x70, 0xe6, 0x27, 0x4b, 0xc4, 0x36, 0xb7, 0x74, - 0xe9, 0xf8, 0x85, 0x17, 0x8c, 0x1a, 0x84, 0x85, 0xfb, 0x56, 0xbd, 0x70, - 0xfc, 0xb5, 0x70, 0xba, 0x79, 0x91, 0x8a, 0x20, 0x54, 0x26, 0x56, 0x8d, - 0xff, 0xa0, 0xc1, 0x4c, 0x9f, 0x9b, 0x97, 0xc5, 0xf, 0xb6, 0x79, 0x14, - 0x2e, 0x57, 0x92, 0xdb, 0x89, 0x87, 0x5e, 0x21, 0xb8, 0xa1, 0x60, 0x6f, - 0xfe, 0xab, 0x49, 0x96, 0x2c, 0xd, 0x64, 0x31, 0xe6, 0x47, 0xd6, 0x5d, - 0x18, 0x1b, 0xeb, 0xdc, 0x35, 0xcc, 0x61, 0x84, 0x9c, 0xe8, 0xb9, 0x15, - 0x34, 0x86, 0x6f, 0xfc, 0x15, 0x7d, 0xb9, 0xa3, 0xb4, 0xdf, 0x2, 0x1c, - 0x25, 0x67, 0xfc, 0x75, 0x5f, 0xb9, 0x1b, 0x9a, 0xc8, 0xf3, 0xdd, 0x8c, - 0x6f, 0xb8, 0xab, 0x30, 0x57, 0x80, 0xc5, 0x63, 0x5, 0x63, 0xbe, 0x74, - 0x73, 0xe4, 0xd6, 0xfe, 0xea, 0x53, 0xc2, 0x55, 0xe8, 0xcd, 0xc7, 0xbc, - 0x72, 0xb4, 0xb, 0xf1, 0xb1, 0xde, 0xdf, 0x17, 0xe4, 0xd, 0xba, 0xfb, - 0x83, 0x71, 0xdf, 0xe7, 0xdb, 0x26, 0x3b, 0xc3, 0x0, 0x57, 0xcb, 0x17, - 0x94, 0xb5, 0x8, 0x1b, 0xb5, 0xf3, 0x48, 0xf7, 0x95, 0x8f, 0x78, 0x1d, - 0xb4, 0xf9, 0x38, 0x6e, 0x2f, 0x59, 0xe8, 0x52, 0x4, 0x8b, 0x80, 0x1b, - 0xa4, 0xd6, 0x44, 0x43, 0xd6, 0x55, 0xd2, 0x5c, 0x51, 0x67, 0x6d, 0xb7, - 0x70, 0xb3, 0xad, 0x45, 0xe3, 0x4d, 0x71, 0x57, 0x86, 0x8c, 0xc3, 0x6d, - 0xf7, 0x8b, 0xd8, 0xc4, 0x3e, 0x78, 0x91, 0x28, 0x4d, 0xf7, 0x55, 0x60, - 0x3f, 0xcb, 0x97, 0x4f, 0xc9, 0x9f, 0x9, 0x6c, 0x97, 0x9f, 0xc, 0xc, - 0xdf, 0xb0, 0x33, 0xf2, 0xf, 0x48, 0xcf, 0x52, 0xe8, 0x38, 0x35, 0x84, - 0x6b, 0x33, 0x48, 0x92, 0xba, 0xb0, 0xbf, 0x55, 0x85, 0xd8, 0xf6, 0x64, - 0xcb, 0x57, 0xcd, 0x6b, 0x52, 0xf4, 0xa5, 0x31, 0xf3, 0x5, 0x86, 0xa2, - 0x6b, 0x1f, 0xa2, 0x7, 0xb8, 0x20, 0x3d, 0xce, 0x6a, 0xf, 0xdc, 0xa, - 0x8a, 0x23, 0xb6, 0xfc, 0x76, 0x76, 0xb1, 0xac, 0x7c, 0xb, 0x23, 0x5b, - 0x7b, 0x90, 0xda, 0x3b, 0xf4, 0x43, 0x48, 0xa5, 0x2, 0x99, 0xe6, 0x21, - 0x7f, 0x3b, 0xe1, 0x63, 0xa8, 0xd7, 0x2e, 0x82, 0xc3, 0x40, 0xd1, 0x98, - 0xee, 0xb, 0x65, 0x67, 0x1d, 0xa, 0x51, 0x57, 0x80, 0x9f, 0xa3, 0xde, - 0x20, 0xa2, 0x79, 0x2b, 0x7d, 0xf4, 0xa5, 0xf4, 0x83, 0xeb, 0x63, 0x65, - 0xb7, 0x41, 0xbf, 0x69, 0xdb, 0x9d, 0x13, 0x15, 0xc0, 0xbc, 0x4d, 0x84, - 0xfe, 0x73, 0x21, 0xd9, 0x1d, 0xa0, 0x33, 0xaf, 0x4, 0x33, 0x9e, 0xf9, - 0xa8, 0xc1, 0xae, 0xaa, 0xa7, 0xc, 0xf4, 0x17, 0xda, 0x59, 0x6a, 0x31, - 0x6f, 0x16, 0xf0, 0xa, 0x0, 0x24, 0xc3, 0x6a, 0xa2, 0x50, 0x50, 0xc9, - 0xdf, 0xb, 0xb6, 0x1f, 0x6f, 0x5e, 0x78, 0x76, 0x29, 0x92, 0x62, 0x62, - 0x91, 0xbc, 0x49, 0x9a, 0xa1, 0xa7, 0x33, 0x3d, 0xf6, 0xdd, 0x68, 0xa3, - 0xf7, 0x42, 0x5a, 0x93, 0xda, 0xb0, 0xa6, 0x8, 0x8f, 0x69, 0x2c, 0x85, - 0xf, 0xf4, 0x96, 0x3, 0xd5, 0xa8, 0xba, 0x28, 0xaf, 0x63, 0xba, 0x55, - 0xbb, 0x97, 0xa4, 0x5b, 0xa, 0x26, 0xf1, 0x7b, 0x28, 0xb7, 0x1f, 0x27, - 0x4b, 0xa6, 0xbe, 0xe5, 0x78, 0x57, 0xf3, 0x77, 0x39, 0xba, 0xf, 0x69, - 0x24, 0x1e, 0x2e, 0x38, 0x9c, 0xba, 0xad, 0xa7, 0x86, 0xa0, 0xfd, 0x2e, - 0xe5, 0x63, 0xb5, 0xb6, 0x6d, 0x54, 0x55, 0xe0, 0xb0, 0x65, 0xb6, 0x34, - 0xce, 0xe, 0xf5, 0x2d, 0xc1, 0x26, 0x2e, 0xc8, 0xbc, 0x2b, 0x7c, 0xfe, - 0xd6, 0xee, 0xd9, 0xc, 0xf6, 0x5d, 0x60, 0xc5, 0x9b, 0xd5, 0xa3, 0xfe, - 0x83, 0x5f, 0x26, 0x7a, 0xcc, 0xb1, 0x5d, 0xe3, 0xad, 0x34, 0x8, 0x64, - 0x44, 0x95, 0x3b, 0xa9, 0xb3, 0x43, 0x3f, 0xec, 0x93, 0x39, 0xc1, 0xa8, - 0x27, 0x49, 0xca, 0xae, 0x70, 0xf, 0x11, 0x54, 0xb2, 0x6b, 0x64, 0x3b, - 0x9d, 0x7a, 0xf5, 0x2c, 0x9a, 0x43, 0x7d, 0xc6, 0x54, 0x9a, 0xfa, 0x9e, - 0xad, 0xcd, 0x94, 0x15, 0xfc, 0x89, 0x89, 0xbe, 0xaa, 0x9e, 0x8f, 0xbb, - 0x6, 0x22, 0x42, 0x5, 0xa0, 0x61, 0xb5, 0x58, 0xd7, 0x58, 0xa2, 0xb8, - 0xfd, 0x4, 0xf3, 0x64, 0x3f, 0x9b, 0x69, 0xcc, 0xc, 0x7a, 0x34, 0x88, - 0x13, 0xeb, 0x90, 0x8e, 0x33, 0x27, 0xe, 0x65, 0xcd, 0x81, 0xe0, 0x0, - 0xbf, 0xa1, 0x94, 0x3e, 0x91, 0xbf, 0x54, 0x3f, 0x2f, 0xc6, 0x30, 0xee, - 0xc1, 0x39, 0xf7, 0x4a, 0xbe, 0xbd, 0xb3, 0xcb, 0x91, 0x16, 0xad, 0xc4, - 0xb6, 0x3e, 0xc8, 0x6c, 0xc1, 0xb5, 0x66, 0x1b, 0xa0, 0x97, 0x2a, 0x30, - 0x6c, 0x20, 0xe5, 0xec, 0x4e, 0xd7, 0xe3, 0xea, 0x3a, 0xd5, 0x41, 0x99, - 0xd0, 0x95, 0xe3, 0x8b, 0x19, 0xee, 0x92, 0x11, 0x84, 0x13, 0xa7, 0x1e, - 0x65, 0xb5, 0xc8, 0x23, 0x3d, 0xb3, 0x89, 0x30, 0xda, 0xdd, 0x1f, 0xe9, - 0x55, 0x3c, 0x22, 0xee, 0x18, 0xa, 0x92, 0x5c, 0x61, 0xc7, 0x39, 0xd, - 0xea, 0x1b, 0xe4, 0xb, 0x5, 0x6e, 0x7b, 0x8e, 0xd0, 0xd5, 0xa5, 0x6b, - 0x3, 0xaf, 0x8b, 0xb7, 0x75, 0x24, 0xc7, 0xf9, 0x1d, 0x32, 0xea, 0xa9, - 0xe5, 0xa5, 0x1a, 0x41, 0x82, 0xdd, 0xc8, 0x86, 0x82, 0x85, 0xcd, 0xe, - 0x89, 0xa4, 0x4a, 0xe0, 0x6a, 0xf4, 0xe, 0x26, 0x33, 0x33, 0xa1, 0x3a, - 0xd2, 0xde, 0xff, 0x2f, 0xa6, 0x8a, 0x7a, 0x9e, 0x44, 0xab, 0xed, 0x53, - 0x30, 0xdf, 0xfd, 0x95, 0xac, 0x6d, 0x82, 0xd, 0x5e, 0x35, 0xc8, 0x3b, - 0xb6, 0x59, 0x93, 0x1d, 0x6b, 0x8c, 0x27, 0x5e, 0x2, 0xa9, 0xa1, 0x64, - 0x65, 0xe3, 0xbf, 0x52, 0x87, 0x26, 0x10, 0x6, 0x5a, 0xaf, 0x7c, 0x10, - 0x44, 0x7e, 0x46, 0xfa, 0xc, 0x85, 0xe5, 0x74, 0x92, 0xf6, 0xd8, 0x8, - 0x59, 0xe8, 0x46, 0xc3, 0x5b, 0x2c, 0x3, 0xda, 0xb3, 0x17, 0xbf, 0x71, - 0x3e, 0xbd, 0xe3, 0x41, 0x1f, 0xad, 0xa4, 0x9f, 0x31, 0x8d, 0x38, 0x5f, - 0x83, 0x92, 0x26, 0x8f, 0xe, 0xe4, 0xcc, 0xdb, 0xf4, 0x83, 0x62, 0x34, - 0xd7, 0xb9, 0xd0, 0x29, 0xa9, 0x4a, 0xba, 0xf2, 0xe2, 0x18, 0x23, 0x30, - 0x27, 0x10, 0xf, 0x2e, 0xad, 0x40, 0xab, 0xed, 0xda, 0x76, 0xd6, 0x4e, - 0x60, 0x80, 0x2a, 0xe3, 0x23, 0x79, 0x27, 0xaa, 0xc8, 0xa4, 0xce, 0x1f, - 0x4f, 0x88, 0x5b, 0x55, 0x83, 0x47, 0x88, 0x56, 0xd4, 0xe9, 0x79, 0x9b, - 0x7d, 0x83, 0x83, 0x4d, 0x26, 0xe3, 0x90, 0xdf, 0xbf, 0x6c, 0xa0, 0x4f, - 0x78, 0x7f, 0x69, 0x86, 0xe7, 0x54, 0xfd, 0x4b, 0x24, 0xe9, 0xb6, 0x46, - 0xf3, 0xdc, 0xae, 0x5e, 0x2c, 0x21, 0x8e, 0xd5, 0x4d, 0x30, 0x25, 0xfa, - 0xcd, 0xb, 0x4b, 0x8, 0x4b, 0x7e, 0x15, 0x60, 0x30, 0xba, 0x75, 0xbd, - 0xfb, 0xe2, 0x49, 0x1, 0xcb, 0xff, 0x3f, 0x23, 0xde, 0xdb, 0xc4, 0xb9, - 0x26, 0x36, 0xb5, 0xc1, 0xd9, 0xc8, 0x63, 0xe0, 0x48, 0xd9, 0xe0, 0xd2, - 0x52, 0xf7, 0x15, 0x94, 0xf2, 0x1c, 0xc, 0x32, 0xe0, 0xfe, 0xf0, 0xb5, - 0x3, 0xa6, 0x50, 0xbd, 0xf3, 0x13, 0x95, 0x92, 0xe9, 0x11, 0xd9, 0x75, - 0xe5, 0xef, 0x94, 0x20, 0xff, 0xff, 0x79, 0xb1, 0x45, 0x27, 0xec, 0x69, - 0xf7, 0xe3, 0x2d, 0x9e, 0x36, 0x7a, 0xec, 0xcc, 0xcb, 0x57, 0xce, 0x11, - 0xcb, 0x60, 0x95, 0x19, 0x49, 0x32, 0x7d, 0xd4, 0x5d, 0x1b, 0x97, 0x3d, - 0xde, 0xd5, 0xb4, 0x4b, 0x8a, 0x31, 0x52, 0x10, 0xb4, 0xe1, 0x35, 0x3a, - 0x10, 0xb5, 0x4b, 0xf8, 0x83, 0xff, 0x7e, 0x90, 0xb6, 0x37, 0x61, 0x4a, - 0xad, 0x80, 0x80, 0x78, 0x67, 0xcf, 0xcb, 0x70, 0x5d, 0xcf, 0x78, 0x46, - 0x1a, 0xa2, 0xfe, 0x68, 0xe3, 0x0, 0x27, 0xc, 0x3a, 0x1, 0xed, 0x89, - 0x11, 0x7, 0xc7, 0x77, 0xa4, 0xe8, 0x6e, 0x7b, 0xaa, 0x7c, 0x20, 0x86, - 0xaf, 0xe2, 0x45, 0x45, 0x9f, 0xb6, 0x65, 0xbe, 0x82, 0x5f, 0xdb, 0xce, - 0x1a, 0x43, 0x15, 0xeb, 0x90, 0x1a, 0x7e, 0xce, 0x5f, 0x0, 0x45, 0xd7, - 0x5e, 0x58, 0xa, 0xde, 0xab, 0xf, 0xca, 0x46, 0x8e, 0x4a, 0x18, 0xc4, - 0xc9, 0x5a, 0xdb, 0x13, 0x2, 0xc8, 0x83, 0xaf, 0x1f, 0xd6, 0xa, 0x29, - 0xae, 0x9e, 0x5d, 0xbe, 0x8f, 0xd0, 0xb0, 0x9e, 0x68, 0x84, 0xd6, 0x4b, - 0x8, 0xa2, 0x59, 0x6d, 0x34, 0x9e, 0x0, 0x5b, 0x83, 0xbf, 0x3, 0x70, - 0x43, 0x3a, 0x15, 0xa6, 0xb0, 0x5e, 0x67, 0xf3, 0xfb, 0x4c, 0xe5, 0x2b, - 0xc1, 0x4f, 0xd5, 0x69, 0xfb, 0x71, 0x62, 0x27, 0x12, 0x35, 0x5b, 0x6e, - 0x32, 0xb4, 0xb2, 0x22, 0x3a, 0xb0, 0x4c, 0xbd, 0xf5, 0x63, 0x89, 0x70, - 0x92, 0xcb, 0x29, 0xca, 0xb7, 0xd9, 0xfe, 0xc5, 0xdb, 0xa3, 0xe3, 0xb3, - 0x36, 0xbf, 0xa8, 0x49, 0xe1, 0x72, 0x61, 0x44, 0x44, 0x21, 0xdb, 0x71, - 0x3a, 0xf2, 0x7a, 0x5c, 0x21, 0x2, 0x64, 0x38, 0xe4, 0xb9, 0xee, 0x98, - 0xd7, 0xa8, 0xde, 0xd0, 0xe1, 0x7e, 0x38, 0x55, 0x79, 0xe1, 0x9a, 0x34, - 0x82, 0xeb, 0x34, 0xd1, 0x45, 0x48, 0xa8, 0xc, 0xc8, 0xf, 0x6a, 0x40, - 0x38, 0x36, 0x92, 0xa0, 0x25, 0x4d, 0xe1, 0x4b, 0x43, 0xe5, 0x17, 0x79, - 0xdb, 0x48, 0xf7, 0x8b, 0x25, 0x4a, 0x61, 0x62, 0x59, 0x71, 0x27, 0xca, - 0x3b, 0x96, 0xe4, 0x54, 0xd8, 0x33, 0x84, 0x90, 0xf, 0x30, 0x1d, 0x10, - 0x4b, 0x99, 0x51, 0x1a, 0x6f, 0x39, 0xb, 0x14, 0xa, 0x74, 0xfe, 0x65, - 0x6a, 0x74, 0xa2, 0x63, 0xc0, 0xbd, 0x97, 0x6e, 0xd6, 0xd3, 0x21, 0x3, - 0xa9, 0x65, 0x39, 0xcf, 0x87, 0x93, 0x37, 0xdc, 0x60, 0x53, 0xbf, 0x79, - 0x6d, 0x37, 0x1b, 0x6d, 0x76, 0xc9, 0x5c, 0xc8, 0xd5, 0x51, 0xdb, 0x4a, - 0xa3, 0x54, 0x0, 0x99, 0x15, 0xab, 0xac, 0x46, 0xae, 0x45, 0xb3, 0xf8, - 0x7e, 0x98, 0x42, 0xf6, 0x95, 0x9e, 0xb5, 0x19, 0x92, 0x79, 0xf4, 0x25, - 0x9c, 0xd7, 0xec, 0xd7, 0x7a, 0x2f, 0xef, 0x82, 0x8a, 0xe0, 0x2d, 0xee, - 0x77, 0xab, 0x81, 0x39, 0x75, 0x44, 0x2b, 0xa4, 0x4b, 0x1c, 0x73, 0x8a, - 0x23, 0x8e, 0xc0, 0x1f, 0x69, 0xbd, 0x53, 0x88, 0x3e, 0xaa, 0x32, 0x1a, - 0xa, 0x93, 0xc0, 0x81, 0x8d, 0x37, 0x5e, 0xd1, 0x4, 0x1d, 0xbb, 0x3a, - 0x56, 0x47, 0xe6, 0x30, 0x7a, 0x6a, 0x6a, 0x9d, 0x4b, 0xb6, 0x4d, 0xce, - 0x26, 0x69, 0x5b, 0x5, 0x57, 0xdc, 0x33, 0x99, 0x68, 0xca, 0xca, 0xe4, - 0x42, 0xfe, 0xad, 0xa, 0x1c, 0xf2, 0xe0, 0xa5, 0x43, 0xb, 0xa4, 0xd9, - 0x9, 0xdc, 0xa1, 0xe, 0x28, 0x77, 0xab, 0xc6, 0x17, 0xc8, 0x47, 0x5e, - 0x4f, 0x3f, 0x6, 0x78, 0x70, 0x12, 0x69, 0xc9, 0x4a, 0x57, 0x87, 0x49, - 0xeb, 0x8d, 0x66, 0xb1, 0x13, 0x13, 0x6c, 0x63, 0x96, 0x6c, 0x29, 0x5e, - 0xce, 0x21, 0x1f, 0xe3, 0x8a, 0xdf, 0xac, 0x5f, 0x9b, 0x34, 0x74, 0x6, - 0x93, 0x9f, 0x4b, 0xf1, 0x50, 0x17, 0x5, 0x1c, 0xf2, 0xcb, 0x1d, 0xc6, - 0x85, 0x30, 0xf8, 0xa4, 0x2f, 0xeb, 0xaa, 0x41, 0xb3, 0xa5, 0x42, 0xfb, - 0x21, 0x4e, 0x4c, 0x4d, 0xc5, 0xda, 0xc8, 0x13, 0xb1, 0x42, 0xba, 0xfe, - 0x2, 0x39, 0x7d, 0xd, 0xcc, 0x7a, 0x18, 0x6b, 0x79, 0x19, 0x11, 0x2b, - 0x25, 0xe2, 0x4c, 0xba, 0x83, 0xb3, 0x13, 0xe9, 0x15, 0x7e, 0x3b, 0x7b, - 0x5b, 0xa3, 0xd, 0x72, 0x70, 0x54, 0xdc, 0x2c, 0xbf, 0xfa, 0x46, 0xc5, - 0xeb, 0xba, 0xb, 0x2c, 0xa1, 0xd6, 0x5a, 0xdd, 0xc8, 0xc4, 0xd, 0x58, - 0x8b, 0x94, 0x2f, 0x5f, 0x4e, 0x8c, 0xa0, 0x48, 0x5c, 0x3a, 0x9b, 0xa5, - 0xbb, 0xa3, 0x88, 0xa8, 0xa2, 0x9a, 0x9, 0xe5, 0x7c, 0x3e, 0x2b, 0x65, - 0xf8, 0x73, 0x92, 0x9e, 0x6c, 0xe7, 0x14, 0x33, 0xc1, 0xa3, 0xec, 0x90, - 0xa6, 0xc2, 0xa5, 0xe8, 0xd9, 0xf8, 0x80, 0xa4, 0xe0, 0x28, 0x36, 0x55, - 0x6b, 0xfd, 0x50, 0xc, 0x4, 0xdb, 0x87, 0xdc, 0xc8, 0x91, 0x76, 0x2c, - 0xec, 0xc4, 0xd3, 0xe1, 0x8a, 0x94, 0xe5, 0xd5, 0x4f, 0x7b, 0xd0, 0xca, - 0xa2, 0x3a, 0x33, 0xa1, 0x1f, 0x62, 0x68, 0x9b, 0x82, 0x9a, 0xd7, 0x43, - 0xcf, 0x62, 0x16, 0x40, 0xe8, 0x4d, 0x69, 0x85, 0x33, 0xad, 0x27, 0x2c, - 0xe2, 0xbb, 0x91, 0x94, 0xf4, 0x2c, 0xa9, 0x9b, 0x2, 0x2, 0xe1, 0x22, - 0x79, 0x65, 0x65, 0xac, 0xf6, 0x4e, 0x29, 0x90, 0x97, 0xf5, 0x69, 0x10, - 0x4a, 0xb1, 0xd6, 0x11, 0xfa, 0xed, 0x33, 0xab, 0x28, 0x76, 0xe8, 0x80, - 0x7f, 0xfb, 0x39, 0x20, 0xe0, 0x34, 0x4c, 0x3f, 0x15, 0x2, 0xac, 0x88, - 0x5d, 0x2d, 0x68, 0x88, 0x4e, 0x53, 0xe9, 0xac, 0x1, 0x9f, 0x73, 0x93, - 0x25, 0x3f, 0x6a, 0x56, 0x52, 0x84, 0x53, 0xf5, 0x4, 0x32, 0xea, 0xc9, - 0x75, 0xa8, 0x4d, 0x2b, 0xd7, 0x85, 0x51, 0xcd, 0x7d, 0x5e, 0xe6, 0x86, - 0xb7, 0x2d, 0x8a, 0x4, 0xce, 0x64, 0xea, 0x6, 0x34, 0x29, 0x62, 0xda, - 0x32, 0xe3, 0xb0, 0x79, 0xd3, 0xf8, 0x8e, 0xc5, 0xf, 0x56, 0x43, 0xec, - 0xc, 0x16, 0x91, 0x77, 0x3d, 0xf0, 0x77, 0x9d, 0x7, 0xb3, 0xa5, 0xc0, - 0x3a, 0x14, 0xf5, 0xc5, 0x96, 0x6c, 0x6b, 0xc9, 0xad, 0xc8, 0x66, 0xe8, - 0x6a, 0xab, 0xaa, 0x40, 0xed, 0x31, 0x8a, 0x2c, 0xf4, 0xa0, 0x41, 0x7b, - 0x28, 0x6f, 0xad, 0x30, 0x6, 0xc0, 0xff, 0xd7, 0xd5, 0x8b, 0xd0, 0x57, - 0x64, 0xc1, 0xbb, 0x76, 0x57, 0xef, 0xed, 0x3f, 0x87, 0xe5, 0x99, 0xca, - 0xd8, 0x41, 0xfd, 0x40, 0xa8, 0x1d, 0xb9, 0x4b, 0xca, 0x29, 0xe2, 0xd1, - 0xcc, 0x4b, 0x31, 0x1, 0x84, 0xe9, 0x14, 0x76, 0xb9, 0xe1, 0x28, 0x75, - 0xae, 0x56, 0x50, 0xec, 0x75, 0xd1, 0x98, 0x98, 0xa2, 0x1c, 0xea, 0xd1, - 0x35, 0xfd, 0x2f, 0x1a, 0xbf, 0x4a, 0x55, 0xa7, 0xb2, 0xc2, 0xef, 0x45, - 0x8c, 0x41, 0x40, 0x89, 0x46, 0xec, 0xab, 0x13, 0x21, 0xe8, 0x66, 0x80, - 0x57, 0x61, 0x78, 0x5f, 0x15, 0x40, 0xe2, 0xc0, 0xd0, 0x89, 0xd5, 0x9a, - 0x66, 0x16, 0x8d, 0xaa, 0x4e, 0xa1, 0x6e, 0xb7, 0xf9, 0x6c, 0xdf, 0xc9, - 0x86, 0x5e, 0x7d, 0x40, 0x76, 0xfa, 0xa6, 0x16, 0x6c, 0x49, 0x2c, 0xcc, - 0x64, 0x85, 0x92, 0xe1, 0x16, 0x67, 0xd, 0x10, 0xff, 0x4d, 0x9b, 0xc8, - 0x3f, 0x9d, 0xae, 0x84, 0x49, 0x6d, 0xb8, 0xe3, 0x8f, 0x5b, 0x3c, 0x21, - 0xf1, 0x94, 0xf5, 0x9d, 0x4, 0x90, 0x3a, 0x2e, 0xf8, 0xde, 0x32, 0xbb, - 0x4d, 0xcb, 0xdd, 0xb3, 0x47, 0xe, 0xef, 0x0, 0x39, 0x60, 0x63, 0x3d, - 0xd9, 0x2f, 0x6e, 0xfd, 0x45, 0x2e, 0xf2, 0x90, 0x37, 0xe2, 0x1b, 0x57, - 0x20, 0xa4, 0x16, 0x6d, 0x0, 0x5b, 0xe7, 0x93, 0xcf, 0x5b, 0x17, 0x22, - 0xd5, 0x44, 0x12, 0x93, 0xdc, 0x91, 0x6e, 0xa9, 0x27, 0xa6, 0x95, 0xe3, - 0xd9, 0xec, 0x95, 0x66, 0xc5, 0x9e, 0x70, 0x7f, 0x89, 0xe5, 0xcb, 0x22, - 0xb2, 0x50, 0x82, 0xc8, 0x10, 0x9e, 0xb3, 0x61, 0x75, 0xcd, 0x14, 0x3e, - 0xd2, 0xd1, 0x27, 0xfa, 0x48, 0xc3, 0x38, 0x45, 0x3d, 0xb8, 0xb2, 0x36, - 0xc9, 0xda, 0x91, 0x8c, 0x35, 0x45, 0x2c, 0x21, 0x85, 0x76, 0xad, 0x67, - 0x3f, 0xf2, 0x1a, 0x6d, 0x16, 0x58, 0x83, 0xf8, 0x15, 0x66, 0x6b, 0xdf, - 0xf8, 0x27, 0x98, 0x8, 0x9f, 0x50, 0xc0, 0x3e, 0xee, 0xf, 0x38, 0x53, - 0x41, 0x33, 0xc6, 0x61, 0x50, 0xc5, 0x49, 0x1b, 0x67, 0x57, 0xac, 0xe1, - 0x67, 0x7c, 0xe0, 0x6a, 0x80, 0x5e, 0x5d, 0xf5, 0xb3, 0xc1, 0xb, 0x27, - 0xdf, 0x72, 0xce, 0xbf, 0xaa, 0x3e, 0x9a, 0x31, 0xf9, 0xcd, 0xbf, 0x29, - 0xb4, 0x3a, 0x7, 0x81, 0x1e, 0x47, 0x1b, 0xd8, 0xf3, 0x82, 0xef, 0x13, - 0xc8, 0xf0, 0xb6, 0x13, 0x5b, 0x4c, 0xb5, 0x2f, 0x5f, 0xa4, 0xc1, 0x52, - 0xb8, 0xe, 0x90, 0x43, 0xc5, 0xa7, 0xc2, 0x36, 0x90, 0x4a, 0xdf, 0x5d, - 0xc8, 0xb7, 0x60, 0x10, 0x38, 0xd6, 0xde, 0x10, 0x7b, 0x5b, 0x76, 0x92, - 0x82, 0xc7, 0x10, 0xc3, 0xc2, 0xb8, 0xf, 0xc, 0x19, 0xaa, 0xdc, 0x15, - 0x55, 0x51, 0x55, 0xe4, 0x7d, 0x61, 0x3f, 0xaf, 0xee, 0x40, 0x53, 0x8e, - 0x7a, 0x63, 0xfe, 0xc9, 0xd6, 0xdb, 0xe3, 0x20, 0xb7, 0xd8, 0x7c, 0x90, - 0x8d, 0xad, 0x6d, 0x82, 0x1c, 0xba, 0xf3, 0xbc, 0x87, 0x1d, 0x18, 0xdc, - 0xea, 0x99, 0x70, 0xa4, - }, +static_assert(base::size(kAltGameImages1xLength) == kAltGameImagesCount, ""); +const uint8_t kAltGameImages2xA[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x9b, 0xf6, 0x93, 0x5e, + 0xf4, 0xc1, 0x6b, 0xa3, 0x71, 0x3b, 0xf3, 0x64, 0x61, 0xb5, 0xd1, 0x1d, + 0xb, 0xe5, 0xb6, 0x81, 0x61, 0x56, 0xd0, 0xa3, 0xd7, 0x75, 0xaa, 0x55, + 0x2e, 0x56, 0xf9, 0xf2, 0x1a, 0xe2, 0x93, 0x19, 0x47, 0xf4, 0x1d, 0x20, + 0xad, 0x83, 0x41, 0xa, 0x31, 0x36, 0x5b, 0x1e, 0x5e, 0xfe, 0x5e, 0x37, + 0x96, 0x3e, 0x1c, 0x34, 0xc4, 0xcd, 0x13, 0x3a, 0xc5, 0xc, 0xc5, 0x21, + 0xaf, 0x58, 0x9c, 0x5a, 0xc9, 0x90, 0xfc, 0x2b, 0x4b, 0xbc, 0x27, 0x96, + 0x57, 0xb5, 0x17, 0x99, 0x6, 0x48, 0x29, 0x67, 0x16, 0x28, 0xd6, 0xfd, + 0xb0, 0xe7, 0x59, 0x41, 0xa3, 0xbf, 0x5, 0xce, 0x26, 0xc4, 0x61, 0x2b, + 0xf1, 0xd, 0x2b, 0x39, 0x5a, 0x99, 0xb6, 0x62, 0x30, 0x4, 0xd2, 0x4d, + 0x68, 0x23, 0x9a, 0x5b, 0xd9, 0x7d, 0xe6, 0xeb, 0xba, 0x96, 0x91, 0xb6, + 0x3d, 0x9a, 0x54, 0xaa, 0xe7, 0x9c, 0xd3, 0x78, 0x11, 0x70, 0xd4, 0xdc, + 0xcd, 0x39, 0xbb, 0x98, 0x38, 0xb0, 0x82, 0x3c, 0x1, 0xed, 0x6c, 0xc2, + 0x82, 0x2, 0xc8, 0x6a, 0xcb, 0x26, 0x7a, 0x12, 0xd0, 0x10, 0xc3, 0xaa, + 0x95, 0x2f, 0x5c, 0x80, 0xc, 0xba, 0xaf, 0xf2, 0x75, 0x51, 0x95, 0xf9, + 0xba, 0xa7, 0x71, 0x2f, 0x38, 0x9a, 0x23, 0xfd, 0xf6, 0x7b, 0x1a, 0xcd, + 0xdb, 0xda, 0xf4, 0x4d, 0x54, 0xc5, 0x7, 0xfa, 0x53, 0x4f, 0x7e, 0x8, + 0x4f, 0x20, 0x69, 0x20, 0x8d, 0xc8, 0xb6, 0x1a, 0x80, 0x79, 0x5e, 0x86, + 0x8b, 0xb, 0xc0, 0x2a, 0x40, 0x58, 0x2d, 0x6b, 0x31, 0x5d, 0xee, 0x24, + 0x9, 0xa1, 0x14, 0x9c, 0x40, 0x44, 0x36, 0x3a, 0x62, 0x7, 0xe4, 0x2f, + 0x38, 0xa2, 0x3, 0x72, 0x95, 0xf1, 0xa3, 0x86, 0x6d, 0x56, 0x4c, 0x80, + 0xf6, 0xa4, 0x4d, 0xb6, 0x1c, 0xad, 0x7c, 0x24, 0x2f, 0x57, 0x12, 0xf, + 0x26, 0x18, 0xef, 0xa5, 0xa2, 0xe8, 0x5e, 0xc5, 0x81, 0x1f, 0x29, 0x85, + 0x5a, 0x3c, 0x39, 0x2c, 0x4d, 0x23, 0x5b, 0x92, 0xf5, 0xe4, 0xf3, 0xc6, + 0x56, 0xde, 0xc0, 0x6b, 0x54, 0x18, 0x8b, 0xa8, 0x45, 0x5, 0xde, 0xf8, + 0x60, 0xa6, 0x75, 0x30, 0x5d, 0x3b, 0x7b, 0x99, 0xfc, 0x61, 0xd9, 0xe7, + 0xc4, 0x13, 0xd8, 0x54, 0xde, 0x1c, 0xe4, 0xf1, 0x5c, 0xf6, 0x67, 0x51, + 0x33, 0x79, 0xcd, 0x10, 0xaa, 0xc7, 0xb4, 0xdf, 0xa3, 0x4a, 0x3b, 0xc1, + 0x5e, 0x14, 0x6c, 0xca, 0x4c, 0xbe, 0xef, 0x4b, 0x70, 0x6, 0xbb, 0xc1, + 0xc8, 0x4, 0xf9, 0x1d, 0x93, 0xb5, 0x8c, 0x0, 0xda, 0x73, 0xc7, 0x7a, + 0xc8, 0xdc, 0xec, 0x92, 0xe0, 0x94, 0x41, 0x1a, 0xab, 0xce, 0x60, 0x42, + 0x8e, 0x7c, 0xb6, 0x93, 0xdb, 0xc2, 0xe5, 0x50, 0xc1, 0x52, 0x46, 0x2d, + 0xf6, 0xa2, 0x22, 0x26, 0x2d, 0xcd, 0x4b, 0x1f, 0x86, 0x22, 0xe5, 0x95, + 0x1, 0x57, 0xe4, 0x1f, 0x3f, 0xd2, 0xb3, 0xcb, 0xf0, 0x44, 0x9e, 0x5a, + 0xbb, 0xc7, 0x27, 0x88, 0x92, 0x81, 0x7d, 0x50, 0xfc, 0xf2, 0x18, 0x21, + 0x66, 0x2c, 0x9b, 0xb5, 0x42, 0x8a, 0x3, 0xf9, 0x6b, 0x77, 0x6b, 0xc8, + 0x8a, 0xf8, 0xa, 0x51, 0xa8, 0xbc, 0x12, 0xe, 0x6b, 0xbc, 0x57, 0xa3, + 0x49, 0xe2, 0xee, 0x2e, 0xe5, 0x5e, 0x12, 0xfa, 0xe1, 0x59, 0xee, 0x8b, + 0x2, 0xad, 0xac, 0xd9, 0x3b, 0x2e, 0xf6, 0x16, 0xee, 0x98, 0x8b, 0x1d, + 0xd6, 0x14, 0x6b, 0x61, 0x60, 0x88, 0x96, 0x89, 0x2b, 0xaf, 0x23, 0xde, + 0xb9, 0xba, 0x6b, 0xc4, 0x82, 0xe5, 0x24, 0x9, 0x3d, 0x32, 0x65, 0x8e, + 0x68, 0x8d, 0xec, 0x94, 0x3d, 0x5, 0xc1, 0xbd, 0x87, 0x87, 0xaa, 0x53, + 0x27, 0xfe, 0xf9, 0x12, 0x74, 0xc7, 0xaf, 0x42, 0x7d, 0x1b, 0x23, 0xbc, + 0x41, 0xa1, 0xba, 0xa6, 0x1f, 0x62, 0x49, 0x32, 0x90, 0x38, 0xa8, 0xec, + 0x83, 0xa4, 0xd1, 0x34, 0x2, 0x63, 0xb1, 0xaf, 0xd9, 0x78, 0x55, 0x90, + 0x3d, 0x1, 0x74, 0xf1, 0x2a, 0x37, 0x2f, 0x46, 0x16, 0xb9, 0xa6, 0x4f, + 0xf6, 0x37, 0xc6, 0xe5, 0x7e, 0x50, 0x4e, 0x49, 0x31, 0x31, 0x61, 0x1f, + 0x8a, 0xe7, 0xf1, 0x7a, 0xd6, 0xd3, 0x4a, 0xbf, 0xc1, 0xd9, 0x7b, 0x68, + 0xa6, 0x9f, 0xd3, 0x69, 0xec, 0x9d, 0xe5, 0x9d, 0xe9, 0x35, 0xdc, 0x55, + 0x21, 0xe3, 0xd2, 0x63, 0x71, 0xf, 0xb6, 0xbd, 0x9c, 0x47, 0x46, 0x61, + 0x1f, 0xf0, 0x44, 0x77, 0x7d, 0xfa, 0xf9, 0x32, 0x5f, 0x71, 0x21, 0xdb, + 0x55, 0x41, 0x64, 0xe2, 0xe6, 0xc4, 0x5, 0xbd, 0x76, 0xfc, 0x44, 0x6e, + 0xef, 0xd7, 0x5, 0x61, 0x94, 0x58, 0xec, 0xcc, 0xdc, 0xd3, 0x1c, 0x4f, + 0x38, 0xa1, 0x28, 0xc, 0xf2, 0x18, 0xa8, 0xf6, 0xb0, 0x4f, 0x29, 0x10, + 0x4b, 0x52, 0x76, 0xb1, 0xc1, 0x6b, 0xb9, 0xe2, 0xd1, 0xd7, 0x4e, 0x82, + 0x48, 0xb6, 0xc8, 0xb3, 0x42, 0x2f, 0xdb, 0xd3, 0x7, 0x6, 0x60, 0xb9, + 0x48, 0x55, 0xdc, 0x27, 0xa3, 0x9d, 0xfa, 0xc2, 0x43, 0xfc, 0xd2, 0xfd, + 0x60, 0x65, 0xd5, 0x50, 0xc, 0x6c, 0x3c, 0x71, 0xdd, 0x19, 0x97, 0xba, + 0xc3, 0x5, 0x2b, 0xcd, 0xd2, 0xf1, 0x0, 0x35, 0x5a, 0x29, 0xc6, 0xf0, + 0x93, 0xd9, 0x2a, 0xf0, 0x22, 0x9f, 0xc0, 0x33, 0x9b, 0xd0, 0x46, 0xae, + 0x1d, 0xe9, 0x65, 0x3d, 0x66, 0xf0, 0xc0, 0xcc, +}; +const uint8_t kAltGameImages2xB[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, + 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, + 0x44, 0x59, 0x55, 0xf7, 0x6, 0x26, 0x3c, 0x46, 0xcf, 0x87, 0xd, 0xfa, + 0xc, 0x4, 0xb8, 0xd1, 0x9a, 0x96, 0x2, 0x3f, 0xa3, 0x31, 0xdd, 0x26, + 0xc5, 0xb4, 0x97, 0xd9, 0xf6, 0x1a, 0xc8, 0xe9, 0x38, 0x9f, 0x52, 0xc3, + 0xb7, 0x9b, 0x4a, 0x4a, 0xc1, 0x8c, 0x27, 0x79, 0x5b, 0xc, 0x95, 0xe6, + 0xa0, 0x4b, 0xa7, 0x70, 0x6d, 0x54, 0xdb, 0x20, 0x56, 0x5f, 0xa4, 0x13, + 0x4d, 0x97, 0xff, 0x3d, 0xf4, 0x48, 0x3e, 0x74, 0x41, 0x9a, 0x6c, 0x72, + 0x4c, 0xc1, 0x89, 0xcd, 0xf, 0xdb, 0x7a, 0x47, 0xf, 0x2d, 0x3d, 0xaf, + 0xff, 0x20, 0x6, 0x55, 0x78, 0x3b, 0xe3, 0xbc, 0xd1, 0x56, 0xd4, 0xbc, + 0x0, 0x4a, 0x9b, 0x48, 0x7b, 0xbd, 0x18, 0x10, 0x6e, 0xe0, 0xbb, 0xcf, + 0xe7, 0xb0, 0x82, 0xd5, 0x50, 0x6c, 0x90, 0xdd, 0x32, 0xc6, 0xd, 0xc2, + 0x64, 0x13, 0xae, 0xa1, 0x74, 0xde, 0x23, 0x78, 0xdd, 0xd, 0x4f, 0x8b, + 0xe4, 0xa3, 0x31, 0x95, 0xde, 0x86, 0xd3, 0x9a, 0x73, 0x3d, 0x44, 0x23, + 0xaa, 0xbb, 0xf9, 0x34, 0x8f, 0xba, 0x53, 0x50, 0xa4, 0x50, 0x8b, 0x51, + 0x63, 0xe3, 0xd0, 0x1e, 0x9c, 0x1c, 0x93, 0x12, 0x67, 0xe0, 0xf1, 0xf9, + 0x57, 0x26, 0x97, 0x16, 0x84, 0xe5, 0x14, 0xd1, 0x18, 0x65, 0xb0, 0x2c, + 0xab, 0x80, 0xd7, 0x76, 0xd3, 0xed, 0x15, 0xe3, 0xc5, 0xbc, 0x0, 0xf5, + 0x48, 0x63, 0x25, 0xb3, 0x23, 0x30, 0x17, 0x2a, 0x1f, 0x13, 0x43, 0x1a, + 0x6f, 0x52, 0xb7, 0x49, 0x47, 0x1b, 0xaf, 0x41, 0xeb, 0x6e, 0x8e, 0x4c, + 0xe6, 0x20, 0xfb, 0x63, 0xd4, 0x98, 0xe, 0xff, 0xb9, 0xbb, 0x91, 0x17, + 0x10, 0x9f, 0x7f, 0xb2, 0xf0, 0xae, 0x57, 0xba, 0x96, 0x1, 0xbb, 0x4b, + 0x7e, 0xd7, 0xc4, 0xc, 0xdb, 0xa9, 0x36, 0x23, 0x6b, 0xaa, 0x3d, 0x8b, + 0x11, 0x7a, 0x17, 0xe4, 0x52, 0x84, 0xc4, 0x5f, 0x95, 0xf7, 0xc5, 0x9, + 0x9b, 0xb, 0xc2, 0x8c, 0x4, 0xd3, 0x32, 0xb7, 0xa9, 0x86, 0x1e, 0x19, + 0xf0, 0xf3, 0xb9, 0x9b, 0xee, 0x17, 0x9f, 0xa, 0x35, 0xd6, 0x5e, 0xb1, + 0x72, 0x92, 0xf, 0x7, 0x50, 0x41, 0x9a, 0xef, 0x35, 0xca, 0xbf, 0xd4, + 0x3e, 0x90, 0x83, 0xfa, 0xa7, 0x52, 0x18, 0x7b, 0xb4, 0x8a, 0x1d, 0x62, + 0x8b, 0xfd, 0x36, 0xda, 0x20, 0x40, 0x33, 0x14, 0x50, 0xb2, 0xfd, 0xc8, + 0xc6, 0x76, 0x82, 0x81, 0xda, 0xb6, 0xd7, 0x47, 0xda, 0x4b, 0xc9, 0xac, + 0x13, 0x87, 0xa2, 0x53, 0xc, 0xbb, 0x32, 0x1, 0xba, 0x24, 0xcb, 0x76, + 0xea, 0xa0, 0x9c, 0x70, 0xd8, 0x3b, 0x52, 0x75, 0xdc, 0x5, 0x40, 0x0, + 0xa2, 0xe3, 0x4c, 0xc5, 0x5f, 0x64, 0xaa, 0xfa, 0x64, 0x9, 0x58, 0x4c, + 0x4a, 0x35, 0xf0, 0x99, 0xd, 0x44, 0xe9, 0x9b, 0x32, 0x9b, 0xa0, 0x84, + 0x81, 0x2, 0xef, 0x65, 0x3b, 0x6b, 0x7f, 0x1b, 0x89, 0x59, 0x9a, 0xd5, + 0x90, 0x44, 0xb9, 0xe7, 0x55, 0xd2, 0x3d, 0x16, 0x68, 0xdd, 0x38, 0xf0, + 0xb2, 0xc6, 0x3c, 0x49, 0xe6, 0xf8, 0x7f, 0xc5, 0x87, 0x67, 0x1c, 0x36, + 0x87, 0xf7, 0x4e, 0xa5, 0x6f, 0x2, 0xab, 0x44, 0xf9, 0xc, 0xee, 0x7d, + 0x82, 0xe7, 0xbf, 0xff, 0x69, 0xf8, 0xa6, 0xbb, 0xf6, 0x91, 0x11, 0x40, + 0x68, 0xc9, 0x94, 0x7b, 0xd4, 0x31, 0xf2, 0x70, 0x49, 0x43, 0x55, 0xa9, + 0xac, 0xce, 0x7d, 0xbf, 0xed, 0x2, 0x9b, 0x57, 0x4c, 0xc, 0x1f, 0xcb, + 0xc5, 0xc7, 0xa3, 0xc0, 0xe7, 0xd8, 0xf4, 0x21, 0xe6, 0xa4, 0x95, 0x27, + 0x1a, 0x52, 0xe5, 0xd7, 0xf, 0x45, 0x2d, 0xd2, 0x85, 0x3c, 0xbb, 0xa0, + 0x3, 0xab, 0x7c, 0xfb, 0xc8, 0x4c, 0x42, 0x2a, 0x68, 0x4e, 0xc9, 0xdc, + 0xbd, 0x11, 0xf2, 0xe2, 0xf1, 0x5b, 0x9, 0x81, 0x28, 0xe3, 0xb0, 0x4a, + 0x38, 0xbc, 0xb3, 0x14, 0xcc, 0x76, 0x24, 0x44, 0x99, 0x4a, 0x8f, 0x8f, + 0x89, 0x54, 0xc, 0x7b, 0xdd, 0x2e, 0xbf, 0xc7, 0xa4, 0x44, 0xec, 0x22, + 0x8c, 0xa4, 0x3b, 0xce, 0x94, 0x64, 0xc6, 0x8e, 0xde, 0xa6, 0x6c, 0x67, + 0xd2, 0x3d, 0xc9, 0xf3, 0x41, 0x58, 0xf7, 0x3f, 0x15, 0xa2, 0xdb, 0x97, + 0xa8, 0x9, 0x60, 0x28, 0x62, 0xbd, 0xe0, 0xa9, 0x4f, 0x9b, 0x66, 0x30, + 0x51, 0x6e, 0x84, 0xf2, 0xdd, 0xab, 0x5a, 0x48, 0x1b, 0x7, 0x87, 0x2f, + 0xfc, 0x3c, 0x6b, 0x49, 0x34, 0x71, 0xd8, 0x32, 0x2a, 0x20, 0x38, 0xdb, + 0xb7, 0x20, 0xba, 0x87, 0xcd, 0x1a, 0x19, 0xf6, 0x7b, 0x91, 0x70, 0x3d, + 0x3a, 0xff, 0xd3, 0xa4, 0x7f, 0x32, 0x62, 0xad, 0x2c, 0x29, 0xae, 0x6, + 0xe5, 0x90, 0x88, 0x76, 0x92, 0x64, 0x57, 0xe6, 0x37, 0x68, 0x2a, 0xb9, + 0x12, 0x4c, 0xd6, 0xc, 0x4, 0xd9, 0x9f, 0x68, 0xac, 0x32, 0x1a, 0x33, + 0xbc, 0x83, 0x32, 0x45, 0xd3, 0x2d, 0x16, 0x8e, 0xaa, 0xcc, 0x85, 0x8c, + 0xd3, 0xda, 0xa1, 0x82, 0xfa, 0x8d, 0x0, 0x1b, 0xad, 0x83, 0xd1, 0xa2, + 0xb9, 0x4f, 0x41, 0x1e, 0xe3, 0x1f, 0x1a, 0x18, 0x9a, 0x91, 0x2c, 0x52, + 0xa5, 0x14, 0xc4, 0xaa, 0x33, 0x20, 0xfc, 0xd5, 0x2b, 0xe0, 0x38, 0x21, + 0x9d, 0xeb, 0x21, 0x16, 0x34, 0xd5, 0x4d, 0x84, 0x95, 0x46, 0x3a, 0xa3, + 0xe8, 0xf5, 0xe6, 0xde, 0x9e, 0x88, 0x1f, 0xdd, 0x25, 0x6b, 0x30, 0x2f, + 0x32, 0xe3, 0x60, 0x1a, 0xc6, 0x6c, 0xe6, 0x63, 0x5c, 0xa7, 0x1d, 0xa2, + 0x43, 0x6d, 0x0, 0x1b, 0x64, 0xce, 0xb3, 0x38, 0xe, 0xae, 0x5b, 0x2b, + 0x1, 0xa7, 0x4c, 0x8b, 0x9e, 0xbc, 0x5a, 0x8a, 0x46, 0x4, 0xa4, 0xb2, + 0xfb, 0x12, 0x61, 0xe5, 0x84, 0x63, 0x1e, 0x13, 0x9c, 0xc7, 0x19, 0x37, + 0x9, 0xb9, 0x6e, 0xcf, 0x64, 0xed, 0x41, 0xb1, 0x8, 0x82, 0x31, 0xc9, + 0xda, 0x2, 0x80, 0x67, 0xf9, 0x85, 0xcf, 0x9f, 0x26, 0xae, 0xfb, 0x3b, + 0x2f, 0x80, 0x38, 0x33, 0x22, 0x34, 0x4, 0xec, 0x5b, 0xc8, 0x55, 0xd6, + 0xa6, 0xef, 0x1d, 0x68, 0x39, 0x70, 0xc4, 0xdc, 0x7e, 0xba, 0x33, 0x9f, + 0xd1, 0xb2, 0xd5, 0x56, 0x95, 0xde, 0x38, 0xd5, 0x26, 0x5d, 0x23, 0xd8, + 0xca, 0xd, 0xe2, 0xdc, 0x3c, 0x61, 0xcb, 0x1d, 0x51, 0xfc, 0x5e, 0x42, + 0x97, 0x83, 0x72, 0xc5, 0xa5, 0x6c, 0xb6, 0x90, 0xa3, 0xe7, 0xda, 0xb2, + 0x8, 0xfc, 0x7e, 0x41, 0x3b, 0xa2, 0x4a, 0xa9, 0x1b, 0x6b, 0x42, 0x1, + 0x5, 0x5b, 0x86, 0xa5, 0x9f, 0x40, 0x4f, 0x87, 0x2e, 0x5f, 0xda, 0x39, + 0x9a, 0xdc, 0x67, 0xff, 0xf8, 0x9d, 0xcb, 0x49, 0xd4, 0x9, 0x41, 0x2d, + 0xf7, 0x2e, 0x44, 0xe, 0x93, 0x96, 0xf2, 0x76, 0xb5, 0xa5, 0x61, 0x3a, + 0x51, 0x9a, 0xa9, 0xb, 0xc2, 0xc1, 0x7d, 0x3d, 0xfb, 0xf4, 0xd9, 0x5f, + 0xbe, 0xa, 0xa2, 0x95, 0xaf, 0x42, 0xf6, 0x5e, 0xc4, 0x1d, 0x34, 0x26, + 0x1, 0x37, 0xbc, 0xa0, 0x4e, 0x4c, 0x1a, 0xd4, 0x10, 0x5f, 0x5a, 0xe4, + 0x69, 0x3e, 0x49, 0xdc, 0x57, 0x56, 0x7e, 0x51, 0x1b, 0x86, 0x6e, 0x87, + 0x4e, 0x40, 0xa4, 0x94, 0x5, 0xbc, 0xf0, 0xaa, 0xf0, 0xef, 0x2d, 0x39, + 0xf1, 0x42, 0x73, 0x4, 0xe4, 0x17, 0x23, 0xec, 0xdd, 0x84, 0x3, 0x2, + 0x4, 0x6b, 0x8c, 0x5a, 0x78, 0xbe, 0x38, 0x61, 0x53, 0x17, 0xc3, 0xcc, + 0xb9, 0x68, 0xc9, 0x1d, 0x6d, 0x37, 0xfb, 0xe3, 0xce, 0xa7, 0x1, 0xb7, + 0xe4, 0x2d, 0xc1, 0xcc, 0xae, 0xb4, 0xf9, 0xfb, 0x53, 0x19, 0x6f, 0xdd, + 0x30, 0xed, 0x54, 0x74, 0xc2, 0x70, 0xec, 0xf8, 0xde, 0xd3, 0x5e, 0x22, + 0xe5, 0xab, 0xc2, 0x19, 0xec, 0x7, 0xcf, 0x28, 0x8, 0xdb, 0xe0, 0x69, + 0x82, 0x58, 0xf6, 0x8d, 0xe9, 0xe5, 0xab, 0x50, 0xa0, 0x63, 0xd, 0x8a, + 0x23, 0x7c, 0xc6, 0x46, 0x4a, 0x18, 0x1e, 0xad, 0x76, 0xfb, 0xb7, 0xc5, + 0x20, 0xa0, 0xa1, 0xfb, 0xa0, 0x11, 0x4a, 0xdf, 0xd2, 0xb3, 0x4b, 0xc2, + 0xce, 0xa9, 0x34, 0xdc, 0xaa, 0x3, 0xcc, 0x45, 0x3a, 0xe9, 0xa5, 0x9a, + 0xc3, 0xaf, 0xc6, 0xb7, 0x7e, 0x73, 0x4c, 0x0, 0x3e, 0x26, 0x35, 0x50, + 0x6a, 0x1f, 0x24, 0x6e, 0xd2, 0x1a, 0x50, 0xb3, 0xa6, 0x4c, 0xfe, 0xd2, + 0xc7, 0x9d, 0xa4, 0xc, 0x5d, 0xc4, 0x36, 0xf6, 0xe9, 0xc5, 0xfe, 0x4d, + 0x87, 0xe3, 0x74, 0xb5, 0xd6, 0x96, 0x6f, 0x6, 0x2c, 0x34, 0x2d, 0x4, + 0xc8, 0xfe, 0xbb, 0x9, 0xa7, 0x32, 0xd3, 0x2d, 0xfd, 0xb1, 0x9, 0xe6, + 0x64, 0x47, 0x5e, 0x5d, 0x9e, 0xe, 0xaf, 0x2, 0x9d, 0xbc, 0x20, 0x21, + 0xa1, 0x75, 0x67, 0x4e, 0x19, 0x7a, 0xa, 0x3b, 0x65, 0xe1, 0xec, 0x6e, + 0xbe, 0xc3, 0x1d, 0x77, 0x3b, 0x97, 0xb5, 0xf1, 0x4a, 0xaf, 0x9e, 0x2e, + 0xdb, 0xb, 0x49, 0xac, 0x11, 0xda, 0x60, 0x83, 0x23, 0xb7, 0xd9, 0x92, + 0x8f, 0x6c, 0x6f, 0xaf, 0xea, 0x18, 0xb0, 0x53, 0x11, 0x84, 0x14, 0x31, + 0x78, 0x6d, 0x9, 0x25, 0x4c, 0x90, 0x8e, 0xe4, 0x7b, 0x79, 0x1f, 0x17, + 0x64, 0x40, 0x78, 0x8e, 0x7f, 0x27, 0x5b, 0x10, 0x75, 0x13, 0xce, 0xd2, + 0x5b, 0xe2, 0xca, 0x16, 0x23, 0xee, 0x92, 0xd6, 0xea, 0x7e, 0xde, 0x68, + 0x98, 0x73, 0x3f, 0x1c, 0x9c, 0x1e, 0x67, 0xfb, 0x92, 0x10, 0x51, 0xe1, + 0x97, 0x15, 0x5d, 0xbb, 0x26, 0x7f, 0xee, 0xb, 0x7d, 0xf6, 0xc6, 0x81, + 0x23, 0xd5, 0x55, 0xae, 0x86, 0x60, 0x5d, 0x8c, 0x0, 0x55, 0x1e, 0xb7, + 0x4b, 0x1c, 0xc5, 0x3e, 0x5b, 0x1f, 0x89, 0x47, 0x17, 0x28, 0x2b, 0x46, + 0x2b, 0xc3, 0x21, 0xdf, 0x1c, 0x20, 0x22, 0x49, 0xea, 0xe8, 0xb5, 0xff, + 0xfd, 0xd0, 0x91, 0x27, 0xe0, 0x15, 0x3f, 0x15, 0xca, 0xd4, 0xe1, 0x28, + 0xa0, 0x7a, 0xf1, 0xb0, 0xa5, 0x6a, 0x62, 0x90, 0x4e, 0xdc, 0x9d, 0xe, + 0x94, 0x31, 0x5f, 0x8f, 0xbf, 0x15, 0xa5, 0xec, 0x9f, 0x66, 0x6, 0xf1, + 0xe8, 0x97, 0x8f, 0xe1, 0xc6, 0xd3, 0xea, 0xc9, 0xa5, 0x50, 0xe1, 0xdc, + 0x91, 0x18, 0xfb, 0xf1, 0x48, 0xe4, 0x91, 0x1a, 0xc, 0xeb, 0xf4, 0xd, + 0xc3, 0x20, 0x3a, 0xac, 0xf7, 0x4b, 0x4c, 0xa2, 0xab, 0x4a, 0x4a, 0x92, + 0xe3, 0x57, 0x94, 0xf7, 0x92, 0x90, 0xb2, 0xa2, 0xd1, 0x9d, 0xcc, 0x4e, + 0x6a, 0x28, 0x83, 0xd3, 0xb8, 0x40, 0x38, 0x1b, 0x4f, 0x8a, 0x25, 0x95, + 0x2d, 0xde, 0xca, 0xc0, 0xc6, 0x15, 0xe7, 0xc9, 0x7f, 0x89, 0xbf, 0x57, + 0xc3, 0x3a, 0x9c, 0xd9, 0x88, 0x97, 0x58, 0xa7, 0xe5, 0x2d, 0xec, 0x47, + 0x87, 0x9, 0x88, 0x21, 0x87, 0x39, 0xc7, 0xbe, 0x40, 0xa, 0x2b, 0x17, + 0x8b, 0x82, 0x4f, 0xa3, 0x31, 0x5, 0x63, 0xfa, 0x36, 0x83, 0x33, 0x28, + 0x51, 0x38, 0xfd, 0xd7, 0xa3, 0x3b, 0xb3, 0xe8, 0x27, 0x3, 0xda, 0xf8, + 0x35, 0x24, 0x78, 0xcd, 0x20, 0xf6, 0xcd, 0x34, 0xca, 0xf2, 0x66, 0xa3, + 0xaf, 0xd0, 0x29, 0xab, 0xf0, 0x76, 0x5e, 0x23, 0x35, 0xf7, 0x91, 0xa6, + 0x13, 0x2a, 0x91, 0xe8, 0x56, 0x38, 0x1d, 0x8a, 0x2c, 0xad, 0xe9, 0x6f, + 0x50, 0x7, 0x83, 0x64, 0xd5, 0x40, 0xd8, 0x9, 0x2c, 0x7d, 0x14, 0x47, + 0xaa, 0xf5, 0xdb, 0x62, 0x5e, 0x14, 0xa7, 0x78, 0xa6, 0x1b, 0x8c, 0x5b, + 0xc5, 0xef, 0x79, 0x69, 0xfd, 0x78, 0xa9, 0x31, 0xb9, 0xf, 0x51, 0xb3, + 0xe8, 0x2b, 0x51, 0x28, 0x49, 0x8e, 0x86, 0x36, 0x9d, 0x57, 0x45, 0x68, + 0xd4, 0xe1, 0xe, 0x12, 0x76, 0x39, 0x77, 0x6f, 0x5a, 0x1f, 0x2f, 0xad, + 0x60, 0x4e, 0x93, 0xdf, 0x73, 0xdd, 0x49, 0x7d, 0xdb, 0x23, 0x8b, 0xaf, + 0xfa, 0xef, 0xf0, 0xee, 0x30, 0xf6, 0x25, 0x71, 0xa, 0x24, 0x78, 0xe9, + 0xaa, 0x2f, 0x12, 0x44, 0x8f, 0x97, 0x6c, 0x7, 0x21, 0xb0, 0x2f, 0x9b, + 0xd, 0x19, 0x6b, 0xc3, 0xb7, 0x31, 0x85, 0x1c, 0xe9, 0xc2, 0xdd, 0x78, + 0xef, 0xf7, 0xed, 0x31, 0xa2, 0x2d, 0x64, 0xcf, 0xcf, 0xa6, 0x42, 0x28, + 0x62, 0x22, 0xb8, 0x2e, 0xf8, 0xfc, 0xd0, 0xe5, 0xcf, 0x27, 0x7d, 0x2b, + 0x37, 0xbe, 0xd4, 0xb5, 0x6e, 0xd5, 0xbc, 0xfe, 0x77, 0x19, 0x7f, 0xa4, + 0x19, 0xcb, 0xcb, 0x63, 0x9c, 0x7c, 0x5, 0xfd, 0xf4, 0xe7, 0x43, 0x83, + 0xca, 0xbd, 0x72, 0x48, 0x18, 0xb4, 0xe3, 0xa, 0xe, 0x71, 0x8b, 0xa8, + 0x2d, 0xed, 0xd, 0x94, 0xea, 0x3a, 0xe, 0xc0, 0xe9, 0x82, 0x93, 0xad, + 0xa0, 0x6, 0x4c, 0x61, 0xf1, 0x9, 0x15, 0x42, 0x2d, 0xc9, 0x9, 0xb, + 0xb6, 0xc, 0x22, 0x6f, 0x84, 0x29, 0xbe, 0x8e, 0x18, 0xe4, 0x9d, 0xb7, + 0xc1, 0x1e, 0xc, 0x5b, 0x2, 0xc2, 0x40, 0xb4, 0xe2, 0xb8, 0xd7, 0x55, + 0x2, 0xd3, 0x81, 0x3a, 0xd7, 0xca, 0x4b, 0x2f, 0x4b, 0x1c, 0x5d, 0xa2, + 0x4d, 0xba, 0x9e, 0xa6, 0xa3, 0xd5, 0xc8, 0x87, 0x48, 0xd2, 0xdf, 0xa1, + 0x41, 0x5, 0x2, 0xa4, 0xee, 0x36, 0x23, 0x1e, 0x41, 0xd0, 0x60, 0x2e, + 0x29, 0x33, 0xb5, 0x50, 0xc5, 0xae, 0x97, 0xe9, 0xbc, 0x15, 0xa5, 0x2d, + 0x4a, 0xae, 0x50, 0xa7, 0xde, 0x1d, 0x6a, 0x4e, 0xe, 0xbc, 0x99, 0xc6, + 0x9, 0x72, 0x1d, 0xb7, 0xf9, 0xbd, 0x61, 0xce, 0x21, 0xc1, 0x29, 0x60, + 0xda, 0xa5, 0x83, 0x4f, 0x9d, 0xff, 0x14, 0xf9, 0x8, 0xbd, 0x3a, 0x85, + 0xc0, 0x5, 0xf2, 0xff, 0x76, 0xeb, 0x1d, 0x5c, 0xb7, 0x41, 0xc4, 0x55, + 0xaa, 0x3f, 0x20, 0x59, 0x9d, 0x9c, 0xc, 0x64, 0xb7, 0x40, 0xd5, 0xfd, + 0xab, 0xd, 0xd6, 0x84, 0xe0, 0x4d, 0x33, 0xd7, 0xdc, 0xfb, 0xde, 0xd3, + 0xa4, 0x94, 0x1f, 0xee, 0x75, 0x60, 0x7d, 0x90, 0xb2, 0xa3, 0xab, 0xcc, + 0xe4, 0xf0, 0x40, 0xaf, 0xce, 0x73, 0xfb, 0x14, 0x9d, 0x43, 0xe4, 0x91, + 0x31, 0xbf, 0x97, 0x8d, 0xa1, 0x0, 0x51, 0x59, 0xe6, 0x7, 0xad, 0x13, + 0x2e, 0x21, 0xd1, 0x37, 0x1e, 0x6, 0xdc, 0xf6, 0xa3, 0xae, 0x9f, 0x14, + 0x97, 0x7b, 0xea, 0x92, 0xfb, 0x93, 0xa4, 0xd4, 0x8a, 0x94, 0xa0, 0x19, + 0x22, 0xfb, 0x3b, 0xce, 0x2, 0x7e, 0x2, 0x40, 0xd0, 0x9b, 0x91, 0x12, + 0xc3, 0x29, 0xd1, 0xf2, 0x85, 0xd8, 0x86, 0xf0, 0x34, 0xda, 0x9b, 0xcb, + 0x17, 0xef, 0xe, 0x29, 0xcb, 0x26, 0xc5, 0xfe, 0x1d, 0xd6, 0x86, 0x43, + 0x5d, 0x8d, 0xec, 0x81, 0x13, 0x89, 0x1a, 0xb6, 0x2a, 0x25, 0x6c, 0x6a, + 0x95, 0x88, 0xd3, 0x69, 0x6e, 0x1f, 0xa3, 0x63, 0x5, 0xf8, 0x1d, 0x8a, + 0xab, 0xcb, 0x63, 0xb9, 0xb9, 0xbc, 0xea, 0x20, 0xdb, 0x81, 0x2c, 0xf9, + 0x81, 0x78, 0x6, 0x91, 0xa6, 0xe0, 0xb7, 0x73, 0x39, 0x43, 0x87, 0xb, + 0x66, 0xb2, 0xc, 0x83, 0xd2, 0x21, 0xeb, 0xfa, 0xc1, 0x99, 0xa2, 0xfb, + 0x8b, 0x41, 0x91, 0x36, 0xdc, 0x95, 0xa2, 0x2e, 0xe0, 0xb6, 0x6e, 0xdc, + 0x6f, 0x76, 0xe0, 0xd0, 0x93, 0x1d, 0x87, 0xdb, 0x4, 0xe, 0x33, 0x83, + 0xf, 0xd, 0x7f, 0xae, 0x5, 0x71, 0x45, 0x11, 0x79, 0xb0, 0xd0, 0x56, + 0x2b, 0x69, 0x7d, 0xe4, 0x6f, 0x2a, 0xc9, 0x7b, 0xe4, 0xb, 0xb4, 0x3e, + 0x73, 0x13, 0x9c, 0xf5, 0xe2, 0xea, 0xd3, 0xbb, 0xed, 0xc4, 0x49, 0xa5, + 0xbb, 0x31, 0x22, 0x29, 0xb8, 0xa6, 0xdb, 0xb1, 0xb0, 0xc, 0x6f, 0x7b, + 0x8a, 0xe6, 0x73, 0x7, 0xb6, 0x12, 0xc3, 0xdd, 0x6e, 0xa9, 0x30, 0xb9, + 0xe9, 0xd1, 0x3a, 0x81, 0x65, 0xd, 0x8a, 0x77, 0x33, 0xab, 0xcf, 0x8, + 0x39, 0x16, 0xca, 0x44, 0x93, 0xdf, 0xcb, 0xa8, 0x3f, 0x93, 0xc1, 0xd6, + 0x11, 0x37, 0x67, 0x9b, 0x6, 0x44, 0x36, 0x78, 0xbf, 0xc3, 0x9d, 0xd8, + 0x3e, 0x31, 0x56, 0x3, 0xc, 0x2f, 0xa4, 0xf0, 0x7b, 0xff, 0x10, 0x5a, + 0xed, 0x31, 0xff, 0xee, 0x22, 0x6c, 0xb6, 0xaa, 0x3b, 0xa7, 0x17, 0xe1, + 0xc1, 0x47, 0x45, 0x37, 0x90, 0xb7, 0x7a, 0xcf, 0x7c, 0xdb, 0x0, 0xbe, + 0xca, 0xc5, 0xe9, 0xfe, 0x1c, 0xa3, 0x58, 0x89, 0xd8, 0xea, 0xff, 0xc2, + 0xa5, 0x8f, 0xe7, 0x42, 0x28, 0x5f, 0x2, 0x68, 0xc6, 0x88, 0x89, 0x29, + 0x56, 0x38, 0x53, 0xd3, 0x27, 0xf8, 0x77, 0xb4, 0x99, 0x55, 0xe9, 0xa4, + 0xfa, 0xfb, 0xad, 0xe0, 0x99, 0xf4, 0xc0, 0xef, 0xe5, 0x63, 0x6b, 0x36, + 0x90, 0xb8, 0x9c, 0x1a, 0xe7, 0x12, 0xad, 0xab, 0xd9, 0x51, 0xbe, 0x5, + 0x95, 0xe4, 0x1e, 0xda, 0x95, 0xd1, 0xd4, 0x51, 0xc5, 0x80, 0x64, 0x17, + 0xeb, 0xf1, 0xee, 0xe0, 0xe0, 0x8c, 0x8a, 0x32, 0xa6, 0xfc, 0x55, 0xa9, + 0x2d, 0xe1, 0xbe, 0xc3, 0x76, 0x78, 0x5f, 0xba, 0xf0, 0x8e, 0x16, 0x5, + 0x1a, 0xc, 0x78, 0xfa, 0xc4, 0x21, 0xcd, 0xaf, 0xc6, 0x8f, 0x84, 0xf5, + 0x16, 0xf8, 0x48, 0xab, 0x5a, 0x68, 0xb0, 0xd4, 0x75, 0xd8, 0x91, 0x69, + 0x4f, 0x93, 0xd1, 0xee, 0xf0, 0x4c, 0x4d, 0x17, 0xc3, 0x89, 0xa0, 0x7b, + 0x56, 0x38, 0xf4, 0xd7, 0x12, 0xa7, 0x7d, 0x39, 0x81, 0x48, 0xb3, 0x67, + 0xe1, 0x15, 0xa0, 0xa4, 0x2a, 0x60, 0x56, 0xa5, 0xed, 0x9c, 0x76, 0x8b, + 0xa7, 0x14, 0x73, 0x33, 0x9f, 0x55, 0x16, 0x6b, 0x5, 0x40, 0x3b, 0xfe, + 0x93, 0x58, 0x7e, 0xee, 0x2d, 0x61, 0xc5, 0x19, 0x6b, 0x6, 0x71, 0x69, + 0x39, 0x21, 0x0, 0x8, 0x39, 0xb7, 0x76, 0xe, 0x81, 0xe5, 0xe3, 0x77, + 0xff, 0x4b, 0x9b, 0x3, 0x8e, 0xc5, 0xe0, 0xb1, 0x8b, 0x16, 0xbd, 0x71, + 0xbc, 0xc6, 0x62, 0x19, 0xaa, 0x6e, 0x54, 0xb6, 0x7a, 0x17, 0xdb, 0xe5, + 0xd9, 0x2, 0xaa, 0x57, 0x78, 0x2f, 0xd2, 0x85, 0xfb, 0x36, 0xb5, 0xdd, + 0x17, 0xbd, 0x4c, 0x8, 0x3c, 0x6b, 0x79, 0x3e, 0x28, 0xab, 0x38, 0xc3, + 0xe9, 0xdb, 0xf1, 0x28, 0xc3, 0x2a, 0xba, 0x51, 0x1a, 0xf, 0x78, 0xec, + 0x25, 0xa8, 0xf5, 0xed, 0xe4, 0x9f, 0xb, 0xa5, 0x66, 0x58, 0x18, 0xb0, + 0xe4, 0x40, 0xb9, 0xf, 0xce, 0x78, 0xc9, 0x49, 0x4d, 0x2e, 0x29, 0xd9, + 0xbb, 0x59, 0x99, 0xef, 0x3d, 0x44, 0x99, 0x75, 0x8f, 0xe1, 0x1d, 0x5, + 0x70, 0xeb, 0x65, 0x93, 0xeb, 0x3f, 0x76, 0x4f, 0xae, 0xa0, 0x12, 0x5b, + 0x18, 0x28, 0xe6, 0x2a, 0x26, 0xae, 0xe0, 0xd3, 0x26, 0xd2, 0x5f, 0xf5, + 0x89, 0xec, 0x1e, 0xc6, 0x1, 0xe9, 0xe1, 0x7c, 0x30, 0x6a, 0x65, 0x4d, + 0x7c, 0x82, 0xb4, 0xd, 0x92, 0xde, 0x2f, 0xe8, 0x9, 0xde, 0x6f, 0x15, + 0x21, 0x78, 0x91, 0xb2, 0x39, 0xab, 0x20, 0xbb, 0x96, 0xf6, 0xc0, 0xba, + 0xeb, 0x8b, 0x63, 0x97, 0xab, 0xc7, 0x21, 0xd2, 0x85, 0xb, 0x66, 0x91, + 0x31, 0xeb, 0x17, 0x18, 0x4e, 0x12, 0x3e, 0xa5, 0x57, 0x6e, 0xe5, 0x95, + 0x70, 0x3c, 0x25, 0x1b, 0x53, 0x4a, 0xde, 0x29, 0x20, 0x13, 0x90, 0xd9, + 0xc7, 0x3f, 0x15, 0xcf, 0x98, 0x94, 0x43, 0xe6, 0x98, 0xee, 0x33, 0xa0, + 0x8a, 0xc6, 0xfb, 0x71, 0x73, 0xfe, 0xd1, 0xf5, 0xd, 0x71, 0xfe, 0x15, + 0xdb, 0x7e, 0xaf, 0x36, 0x5a, 0x59, 0xab, 0xaf, 0x96, 0xa0, 0x3b, 0x5, + 0xda, 0xa, 0x46, 0x76, 0xa0, 0x55, 0x93, 0xd9, 0xf0, 0x63, 0xc9, 0x8c, + 0x40, 0x2d, 0x97, 0x1b, 0x6e, 0x54, 0x0, 0x78, 0xfb, 0x88, 0xc2, 0x46, + 0xef, 0xf, 0x45, 0xba, 0xa0, 0xc7, 0x99, 0xa2, 0xcf, 0x88, 0x9e, 0x96, + 0x27, 0x15, 0x24, 0x28, 0xf8, 0xa0, 0xa4, 0xbb, 0x57, 0x7c, 0xc7, 0xef, + 0x2b, 0x50, 0xa, 0x78, 0x92, 0x82, 0x6e, 0x6e, 0x75, 0x4a, 0x29, 0x20, + 0xab, 0xef, 0x9e, 0x85, 0x7f, 0x33, 0x2c, 0x5, 0xfa, 0xd, 0x6e, 0xab, + 0xc8, 0xb9, 0xee, 0xd0, 0x22, 0xd6, 0xd9, 0xc9, 0x90, 0xe4, 0xea, 0x42, + 0x9, 0x72, 0x15, 0x3c, 0xbe, 0x6f, 0x6e, 0x85, 0x18, 0x2e, 0xb0, 0xc8, + 0xac, 0xe2, 0xc, 0xd3, 0xa3, 0x6, 0xbf, 0xdc, 0x93, 0x2a, 0xb8, 0xa0, + 0x21, 0x3c, 0x7f, 0x8c, 0xbe, 0xda, 0x8e, 0xf3, 0xf7, 0xfe, 0x83, 0x4a, + 0x35, 0x5, 0x80, 0x39, 0x66, 0xab, 0x38, 0x3a, 0x8a, 0xc6, 0x5e, 0xca, + 0xb0, 0x74, 0x39, 0xfd, 0x23, 0xa0, 0x4f, 0x5, 0xb3, 0x23, 0xe9, 0xfd, + 0xb5, 0xe, 0x47, 0x20, 0x14, 0x27, 0x6, 0x33, 0x60, 0xbc, 0xd4, 0xb0, + 0x84, 0x17, 0x87, 0xcf, 0x24, 0x79, 0xa0, 0x26, 0x91, 0x81, 0xe3, 0x4c, + 0x73, 0x7c, 0xa3, 0xc2, 0xc6, 0x4b, 0xb8, 0xda, 0xff, 0xaa, 0x89, 0x38, + 0x84, 0xea, 0xfe, 0x58, 0xd9, 0x11, 0x82, 0x30, 0x90, 0x39, 0x39, 0x88, + 0x10, 0xec, 0xf8, 0xc0, 0x1, 0x16, 0xb6, 0xc1, 0x74, 0xf6, 0xb2, 0xb3, + 0x6d, 0x8d, 0xf8, 0x76, 0xa0, 0x7f, 0x12, 0x26, 0xba, 0x9d, 0xed, 0x45, + 0x27, 0x5d, 0x3f, 0x4b, 0xe7, 0xd2, 0xc5, 0xf9, 0xf8, 0xde, 0x95, 0x74, + 0xb1, 0x2a, 0x3f, 0xed, 0x1f, 0x73, 0x15, 0x18, 0xc4, 0xb1, 0x32, 0x90, + 0x52, 0xc4, 0x11, 0x78, 0x21, 0x25, 0x61, 0x2c, 0x8f, 0x78, 0x7f, 0xee, + 0x31, 0x92, 0x4f, 0x36, 0xbc, 0xd5, 0x70, 0x84, 0x4c, 0xb4, 0x39, 0xa3, + 0x73, 0x53, 0xbb, 0x48, 0x3d, 0xff, 0x3, 0x74, 0xea, 0x2f, 0x7, 0xf3, + 0xaa, 0xeb, 0x1b, 0x69, 0xa3, 0x28, 0x56, 0x45, 0x6d, 0xb2, 0xb2, 0x12, + 0xc1, 0xf7, 0x21, 0x35, 0x5, 0x14, 0x9c, 0x6, 0xf9, 0x1c, 0x9e, 0x8e, + 0xda, 0x19, 0xa8, 0x6, 0x5f, 0xa1, 0x21, 0x1e, 0x1e, 0x96, 0x38, 0x2, + 0x29, 0xd5, 0x6d, 0x8e, 0x24, 0x4e, 0x94, 0x79, 0x22, 0xc7, 0x67, 0xe8, + 0xc2, 0x12, 0xdf, 0xed, 0x82, 0x22, 0xdb, 0x80, 0x52, 0xc, 0x60, 0xdf, + 0x84, 0x92, 0x55, 0xc2, 0xce, 0xfc, 0x7, 0x69, 0x9f, 0xd2, 0xd0, 0x37, + 0xbf, 0x1d, 0x11, 0x8a, 0xab, 0x26, 0x92, 0x6b, 0xe, 0xbc, 0x1c, 0x6f, + 0xdf, 0x78, 0x8f, 0x8a, 0xce, 0x16, 0x70, 0x90, 0x2a, 0x66, 0x13, 0x9a, + 0x57, 0xda, 0x5f, 0x93, 0xcd, 0xef, 0x8f, 0x76, 0x1e, 0x8e, 0x59, 0xdf, + 0x7, 0x49, 0x35, 0x81, 0xa4, 0x7d, 0x1b, 0xe0, 0x61, 0x6f, 0x10, 0xc1, + 0x1c, 0xf2, 0xc6, 0x7f, 0x1, 0x92, 0xa0, 0x4d, 0x58, 0x2a, 0xe0, 0x27, + 0xbf, 0x3a, 0x8f, 0xb0, 0x2a, 0xfd, 0x6, 0xb, 0x35, 0xfd, 0x49, 0x2, + 0x2, 0xf6, 0x52, 0x35, 0x15, 0x78, 0x3d, 0xa0, 0x99, 0x98, 0x5f, 0xf3, + 0xce, 0x38, 0xfd, 0xd6, 0x81, 0xb1, 0xed, 0xb1, 0x89, 0x2d, 0x7c, 0xee, + 0x1c, 0x65, 0x36, 0x24, 0xc2, 0xd, 0xbe, 0xa6, 0xf1, 0xa2, 0x95, 0xb8, + 0x9d, 0xc9, 0xaf, 0x5, 0xb2, 0xe5, 0x95, 0x45, 0xe5, 0x9b, 0x82, 0x3d, + 0xbb, 0x65, 0x0, 0xfe, 0x24, 0xb9, 0xc8, 0x43, 0x57, 0xd6, 0x2d, 0x9e, + 0xa4, 0xfa, 0x99, 0x1a, 0xc9, 0xb0, 0xdb, 0x70, 0xd9, 0x28, 0x85, 0x4c, + 0x33, 0x33, 0xa7, 0x37, 0x86, 0xa7, 0x62, 0x8a, 0xca, 0xbc, 0xfd, 0x25, + 0x43, 0x4c, 0xbe, 0x3e, 0xb7, 0xfb, 0x99, 0x5e, 0xe4, 0x9, 0x9a, 0x92, + 0xdd, 0xec, 0x6f, 0xab, 0x39, 0x65, 0x75, 0x6e, 0x98, 0xbd, 0xd0, 0xd9, + 0x87, 0x46, 0xa3, 0x9c, 0xfe, 0x41, 0x4f, 0x20, 0x3d, 0x68, 0x32, 0x21, + 0x94, 0x5a, 0xbd, 0x67, 0x9f, 0x79, 0x51, 0x8a, 0xe9, 0x16, 0xa3, 0xc0, + 0x33, 0x69, 0x21, 0x45, 0x62, 0xa2, 0x45, 0x36, 0xaa, 0xd1, 0x80, 0x3a, + 0x6a, 0x51, 0x86, 0xb4, 0x49, 0x56, 0xd6, 0x65, 0xdd, 0x87, 0x9e, 0xb0, + 0x4a, 0xbe, 0x80, 0x42, 0x13, 0x44, 0xc4, 0x5d, 0x8a, 0x54, 0x37, 0x11, + 0xfc, 0xe6, 0xa5, 0xd, 0x59, 0xd7, 0x11, 0xa6, 0x61, 0x44, 0x87, 0xf0, + 0x93, 0x36, 0x57, 0x15, 0x6c, 0xe2, 0x8f, 0x37, 0x27, 0x87, 0x96, 0x1, + 0xe0, 0x98, 0xc4, 0xda, 0x1, 0xf4, 0x21, 0x3, 0x97, 0x28, 0x71, 0xdc, + 0xd2, 0xf3, 0xb0, 0x24, 0x10, 0xb9, 0x89, 0xd5, 0x97, 0x34, 0x60, 0xcb, + 0x39, 0x6, 0xb3, 0x59, 0xeb, 0x3b, 0x86, 0xd0, 0x1b, 0x51, 0x6d, 0x46, + 0xa8, 0xb6, 0xcd, 0xec, 0xf7, 0xe1, 0xf6, 0xc8, 0x9, 0xe0, 0xfa, 0x29, + 0xf4, 0x96, 0x53, 0x9f, 0x3, 0xe1, 0x3e, 0x72, 0x23, 0x32, 0x8f, 0xa7, + 0xb, 0x94, 0x55, 0x71, 0x4f, 0x41, 0x6d, 0xcf, 0xf, 0x87, 0xd, 0x45, + 0xcd, 0x33, 0x63, 0x10, 0x7, 0xff, 0x95, 0x58, 0xb6, 0xc1, 0x2, 0x0, + 0x8d, 0xbb, 0x4e, 0x16, 0x9f, 0x5d, 0x3f, 0xbe, 0x44, 0x16, 0x4, 0x73, + 0x6e, 0xf5, 0xb8, 0x72, 0x5b, 0xed, 0x36, 0x4e, 0xf8, 0x86, 0xb9, 0x71, + 0x63, 0x10, 0x7f, 0x4e, 0x69, 0xc8, 0xa, 0xc0, 0x75, 0xdd, 0xd3, 0xe0, + 0xa5, 0x2c, 0xd2, 0xf4, 0xc1, 0x9a, 0x72, 0xe3, 0xf2, 0xb1, 0x46, 0x56, + 0x6b, 0x3f, 0x3, 0x87, 0x53, 0x75, 0x7d, 0xce, 0x1b, 0x31, 0xd6, 0x29, + 0x99, 0xcf, 0xc0, 0x5f, 0xb5, 0x7b, 0x3a, 0xa0, 0x7d, 0x66, 0xda, 0x86, + 0x5f, 0x74, 0x29, 0x8f, 0x37, 0x90, 0x65, 0xec, 0xef, 0x1c, 0xb0, 0xf6, + 0x68, 0xe, 0x34, 0x78, 0xd5, 0xae, 0x4, 0x5d, 0x6, 0xa, 0x5c, 0xb8, + 0x74, 0x67, 0xbc, 0xa8, 0x97, 0x3d, 0x2a, 0xbe, 0xd3, 0x74, 0x5, 0xdc, + 0x3d, 0x61, 0x22, 0x5a, 0x84, 0x98, 0xe1, 0xae, 0x59, 0x20, 0x6a, 0xe0, + 0xb6, 0x78, 0xc, 0x8, 0xfa, 0x75, 0xb4, 0xb7, 0xd2, 0x14, 0x1e, 0x8a, + 0x3c, 0x58, 0x7c, 0x95, 0x91, 0x5d, 0x56, 0xbf, 0xfe, 0xbe, 0x7f, 0xb1, + 0x2e, 0x81, 0x7b, 0x4e, 0x1e, 0xd1, 0x2a, 0x25, 0x30, 0x87, 0xf5, 0x40, + 0xd7, 0xcc, 0x1d, 0xd8, 0x9d, 0x77, 0x37, 0x3, 0x6, 0x91, 0x6c, 0x1d, + 0xa3, 0xaa, 0xa9, 0x9b, 0xa9, 0xf5, 0x92, 0x31, 0x44, 0xdc, 0x7b, 0xcf, + 0xe8, 0x9a, 0xa5, 0x46, 0x9a, 0xac, 0x20, 0x56, 0x8, 0x56, 0x7d, 0x82, + 0xba, 0x4b, 0x3, 0x3e, 0xa3, 0x62, 0xe2, 0xcc, 0x19, 0x48, 0xc7, 0xfe, + 0xde, 0x2, 0xa4, 0x59, 0x6e, 0xf0, 0x19, 0x40, 0xd7, 0x35, 0x64, 0x8b, + 0x40, 0xb, 0x3d, 0x87, 0xb8, 0xd9, 0x11, 0xed, 0xae, 0x2c, 0x8b, 0x6c, + 0x45, 0x91, 0x81, 0x27, 0xc, 0xea, 0xb2, 0x9f, 0xb7, 0x27, 0x90, 0x32, + 0xd4, 0x19, 0xb1, 0xff, 0x48, 0xa, 0xac, 0x55, 0x8d, 0x1b, 0x22, 0xef, + 0x51, 0xcc, 0x9, 0xff, 0xab, 0x1e, 0x70, 0xa8, 0x49, 0xf2, 0x68, 0xc4, + 0xdf, 0xd, 0xee, 0x3, 0x67, 0xb3, 0xa, 0x39, 0x8b, 0x59, 0x1a, 0x8a, + 0x95, 0xba, 0xc8, 0xde, 0x6, 0xf6, 0xb7, 0xa5, 0xbc, 0xa0, 0x4d, 0xb2, + 0xd2, 0x58, 0x6e, 0xcc, 0x94, 0xa1, 0xaf, 0xf1, 0xf4, 0x73, 0x64, 0xc3, + 0x90, 0xdd, 0xd7, 0x4f, 0xb7, 0xbc, 0x65, 0x11, 0xdd, 0x40, 0xd6, 0xf, + 0x73, 0xeb, 0xef, 0x4e, 0x57, 0x72, 0xd7, 0xe6, 0xe6, 0xe1, 0xb1, 0x2d, + 0x80, 0xb2, 0x59, 0x95, 0xa9, 0xca, 0x85, 0x3f, 0x5e, 0x9c, 0x7d, 0xa9, + 0x9d, 0x22, 0x7b, 0xcc, 0x89, 0xda, 0xe0, 0x7e, 0x56, 0x42, 0x69, 0x28, + 0x76, 0x12, 0x2a, 0xa, 0xa1, 0xc9, 0x19, 0x2c, 0x46, 0xd3, 0xe8, 0x22, + 0xd4, 0x9, 0x92, 0x9f, 0x75, 0x53, 0x82, 0xfb, 0xf0, 0x2f, 0x96, 0x4, + 0xc6, 0xf4, 0xc3, 0xdf, 0x2, 0x31, 0xfd, 0x74, 0x24, 0xda, 0xe5, 0xdf, + 0x4d, 0x68, 0xe4, 0x5e, 0x20, 0xd5, 0x55, 0x9b, 0x9d, 0xe3, 0xc6, 0x70, + 0x10, 0x70, 0x56, 0xe4, 0x4d, 0x7e, 0x78, 0x69, 0xb3, 0x7f, 0xc0, 0x8c, + 0xea, 0xc, 0xf0, 0xdc, 0x3a, 0x87, 0x34, 0xa8, 0x9f, 0x6a, 0x4d, 0xae, + 0x49, 0x9e, 0x35, 0x66, 0xc8, 0x6f, 0xaa, 0xa7, 0xfb, 0x4c, 0xf6, 0xb, + 0x58, 0x11, 0x26, 0xa7, 0x45, 0xef, 0x3c, 0xdb, 0x5e, 0xce, 0xf8, 0xb4, + 0x6d, 0x7c, 0x85, 0x93, 0xb1, 0x27, 0x56, 0x60, 0x3a, 0x1b, 0xd0, 0x96, + 0xba, 0x8b, 0xf4, 0x65, 0xa4, 0xda, 0x8f, 0x71, 0xc, 0xa6, 0x81, 0x8c, + 0x8a, 0x3c, 0xb4, 0x27, 0x6a, 0xcf, 0x16, 0x7, 0x81, 0x2e, 0xa0, 0xb, + 0xf6, 0xd1, 0xec, 0x1d, 0x85, 0x0, 0xf7, 0x49, 0xeb, 0x19, 0xd3, 0xa7, + 0xc0, 0xec, 0x79, 0xf7, 0xa3, 0x91, 0x27, 0x9a, 0xe3, 0x16, 0x60, 0x52, + 0xe7, 0xfe, 0xe5, 0x7, 0x16, 0x88, 0xf4, 0x27, 0x69, 0x47, 0x5, 0x1e, + 0x76, 0xe6, 0x16, 0x5d, 0x32, 0x5a, 0x92, 0x41, 0x5, 0x97, 0x3e, 0xcf, + 0x3f, 0x22, 0x63, 0xa1, 0xa7, 0x8f, 0xac, 0xa9, 0x56, 0x82, 0x7, 0xbc, + 0x79, 0xbc, 0x4f, 0xe5, 0x84, 0xa4, 0xe8, 0xde, 0xd3, 0xe7, 0x96, 0x5f, + 0x0, 0xde, 0xba, 0x27, 0xa4, 0x23, 0x57, 0xc6, 0x4a, 0x69, 0xab, 0xbf, + 0x3d, 0x34, 0xe7, 0xec, 0xc4, 0xe9, 0xee, 0xd6, 0xc8, 0x2d, 0x52, 0x47, + 0x11, 0x19, 0xd8, 0xc6, 0x4e, 0x2c, 0xf2, 0x68, 0x9a, 0xd5, 0xb, 0x25, + 0xe8, 0x77, 0xa1, 0x38, 0x7e, 0x15, 0xf, 0xc6, 0x85, 0x7d, 0x14, 0x2a, + 0x41, 0x55, 0xb, 0xe7, 0x83, 0xcc, 0x6b, 0x4f, 0xbe, 0xde, 0xec, 0x38, + 0xd1, 0xf4, 0x32, 0x4c, 0x36, 0xe1, 0xf3, 0x70, 0x1b, 0xbb, 0x82, 0xd9, + 0x80, 0x19, 0x67, 0x25, 0xa0, 0x1c, 0xdd, 0x63, 0xb2, 0x80, 0xf8, 0xef, + 0xd, 0xa9, 0xde, 0x77, 0x4c, 0x53, 0x17, 0x9d, 0x2f, 0x3d, 0x91, 0x80, + 0x6b, 0xcc, 0x55, 0x5d, 0xbc, 0x14, 0x8f, 0xfa, 0x6e, 0xfd, 0xf5, 0xf1, + 0x22, 0x33, 0xf5, 0x39, 0x6f, 0xe0, 0xc, 0x69, +}; +const uint8_t kAltGameImages2xC[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, + 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, + 0x9c, 0xe5, 0x73, 0xd9, 0x39, 0xba, 0x2, 0x36, 0xe2, 0x8a, 0xd1, 0x1, + 0xb, 0x82, 0x86, 0x7e, 0x6, 0xa9, 0xae, 0xfd, 0x76, 0x74, 0xfb, 0x7b, + 0xea, 0xea, 0x4a, 0xd4, 0x8c, 0xd2, 0xec, 0x68, 0xf5, 0xd2, 0xfe, 0x7e, + 0xc6, 0x5f, 0xa7, 0x53, 0x22, 0xe7, 0xed, 0x68, 0x22, 0xf7, 0x1d, 0x8b, + 0xcb, 0x84, 0xfd, 0x82, 0xf9, 0x48, 0xe6, 0x91, 0xc9, 0x81, 0x2c, 0x40, + 0x53, 0x7b, 0x7f, 0x85, 0x83, 0xab, 0x99, 0xf6, 0xbb, 0xc2, 0x20, 0xaf, + 0x40, 0xd9, 0xb, 0xc8, 0x7d, 0x55, 0x68, 0xda, 0x6d, 0xe6, 0x8c, 0xd9, + 0x20, 0xaf, 0xd, 0x7e, 0x8b, 0x66, 0xe1, 0x43, 0x3a, 0x6e, 0xb8, 0x97, + 0x50, 0xbe, 0xd1, 0x33, 0xb7, 0x18, 0xe3, 0x68, 0xa, 0x4, 0x4b, 0x76, + 0x1e, 0xd6, 0x6e, 0x6c, 0x68, 0x43, 0xd7, 0x14, 0xff, 0xc6, 0xee, 0xfb, + 0xe7, 0xab, 0x36, 0x81, 0x85, 0x58, 0xe, 0x4b, 0xdd, 0x24, 0x7, 0x8b, + 0xa7, 0x3a, 0x8f, 0xc0, 0x58, 0xad, 0x68, 0x32, 0xaf, 0xf6, 0xdf, 0x2a, + 0x86, 0xd1, 0x47, 0xa7, 0x76, 0xe1, 0x2b, 0xcb, 0xf7, 0xfc, 0x75, 0x35, + 0x2c, 0x1a, 0x24, 0xd, 0x6d, 0x91, 0x27, 0x4, 0x4d, 0x2b, 0xad, 0xa7, + 0x8f, 0x48, 0xf4, 0xa4, 0xfe, 0x92, 0x75, 0xc3, 0x10, 0x82, 0xb2, 0xd0, + 0x2d, 0xf4, 0x89, 0xda, 0x25, 0xb3, 0x85, 0x1, 0x50, 0xd5, 0x27, 0x27, + 0x81, 0x5, 0x4e, 0x9, 0x1a, 0x36, 0x87, 0xd3, 0xe2, 0x32, 0xb7, 0x43, + 0x4d, 0x4c, 0x15, 0x83, 0xe1, 0x1b, 0xd8, 0xae, 0xe8, 0x10, 0x44, 0x78, + 0x11, 0x9f, 0x52, 0xc0, 0xa6, 0x70, 0x23, 0xe4, 0xa9, 0xbc, 0xdd, 0x44, + 0x61, 0x42, 0xc5, 0x30, 0xd3, 0xe8, 0x1, 0x24, 0x61, 0x2b, 0x9, 0x1, + 0xe2, 0x8e, 0xca, 0x2, 0x1b, 0x52, 0xc5, 0xe2, 0xd8, 0x1b, 0x25, 0x49, + 0xed, 0x29, 0x85, 0x56, 0xef, 0xa4, 0xce, 0x32, 0x9, 0xcd, 0x94, 0x6b, + 0x7d, 0x9, 0x7d, 0xf1, 0xcc, 0x4c, 0xc7, 0x42, 0x98, 0xd3, 0x70, 0xd2, + 0xf2, 0xee, 0xa3, 0xac, 0x6b, 0x7c, 0x52, 0xfe, 0x26, 0x1d, 0x9b, 0x6d, + 0x53, 0xb3, 0x33, 0xa6, 0x9f, 0x8d, 0xb1, 0xd3, 0x8a, 0x87, 0x52, 0xf5, + 0x42, 0xff, 0xf3, 0x81, 0x0, 0x5f, 0xf0, 0x2f, 0x25, 0xf2, 0xf6, 0xc1, + 0xe1, 0x8c, 0x41, 0x10, 0x74, 0xd6, 0x3c, 0x2e, 0x5b, 0x2c, 0x93, 0xd6, + 0xcb, 0x67, 0x15, 0x4, 0x1f, 0x27, 0x28, 0xf9, 0xe9, 0x4d, 0x4, 0x47, + 0x49, 0x77, 0xeb, 0x8c, 0x3c, 0x96, 0x1b, 0x7f, 0xf3, 0x31, 0xf5, 0xff, + 0x20, 0x9d, 0x18, 0x94, 0xdf, 0x6f, 0x77, 0x9c, 0x63, 0x7c, 0xcf, 0x4f, + 0x3e, 0x55, 0x32, 0xc8, 0xe9, 0xd5, 0x37, 0x8f, 0x3e, 0x9c, 0x4b, 0x12, + 0x6, 0xcf, 0xf4, 0xfb, 0x1a, 0x9a, 0x58, 0x2, 0xb0, 0xc1, 0xf5, 0x32, + 0x91, 0xfd, 0xec, 0xa5, 0xb2, 0x79, 0x99, 0x64, 0xbb, 0xb8, 0x8b, 0xf9, + 0xe4, 0xb2, 0xa2, 0x84, 0xdf, 0x92, 0x71, 0x87, 0xbb, 0x75, 0x3, 0xfc, + 0x37, 0x72, 0x13, 0x31, 0xd, 0xec, 0xdd, 0x6e, 0xa6, 0x3f, 0xef, 0xbf, + 0xe2, 0xdd, 0x20, 0x98, 0x24, 0x7c, 0x57, 0xfd, 0x4b, 0x77, 0x6, 0x73, + 0xbd, 0xb2, 0xa1, 0xb0, 0x6e, 0x8c, 0x28, 0x71, 0x11, 0x92, 0x1d, 0x7b, + 0x2b, 0x28, 0x1, 0x85, 0x73, 0x1b, 0xff, 0xf3, 0xdc, 0x31, 0xbb, 0x14, + 0x2c, 0x6e, 0x77, 0x19, 0x67, 0xf7, 0x1c, 0xc4, 0xba, 0x1c, 0xaa, 0x4d, + 0x9f, 0xa6, 0x33, 0xa0, 0x7d, 0xc4, 0x70, 0xd7, 0xeb, 0x93, 0x7c, 0x64, + 0x18, 0xf7, 0x77, 0xc, 0x1b, 0x1, 0x91, 0x70, 0x90, 0x3f, 0x92, 0x5e, + 0xc2, 0xe7, 0xc9, 0x3e, 0x0, 0xab, 0x3a, 0x75, 0x8a, 0x42, 0x39, 0x47, + 0x26, 0x51, 0x91, 0x20, 0xbb, 0x96, 0xac, 0xfb, 0xa6, 0x9c, 0x5f, 0xa8, + 0x58, 0x3c, 0x4e, 0x1e, 0xe0, 0xd0, 0xf1, 0x84, 0x7e, 0xe8, 0x83, 0xa5, + 0x54, 0x3e, 0xae, 0xdf, 0xd9, 0x75, 0xf8, 0x7a, 0xed, 0xb7, 0x28, 0xfb, + 0x11, 0xb7, 0xd, 0x67, 0xf, 0xea, 0x3b, 0xbd, 0x97, 0xc0, 0x43, 0x41, + 0x26, 0xaf, 0xfb, 0x5c, 0xb7, 0x56, 0xb1, 0x7d, 0xcb, 0x8, 0xa8, 0x63, + 0xfc, 0xfb, 0x61, 0x1b, 0xc1, 0x77, 0xee, 0xd, 0x2e, 0xdd, 0xc6, 0x74, + 0x14, 0x9f, 0x90, 0x5d, 0x50, 0xe4, 0x96, 0xc, 0xb3, 0x5c, 0x5e, 0x6c, + 0xec, 0x63, 0x43, 0xf4, 0xa5, 0xc0, 0xf1, 0x18, 0xc0, 0x25, 0x76, 0x80, + 0x8a, 0x51, 0x38, 0xb9, 0x29, 0x2b, 0x8e, 0x5, 0x63, 0xb1, 0x4f, 0x3e, + 0x92, 0xc0, 0xc1, 0xf7, 0x94, 0x4a, 0xd8, 0x9d, 0xba, 0xc1, 0x8e, 0xc9, + 0x16, 0x4c, 0xe4, 0xd4, 0x6f, 0x78, 0x4d, 0xa3, 0x79, 0x44, 0x63, 0x66, + 0x9d, 0x28, 0xee, 0xae, 0x8e, 0x1d, 0xa0, 0x45, 0x1b, 0xf, 0x13, 0x87, + 0x45, 0x48, 0x47, 0xf9, 0xe7, 0x90, 0x4e, 0x47, 0xce, 0xcf, 0xca, 0x26, + 0xb3, 0x5d, 0xa3, 0xb9, 0xa0, 0x97, 0x1e, 0x57, 0x7d, 0x11, 0xa7, 0xfc, + 0x1c, 0xe8, 0x93, 0x47, 0xc9, 0x1f, 0x60, 0x1f, 0x15, 0x9f, 0x61, 0xc5, + 0x2c, 0xc6, 0xaa, 0xa2, 0xc2, 0xaa, 0x25, 0xdc, 0xfe, 0x74, 0x2, 0xb6, + 0xd0, 0x5, 0x63, 0xe7, 0x4, 0xa8, 0xe, 0x3e, 0x3d, 0x80, 0x45, 0x95, + 0xa7, 0xc6, 0x53, 0xd7, 0xed, 0xb, 0x1c, 0x1d, 0x21, 0x8, 0x8f, 0x3e, + 0xec, 0xf, 0x71, 0x14, 0x3e, 0xc0, 0x88, 0x15, 0xfd, 0x18, 0x7f, 0x7b, + 0x8, 0x5c, 0xfd, 0x27, 0xa2, 0x82, 0xfd, 0xb8, 0x4, 0xed, 0xe1, 0x10, + 0x33, 0xdd, 0x43, 0x6d, 0x75, 0xd5, 0x26, 0x50, 0xb, 0xc1, 0xa0, 0x14, + 0xa1, 0x6b, 0xad, 0xc8, 0x1f, 0xe0, 0x25, 0x2c, 0x3e, 0x1f, 0x58, 0xf9, + 0x3f, 0x18, 0x5f, 0xb7, 0xa4, 0x56, 0x90, 0x4d, 0x66, 0xab, 0x77, 0x66, + 0x54, 0xbd, 0x7d, 0xff, 0x1f, 0x3a, 0x6c, 0x7, 0x6e, 0x5a, 0x64, 0xf0, + 0x5b, 0x75, 0x20, 0xc4, 0x30, 0x1d, 0x3e, 0xd0, 0xf3, 0x31, 0x14, 0xe5, + 0x6d, 0xd0, 0x35, 0xa0, 0x62, 0x7, 0x14, 0x25, 0x14, 0x45, 0x19, 0xfb, + 0x7a, 0x93, 0x69, 0xbc, 0x1, 0xd2, 0x17, 0x92, 0xc4, 0x53, 0xa2, 0xcf, + 0xa5, 0xa, 0xde, 0xc5, 0x3d, 0x25, 0x91, 0x62, 0x4e, 0x0, 0xdd, 0xc5, + 0x2b, 0xc9, 0x39, 0x80, 0x3a, 0xc8, 0x4a, 0x15, 0xe5, 0x62, 0x2a, 0x25, + 0xfc, 0x3d, 0xaf, 0x4b, 0x72, 0x74, 0x12, 0x1c, 0xdc, 0xbb, 0x79, 0x34, + 0xfb, 0x4, 0xeb, 0xd4, 0x87, 0xf6, 0x60, 0x3a, 0x84, 0x97, 0x17, 0x58, + 0x44, 0x8f, 0xd4, 0xbf, 0x27, 0x27, 0x6a, 0x7a, 0x7a, 0x1a, 0x4a, 0x38, + 0xfe, 0xa8, 0xde, 0xcf, 0xd0, 0x23, 0xcd, 0x7a, 0x56, 0x7f, 0x76, 0x62, + 0x3f, 0xaf, 0xb6, 0xde, 0x47, 0x4c, 0xea, 0xb4, 0x6, 0x7c, 0xb0, 0x8, + 0x2d, 0x4b, 0xfe, 0x6b, 0x1e, 0x94, 0x91, 0x72, 0xb9, 0x13, 0x67, 0x71, + 0x21, 0xeb, 0x8e, 0xd4, 0xf5, 0x3c, 0xe8, 0xc8, 0x7c, 0xcb, 0x1d, 0xcf, + 0x82, 0x8b, 0xa7, 0x60, 0x81, 0x9f, 0xb, 0xce, 0x4e, 0x22, 0x23, 0x11, + 0x72, 0x5e, 0xeb, 0xd, 0xca, 0x31, 0xdb, 0x18, 0x9d, 0x1d, 0x3f, 0xa3, + 0xe5, 0x25, 0xdc, 0xc2, 0xd3, 0x99, 0xad, 0xaa, 0xd6, 0x89, 0xc4, 0x2d, + 0x3f, 0x54, 0x3, 0x90, 0x75, 0xfb, 0xc7, 0x73, 0xc3, 0xbc, 0x4e, 0xe7, + 0xaf, 0x9, 0x6a, 0x67, 0xec, 0xb5, 0x9c, 0x6b, 0x3a, 0xc6, 0x24, 0xa8, + 0x12, 0xd, 0xbe, 0xf8, 0xec, 0x3d, 0xe7, 0x76, 0x2b, 0xb9, 0x1e, 0xed, + 0x65, 0xf6, 0xb3, 0x7e, 0x54, 0x58, 0xbf, 0x60, 0x78, 0x74, 0x0, 0xe1, + 0x93, 0x18, 0xd, 0x64, 0xc0, 0x89, 0xfb, 0x5a, 0x1b, 0x1b, 0x30, 0x4c, + 0x9a, 0xa5, 0x6e, 0x72, 0x1f, 0x77, 0x60, 0xb8, 0x36, 0x63, 0x5a, 0x35, + 0x4, 0xd6, 0x19, 0xbb, 0x84, 0x11, 0xbd, 0x8d, 0x10, 0x8e, 0xe5, 0xee, + 0xa7, 0x7e, 0xc2, 0xf8, 0x4f, 0xf4, 0x48, 0x63, 0xd3, 0x5c, 0xdc, 0x63, + 0x71, 0x2f, 0xdf, 0xe, 0xbf, 0x6c, 0x6a, 0x54, 0x25, 0xe4, 0xea, 0xd7, + 0x6e, 0x25, 0x36, 0x84, 0xf0, 0xcf, 0x2d, 0x5f, 0x4c, 0x49, 0x1b, 0x19, + 0xdd, 0x38, 0xb, 0x69, 0xa, 0x2c, 0x51, 0xfe, 0x4, 0xf5, 0x57, 0xa7, + 0xf0, 0xd6, 0x8c, 0x54, 0x78, 0x50, 0x11, 0x88, 0xd3, 0x5c, 0xdc, 0x1a, + 0x3d, 0x6b, 0xb1, 0x3a, 0x1, 0x66, 0xf0, 0xb4, 0x11, 0x5, 0x14, 0x38, + 0x34, 0x72, 0xbb, 0xde, 0xec, 0x26, 0xdb, 0x8b, 0x4c, 0xdf, 0xa7, 0xb6, + 0x52, 0xfe, 0x30, 0x46, 0xf3, 0x10, 0x7c, 0xc6, 0xa1, 0x97, 0x13, 0xdc, + 0xd6, 0xa1, 0x20, 0x45, 0x5e, 0x47, 0x98, 0x77, 0xf6, 0x57, 0xd2, 0x81, + 0x44, 0x2b, 0x4, 0x7f, 0x19, 0x80, 0x38, 0xc6, 0xfd, 0xcf, 0xa8, 0xa0, + 0x80, 0x10, 0xfb, 0xb0, 0x8b, 0x48, 0x52, 0xf8, 0x5c, 0x24, 0x20, 0x42, + 0x50, 0xfc, 0x6c, 0x76, 0x76, 0x5, 0x3d, 0x9f, 0xd4, 0xa7, 0xa8, 0x38, + 0x1c, 0xa3, 0xd1, 0xe8, 0x3f, 0xfd, 0x4b, 0xb5, 0x7, 0x3f, 0xe7, 0x9c, + 0x4a, 0xa4, 0x7d, 0xd6, 0x7c, 0x3e, 0xfb, 0x9c, 0x3d, 0xf2, 0xa9, 0x2e, + 0x82, 0x1b, 0x51, 0xb0, 0x94, 0x3f, 0x37, 0xc8, 0x1c, 0x6c, 0xff, 0xcb, + 0xe0, 0x87, 0xd3, 0xab, 0x56, 0x41, 0xd7, 0xc1, 0xee, 0x6d, 0x9d, 0xab, + 0xd8, 0x29, 0x79, 0xec, 0xff, 0xa8, 0xaa, 0xf4, 0xd9, 0xfc, 0xa0, 0xe4, + 0xf7, 0x22, 0x79, 0xe4, 0xcf, 0x5, 0x7e, 0x59, 0x94, 0x4d, 0x2f, 0x18, + 0xeb, 0x4c, 0xab, 0x78, 0xb3, 0x58, 0x69, 0x73, 0x8e, 0x7b, 0xc1, 0xc9, + 0x7f, 0x90, 0x63, 0xe, 0x48, 0x7c, 0x40, 0x49, 0x2c, 0xb9, 0xf0, 0x50, + 0xed, 0x82, 0x15, 0x14, 0x8f, 0xac, 0xab, 0x46, 0xf2, 0x46, 0x59, 0x9c, + 0x5f, 0x7b, 0xf7, 0x42, 0xc8, 0x31, 0x90, 0xa0, 0x39, 0xe8, 0x69, 0xd2, + 0xd4, 0xe6, 0x96, 0x5e, 0xe4, 0x57, 0x32, 0xa3, 0x39, 0x7f, 0x67, 0xb, + 0xfd, 0xf1, 0x54, 0x45, 0xe1, 0xa0, 0xe, 0x69, 0xa7, 0x31, 0x2, 0xf3, + 0xd1, 0x57, 0xea, 0x2, 0x93, 0xdc, 0xb6, 0x6, 0x74, 0x3, 0xae, 0xd7, + 0x18, 0x51, 0x6c, 0xf4, 0x96, 0x16, 0x59, 0x90, 0x3a, 0xe, 0x23, 0xf4, + 0x41, 0xc4, 0x43, 0xa2, 0x22, 0xa2, 0xaa, 0xf7, 0x68, 0x72, 0x98, 0x69, + 0x95, 0xc1, 0xc8, 0xf3, 0xc6, 0xb2, 0x9d, 0xc4, 0x5e, 0xbd, 0x56, 0xd8, + 0xc5, 0x21, 0x76, 0x3f, 0x83, 0xbf, 0x4b, 0xb4, 0xd7, 0xc6, 0x67, 0xf5, + 0x49, 0x9, 0x7d, 0x99, 0xee, 0x72, 0x22, 0x6c, 0xc0, 0x6b, 0xe3, 0x3c, + 0x38, 0xb7, 0x37, 0xe2, 0x3c, 0x44, 0x5e, 0x67, 0xbd, 0xff, 0xd3, 0xfa, + 0xe3, 0x56, 0x50, 0x26, 0xc6, 0xbe, 0x2a, 0x4f, 0xba, 0x50, 0xe5, 0x43, + 0xb5, 0x4a, 0xc4, 0xe, 0xe3, 0x67, 0xa5, 0xa9, 0xf, 0x2d, 0xbc, 0x9a, + 0x34, 0xba, 0xed, 0xa1, 0x4f, 0xd9, 0xd, 0x81, 0xf6, 0x44, 0x4c, 0xa2, + 0x4a, 0x69, 0x4c, 0xe2, 0x77, 0xb3, 0x91, 0x9c, 0xa5, 0x9b, 0xe9, 0xa4, + 0xba, 0xbd, 0x84, 0xc9, 0x45, 0x60, 0xdd, 0x5d, 0x27, 0x95, 0x16, 0xa1, + 0x95, 0xfa, 0xf, 0x3c, 0x92, 0xc0, 0xee, 0xc8, 0x6b, 0x25, 0x30, 0xf2, + 0x64, 0x5f, 0x8d, 0x84, 0xd9, 0x34, 0x41, 0x62, 0xdf, 0x4e, 0x5, 0x4f, + 0x8d, 0xa8, 0x90, 0x1b, 0xe, 0xc8, 0xc7, 0xe, 0xdd, 0xd3, 0x47, 0x88, + 0x9a, 0xc5, 0xf8, 0xbf, 0x34, 0x1d, 0x84, 0xd1, 0x67, 0xd3, 0xee, 0x4e, + 0x62, 0x60, 0x66, 0x5a, 0x8f, 0x5c, 0xe4, 0x88, 0xc9, 0xd8, 0x9e, 0xb9, + 0x15, 0xd1, 0x4, 0x70, 0x62, 0x7, 0x4e, 0x4d, 0xfd, 0x25, 0x83, 0xc9, + 0xa4, 0xa7, 0x97, 0xd7, 0xf7, 0x5, 0xca, 0x14, 0x5f, 0xc1, 0x38, 0x34, + 0x4a, 0xc9, 0x7e, 0x2d, 0xdb, 0x1b, 0x4f, 0x3d, 0xab, 0xd3, 0x6a, 0x64, + 0xe9, 0xbf, 0x5a, 0x84, 0xa7, 0xc1, 0x31, 0xf5, 0x45, 0xec, 0x1e, 0x29, + 0x98, 0x1f, 0xc5, 0xab, 0x37, 0xd, 0xcc, 0xf, 0xc4, 0x56, 0x3, 0x6d, + 0xdb, 0xd1, 0x57, 0x4e, 0x9e, 0x9c, 0x64, 0x29, 0x87, 0x95, 0x8c, 0x6d, + 0x3c, 0x4e, 0x68, 0x24, 0xd6, 0x4, 0xc7, 0xed, 0xc1, 0x5f, 0x43, 0x4e, + 0x1c, 0x59, 0x1c, 0x84, 0x58, 0x97, 0xa9, 0xf3, 0x49, 0x90, 0x22, 0x6e, + 0x51, 0xae, 0x96, 0x9f, 0xb3, 0x55, 0x59, 0xf4, 0xc3, 0xfe, 0x87, 0x97, + 0xa8, 0xa6, 0xee, 0x0, 0xae, 0xf2, 0x7e, 0x28, 0xe1, 0xca, 0x83, 0xcc, + 0x1b, 0xf0, 0x56, 0xee, 0xba, 0x25, 0xf6, 0x7e, 0xf4, 0xb6, 0x2e, 0xaf, + 0xbf, 0x6f, 0x3b, 0xac, 0xf0, 0xc5, 0x8d, 0xe7, 0x4b, 0x61, 0x2c, 0x11, + 0xcd, 0x85, 0x5c, 0xe6, 0x3b, 0xbe, 0xa4, 0x3c, 0x5e, 0x15, 0x1f, 0x51, + 0x65, 0xe2, 0xcb, 0xbe, 0x34, 0x27, 0x97, 0x6, 0x7e, 0x35, 0xc8, 0x19, + 0x99, 0xe0, 0x54, 0x64, 0x12, 0x52, 0x1e, 0x97, 0x9f, 0x1, 0x1f, 0x96, + 0x35, 0xdc, 0x56, 0xc6, 0x95, 0xa3, 0x54, 0x1f, 0xc8, 0x20, 0x1e, 0xcc, + 0xe9, 0xf8, 0x7b, 0xf, 0x63, 0x18, 0xd2, 0xfd, 0x64, 0x84, 0x0, 0xdf, + 0x13, 0x33, 0x27, 0x47, 0x6f, 0xb9, 0x92, 0xe, 0x1e, 0xec, 0x25, 0xe5, + 0x77, 0x36, 0xd6, 0x70, 0x91, 0x2e, 0x2a, 0xd7, 0x5c, 0x38, 0xfa, 0x53, + 0xc, 0x1e, 0xae, 0xef, 0x54, 0xbd, 0x91, 0x76, 0x99, 0x2c, 0xbb, 0xa2, + 0xdc, 0xa8, 0x2e, 0xc7, 0x25, 0x4b, 0x66, 0xe3, 0xa5, 0x54, 0x56, 0xa8, + 0x53, 0xc2, 0xe, 0xe8, 0x0, 0xaf, 0xcf, 0x8b, 0xc5, 0x77, 0x74, 0x31, + 0x75, 0xe1, 0x22, 0x24, 0x31, 0xb2, 0x69, 0xec, 0x3, 0x69, 0xa3, 0xf7, + 0x14, 0x69, 0x2e, 0x3d, 0x75, 0x69, 0x9c, 0xaa, 0x52, 0x1, 0xb1, 0x91, + 0x16, 0x9b, 0x95, 0xd4, 0x11, 0x6d, 0x73, 0x1e, 0xb1, 0x5c, 0x5f, 0x9b, + 0xb7, 0x42, 0xf2, 0x3a, 0xc5, 0xc8, 0xad, 0xa7, 0xd, 0x5f, 0x65, 0xe7, + 0x42, 0x86, 0xd, 0x5b, 0x8a, 0x40, 0x15, 0x7a, 0x5c, 0xa1, 0x59, 0x7d, + 0xe7, 0xf6, 0xff, 0xa2, 0x33, 0xb1, 0x6d, 0x97, 0x4b, 0x22, 0xb6, 0x79, + 0xf0, 0xd1, 0x5a, 0x25, 0x6, 0x9c, 0x72, 0xf, 0x95, 0xc6, 0x2e, 0x29, + 0xc8, 0x5, 0x9d, 0x79, 0x1e, 0xc7, 0x10, 0x4a, 0x96, 0xe5, 0xa9, 0x1, + 0x81, 0xc7, 0x87, 0x5a, 0x62, 0xed, 0x4f, 0xa9, 0x24, 0xe6, 0x76, 0x85, + 0x95, 0xf9, 0xf1, 0x73, 0x30, 0xad, 0xd4, 0xbc, 0xeb, 0x91, 0x6a, 0xcc, + 0xfc, 0xb6, 0x18, 0xc2, 0xcb, 0x20, 0x32, 0x7f, 0xd0, 0x4d, 0x55, 0x1c, + 0x91, 0xd5, 0xd4, 0x2, 0x3a, 0xab, 0xcd, 0x61, 0x7, 0x92, 0x31, 0x4e, + 0xc6, 0xdb, 0xed, 0x5, 0x76, 0x2d, 0x2, 0x9a, 0xd8, 0xd2, 0x54, 0x40, + 0x98, 0x79, 0xd2, 0x95, 0xfd, 0xda, 0x1d, 0x8e, 0xf4, 0xc8, 0xd1, 0xe0, + 0x24, 0x8b, 0x7d, 0x5a, 0x7b, 0xfa, 0xa2, 0xc7, 0xe0, 0x14, 0xbc, 0x9, + 0x7e, 0xe8, 0x19, 0x16, 0x93, 0x3a, 0xc6, 0x26, 0x9d, 0x3d, 0x6e, 0xec, + 0x4a, 0x9a, 0x61, 0xc9, 0xc, 0x74, 0x93, 0xd1, 0x41, 0x97, 0x17, 0x88, + 0x40, 0x8e, 0x60, 0x76, 0xdd, 0xb0, 0x46, 0x3e, 0x25, 0xad, 0xa4, 0x5f, + 0x8b, 0x26, 0x81, 0x92, 0x51, 0x77, 0xe, 0x85, 0xa6, 0xb, 0xac, 0x8b, + 0x8c, 0x30, 0x24, 0x88, 0xf1, 0xc5, 0xf2, 0x3a, 0x9d, 0x49, 0x54, 0xe8, + 0x52, 0xe1, 0x20, 0xc8, 0x41, 0xee, 0x46, 0xee, 0x6, 0x40, 0x74, 0x3, + 0x14, 0xe7, 0x96, 0xe4, 0x44, 0xcf, 0xa2, 0xae, 0xf8, 0x9b, 0xcd, 0x5f, + 0x48, 0xc8, 0xb4, 0x27, 0x85, 0x9d, 0x51, 0x8f, 0x73, 0x64, 0x56, 0x9a, + 0xef, 0x87, 0xbf, 0x94, 0x8a, 0x54, 0x1b, 0xd1, 0xc7, 0x7a, 0xd5, 0x2c, + 0xbd, 0xba, 0x3d, 0x1, 0xb4, 0xfa, 0x82, 0x84, 0x88, 0x4c, 0x0, 0x29, + 0x37, 0x4e, 0xc0, 0x23, 0xf2, 0x75, 0x27, 0x55, 0xd5, 0xa8, 0x83, 0xea, + 0x7a, 0xab, 0xd5, 0x5f, 0x79, 0xa6, 0x4f, 0xf2, 0x9b, 0xc0, 0x32, 0x94, + 0xcb, 0x8, 0xa9, 0x92, 0xf7, 0x36, 0xef, 0x9, 0xb9, 0x63, 0x6a, 0xe0, + 0x75, 0x3, 0x26, 0x53, 0xf, 0xda, 0x36, 0x10, 0x29, 0x4c, 0xaf, 0xa9, + 0x75, 0xb0, 0xc0, 0xd7, 0xef, 0xd5, 0xf9, 0x2b, 0xb9, 0x5a, 0xe7, 0xfb, + 0xc1, 0xc7, 0x34, 0x7b, 0x33, 0x55, 0x8, 0xc4, 0x19, 0xf8, 0x7c, 0xa1, + 0x61, 0x0, 0x43, 0x68, 0xf0, 0xf, 0xbc, 0x41, 0xce, 0x78, 0xc9, 0x61, + 0xbb, 0xa3, 0x8e, 0xc1, 0xac, 0x7, 0x8b, 0x80, 0xf9, 0x34, 0x14, 0xe8, + 0xee, 0x2e, 0xb6, 0xb2, 0x82, 0x74, 0x78, 0x96, 0xf0, 0xf2, 0xd5, 0x4f, + 0xaf, 0x16, 0x5f, 0x8c, 0x50, 0xe9, 0xb2, 0x92, 0xbc, 0xe5, 0x68, 0x26, + 0x11, 0xf9, 0xbc, 0xa5, 0xd8, 0xe1, 0xd4, 0xad, 0xc, 0x0, 0xde, 0x3a, + 0x57, 0xfe, 0x4b, 0x63, 0x9a, 0x5b, 0x32, 0xd0, 0x52, 0xc3, 0x88, 0x2b, + 0x26, 0xc2, 0x73, 0x4, 0x1a, 0xf5, 0x92, 0x54, 0x42, 0x35, 0x8e, 0x11, + 0x60, 0xb0, 0x10, 0x6c, 0xb4, 0xe2, 0x3a, 0xdc, 0xec, 0x13, 0xa2, 0x44, + 0xac, 0x95, 0xe5, 0x2c, 0xed, 0x15, 0xe3, 0xdd, 0x52, 0x8, 0x78, 0x21, + 0x76, 0xfa, 0xab, 0x8d, 0x38, 0x28, 0xda, 0x28, 0x2b, 0x55, 0xe2, 0x95, + 0x51, 0xeb, 0x51, 0x20, 0xa3, 0x7e, 0xe9, 0x5a, 0x26, 0xd9, 0x5, 0x7d, + 0x76, 0x55, 0xb6, 0xd8, 0x5b, 0x37, 0x8e, 0xda, 0x2f, 0x71, 0x12, 0xc9, + 0x9b, 0xdf, 0x3d, 0x6e, 0x8c, 0xf0, 0xe4, 0xb1, 0x9, 0xe4, 0x5, 0x54, + 0x56, 0x23, 0xf3, 0x7e, 0x6, 0x23, 0xc6, 0xf4, 0x7f, 0x7f, 0x7f, 0xe7, + 0x7c, 0x23, 0x9c, 0xc4, 0x55, 0x38, 0x3b, 0x59, 0xe3, 0x37, 0x9f, 0xfc, + 0x6e, 0x89, 0x6d, 0x8d, 0x33, 0xfc, 0x15, 0x68, 0xda, 0x56, 0x8e, 0x14, + 0x57, 0x3e, 0x8b, 0x7, 0xa3, 0xce, 0xe2, 0x8e, 0x43, 0xef, 0x94, 0xaf, + 0x2d, 0x10, 0xa3, 0x45, 0xb2, 0x68, 0x8e, 0xd7, 0xf4, 0xe0, 0x2c, 0x62, + 0x7d, 0x98, 0x7c, 0xe3, 0xc9, 0x8a, 0x99, 0x7a, 0xdb, 0x63, 0xe, 0xb1, + 0x6f, 0x81, 0xfd, 0x60, 0x8d, 0xaa, 0x9e, 0x53, 0x7a, 0xa3, 0x31, 0x7f, + 0x1c, 0xbf, 0x0, 0xe9, 0x4c, 0xd, 0x2b, 0xa5, 0x49, 0x23, 0xff, 0x20, + 0x62, 0xcf, 0xc9, 0x4e, 0x2e, 0xd3, 0x26, 0xaf, 0xdf, 0xe7, 0xef, 0xbf, + 0xad, 0x3f, 0xa7, 0xb, 0x47, 0x8, 0xc9, 0x59, 0xb1, 0x59, 0xfa, 0xc6, + 0x39, 0xb9, 0x27, 0xdf, 0x7a, 0xbb, 0x6c, 0xde, 0x9d, 0x81, 0x9a, 0xee, + 0x4a, 0x9e, 0x8a, 0xc6, 0xd4, 0x48, 0xe9, 0xc9, 0x94, 0x57, 0x6e, 0x84, + 0x46, 0x69, 0x62, 0x9f, 0x89, 0x94, 0x38, 0x4a, 0xc1, 0xa9, 0x5a, 0x22, + 0x91, 0x3e, 0xcf, 0x1d, 0x83, 0x7a, 0xe6, 0x7c, 0x8d, 0x74, 0x7, 0x7f, + 0xf8, 0x44, 0xb5, 0x3f, 0xda, 0x65, 0xe8, 0x2b, 0x9b, 0x1, 0x51, 0x1b, + 0x89, 0xb0, 0x5c, 0x27, 0x94, 0x1, 0x43, 0x1d, 0x2c, 0x19, 0xcd, 0xda, + 0xdd, 0x9d, 0x20, 0xe3, 0x24, 0x3, 0x88, 0x83, 0x5, 0xd6, 0x83, 0xee, + 0x3d, 0x3c, 0x77, 0x14, 0xfd, 0x82, 0x3b, 0x0, 0xbd, 0xb5, 0x0, 0x56, + 0x59, 0x6b, 0xfb, 0xeb, 0x69, 0xbc, 0xe1, 0xe2, 0x57, 0x53, 0x9f, 0xf6, + 0xdc, 0x1a, 0x5a, 0x96, 0xea, 0xc6, 0x61, 0x1b, 0xd9, 0x15, 0x14, 0xce, + 0xd2, 0x3c, 0x59, 0x9a, 0x78, 0x94, 0x5a, 0xe7, 0xd8, 0xea, 0x87, 0xee, + 0xcd, 0x9d, 0x54, 0xd6, 0xce, 0x9a, 0x91, 0xab, 0x49, 0x61, 0x9, 0xa4, + 0x5b, 0x9f, 0x78, 0x75, 0xdc, 0x45, 0x7a, 0x34, 0xd1, 0xfb, 0x5c, 0xc0, + 0x95, 0xe4, 0x49, 0x4f, 0x8a, 0xda, 0xcf, 0x4a, 0x27, 0x3, 0x1b, 0x59, + 0xcf, 0x23, 0x19, 0xcc, 0x75, 0xdf, 0x26, 0xa6, 0x3c, 0xfa, 0x7f, 0x6d, + 0x90, 0x8e, 0xcf, 0xc, 0x5e, 0x94, 0x38, 0x1e, 0xe4, 0x82, 0x78, 0xd1, + 0x4c, 0xcc, 0xac, 0xe8, 0x4d, 0x87, 0xf2, 0x95, 0x8, 0xa3, 0xd6, 0xf4, + 0x5a, 0x46, 0xde, 0x0, 0x4f, 0x86, 0x2f, 0xf4, 0x15, 0x2d, 0xe7, 0x90, + 0x11, 0x40, 0xb6, 0xa7, 0x5c, 0x4f, 0x3, 0x28, 0x4a, 0x8b, 0x1d, 0x47, + 0xfb, 0x49, 0x77, 0x65, 0x83, 0x1e, 0x18, 0xfd, 0xe7, 0x5e, 0x5c, 0x3a, + 0x21, 0x7f, 0xff, 0xf8, 0x2a, 0x5e, 0x6b, 0xba, 0x19, 0xf2, 0x6e, 0x2b, + 0x17, 0x80, 0xa7, 0x5b, 0xf7, 0xb2, 0xa3, 0xc3, 0x37, 0x2b, 0xd9, 0x29, + 0x25, 0x9c, 0x98, 0x6e, 0x5c, 0xed, 0x1d, 0x8f, 0xf4, 0xcb, 0xb6, 0x43, + 0x80, 0xf8, 0x4d, 0x7d, 0xe8, 0x94, 0xd1, 0x44, 0x2f, 0x7e, 0xb6, 0x80, + 0xc0, 0x1, 0xc5, 0xc6, 0xb, 0xfc, 0x1, 0xc7, 0x11, 0x13, 0x90, 0xcb, + 0x29, 0x64, 0xbf, 0xfa, 0x84, 0xde, 0x50, 0x91, 0xfa, 0x8d, 0x87, 0x8c, + 0xc, 0x19, 0x4b, 0x83, 0x4e, 0x8a, 0x83, 0xb8, 0xbc, 0x79, 0x5f, 0x8d, + 0xe3, 0x19, 0x9a, 0xae, 0xdd, 0xe6, 0x8f, 0xda, 0xb2, 0x11, 0x63, 0xe9, + 0x44, 0x4c, 0x20, 0x11, 0x1d, 0x27, 0x63, 0x10, 0xf9, 0x70, 0x1d, 0x42, + 0xf, 0x3f, 0x8b, 0x30, 0x92, 0x66, 0x7c, 0x20, 0x9e, 0xfc, 0xf6, 0x87, + 0x6b, 0x3b, 0xc4, 0x8f, 0x8, 0xdf, 0x74, 0x92, 0xb8, 0x7, 0xc4, 0x47, + 0x6b, 0xe9, 0xc0, 0x93, 0xc7, 0x27, 0x7f, 0xc4, 0x42, 0xaf, 0xde, 0x10, + 0xfb, 0x8d, 0x7b, 0x3f, 0xba, 0x5, 0x71, 0x43, 0xc3, 0xa7, 0xc1, 0x65, + 0x35, 0x52, 0xba, 0xb7, 0xe3, 0x4a, 0x9e, 0x7, 0xb4, 0x95, 0x74, 0x82, + 0x60, 0x9f, 0xbc, 0x84, 0xf4, 0xa4, 0x82, 0x37, 0xcf, 0x12, 0x44, 0x15, + 0xed, 0x68, 0x1f, 0x6b, 0x4c, 0xbc, 0xe8, 0xd8, 0x2e, 0x9e, 0x81, 0x87, + 0x4a, 0x40, 0xf2, 0x1e, 0xd0, 0x60, 0xee, 0xeb, 0x5e, 0x4d, 0x44, 0xc8, + 0x9, 0x11, 0x77, 0x5d, 0xa5, 0x1b, 0xf3, 0x1a, 0x31, 0xbe, 0xba, 0x7d, + 0x33, 0x97, 0x36, 0xcd, 0x91, 0xea, 0x1c, 0xc7, 0xbf, 0x1d, 0xd0, 0x3e, + 0x24, 0x7c, 0x10, 0x6c, 0xbb, 0x5c, 0xfd, 0xbe, 0xde, 0xdb, 0x48, 0x1a, + 0xbf, 0x91, 0x1b, 0xe7, 0x7e, 0xc2, 0xb, 0x7c, 0x36, 0x13, 0xb1, 0x18, + 0xad, 0x60, 0xf2, 0x1d, 0x2b, 0xb1, 0x88, 0xb1, 0x72, 0x7a, 0x7a, 0xa0, + 0xe6, 0x38, 0xde, 0xa4, 0x86, 0xfc, 0x43, 0xc4, 0xa1, 0xa6, 0xf5, 0x2f, + 0x9a, 0x9e, 0x5, 0xf1, 0xef, 0xaa, 0x42, 0x40, 0xe2, 0xba, 0x81, 0x3e, + 0xa, 0x5f, 0xa0, 0xa6, 0x37, 0x5a, 0xc8, 0x4b, 0x7, 0x60, 0x5f, 0xb6, + 0xf8, 0x70, 0xd6, 0x5c, 0x85, 0x97, 0x1a, 0x66, 0x7c, 0xae, 0x9d, 0xd7, + 0xb4, 0xfa, 0x94, 0x3a, 0x2f, 0x1e, 0x1f, 0xee, 0x2b, 0x45, 0xa6, 0xc6, + 0xd7, 0x9b, 0xec, 0x7b, 0x3e, 0xf8, 0xc, 0x4f, 0x6a, 0xad, 0x6e, 0xc7, + 0x9d, 0xee, 0xc, 0x29, 0x9, 0xfc, 0x86, 0x4b, 0xe4, 0x8, 0x44, 0x2a, + 0x6f, 0xbc, 0xea, 0x9f, 0xcf, 0x58, 0xb1, 0x36, 0x2f, 0xce, 0xb4, 0x93, + 0xae, 0x67, 0xca, 0xe5, 0x3b, 0xed, 0xe0, 0x6d, 0xaf, 0xc7, 0x9, 0xc8, + 0x42, 0x3d, 0x9a, 0x33, 0xc5, 0x80, 0x72, 0x1, 0xd3, 0x67, 0xbf, 0x2f, + 0x9c, 0xe1, 0xb9, 0x4d, 0x0, 0x58, 0x5e, 0x94, 0x9a, 0xda, 0x72, 0xc5, + 0x17, 0x81, 0xd8, 0xb6, 0xcd, 0xa8, 0xf6, 0xed, 0x91, 0x43, 0xa2, 0x82, + 0x80, 0x7d, 0xa, 0x75, 0xe4, 0xef, 0x2, 0xb9, 0x1, 0x5a, 0x6a, 0xd4, + 0x47, 0x70, 0x2c, 0x66, 0x2c, 0x39, 0xcb, 0xad, 0xd5, 0x89, 0x89, 0x4a, + 0x39, 0x59, 0x7d, 0xd6, 0x6a, 0x27, 0x2c, 0x7a, 0xcc, 0xc9, 0x85, 0xe2, + 0xc5, 0x50, 0xf7, 0x13, 0xfc, 0x41, 0x1a, 0xaa, 0x24, 0x66, 0x88, 0x54, + 0x99, 0xe1, 0x72, 0x2a, 0xd4, 0x42, 0x67, 0x4d, 0xa2, 0x81, 0x27, 0xce, + 0xd, 0x7e, 0x7f, 0x81, 0x44, 0xaa, 0x92, 0x69, 0x75, 0x3c, 0xb, 0x60, + 0xa5, 0xa3, 0xd0, 0x45, 0x56, 0x17, 0x58, 0xce, 0xdd, 0x9f, 0x4e, 0x32, + 0x25, 0x98, 0x4b, 0xfb, 0xd0, 0xf0, 0x4b, 0x24, 0x1a, 0xb2, 0xec, 0xca, + 0x16, 0x74, 0xdf, 0xf8, 0x4, 0x27, 0x64, 0xf3, 0x85, 0x9, 0x11, 0x2a, + 0xf6, 0x43, 0x40, 0x4c, 0x3a, 0xe1, 0x4d, 0xdb, 0x2, 0xd1, 0xb7, 0x29, + 0x2f, 0x9e, 0x38, 0x4f, 0xb0, 0x6, 0xb8, 0xe5, 0xc3, 0x18, 0x54, 0xb9, + 0x49, 0xcb, 0x4a, 0xc9, 0x47, 0xba, 0x3a, 0x67, 0x1, 0x10, 0x76, 0x1a, + 0xe8, 0xa7, 0xd6, 0x9b, 0x78, 0x9d, 0xf5, 0xb2, 0xf8, 0xb5, 0x24, 0x45, + 0xf, 0x92, 0x64, 0x19, 0xe7, 0x78, 0x1d, 0xdb, 0x43, 0x2a, 0x27, 0x6a, + 0x66, 0xdf, 0xc1, 0xc2, 0x59, 0xf8, 0x4f, 0x76, 0xd3, 0x87, 0x75, 0x46, + 0x9d, 0xd9, 0xd8, 0x4d, 0xd3, 0xcf, 0x92, 0x7d, 0x4f, 0x4e, 0x90, 0xc9, + 0x6c, 0x7a, 0x42, 0x71, 0x99, 0xc1, 0x2a, 0xb0, 0x31, 0x80, 0x33, 0x30, + 0x78, 0x5c, 0xac, 0x12, 0xa3, 0x8b, 0x7, 0x4a, 0x36, 0x1c, 0xf9, 0xcc, + 0xc, 0xb4, 0xec, 0x34, 0x68, 0xa6, 0x21, 0x81, 0xe4, 0x65, 0x2f, 0x2c, + 0x18, 0x20, 0x55, 0x4, 0xad, 0xf4, 0x21, 0x43, 0x3b, 0xb0, 0xfc, 0xe3, + 0xea, 0x39, 0x4f, 0x51, 0x77, 0x7e, 0xa8, 0xd, 0x8b, 0xb9, 0xef, 0x9c, + 0x2d, 0xfd, 0x4b, 0x2a, 0xac, 0x34, 0x4a, 0x60, 0xb7, 0xa6, 0xa5, 0x8c, + 0xd8, 0x2d, 0x45, 0x1b, 0x0, 0xe7, 0xdd, 0x2d, 0xeb, 0x9d, 0x7e, 0x4c, + 0x49, 0xa8, 0xe6, 0x8d, 0x48, 0xde, 0x8b, 0x98, 0xff, 0x4f, 0xd5, 0x16, + 0x8, 0x6, 0x36, 0x7a, 0xe1, 0x7d, 0x2a, 0x85, 0xc8, 0xb1, 0x6f, 0x3e, + 0xb2, 0x10, 0x90, 0x91, 0xdc, 0x56, 0xb, 0xbf, 0xe5, 0x46, 0xa6, 0x56, + 0x4e, 0x9c, 0x2d, 0xdd, 0x34, 0x0, 0xe1, 0xe9, 0xf7, 0xaf, 0x90, 0x63, + 0x32, 0x74, 0x35, 0xfd, 0xf5, 0x28, 0x73, 0x81, 0x32, 0x50, 0x42, 0x11, + 0xbe, 0x33, 0x77, 0x6a, 0xea, 0x29, 0xdf, 0x98, 0x6e, 0xeb, 0xc6, 0x2f, + 0x5a, 0x5a, 0x93, 0xd9, 0xdf, 0xc8, 0x41, 0x33, 0x3c, 0xae, 0xc7, 0x2f, + 0x35, 0x1c, 0xce, 0x5b, 0xa8, 0x68, 0x3e, 0x43, 0x73, 0x62, 0x30, 0xd3, + 0xa3, 0xfc, 0x61, 0x2c, 0x95, 0xe0, 0xdb, 0xf, 0x35, 0x96, 0x1c, 0x28, + 0xb9, 0x6e, 0xbb, 0xda, 0x96, 0xf2, 0x92, 0x5a, 0x7, 0xbf, 0x4c, 0xd1, + 0xe1, 0x77, 0x14, 0x90, 0xb6, 0x48, 0x2b, 0xc1, 0x3e, 0xe4, 0x9a, 0xfe, + 0x3c, 0xbc, 0xf4, 0xf1, 0x1f, 0x54, 0x17, 0xdd, 0x85, 0xf5, 0xc3, 0x7b, + 0xda, 0xca, 0x9e, 0xc8, 0x91, 0xe9, 0xbd, 0xc7, 0xa3, 0x51, 0x4e, 0x3d, + 0x55, 0xd9, 0xf7, 0x79, 0x1b, 0xbf, 0x69, 0xa3, 0x58, 0x4d, 0x96, 0xd8, + 0x57, 0x3a, 0x49, 0x71, 0x38, 0xe, 0xec, 0x68, 0x73, 0x8f, 0x2b, 0xbc, + 0xb9, 0x53, 0x43, 0x11, 0xc8, 0xff, 0x92, 0x81, 0x7d, 0xe6, 0x29, 0xdf, + 0x7a, 0xb0, 0xd3, 0x7f, 0x31, 0xa, 0xef, 0xce, 0xac, 0xdd, 0x57, 0xbb, + 0x3a, 0x0, 0x87, 0x57, 0x7, 0xce, 0x84, 0xa7, 0x5, 0x76, 0x10, 0xe0, + 0x69, 0xf3, 0xec, 0xa5, 0x12, 0x91, 0x97, 0x5d, 0x83, 0xd5, 0x35, 0xba, + 0x30, 0xe1, 0xf1, 0x1, 0x49, 0xe1, 0x86, 0x50, 0xd4, 0x52, 0x32, 0x73, + 0xc7, 0xab, 0x1a, 0xe6, 0xb2, 0xab, 0xff, 0x77, 0xc4, 0x14, 0x20, 0xad, + 0xd1, 0xbf, 0x69, 0xc6, 0x11, 0x4c, 0x24, 0x3e, 0x1d, 0xc9, 0x84, 0x9d, + 0xe2, 0xa6, 0xc8, 0x4d, 0xed, 0xf5, 0x84, 0x74, 0xae, 0x68, 0x17, 0x70, + 0x59, 0xe, 0xeb, 0xe2, 0xda, 0x83, 0x21, 0xfd, 0x81, 0x66, 0x21, 0x61, + 0x47, 0xb2, 0xb7, 0xa5, 0x9a, 0x95, 0xf8, 0x91, 0x51, 0x5c, 0xf8, 0x63, + 0x52, 0xe2, 0x5a, 0x5e, 0x58, 0xd3, 0xda, 0x74, 0x68, 0xba, 0xfe, 0xda, + 0xe7, 0x96, 0xd8, 0x61, 0x5c, 0xf6, 0x7c, 0xd, 0x1d, 0xb1, 0x80, 0x1b, + 0x7f, 0x5e, 0x85, 0x4a, 0xfe, 0xe, 0x62, 0x65, 0x77, 0x84, 0xe, 0x4e, + 0x59, 0xfc, 0x7d, 0xc2, 0xe4, 0x7d, 0x43, 0x27, 0x6d, 0xc7, 0x4, 0xb8, + 0x47, 0xe, 0x8c, 0x25, 0xec, 0x25, 0x9d, 0x88, 0x16, 0x73, 0x7d, 0x6f, + 0x46, 0x24, 0xd5, 0x16, 0x14, 0xde, 0x54, 0x94, 0xed, 0x1c, 0x9e, 0xe3, + 0x6d, 0xb3, 0xe1, 0x57, 0xab, 0xab, 0x87, 0xbb, 0xf7, 0x6c, 0x87, 0xcf, + 0x94, 0xde, 0x8d, 0x23, 0xe2, 0x9d, 0xbb, 0x93, 0xf8, 0x69, 0x43, 0x74, + 0x22, 0x31, 0x85, 0x8e, 0x6a, 0x91, 0x9, 0x9e, 0xac, 0xc9, 0xdb, 0xe6, + 0xec, 0x39, 0xe3, 0x86, 0x42, 0xd3, 0xfc, 0xbe, 0x57, 0xdb, 0x7c, 0xa7, + 0x9b, 0x5, 0xed, 0x8e, 0x26, 0xde, 0x5a, 0xc4, 0xe2, 0x4b, 0xa2, 0x13, + 0xd8, 0x59, 0x9d, 0x67, 0x3, 0x6a, 0x93, 0x68, 0x41, 0x34, 0x5, 0xfd, + 0x1e, 0x65, 0xdf, 0xac, 0xbe, 0xa6, 0x17, 0xf1, 0x56, 0x92, 0x7a, 0xfe, + 0x80, 0xbd, 0xd9, 0xfa, 0xb6, 0x37, 0x2d, 0x56, 0x23, 0xc9, 0x5d, 0x87, + 0x1c, 0xa9, 0x7, 0xbc, 0xf3, 0x3c, 0x28, 0xdc, 0x4d, 0x85, 0x29, 0x72, + 0x64, 0x7, 0x49, 0x6f, 0x96, 0xae, 0xb4, 0x55, 0xc8, 0x18, 0xfe, 0xb, + 0x36, 0x10, 0xc8, 0xbd, 0x5b, 0x66, 0xd, 0xef, 0xf5, 0x22, 0xe9, 0x5e, + 0x39, 0x2e, 0xb5, 0x2a, 0x36, 0x2a, 0x53, 0x8e, 0xda, 0x7c, 0x3d, 0xbb, + 0xc, 0x7d, 0x27, 0x5a, 0x21, 0x7a, 0xf8, 0xb3, 0xd2, 0x26, 0x1f, 0x0, + 0xe5, 0x13, 0xee, 0x70, 0x56, 0x6d, 0x85, 0x30, 0x24, 0x10, 0xe7, 0x49, + 0x11, 0x5c, 0xec, 0x3a, 0x5, 0x74, 0xc7, 0xe7, 0x51, 0x93, 0x5, 0x3a, + 0x7c, 0x96, 0x43, 0xe7, 0xd4, 0x5d, 0x32, 0x62, 0xf7, 0xff, 0x3a, 0xc7, + 0x72, 0xba, 0x91, 0x59, 0x86, 0xa, 0x7d, 0x84, 0xd4, 0xd4, 0x0, 0x1d, + 0xe3, 0xb9, 0x1a, 0xc5, 0xa2, 0xed, 0x67, 0xc2, 0x4f, 0xe3, 0xeb, 0xd0, + 0xae, 0x1a, 0x49, 0x55, 0x50, 0x57, 0xf0, 0x78, 0xc8, 0xbc, 0x20, 0x8, + 0x6a, 0x4, 0x1c, 0x21, 0xa1, 0xf, 0x5b, 0x9d, 0xad, 0xc1, 0x22, 0x26, + 0xe0, 0x50, 0x8, 0x1f, 0xfe, 0xe5, 0x8c, 0x9e, 0xf7, 0xd9, 0x3d, 0x92, + 0xed, 0xb3, 0x7d, 0x7e, 0xa6, 0xac, 0x3a, 0x57, 0xaa, 0x4c, 0xb3, 0xb, + 0xc0, 0x86, 0xd2, 0x9b, 0x2e, 0xbe, 0xbe, 0xfd, 0xc2, 0xc2, 0xd6, 0xe7, + 0xec, 0x53, 0x4, 0xe9, 0x21, 0x81, 0x1f, 0x37, 0xe4, 0xbe, 0xa9, 0x92, + 0x72, 0x7d, 0x9f, 0x9a, 0xe8, 0x80, 0x2d, 0xe5, 0x6f, 0xbb, 0x21, 0xbd, + 0x7d, 0xbe, 0xee, 0xac, 0x11, 0x3c, 0x7b, 0x15, 0x16, 0x27, 0xa7, 0x13, + 0x42, 0x40, 0xa3, 0x73, 0xf7, 0x3b, 0xd9, 0xf2, 0xc9, 0x69, 0x5f, 0xed, + 0xbf, 0x2e, 0xd6, 0x4e, 0xe5, 0x17, 0x95, 0x1c, 0xdd, 0x81, 0xae, 0x64, + 0x6a, 0x2c, 0x15, 0x6f, 0xe4, 0x37, 0x65, 0x26, 0xd6, 0xd0, 0x86, 0x48, + 0x4d, 0x3d, 0xa1, 0x2e, 0x9e, 0xd4, 0xd4, 0x8d, 0xd2, 0x33, 0x6c, 0x8b, + 0x1d, 0x50, 0x3e, 0x1e, 0xe0, 0xad, 0x9a, 0xe7, 0x45, 0x17, 0xa8, 0xbe, + 0x52, 0x13, 0xec, 0x5d, 0x8d, 0x10, 0x85, 0x1a, 0xf7, 0xbc, 0x98, 0xe8, + 0x57, 0xbd, 0x75, 0x1d, 0x7a, 0xb9, 0x7f, 0xf1, 0xa1, 0x83, 0x8f, 0x53, + 0x5f, 0xc7, 0x8, 0x31, 0x86, 0xb3, 0x33, 0x73, 0xa1, 0x6a, 0xce, 0x88, + 0x8b, 0x5d, 0xe4, 0x3f, 0x90, 0x1b, 0x4e, 0xb, 0x51, 0x2f, 0xb3, 0x4b, + 0x60, 0x9f, 0xf6, 0xc7, 0x90, 0xfb, 0x4c, 0x38, 0xd6, 0xaa, 0xc0, 0x78, + 0x52, 0x9a, 0x85, 0xf0, 0x1, 0xeb, 0xd0, 0x4c, 0xc8, 0x72, 0x39, 0x75, + 0x22, 0xae, 0xd1, 0x62, 0x9d, 0x4f, 0x4e, 0xf3, 0xdd, 0x1b, 0x89, 0x9f, + 0x1e, 0x4f, 0x8a, 0x45, 0xd6, 0x4e, 0x15, 0xef, 0xf2, 0x6b, 0x32, 0x15, + 0x5b, 0xf8, 0x94, 0xbb, 0x1, 0x25, 0xd2, 0xf1, 0x77, 0x7a, 0x9b, 0x73, + 0xc4, 0xe4, 0x2d, 0x3f, +}; +const uint8_t kAltGameImages2xD[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, + 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, + 0x96, 0xf6, 0x93, 0xd, 0x9d, 0xce, 0xd2, 0xdd, 0x5e, 0x30, 0xaf, 0x79, + 0x5e, 0x2d, 0x5b, 0x8c, 0xac, 0x2, 0x2a, 0x7e, 0xbb, 0x7b, 0xb7, 0xb6, + 0xd6, 0x1d, 0xf0, 0x24, 0xd, 0x14, 0xd0, 0x5a, 0x22, 0xea, 0xda, 0x95, + 0x3a, 0xd1, 0x12, 0x93, 0xd3, 0xb2, 0xc8, 0xbd, 0x37, 0xbf, 0xc3, 0xfa, + 0x2d, 0x7c, 0x3, 0x7d, 0xab, 0xdc, 0xf6, 0x40, 0x5e, 0xad, 0x77, 0xa, + 0x21, 0xe3, 0xc0, 0xec, 0x42, 0x3b, 0x2b, 0xf3, 0xa6, 0x7d, 0x59, 0x5b, + 0xe8, 0xcf, 0x5, 0x5c, 0x75, 0xb5, 0x6f, 0x10, 0x7a, 0xa3, 0xb8, 0x71, + 0xaa, 0x39, 0xe0, 0x13, 0x5e, 0xa2, 0x7, 0xa5, 0x85, 0xd4, 0x4c, 0xb6, + 0x13, 0x94, 0xe0, 0x62, 0xc0, 0xb2, 0xa4, 0xbe, 0x96, 0xe5, 0x3, 0xf2, + 0xb5, 0xd7, 0x93, 0x69, 0xb5, 0x85, 0x4a, 0x84, 0x92, 0xc7, 0x45, 0xf5, + 0xec, 0x5b, 0x91, 0x6a, 0xf7, 0x64, 0xf7, 0x4, 0x70, 0x88, 0x5c, 0xca, + 0xf, 0xa1, 0x91, 0x12, 0x6d, 0x7a, 0xe9, 0x4b, 0xc, 0x7c, 0x1b, 0x1b, + 0x5e, 0xba, 0x13, 0xd6, 0x88, 0x9b, 0xc1, 0x19, 0x6a, 0x30, 0xa2, 0xc2, + 0x3a, 0x1e, 0x21, 0x5b, 0xc3, 0x2, 0x3f, 0xbb, 0xf6, 0x1c, 0x56, 0x60, + 0xf9, 0xb7, 0xad, 0xaa, 0x7, 0x62, 0x37, 0xbb, 0xcc, 0xd5, 0x1d, 0xeb, + 0x92, 0x12, 0x37, 0x75, 0xcb, 0x4f, 0xeb, 0x44, 0x7a, 0x3c, 0xd4, 0xc5, + 0x3e, 0x2f, 0x73, 0x9b, 0x50, 0x12, 0x8d, 0xa7, 0x7f, 0xe6, 0xe6, 0xc0, + 0xe, 0x47, 0x39, 0x60, 0x3a, 0x9b, 0x26, 0x93, 0x4d, 0xa3, 0xef, 0xc9, + 0x8a, 0xa7, 0x69, 0xfb, 0x8f, 0x68, 0x3a, 0x93, 0x6a, 0x44, 0x28, 0x33, + 0x15, 0xdd, 0xcb, 0x0, 0xe8, 0xcd, 0x43, 0xeb, 0xd0, 0x6b, 0xeb, 0x2b, + 0x10, 0x9a, 0x9f, 0x7a, 0x40, 0xf5, 0x62, 0xa3, 0x78, 0xb2, 0xfa, 0x29, + 0xcb, 0x21, 0xec, 0xcd, 0x4c, 0xd6, 0xd9, 0x75, 0xc0, 0xb8, 0x53, 0xa9, + 0x5f, 0xc2, 0x25, 0x1c, 0x29, 0xed, 0x9, 0x25, 0xf, 0xf7, 0xd5, 0xc1, + 0x4d, 0xd9, 0x97, 0x23, 0x38, 0xda, 0x78, 0x1c, 0x93, 0x6f, 0xca, 0x3c, + 0xd0, 0xa6, 0xbd, 0x17, 0xa6, 0xc4, 0xd5, 0xa4, 0x6c, 0x8a, 0x9e, 0xa3, + 0x94, 0x83, 0xb4, 0xbf, 0x20, 0x35, 0xbd, 0x68, 0xeb, 0x7e, 0x71, 0xc4, + 0xc0, 0x49, 0x47, 0xbd, 0x8b, 0xe9, 0x96, 0x74, 0x4d, 0xe7, 0xd1, 0xe9, + 0xcf, 0x7, 0x79, 0xf5, 0x7f, 0x21, 0x52, 0x9a, 0x50, 0x2, 0xdc, 0x8b, + 0xb0, 0x63, 0xb1, 0x34, 0xb8, 0x7b, 0x6b, 0x3f, 0xa3, 0xa7, 0xa0, 0x2f, + 0xfa, 0xb3, 0xd3, 0xbe, 0xd3, 0xd4, 0xa6, 0xde, 0x30, 0x7c, 0x1, 0x86, + 0x3e, 0xa1, 0xd, 0x11, 0x1d, 0xd8, 0xe1, 0x90, 0xd2, 0x6e, 0x2a, 0x81, + 0x2e, 0x43, 0xb5, 0x46, 0x45, 0xc6, 0x47, 0x80, 0xab, 0x8d, 0x6c, 0xc6, + 0xd2, 0xe1, 0xe4, 0x76, 0x6e, 0x2a, 0x3d, 0x1b, 0x73, 0x5b, 0x24, 0x36, + 0x61, 0xda, 0x6d, 0x30, 0xd3, 0x1a, 0x3, 0xf, 0x26, 0x67, 0x8f, 0x9f, + 0xbc, 0xc1, 0xed, 0x90, 0x8e, 0xaf, 0x6b, 0x9a, 0xc4, 0x1d, 0xad, 0x1e, + 0x4d, 0xbc, 0xe, 0xfa, 0x17, 0xde, 0xcc, 0x7b, 0xd0, 0x5a, 0xb2, 0x53, + 0x71, 0x8f, 0xf2, 0x45, 0x69, 0x38, 0xe0, 0xd3, 0xd4, 0xd2, 0xab, 0xad, + 0xe0, 0x3, 0x3, 0x58, 0xe, 0xcc, 0xe9, 0x65, 0x52, 0x1f, 0xe, 0xc3, + 0x9d, 0x68, 0x4a, 0xc3, 0x22, 0x71, 0x67, 0x22, 0x41, 0x50, 0x8, 0x28, + 0xb2, 0x26, 0x0, 0x8a, 0x52, 0xf3, 0x66, 0xa8, 0x6e, 0xa1, 0x33, 0x2c, + 0xab, 0x5a, 0x29, 0x69, 0x46, 0x73, 0xeb, 0x2c, 0xa8, 0xbe, 0x3f, 0xc6, + 0xd7, 0x32, 0x14, 0x3d, 0x56, 0xf6, 0xdf, 0x8c, 0x65, 0x68, 0x87, 0xfd, + 0xf2, 0xdc, 0xcc, 0x71, 0x21, 0xd0, 0x13, 0xe, 0x56, 0x94, 0xa0, 0x1a, + 0xf2, 0x11, 0x7a, 0xe, 0x2b, 0x87, 0x98, 0x48, 0xb8, 0x76, 0xda, 0xf3, + 0xeb, 0x30, 0xc, 0xa8, 0x87, 0x4a, 0x91, 0xb7, 0x95, 0xf0, 0x86, 0x5, + 0xe2, 0xd7, 0xd6, 0xf9, 0x5, 0xbd, 0x3, 0x62, 0x90, 0x32, 0x37, 0xb4, + 0xf, 0x29, 0xaf, 0x7, 0x6d, 0x82, 0x56, 0x97, 0xb3, 0x9c, 0x55, 0x33, + 0xd7, 0x24, 0x1d, 0x7, 0xc7, 0xf, 0x3e, 0x18, 0xd4, 0x69, 0xd4, 0x35, + 0xb4, 0x5, 0x13, 0xf3, 0xe, 0xe1, 0xf8, 0x19, 0x21, 0x7, 0x46, 0xa4, + 0x57, 0x93, 0x7, 0x2f, 0x49, 0x30, 0x3c, 0xa6, 0xde, 0x4, 0xee, 0x33, + 0xe3, 0x4d, 0x4, 0x46, 0xca, 0x6b, 0xe6, 0xda, 0x87, 0x44, 0x9f, 0xf5, + 0xc7, 0xce, 0x60, 0x66, 0x32, 0xde, 0x89, 0xc5, 0x23, 0xd, 0xe3, 0x53, + 0xdd, 0x99, 0xd1, 0x17, 0x81, 0x83, 0x7b, 0x7c, 0xb6, 0xed, 0x8c, 0xaa, + 0x6c, 0x5e, 0x7b, 0xba, 0x58, 0x89, 0x61, 0xea, 0x2f, 0x15, 0xa6, 0x67, + 0x6d, 0x2, 0x91, 0xd6, 0x7, 0x2f, 0x68, 0xaa, 0xf1, 0x7, 0x73, 0x1c, + 0xe1, 0xc9, 0x98, 0xc, 0x61, 0xfa, 0x52, 0x63, 0x8f, 0x14, 0xb0, 0x54, + 0x64, 0xd9, 0xfe, 0x2d, 0x74, 0x5c, 0x80, 0x36, 0x86, 0xb, 0xb9, 0xe2, + 0xf7, 0x45, 0xb3, 0x56, 0xb8, 0x49, 0x21, 0x39, 0x2f, 0x90, 0xf3, 0x3d, + 0x2f, 0xb8, 0xc8, 0x9c, 0x2a, 0x3b, 0xb5, 0x99, 0x35, 0xa5, 0x31, 0xaa, + 0x1d, 0x30, 0xf, 0x12, 0xe0, 0x43, 0xaa, 0xf9, 0xd5, 0x5f, 0x75, 0xcf, + 0xda, 0xd2, 0x92, 0x7a, 0x73, 0xc2, 0x93, 0x5a, 0xdf, 0x3d, 0x92, 0x3a, + 0x32, 0xa9, 0xd4, 0x4f, 0x88, 0xb0, 0x4d, 0xdf, 0xf4, 0xb7, 0xa9, 0x81, + 0xa8, 0x68, 0x1f, 0x3, 0xd4, 0x5f, 0xe6, 0xd0, 0x36, 0x8d, 0x6c, 0xa, + 0x2b, 0x32, 0x83, 0x75, 0xfa, 0x76, 0xd0, 0xc3, 0xc6, 0xcd, 0xd1, 0xb0, + 0x58, 0x7a, 0xa0, 0x28, 0xe8, 0xf1, 0x94, 0xcd, 0xb9, 0x97, 0x6d, 0xc0, + 0x8f, 0xd3, 0xc8, 0xd8, 0x11, 0xcf, 0xc8, 0x5f, 0xa6, 0x3e, 0xfd, 0x22, + 0x2, 0xcc, 0x7, 0xc9, 0x3f, 0xf9, 0x9e, 0x6d, 0x79, 0x5a, 0xa5, 0x7f, + 0x40, 0x58, 0x2c, 0x64, 0xa8, 0x9c, 0x26, 0x6c, 0xbe, 0x93, 0x9, 0xf7, + 0xf, 0x9e, 0x41, 0xef, 0x1d, 0x64, 0xed, 0x46, 0x76, 0x96, 0xb8, 0x47, + 0xa8, 0x2c, 0x30, 0xbf, 0xae, 0x31, 0xff, 0x2, 0x74, 0x4b, 0xb6, 0x72, + 0x43, 0x37, 0x3d, 0x28, 0x54, 0x8e, 0x98, 0xcb, 0x5d, 0xeb, 0xc6, 0x51, + 0x8, 0xc, 0xd9, 0xb5, 0xef, 0x5d, 0x78, 0xe3, 0x8a, 0xce, 0x99, 0xbe, + 0xb8, 0xc1, 0x16, 0x64, 0xad, 0x52, 0xc, 0x33, 0x7, 0xad, 0x7d, 0xbb, + 0xcb, 0x27, 0xb8, 0x20, 0x54, 0xab, 0x49, 0xa8, 0xf3, 0xbb, 0xfd, 0x7e, + 0xb3, 0x2, 0x40, 0xd8, 0x7, 0x43, 0xce, 0xa, 0xb5, 0xe5, 0xa4, 0x28, + 0xaa, 0xcd, 0x54, 0x5c, 0xc8, 0xd3, 0x13, 0x4, 0xda, 0x28, 0x15, 0xd8, + 0xb7, 0xea, 0x99, 0x6, 0x7, 0xad, 0x43, 0x50, 0xe4, 0xe0, 0xe9, 0xf3, + 0x31, 0x65, 0xd7, 0x4f, 0xd1, 0x27, 0xe3, 0x4d, 0x56, 0xd8, 0xfb, 0x67, + 0x2f, 0xed, 0x1c, 0xfd, 0xf7, 0xf0, 0xe9, 0x27, 0x1c, 0x8c, 0x93, 0xeb, + 0x59, 0x6f, 0x6b, 0x69, 0x6, 0x9f, 0x71, 0x7a, 0x2, 0x33, 0xf4, 0x95, + 0xfa, 0x61, 0x1, 0xfb, 0xc8, 0x7, 0x5d, 0x12, 0x46, 0x50, 0xef, 0xe9, + 0xa7, 0xd3, 0xe3, 0x33, 0x69, 0x59, 0xd0, 0x83, 0xad, 0xf0, 0x99, 0xdd, + 0x2d, 0xcd, 0x5e, 0xf7, 0x4, 0xac, 0xd4, 0x36, 0xcf, 0xc0, 0xdf, 0xd5, + 0xce, 0xbd, 0x3d, 0xc8, 0x40, 0x3d, 0xc2, 0x6b, 0xb8, 0x32, 0xff, 0x82, + 0xa2, 0x62, 0x94, 0x51, 0x9, 0xb6, 0x86, 0xa1, 0x71, 0xf7, 0xbf, 0x7, + 0x45, 0x2a, 0x63, 0xc3, 0xc3, 0x3a, 0xa4, 0x21, 0x39, 0x12, 0x6f, 0x49, + 0x53, 0x1b, 0xde, 0x53, 0xa3, 0xde, 0xbb, 0xa4, 0x6d, 0x65, 0x39, 0x7c, + 0x6d, 0x31, 0x5a, 0x8, 0x8c, 0x5a, 0x87, 0xee, 0x6f, 0xfb, 0x92, 0x4a, + 0xf9, 0x73, 0x56, 0x9a, 0xb8, 0x3f, 0x8d, 0xb6, 0x5b, 0x8, 0x80, 0xec, + 0x51, 0xbb, 0x6, 0x2f, 0x98, 0x80, 0x7c, 0x26, 0xab, 0xbb, 0x85, 0xfb, + 0x9e, 0xe6, 0x90, 0x16, 0xa2, 0xa5, 0x9b, 0xb3, 0x53, 0x40, 0x5c, 0x75, + 0x23, 0x3, 0xee, 0xe8, 0x8f, 0x4, 0xb2, 0x77, 0x3, 0x9, 0xd6, 0xa3, + 0xe5, 0xd8, 0xd, 0x11, 0xb3, 0x2d, 0x33, 0xf2, 0x39, 0x64, 0x8, 0x41, + 0x69, 0x38, 0xaa, 0xfb, 0xac, 0xaa, 0xd, 0x85, 0x82, 0x7a, 0x4b, 0x87, + 0x43, 0x95, 0xca, 0x43, 0x10, 0x69, 0x3d, 0x47, 0x6f, 0x28, 0x36, 0x52, + 0xcd, 0x9d, 0x61, 0xa9, 0x2e, 0x4a, 0x7c, 0xcb, 0x60, 0x4c, 0x80, 0xc1, + 0x8f, 0x61, 0x1d, 0xb6, 0xd2, 0x9f, 0x1a, 0x87, 0xd, 0x78, 0xe7, 0xb9, + 0x83, 0xaf, 0x48, 0xb0, 0x53, 0xe1, 0x22, 0x99, 0xa3, 0x80, 0xae, 0x8b, + 0xd0, 0x2f, 0x94, 0x2c, 0xbb, 0xf5, 0x84, 0x6a, 0x9, 0xb7, 0x28, 0xbe, + 0x3f, 0x4, 0xb7, 0xb8, 0x9c, 0x41, 0xe6, 0x61, 0x5, 0x13, 0x6e, 0x36, + 0xa1, 0x7e, 0x80, 0x95, 0x5f, 0x23, 0x73, 0xac, 0xe5, 0xd9, 0xb1, 0x82, + 0xb2, 0xd9, 0x3d, 0xe8, 0x28, 0x27, 0xcb, 0xb7, 0xfc, 0xe, 0xb4, 0x3e, + 0xc5, 0x14, 0x1d, 0x33, 0x63, 0xc3, 0x15, 0x79, 0x2e, 0xa8, 0xf4, 0xa5, + 0xbd, 0xd8, 0x3a, 0x61, 0xdf, 0x59, 0xff, 0x8a, 0xd7, 0xe9, 0xe3, 0x51, + 0xd2, 0xd2, 0x4e, 0x96, 0x2d, 0x7, 0xa, 0xe, 0xa5, 0x7b, 0x64, 0x68, + 0xcc, 0xc6, 0x40, 0x3a, 0x81, 0x73, 0x67, 0xbc, 0x6b, 0xaa, 0x41, 0x82, + 0xd5, 0xbd, 0xeb, 0xe9, 0xb8, 0x49, 0x8a, 0x1f, 0x9d, 0xbb, 0x36, 0x39, + 0x7a, 0xa6, 0xc1, 0xed, 0x42, 0x83, 0xe6, 0x77, 0xa7, 0x6, 0xaa, 0x32, + 0xdc, 0x2, 0x59, 0x11, 0x94, 0x3, 0xd5, 0xc3, 0x22, 0xb9, 0xf7, 0x8e, + 0x27, 0x44, 0xec, 0xfb, 0x1a, 0x25, 0x99, 0x47, 0x0, 0x7c, 0xa3, 0xc6, + 0x1d, 0x58, 0xbf, 0xcd, 0xa5, 0x13, 0x4d, 0xba, 0xc8, 0x2d, 0x7f, 0x97, + 0x9d, 0xc2, 0x57, 0x20, 0xf1, 0x9a, 0xa7, 0x6e, 0xc8, 0x44, 0x89, 0x53, + 0x94, 0xdd, 0x21, 0xd0, 0xd4, 0x54, 0x65, 0x20, 0x7f, 0x3d, 0x55, 0xfe, + 0x13, 0x4d, 0xa0, 0xe2, 0x39, 0x74, 0x1c, 0x18, 0xc5, 0x58, 0x56, 0x15, + 0x5e, 0x27, 0x6d, 0xca, 0x8a, 0x90, 0x24, 0x2, 0x7, 0xe9, 0xd1, 0x5d, + 0x6c, 0xc8, 0xe4, 0x6a, 0x5e, 0x17, 0x49, 0x0, 0x8f, 0xea, 0xcb, 0x3b, + 0x8b, 0x2f, 0x9e, 0xae, 0x8d, 0x8d, 0x65, 0x65, 0xb1, 0x28, 0xd1, 0x5c, + 0x7c, 0xd, 0x1c, 0x52, 0xb8, 0xb7, 0x4e, 0x3b, 0x33, 0x5, 0x5f, 0x6e, + 0x1d, 0x94, 0x3, 0xc6, 0x25, 0xd2, 0x53, 0x99, 0x35, 0xd9, 0xaf, 0xec, + 0x42, 0x90, 0x14, 0x94, 0x66, 0x6a, 0x3a, 0xa7, 0xf3, 0xa6, 0x7e, 0x7f, + 0x25, 0x57, 0xba, 0x94, 0xff, 0x50, 0x64, 0x4e, 0x63, 0x79, 0xc2, 0x76, + 0xd5, 0x32, 0x13, 0x22, 0xe0, 0x62, 0x64, 0x24, 0xe4, 0x35, 0x54, 0x99, + 0xa, 0xe8, 0x64, 0x75, 0xa0, 0x36, 0xbf, 0xa0, 0xc2, 0x82, 0xdf, 0xa3, + 0xbf, 0xc1, 0x6f, 0xbb, 0xe7, 0x20, 0x6e, 0xb3, 0x49, 0xcc, 0xb9, 0xdc, + 0xdb, 0xd2, 0x52, 0x2c, 0x1f, 0xbb, 0x6c, 0x21, 0xb, 0x8, 0xfa, 0x33, + 0x22, 0xa6, 0xaa, 0xe0, 0x4, 0x20, 0x5f, 0xaa, 0x29, 0xdd, 0x8b, 0xf2, + 0x15, 0x8a, 0x67, 0xdc, 0xc2, 0x95, 0xac, 0xbd, 0x3e, 0x72, 0x2a, 0x6c, + 0x11, 0x5d, 0x6e, 0xfc, 0x77, 0x94, 0xa7, 0x81, 0x93, 0xb9, 0x49, 0x2b, + 0x21, 0xb1, 0xd9, 0xa, 0xc5, 0x1f, 0xe8, 0x5c, 0xce, 0x11, 0xab, 0x65, + 0xe2, 0x32, 0xa5, 0x5, 0xc2, 0x8b, 0x9d, 0x1c, 0xae, 0x7d, 0x1, 0x6c, + 0x20, 0xed, 0xbe, 0xb8, 0x1e, 0xbd, 0xc7, 0xaa, 0x84, 0x87, 0xc4, 0xf1, + 0x8, 0x32, 0xe5, 0x27, 0xb1, 0xa7, 0x15, 0x86, 0xf9, 0x32, 0xf, 0x16, + 0x9c, 0x3f, 0xdd, 0xa4, 0xfb, 0x0, 0x65, 0xe8, 0xf5, 0x7e, 0xbc, 0x14, + 0x78, 0x82, 0x1b, 0xdc, 0x13, 0xd6, 0x98, 0xe6, 0x69, 0x6d, 0x4a, 0xc2, + 0xcd, 0x39, 0x7d, 0x71, 0xf1, 0xca, 0x26, 0x55, 0xcc, 0xe9, 0x99, 0xc5, + 0x50, 0x9a, 0xb8, 0x25, 0x4b, 0x11, 0xb5, 0x7, 0xa7, 0x7f, 0x75, 0x21, + 0x16, 0x24, 0xc5, 0xc, 0x69, 0xff, 0x59, 0x8d, 0xaa, 0xda, 0xc7, 0x57, + 0x1a, 0x6e, 0xc4, 0xcc, 0xc, 0x54, 0xfc, 0x81, 0x32, 0x74, 0x86, 0xeb, + 0xf9, 0xfa, 0x73, 0x60, 0x1e, 0xed, 0x93, 0x6, 0x99, 0xdb, 0xf, 0xbc, + 0x2c, 0x99, 0x6, 0xe6, 0x1a, 0xf5, 0x6d, 0xc7, 0x18, 0xc2, 0x6c, 0xc7, + 0x57, 0x48, 0x59, 0x9f, 0xed, 0x24, 0xb1, 0xb9, 0xb5, 0xe4, 0x8b, 0xc1, + 0x3e, 0x50, 0x20, 0x7d, 0x60, 0xba, 0x2b, 0xaa, 0x2b, 0x64, 0xe7, 0xac, + 0x6e, 0xce, 0x53, 0x84, 0xea, 0x79, 0x70, 0xe8, 0xfa, 0x14, 0xca, 0x4d, + 0x38, 0x9, 0x85, 0x28, 0xc7, 0xd3, 0x6e, 0xd, 0xe9, 0xbf, 0xff, 0x0, + 0xb9, 0x14, 0xff, 0x38, 0xb8, 0x92, 0x35, 0x63, 0xa1, 0xee, 0x4c, 0xb0, + 0x64, 0x90, 0x1, 0x84, 0xd, 0x89, 0xaa, 0x5c, 0xf0, 0x8, 0x99, 0xb3, + 0x8a, 0x72, 0x1, 0x62, 0x77, 0x73, 0x92, 0xbb, 0x5c, 0x71, 0x50, 0xa4, + 0xdf, 0x1c, 0x2a, 0xdd, 0x79, 0x1a, 0x7b, 0xb6, 0x36, 0xff, 0x7d, 0x8c, + 0xd0, 0x4f, 0x3f, 0x56, 0x5f, 0x95, 0x92, 0x58, 0xc, 0x3a, 0xe0, 0x10, + 0x48, 0x77, 0xd, 0x2, 0xfc, 0xba, 0x82, 0xff, 0x45, 0xd6, 0x19, 0xb5, + 0xaa, 0x1c, 0xab, 0xcd, 0x54, 0xf, 0x84, 0xe, 0xa3, 0xfb, 0xcd, 0xac, + 0x3b, 0xa0, 0x38, 0x4c, 0xf9, 0xb1, 0xf6, 0xa2, 0x21, 0xb8, 0x57, 0x45, + 0x3d, 0x4, 0x75, 0x5, 0xc8, 0x64, 0xd2, 0x6c, 0xfb, 0x28, 0xd1, 0x48, + 0x35, 0xde, 0x4a, 0x91, 0xe1, 0x9, 0xea, 0x3c, 0xa6, 0xa9, 0x15, 0xc8, + 0xa5, 0xf3, 0x3f, 0xa2, 0xae, 0x4a, 0xca, 0xe5, 0xb1, 0xfa, 0xeb, 0x9c, + 0xc7, 0xd6, 0x1, 0xbd, 0xb7, 0x3c, 0x8a, 0x24, 0x4b, 0x3, 0xc2, 0x36, + 0x38, 0x3a, 0x65, 0xd4, 0xbb, 0x7a, 0x87, 0xf8, 0x5f, 0x14, 0xdd, 0x94, + 0x74, 0xd9, 0xf0, 0x43, 0x35, 0xbc, 0x68, 0x39, 0x2b, 0x28, 0xb8, 0x39, + 0x40, 0x2, 0x51, 0x30, 0x8b, 0x90, 0xb5, 0xc2, 0xcb, 0x7d, 0x6, 0x2d, + 0xeb, 0xed, 0xc6, 0x47, 0x76, 0xcb, 0x2, 0x47, 0x85, 0xe0, 0xff, 0x77, + 0x6d, 0x1a, 0x24, 0xff, 0xbb, 0x5a, 0xf4, 0xdb, 0xa1, 0xea, 0x16, 0x11, + 0x50, 0x13, 0xc5, 0xe4, 0x66, 0xcb, 0xc7, 0x90, 0x10, 0xe4, 0xa7, 0x74, + 0x93, 0xde, 0x67, 0x16, 0x1e, 0x21, 0x28, 0x96, 0x93, 0x71, 0xdc, 0xb5, + 0x6d, 0x3e, 0x5f, 0x1e, 0x9b, 0xd4, 0x78, 0x5d, 0xdb, 0xce, 0xfe, 0x60, + 0x38, 0xed, 0xd7, 0xce, 0x12, 0x33, 0x1c, 0x34, 0x40, 0xeb, 0xfe, 0x69, + 0x5d, 0x3d, 0xd3, 0xf3, 0xd1, 0x3d, 0xd4, 0x1f, 0x4a, 0xd9, 0xab, 0xc5, + 0x94, 0x8b, 0x9a, 0x33, 0xe2, 0xf4, 0x92, 0xda, 0xe2, 0x8f, 0x75, 0x8f, + 0xb3, 0x23, 0x24, 0x3e, 0xd7, 0x53, 0x78, 0x4d, 0xf0, 0xa6, 0x1d, 0xb1, + 0x6a, 0xcc, 0x66, 0x21, 0x26, 0x43, 0x6d, 0xbe, 0x86, 0x12, 0x9, 0xed, + 0xf2, 0xd6, 0xd3, 0x90, 0x19, 0x10, 0xe1, 0x44, 0x11, 0x90, 0x6a, 0x86, + 0x30, 0x6d, 0x77, 0x0, 0x3, 0xae, 0x0, 0xdd, 0x51, 0x97, 0xa8, 0xc2, + 0x77, 0x77, 0x0, 0xdd, 0x62, 0x84, 0x1, 0x7e, 0xc6, 0xd6, 0x4c, 0x49, + 0x72, 0x8a, 0xdb, 0x4e, 0x7e, 0x1a, 0x4b, 0xfb, 0xd6, 0x40, 0xad, 0x64, + 0x64, 0x99, 0x9, 0x56, 0xec, 0xad, 0x3d, 0x88, 0x9a, 0xb4, 0x6c, 0x17, + 0x62, 0xf9, 0xd8, 0xb3, 0x2f, 0x8, 0x3e, 0xc, 0xc6, 0xc1, 0xee, 0x20, + 0x9f, 0xe6, 0xeb, 0xc6, 0xe6, 0xcc, 0xb4, 0xe7, 0xe6, 0xca, 0xf1, 0x2c, + 0x9, 0x73, 0xb2, 0xa, 0xd6, 0xf5, 0x40, 0x44, 0xfd, 0xa, 0x36, 0xb3, + 0xe6, 0xf, 0x84, 0xf8, 0x8a, 0x22, 0xc, 0x15, 0x99, 0xf1, 0xe1, 0x3f, + 0xe5, 0x73, 0x5f, 0x63, 0x1d, 0xdf, 0xb6, 0xf6, 0x2f, 0xa3, 0x7e, 0x2, + 0x7, 0xba, 0xc1, 0x0, 0x72, 0x38, 0x41, 0xe3, 0x33, 0x3, 0x16, 0x2f, + 0x2a, 0xd7, 0x54, 0x94, 0x78, 0xd2, 0x5e, 0xe4, 0x6e, 0x19, 0xa0, 0xe3, + 0xa, 0xc1, 0x8b, 0xd4, 0x6f, 0x1f, 0xc2, 0x5f, 0xca, 0x23, 0x30, 0x7b, + 0xd3, 0xe, 0x45, 0xf9, 0x2a, 0x1d, 0x6e, 0x8c, 0x8, 0xc8, 0x9c, 0x84, + 0xd2, 0x71, 0xe8, 0xfc, 0x68, 0x1b, 0xf5, 0xca, 0xb3, 0x98, 0xe3, 0xeb, + 0xb4, 0xb7, 0x88, 0x4f, 0xfb, 0x37, 0xdf, 0x4c, 0xf9, 0x3e, 0x71, 0x36, + 0xfa, 0xd0, 0x98, 0x38, 0x8, 0x77, 0xa8, 0xdb, 0x75, 0x8d, 0x1f, 0x25, + 0x92, 0x4c, 0xe, 0x47, 0x5c, 0x83, 0x91, 0x36, 0x57, 0x3a, 0x8e, 0xf, + 0x70, 0xb1, 0x2b, 0x15, 0x46, 0x92, 0x35, 0x16, 0x78, 0xca, 0xf, 0x37, + 0xa1, 0xce, 0x9c, 0x44, 0x29, 0xad, 0xdf, 0x28, 0x69, 0x27, 0x6d, 0x72, + 0x71, 0x62, 0x48, 0xe5, 0xdc, 0xe8, 0x64, 0x11, 0x47, 0x9b, 0x2d, 0xc, + 0xe4, 0x5, 0xd8, 0x72, 0x1f, 0xc6, 0x35, 0x14, 0x8e, 0x6a, 0x11, 0x90, + 0xa9, 0x1f, 0xd3, 0x8d, 0x7c, 0x28, 0x10, 0x22, 0x88, 0x2e, 0x15, 0xcb, + 0x3d, 0xf7, 0xef, 0x60, 0x4a, 0x83, 0xeb, 0x1a, 0x8, 0xd2, 0x43, 0xae, + 0x5e, 0xbe, 0xd6, 0x8e, 0x69, 0x9, 0x2f, 0x7f, 0x7f, 0x2a, 0xcd, 0x55, + 0x5d, 0x30, 0x8, 0x5, 0xe3, 0xd6, 0xc8, 0xb4, 0x7, 0x78, 0xc4, 0x69, + 0x0, 0x70, 0x4f, 0x92, 0x1b, 0x9c, 0x9d, 0xaa, 0x1a, 0x6a, 0x13, 0x54, + 0xa8, 0x3d, 0x66, 0xf4, 0xad, 0xc3, 0x8a, 0xb4, 0x48, 0x31, 0xc3, 0xe8, + 0x23, 0x48, 0x1b, 0xee, 0x32, 0x66, 0x23, 0xca, 0xe6, 0x97, 0x3c, 0x63, + 0xfc, 0xf, 0x4c, 0x45, 0xd1, 0xbf, 0x55, 0x78, 0xf2, 0x7b, 0x32, 0xd9, + 0x7d, 0xe4, 0xdb, 0x8, 0x2c, 0xdd, 0xa7, 0xf0, 0xae, 0xfb, 0x74, 0x6, + 0x5d, 0x62, 0xb1, 0x6f, 0xc6, 0x2b, 0x93, 0x82, 0xd7, 0x98, 0x4, 0x8f, + 0x9a, 0x9e, 0xa2, 0x88, 0x8d, 0xa2, 0xe, 0xc1, 0x8b, 0xdc, 0x1b, 0xb4, + 0xcc, 0xe6, 0x6f, 0xe, 0x23, 0x3f, 0xaf, 0x3b, 0x60, 0x4c, 0xaa, 0x1d, + 0xb0, 0xe6, 0x14, 0x0, 0x1b, 0x68, 0x4f, 0xcc, 0xdb, 0x16, 0xdd, 0x96, + 0x71, 0x6c, 0xbe, 0x1, 0x7b, 0x80, 0x2b, 0xb8, 0xc4, 0x85, 0xf9, 0x98, + 0x25, 0x3d, 0xa7, 0x28, 0x71, 0xab, 0xbe, 0x80, 0x3e, 0x45, 0x42, 0x14, + 0xa6, 0x5c, 0x84, 0x37, 0x49, 0x66, 0x2f, 0x2d, 0x4b, 0x3d, 0x22, 0x92, + 0x6a, 0x1a, 0x9e, 0x1d, 0xe6, 0xc7, 0x58, 0x16, 0x70, 0xb2, 0xe, 0x89, + 0xd1, 0xec, 0xc8, 0x47, 0xdf, 0x8b, 0xce, 0x5a, 0x31, 0x64, 0xa1, 0xa0, + 0xf1, 0xed, 0x51, 0x89, 0x86, 0x72, 0xd0, 0xa, 0x9b, 0x65, 0xbb, 0x57, + 0x35, 0x13, 0x21, 0x86, 0xbf, 0xb9, 0x49, 0x7c, 0x94, 0xfe, 0x40, 0xaf, + 0x3b, 0x27, 0xc3, 0x74, 0x2e, 0xcd, 0xea, 0x30, 0x60, 0xb8, 0x5c, 0x7c, + 0x21, 0x39, 0x30, 0xd9, 0x57, 0x5f, 0xd3, 0xc7, 0xd6, 0x6b, 0xb2, 0x88, + 0x7d, 0xb6, 0xa0, 0xca, 0x18, 0xf3, 0x9c, 0xf, 0xb0, 0xb6, 0x98, 0x20, + 0x33, 0xe9, 0xf5, 0x92, 0x7, 0xba, 0x1c, 0x6a, 0x59, 0x4c, 0xe6, 0xf0, + 0x43, 0xdf, 0x49, 0x72, 0x1a, 0x8a, 0x8f, 0x9a, 0x6b, 0x28, 0xef, 0xeb, + 0x5a, 0x96, 0x6d, 0xa5, 0x3a, 0xd4, 0xf9, 0x1e, 0x93, 0x8f, 0xef, 0xd2, + 0x1f, 0xbc, 0x2a, 0xd6, 0x21, 0xd0, 0x4b, 0x49, 0x5d, 0x6d, 0x45, 0xd0, + 0xc, 0xbf, 0xf7, 0x25, 0xe9, 0xca, 0x45, 0x8f, 0x22, 0xed, 0x48, 0x1a, + 0xa0, 0xc5, 0x73, 0xb5, 0x44, 0x96, 0x0, 0x8, 0x9b, 0xfd, 0xc0, 0xd0, + 0x7e, 0xd5, 0x1b, 0xb1, 0xe1, 0xf7, 0x19, 0x5c, 0x59, 0xbb, 0x86, 0xd5, + 0xb1, 0x17, 0x16, 0xbf, 0x10, 0x5b, 0xdc, 0x6f, 0xa9, 0x8f, 0xf9, 0x4a, + 0x11, 0xac, 0x2, 0xc1, 0x9e, 0x92, 0x23, 0xd8, 0xfb, 0x38, 0x95, 0xc9, + 0x70, 0x1f, 0x57, 0x5f, 0x7, 0xb2, 0xa1, 0xe2, 0xe2, 0xd5, 0x24, 0xe5, + 0xbb, 0x6a, 0x90, 0xf, 0xbe, 0x18, 0x90, 0xf3, 0x47, 0x95, 0xfa, 0xe8, + 0x13, 0xe2, 0x2c, 0x4f, 0xc5, 0xb9, 0x64, 0xb, 0x67, 0x1f, 0xbc, 0x34, + 0xb0, 0x66, 0xd2, 0xa3, 0x6, 0xfa, 0xae, 0x6, 0xff, 0x17, 0x96, 0xfe, + 0xa, 0xec, 0xf2, 0xe2, 0x7c, 0x3c, 0xe1, 0x16, 0xcc, 0x3c, 0x69, 0xf7, + 0x23, 0xaa, 0x51, 0x3f, 0x39, 0xb3, 0x94, 0xa0, 0x8c, 0x59, 0x21, 0xd3, + 0xb0, 0xac, 0x35, 0xa2, 0xa, 0x50, 0x89, 0x33, 0x34, 0x83, 0x45, 0xa1, + 0x9d, 0xf4, 0xec, 0xbe, 0x8d, 0x9, 0xda, 0xd7, 0x10, 0xee, 0xb3, 0x10, + 0xea, 0x85, 0x16, 0xc8, 0x89, 0x8e, 0xdf, 0x8b, 0xf1, 0x7a, 0x7, 0xb4, + 0xe7, 0xc9, 0x1f, 0x4c, 0x6a, 0x4a, 0xfe, 0x0, 0xd8, 0xd4, 0xd0, 0x1c, + 0xc4, 0xa4, 0x3, 0x4c, 0xf, 0xc3, 0x95, 0x2d, 0xb5, 0x80, 0x4, 0x61, + 0xdf, 0xac, 0x79, 0x10, 0xd3, 0xd8, 0x1d, 0xc5, 0x80, 0x10, 0xe6, 0x77, + 0x37, 0xec, 0x80, 0x44, 0x30, 0x5a, 0xad, 0x21, 0xa, 0x4f, 0xe6, 0x77, + 0x45, 0x6b, 0x5d, 0xc2, 0x10, 0x26, 0xaa, 0x9e, 0x5f, 0x4e, 0x31, 0x22, + 0x27, 0xa7, 0xef, 0x44, 0x17, 0x3b, 0xad, 0xea, 0xc7, 0x55, 0x32, 0x2, + 0x2a, 0x5b, 0xfc, 0xbd, 0x13, 0xe5, 0x7e, 0x96, 0x19, 0x89, 0xd3, 0xc9, + 0x7c, 0x23, 0x7d, 0x4c, 0x4d, 0x90, 0xc1, 0x46, 0x32, 0x21, 0xdb, 0xbd, + 0xdc, 0x65, 0x4, 0x4, 0x23, 0x8a, 0x24, 0xe4, 0xf0, 0x61, 0x8e, 0x9e, + 0x57, 0x8e, 0x99, 0x2b, 0xe6, 0xda, 0x10, 0xd6, 0x6d, 0xae, 0xb4, 0x4b, + 0xfa, 0x3a, 0x1e, 0x4, 0xb4, 0xd0, 0xd1, 0x8f, 0x97, 0x51, 0x82, 0x80, + 0x67, 0x56, 0x3b, 0xed, 0x6d, 0x86, 0x47, 0x34, 0x3c, 0x40, 0xd2, 0x9d, + 0xa9, 0x12, 0x77, 0x60, 0x94, 0x4f, 0x35, 0x85, 0x7e, 0x29, 0xb8, 0x50, + 0x1, 0x9f, 0x32, 0x95, 0x99, 0x6a, 0x7b, 0xf8, 0xf0, 0xc2, 0x4d, 0x4, + 0x7e, 0x8a, 0x88, 0x57, 0x67, 0x62, 0x98, 0x7c, 0x49, 0x7d, 0x3d, 0x49, + 0x98, 0x9, 0xd9, 0xff, 0x85, 0xdb, 0xfd, 0xc5, 0xa2, 0xdc, 0xc0, 0xa7, + 0xc0, 0xd7, 0x23, 0x19, 0x2b, 0x33, 0x1c, 0x2a, 0xb8, 0xe6, 0xef, 0xb9, + 0x41, 0x12, 0xea, 0xc, 0x20, 0x52, 0x7b, 0xd2, 0xc6, 0xfb, 0xea, 0xc1, + 0x30, 0x18, 0x67, 0xe9, 0x3e, 0x3e, 0x1, 0xb3, 0xf8, 0x72, 0xd2, 0x79, + 0xc6, 0x27, 0x62, 0xfd, 0x2c, 0xe1, 0xeb, 0xf4, 0x4e, 0xa6, 0x68, 0x6c, + 0x17, 0x3a, 0xbf, 0xfb, 0x4b, 0x6c, 0xe, 0x3a, 0x7a, 0xcc, 0x9a, 0xe4, + 0x45, 0xd2, 0x35, 0x8, 0x7c, 0xcc, 0x43, 0x91, 0x31, 0x1d, 0x40, 0x7d, + 0xd7, 0x62, 0xab, 0x5d, 0x30, 0xa2, 0x10, 0xea, 0x9c, 0xa9, 0xb2, 0x35, + 0xa, 0xb9, 0x84, 0xd8, 0xf4, 0xd3, 0x82, 0x96, 0xb4, 0xbb, 0x3c, 0x65, + 0xe8, 0xa4, 0x74, 0xc7, 0xa5, 0xde, 0x3b, 0xea, 0xf3, 0xf6, 0xf3, 0xf1, + 0xd9, 0xb1, 0xd5, 0x29, 0x68, 0x51, 0x1d, 0x1e, 0x7a, 0xd4, 0xab, 0x44, + 0x61, 0x49, 0xa5, 0x94, 0xd1, 0x7b, 0x77, 0x93, 0x24, 0x7d, 0x9f, 0xa1, + 0x6d, 0xf0, 0x10, 0xfc, 0x96, 0xfc, 0xc7, 0xa3, 0x2d, 0x43, 0x9, 0x56, + 0x23, 0x0, 0xaf, 0x4b, 0xb8, 0xe3, 0xc5, 0x3c, 0x1b, 0x7c, 0x6a, 0x25, + 0x2e, 0xa2, 0xdc, 0x2d, 0x6e, 0xb3, 0xa6, 0x63, 0xed, 0xb2, 0xa6, 0x12, + 0x33, 0x6e, 0xfa, 0x3a, 0x66, 0x83, 0xcd, 0x20, 0x39, 0xd7, 0xb7, 0xe, + 0x2b, 0x26, 0x69, 0xd9, 0x29, 0x35, 0x72, 0xc9, 0xee, 0x57, 0xef, 0x6c, + 0x6f, 0x7e, 0x57, 0xa9, 0x12, 0xd2, 0x8c, 0x6, 0xa8, 0x74, 0xe0, 0x2, + 0x28, 0xdf, 0x54, 0x6b, 0x32, 0x9c, 0x53, 0x64, 0x23, 0xd6, 0x9e, 0xf9, + 0x75, 0xe0, 0x56, 0x27, 0xf8, 0x56, 0xdb, 0x27, 0xd5, 0x39, 0x61, 0x4f, + 0x82, 0x79, 0x35, 0xa4, 0x1, 0x35, 0x74, 0x74, 0x47, 0x29, 0x98, 0xa4, + 0x19, 0x28, 0x95, 0x1e, 0xac, 0x0, 0x63, 0x40, 0xac, 0x2, 0x12, 0x86, + 0x86, 0xf0, 0x6c, 0x7f, 0xd9, 0xe9, 0xe4, 0x57, 0x96, 0x37, 0x77, 0xb9, + 0x4b, 0xda, 0x3c, 0x82, 0x86, 0x53, 0xf2, 0x89, 0x6b, 0x71, 0x5b, 0xef, + 0x46, 0xa9, 0x84, 0x99, 0xf7, 0x30, 0x5f, 0xbb, 0xf4, 0x90, 0x50, 0xbe, + 0xb7, 0x45, 0xec, 0x19, 0x62, 0xab, 0x8b, 0xdf, 0xa7, 0x54, 0x11, 0xc0, + 0xf7, 0x78, 0xe3, 0x80, 0x4b, 0xa2, 0x8c, 0x26, 0x49, 0x6d, 0x96, 0xb, + 0xca, 0x2a, 0xd1, 0xe2, 0x88, 0xd3, 0x9, 0xef, 0xef, 0x89, 0xca, 0xe, + 0xb8, 0x5d, 0x2f, 0xea, 0xc6, 0x26, 0x24, 0xc2, 0x96, 0xaf, 0xf9, 0x6e, + 0xd4, 0x1c, 0xae, 0x24, 0x68, 0x3b, 0xad, 0x24, 0x59, 0x80, 0xc3, 0x15, + 0x25, 0xb0, 0xd8, 0x65, 0x5b, 0x17, 0x93, 0xe7, 0x15, 0xc9, 0x39, 0xbf, + 0x81, 0xfd, 0xa8, 0x16, 0xf0, 0x1f, 0x43, 0xf0, 0xb, 0x1d, 0x63, 0xa8, + 0x50, 0x8e, 0x2e, 0xe9, 0x42, 0xec, 0x53, 0xa0, 0x5a, 0xa5, 0x2e, 0x93, + 0x19, 0xbf, 0x9a, 0xf7, 0x9c, 0x9, 0x44, 0x56, 0xf5, 0x68, 0xd6, 0x90, + 0xb3, 0xc3, 0x77, 0x9d, 0x7c, 0x85, 0x53, 0xcf, 0xb8, 0x53, 0x48, 0x88, + 0xa, 0xfa, 0x9c, 0xdb, 0x5a, 0xbe, 0xcd, 0xce, 0x81, 0xab, 0xb, 0x18, + 0x3d, 0xf4, 0xc9, 0xfb, 0xac, 0xf9, 0x68, 0xf6, 0x2b, 0xd9, 0x4a, 0xe, + 0x2d, 0x20, 0x3e, 0xd8, 0x29, 0x1a, 0xa, 0xe6, 0x9f, 0xf, 0xf, 0x13, + 0x48, 0x8c, 0xdd, 0x66, 0x2b, 0x4e, 0x70, 0x9b, 0x54, 0x8a, 0x9f, 0x83, + 0x71, 0x86, 0xc, 0xae, 0x6d, 0xd5, 0x2c, 0x13, 0xf1, 0x16, 0x9d, 0xe9, + 0xcc, 0xa2, 0xfc, 0x6c, 0xc3, 0xbf, 0x94, 0xfd, 0xd5, 0xac, 0xd8, 0x46, + 0x2f, 0xf5, 0xc6, 0x53, 0xe5, 0xdf, 0x90, 0x23, 0x20, 0x1d, 0xa5, 0x86, + 0x11, 0x63, 0xea, 0xe1, 0xc5, 0xf8, 0x31, 0x80, 0x27, 0xba, 0x71, 0x54, + 0x78, 0x12, 0xc1, 0xa9, 0x42, 0x6f, 0xba, 0xe8, 0x11, 0x34, 0x6e, 0xc7, + 0xca, 0x4c, 0x56, 0x23, 0x19, 0x8a, 0xa9, 0x43, 0x23, 0xab, 0xcb, 0x37, + 0xb5, 0xaf, 0xe4, 0xcd, 0x23, 0xcb, 0xf7, 0xcf, 0x64, 0x8a, 0x68, 0x87, + 0x84, 0x4f, 0x55, 0xde, 0x22, 0x3b, 0xca, 0x7c, 0x4c, 0x3, 0xf4, 0xd3, + 0x67, 0x3c, 0xf3, 0xd1, 0xeb, 0xf0, 0x90, 0xb1, 0xa7, 0xd9, 0x39, 0x19, + 0xd9, 0x40, 0xea, 0x55, 0x13, 0x56, 0xc7, 0x12, 0x9e, 0x34, 0x17, 0xcf, + 0xbf, 0xc7, 0x17, 0xb5, 0xe7, 0xfd, 0xdc, 0xd8, 0x51, 0x85, 0x75, 0x37, + 0xc4, 0xdc, 0xf3, 0x51, 0x2d, 0x62, 0xfc, 0x2a, 0x76, 0x84, 0x36, 0xc3, + 0x3a, 0xf3, 0xeb, 0x7f, 0x6f, 0x9f, 0xe0, 0xe8, 0x92, 0x37, 0xf7, 0x53, + 0xb2, 0x7d, 0x1d, 0xef, 0xe4, 0x8f, 0x72, 0xe9, 0xea, 0x8b, 0x2d, 0xf5, + 0x7, 0x12, 0xbf, 0xee, 0x89, 0xc3, 0xc0, 0x59, 0x7a, 0x91, 0xdd, 0x76, + 0x21, 0xb5, 0xeb, 0xda, 0x9a, 0xb4, 0x87, 0x29, 0xbd, 0x14, 0xa3, 0x3f, + 0xd0, 0x9b, 0xb, 0x12, 0xf6, 0x65, 0x1a, 0x43, 0x44, 0xed, 0x88, 0xb9, + 0xba, 0xef, 0xe1, 0xc5, 0x10, 0x7d, 0xe4, 0x55, 0x72, 0x90, 0xc4, 0xa5, + 0x7f, 0x2a, 0xee, 0x62, 0x7e, 0xfe, 0x21, 0x27, 0xac, 0x7c, 0x41, 0x75, + 0x2b, 0x46, 0xef, 0x3c, 0x37, 0x86, 0xbb, 0xeb, 0x4c, 0xf1, 0x21, 0x62, + 0xdd, 0x44, 0xca, 0xce, 0xf7, 0xbb, 0xf8, 0x3d, 0x44, 0x84, 0x47, 0x0, + 0x44, 0xf4, 0x26, 0xd7, 0x8a, 0x24, 0x14, 0x99, 0xaa, 0x93, 0x86, 0x48, + 0x86, 0x2, 0x39, 0x55, 0x26, 0x76, 0xbf, 0xdc, 0x99, 0x3, 0x3b, 0x93, + 0x7d, 0x50, 0x8d, 0x75, 0x3f, 0xd7, 0xfd, 0x25, 0xcf, 0x64, 0xaf, 0xcb, + 0x66, 0x24, 0xed, 0x13, 0xbc, 0x1d, 0xe3, 0x9e, 0x21, 0xd7, 0xcb, 0xc9, + 0x1f, 0x3b, 0xc0, 0x2e, 0xad, 0xcf, 0x96, 0x2, 0x26, 0x92, 0x61, 0xce, + 0xa9, 0xea, 0xd8, 0xec, 0x15, 0x9c, 0x65, 0x12, 0x26, 0x9c, 0xf5, 0x79, + 0x3e, 0x3c, 0xa5, 0x80, 0x4f, 0xf2, 0xb4, 0x95, 0x75, 0xf4, 0x57, 0x20, + 0xf0, 0xf5, 0x89, 0x58, 0x19, 0x92, 0x25, 0x86, 0x41, 0x82, 0x8c, 0x31, + 0x23, 0x71, 0xf4, 0xbf, 0x13, 0xd6, 0xcb, 0xc7, 0xff, 0x2f, 0x96, 0x7a, + 0x7c, 0xec, 0xcd, 0xa6, 0xba, 0x21, 0x14, 0xf, 0x4, 0x6f, 0xa7, 0x10, + 0xc4, 0x8f, 0xb4, 0xb9, 0xa9, 0x5c, 0x59, 0x94, 0xa0, 0xf1, 0xf9, 0x60, + 0xc3, 0xf0, 0xe4, 0xf5, 0x2f, 0xe4, 0x98, 0xf0, 0xe0, 0x88, 0x88, 0xa1, + 0xd5, 0xdf, 0x9b, 0xb4, 0x33, 0xa0, 0x29, 0xa3, 0xbb, 0xd5, 0x1c, 0x71, + 0x5d, 0xec, 0x60, 0x9f, 0x40, 0x20, 0x64, 0xf, 0x26, 0x18, 0x17, 0xdc, + 0x1f, 0x68, 0x8d, 0x1c, 0x57, 0xf0, 0x14, 0xbc, 0xb1, 0xec, 0x60, 0x5a, + 0x9a, 0xe8, 0x49, 0xfb, 0x64, 0x41, 0xbf, 0x14, 0x69, 0x40, 0x5c, 0xb8, + 0x8c, 0x96, 0x21, 0x5c, 0x4d, 0xae, 0x75, 0x22, 0x9c, 0x94, 0x1f, 0xf8, + 0xb, 0xab, 0xc0, 0x67, 0xd4, 0x58, 0x56, 0xfa, 0xb5, 0x23, 0xef, 0x1c, + 0x4d, 0x91, 0xde, 0x6a, 0x27, 0x69, 0x17, 0x54, 0x94, 0xbe, 0x32, 0x3f, + 0x8d, 0x13, 0x66, 0x45, 0x9c, 0xf0, 0x7, 0x16, 0x9, 0xf0, 0xe, 0x9a, + 0x6e, 0x8c, 0x28, 0x8a, 0xc9, 0x2b, 0x2b, 0x89, 0x30, 0x9f, 0xde, 0xf7, + 0xbd, 0x55, 0x4f, 0x1d, 0xf4, 0xeb, 0x80, 0xf3, 0x41, 0x5d, 0xe0, 0x1a, + 0x54, 0xb6, 0x44, 0x46, 0x71, 0xc8, 0xe2, 0xfa, 0x98, 0x20, 0xcd, 0x35, + 0x46, 0xb4, 0xd0, 0x5d, 0x94, 0xed, 0xd8, 0x9c, 0xda, 0x2a, 0x5c, 0xec, + 0x7, 0xb2, 0x22, 0xa3, 0xce, 0xa6, 0x43, 0x4d, 0x49, 0xf8, 0x78, 0x68, + 0xa7, 0x3, 0xed, 0xfb, 0x52, 0x9f, 0x92, 0x16, 0x84, 0x72, 0xd7, 0x94, + 0x53, 0x1a, 0x91, 0xb7, 0x1d, 0xbf, 0x91, 0x7c, 0x2d, 0x65, 0x28, 0x5f, + 0xff, 0xb0, 0xfb, 0xe4, 0xa3, 0xf5, 0x35, 0x74, 0x11, 0x59, 0x64, 0x45, + 0x44, 0xeb, 0x7a, 0xf7, 0xca, 0x2d, 0x73, 0x9d, 0x4, 0x25, 0xb5, 0xad, + 0xde, 0xd4, 0x17, 0xc5, 0x55, 0x66, 0x19, 0xb1, 0x61, 0x47, 0x45, 0x6c, + 0x99, 0x8, 0xe9, 0x83, 0x8e, 0x84, 0x5f, 0xf6, 0xca, 0x5, 0x42, 0x8, + 0x7d, 0x69, 0x8f, 0x69, 0x89, 0x6e, 0x84, 0x44, 0x44, 0x52, 0x98, 0xc3, + 0x90, 0xa9, 0xfa, 0xf, 0xd0, 0x2, 0xe2, 0x6f, 0xbb, 0x23, 0xe2, 0x5b, + 0x34, 0xb1, 0xfc, 0x48, 0xaf, 0xbe, 0x96, 0x1a, 0xe, 0x5c, 0x5e, 0xa, + 0xaf, 0x1a, 0xc4, 0x5f, 0x13, 0x65, 0x3f, 0x7c, 0xd6, 0x27, 0x9e, 0xfc, + 0x53, 0x37, 0x59, 0x40, 0x48, 0x9, 0x24, 0xfa, 0x59, 0x45, 0xf, 0xc0, + 0xae, 0xa1, 0x71, 0x9, 0xb, 0x77, 0x41, 0xe0, 0xdd, 0xaa, 0xfe, 0xc4, + 0x31, 0x2b, 0x90, 0xfa, 0x28, 0x5c, 0x88, 0x67, 0xd7, 0xcf, 0x40, 0x31, + 0x8c, 0x85, 0x6, 0xd, 0x8, 0x3e, 0x5e, 0x3c, 0x87, 0xf, 0x3f, 0x7b, + 0x22, 0x3d, 0x47, 0x3e, 0xdf, 0x9b, 0x72, 0x8c, 0x77, 0x29, 0xd5, 0xfe, + 0x5d, 0x16, 0x91, 0x87, 0x6d, 0x45, 0x92, 0x7d, 0xea, 0x13, 0x7c, 0xc9, + 0x94, 0xc3, 0xb, 0xf7, 0x49, 0xf3, 0x22, 0xd5, 0x5b, 0x60, 0xda, 0xc3, + 0x53, 0x6e, 0x70, 0x8d, 0x87, 0x79, 0x6e, 0x90, 0xd3, 0x6a, 0x7c, 0xae, + 0xc8, 0x28, 0xb, 0x9c, 0x6, 0xf6, 0xdb, 0x1e, 0x4b, 0x18, 0x34, 0x69, + 0x1c, 0x3c, 0x1a, 0xf4, 0xf8, 0x9c, 0xc8, 0x7f, 0xf9, 0x40, 0xf2, 0xb1, + 0x3f, 0xa, 0x56, 0xc7, 0xc5, 0x3c, 0x31, 0xdb, 0x8f, 0x1b, 0xc3, 0x5, + 0x0, 0xd4, 0x8c, 0x34, 0x73, 0xc, 0xa7, 0x3e, 0xd1, 0xca, 0x8b, 0x6e, + 0x42, 0x71, 0xfc, 0x62, 0x90, 0x4c, 0x33, 0xca, 0xdd, 0x4d, 0xc9, 0xe0, + 0x38, 0xb4, 0xa8, 0x50, 0xd4, 0x18, 0x7d, 0xd4, 0x59, 0x4d, 0x2, 0xdb, + 0xbd, 0x92, 0x60, 0xf1, 0x7e, 0x61, 0x36, 0xf5, 0x2a, 0x55, 0x8f, 0x32, + 0x3d, 0x21, 0xa7, 0xa, 0x23, 0x35, 0xe7, 0xb4, 0x35, 0x83, 0x6a, 0x35, + 0xbd, 0xe7, 0xfc, 0x55, 0x1a, 0x53, 0xc1, 0x63, 0xe4, 0x89, 0xa8, 0xce, + 0xc8, 0x23, 0x55, 0x17, 0xea, 0xa8, 0xe9, 0xf2, 0xe9, 0x4e, 0x6f, 0xf8, + 0x78, 0xa7, 0xdf, 0xe0, 0x75, 0xf4, 0x2e, 0x3, 0xb5, 0x57, 0x99, 0xb3, + 0x93, 0x1f, 0xf0, 0x7, 0x43, 0xc6, 0x3a, 0xf2, 0x5d, 0xae, 0xd7, 0xe6, + 0x1b, 0x4c, 0x8a, 0x5, 0x35, 0x12, 0x74, 0x25, 0x76, 0x8d, 0x83, 0xba, + 0xbe, 0x25, 0x4f, 0x10, 0x5e, 0xd2, 0xc8, 0xc5, 0xa8, 0xdc, 0x31, 0x2c, + 0xe9, 0x18, 0x40, 0x3d, 0x4a, 0x4a, 0x5f, 0xd7, 0xf0, 0xfa, 0xd9, 0xa0, + 0x6e, 0x0, 0x14, 0xf7, 0xa9, 0xe6, 0x6e, 0x43, 0xb3, 0x80, 0x95, 0x1f, + 0x2d, 0x72, 0x77, 0x3f, 0x2f, 0xbc, 0xc4, 0xea, 0x5f, 0xaa, 0xa1, 0x1f, + 0x55, 0x94, 0x94, 0xe8, 0x9f, 0x21, 0x28, 0xbd, 0xd, 0x4a, 0x39, 0x4c, + 0xac, 0x27, 0xd, 0xf3, 0x4c, 0x34, 0xc7, 0xc, 0xf8, 0x4f, 0x70, 0x7, + 0xa7, 0x49, 0x63, 0x1, 0xc7, 0xe9, 0xb9, 0xc6, 0xe6, 0x4a, 0x26, 0xec, + 0xfd, 0x73, 0xb3, 0x45, 0xe9, 0x69, 0xf4, 0x2c, 0x1e, 0xc5, 0xd7, 0xa, + 0x1d, 0x95, 0xd6, 0x9b, 0x4c, 0xb0, 0xa, 0x80, 0x45, 0x98, 0x70, 0x80, + 0xa7, 0x15, 0xc7, 0x8, 0x76, 0xa9, 0x87, 0x99, 0xcb, 0xeb, 0x44, 0xb2, + 0x36, 0xdd, 0x75, 0x60, 0x13, 0x75, 0x33, 0xe1, 0xb8, 0x3b, 0xde, 0xac, + 0xcc, 0xc, 0x15, 0x2c, 0x4a, 0xb5, 0x7b, 0x65, 0x49, 0x1f, 0x1, 0x4c, + 0x56, 0xcb, 0x5d, 0x8f, 0x99, 0xcc, 0xc4, 0x21, 0xe7, 0x6c, 0x84, 0x89, + 0xac, 0x9c, 0x50, 0x77, 0x32, 0xf9, 0xc8, 0xf2, 0x61, 0x87, 0x3f, 0xc7, + 0x69, 0xff, 0xb7, 0xbd, +}; +const uint8_t kAltGameImages2xE[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, + 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, + 0xa2, 0x67, 0x30, 0xc1, 0x9a, 0x9b, 0x60, 0x1, 0x9e, 0x5f, 0xc3, 0xba, + 0xdb, 0xdc, 0x7, 0xf7, 0x41, 0x11, 0xf3, 0xe3, 0x98, 0x14, 0xfe, 0x57, + 0xa4, 0x20, 0x8e, 0xf5, 0x2, 0x52, 0xd0, 0xac, 0x81, 0xb2, 0x93, 0x5a, + 0x67, 0xee, 0x2e, 0x8d, 0x87, 0xf5, 0x49, 0x93, 0x75, 0x76, 0x34, 0x1a, + 0x3a, 0x76, 0xdd, 0x5f, 0x8f, 0xdf, 0x5, 0x5e, 0xea, 0xa8, 0xb9, 0xae, + 0xf9, 0xd, 0x87, 0xa0, 0x66, 0x68, 0x6, 0xfe, 0xad, 0xc7, 0xe2, 0x12, + 0x88, 0xd1, 0x3f, 0x6d, 0xd7, 0x6d, 0xb0, 0x7, 0x71, 0xe2, 0x75, 0x88, + 0x8b, 0xb6, 0xb5, 0xcd, 0x7d, 0x67, 0xe3, 0x80, 0x4f, 0xcc, 0x63, 0xd3, + 0x8f, 0x1a, 0x4, 0xd6, 0xe5, 0xf3, 0x56, 0xa, 0x21, 0x18, 0x56, 0x7b, + 0x1, 0x15, 0x46, 0x19, 0xb8, 0xd4, 0xe8, 0xad, 0xb9, 0x49, 0x13, 0x3e, + 0x8f, 0x27, 0xfd, 0x38, 0xe4, 0x85, 0x58, 0xae, 0x30, 0x2a, 0x8, 0x69, + 0xa4, 0x22, 0xef, 0xcc, 0x3b, 0x26, 0x9f, 0x57, 0xc4, 0x9b, 0x7e, 0x3b, + 0xf3, 0x72, 0xb3, 0x2a, 0x27, 0x18, 0xd9, 0xc4, 0xf3, 0x1e, 0x9a, 0xda, + 0x71, 0x29, 0x1d, 0xf3, 0xaf, 0x85, 0xc, 0x5e, 0x53, 0x90, 0xc0, 0x33, + 0x44, 0x88, 0x51, 0x59, 0xd8, 0x95, 0xbc, 0x31, 0xed, 0xed, 0x35, 0x7, + 0xf4, 0xb2, 0x8a, 0xe6, 0x84, 0x19, 0xab, 0xed, 0xab, 0xae, 0xce, 0x9, + 0x30, 0xee, 0xa9, 0x3d, 0xf0, 0xf8, 0x67, 0xfa, 0xaf, 0xeb, 0x7e, 0xb0, + 0x79, 0xe3, 0xfc, 0x2, 0xc3, 0x74, 0xf6, 0x69, 0xbd, 0x3c, 0xef, 0xf0, + 0x3c, 0x85, 0xc2, 0xf4, 0x7c, 0xe3, 0xef, 0x2f, 0x54, 0x8e, 0x1f, 0x95, + 0xbb, 0x40, 0x5d, 0x2f, 0x0, 0x5, 0xc3, 0x39, 0x8b, 0xbe, 0x51, 0x77, + 0xbe, 0xe8, 0x5b, 0x6e, 0x16, 0x27, 0x94, 0xda, 0xba, 0x3e, 0x2f, 0xb1, + 0x61, 0x77, 0x2d, 0xfe, 0x2a, 0x5a, 0x70, 0xd2, 0xab, 0xdb, 0x46, 0x7a, + 0xb6, 0x42, 0x86, 0xbf, 0x97, 0x9f, 0xa, 0xa3, 0xc1, 0x82, 0x2c, 0x58, + 0x21, 0xba, 0xad, 0x61, 0xab, 0x4d, 0x31, 0xe1, 0xd8, 0x81, 0x59, 0xfb, + 0x29, 0xe9, 0xaf, 0xef, 0x79, 0xfa, 0x9, 0x4a, 0x32, 0x3, 0xa9, 0xc, + 0x7d, 0xb5, 0x8b, 0x28, 0xbf, 0xfb, 0xae, 0xd7, 0x55, 0x5f, 0x10, 0x7d, + 0xc6, 0xe8, 0x87, 0x2d, 0x6e, 0xdb, 0x84, 0xa7, 0xbb, 0x2d, 0xb4, 0x8b, + 0x49, 0xf1, 0x3c, 0x7a, 0xdd, 0x7e, 0xcc, 0x4b, 0x1d, 0x5d, 0x1f, 0x3e, + 0x3c, 0xf3, 0xcd, 0x4f, 0xde, 0x17, 0xe2, 0xcc, 0x1d, 0x9b, 0x6e, 0x34, + 0xf3, 0xca, 0x4b, 0xda, 0x0, 0xb7, 0xc4, 0x82, 0x5e, 0x97, 0xbb, 0x59, + 0x7d, 0xe8, 0x76, 0x5c, 0x5b, 0x7d, 0x79, 0x41, 0x29, 0x32, 0xe1, 0xa7, + 0xce, 0x82, 0x51, 0xbe, 0x7, 0x81, 0x8, 0x79, 0xc1, 0x94, 0x65, 0xf9, + 0xfb, 0x6e, 0xa2, 0x52, 0xe5, 0xc, 0xa6, 0x9e, 0xe4, 0xcd, 0xa8, 0x76, + 0xb3, 0xb1, 0x97, 0xc6, 0x37, 0xb0, 0x59, 0xe2, 0x93, 0x9b, 0xc5, 0x9d, + 0x4b, 0xc7, 0xcf, 0x6b, 0xd2, 0x3d, 0x74, 0xda, 0x7e, 0xd1, 0x92, 0xf3, + 0xd2, 0xb7, 0x86, 0x53, 0x25, 0x2a, 0xdf, 0x6d, 0xe2, 0x6, 0x25, 0x38, + 0x36, 0xb2, 0x39, 0xe1, 0x2e, 0xa, 0xe9, 0x18, 0xfe, 0x37, 0xfe, 0x3f, + 0xcd, 0x1a, 0xcf, 0x9, 0xb6, 0xfd, 0x90, 0xc0, 0x8a, 0x28, 0xde, 0xa9, + 0x94, 0xa, 0x77, 0xf3, 0x22, 0xf8, 0xbc, 0xa6, 0xba, 0x1a, 0xb7, 0x3b, + 0x1f, 0x80, 0x4c, 0x1f, 0xa6, 0x59, 0xb9, 0x64, 0x73, 0xfa, 0x4c, 0xe8, + 0x1a, 0xd5, 0x9, 0xa5, 0x2e, 0x24, 0xb0, 0x68, 0xf0, 0x68, 0x12, 0xef, + 0x72, 0x2b, 0x1, 0x15, 0xfc, 0xd9, 0x70, 0x41, 0x1, 0xa6, 0x94, 0x89, + 0x3f, 0x76, 0x25, 0x79, 0xf8, 0x5d, 0x24, 0xe, 0x83, 0xdb, 0x8a, 0xfb, + 0x93, 0xeb, 0x61, 0x63, 0xc0, 0x4e, 0xf8, 0x7e, 0x55, 0xf0, 0xfe, 0x2c, + 0xf7, 0x18, 0xd7, 0x83, 0x29, 0x3, 0x68, 0xf5, 0xd9, 0xd0, 0x20, 0x52, + 0x63, 0x5, 0xbd, 0x74, 0x15, 0xe6, 0xab, 0xf2, 0x49, 0x34, 0xe7, 0x20, + 0xb1, 0x12, 0xbd, 0x87, 0x14, 0x82, 0xbc, 0xef, 0x79, 0x1c, 0x4e, 0xdd, + 0x62, 0x0, 0xba, 0x87, 0x4e, 0x64, 0xe5, 0x9b, 0x97, 0xf4, 0x2b, 0xc, + 0x22, 0x65, 0x35, 0x35, 0xa6, 0xb0, 0x80, 0x75, 0x14, 0x35, 0x2e, 0x9a, + 0xdb, 0x75, 0x92, 0x2, 0xec, 0x33, 0x53, 0x43, 0x57, 0x44, 0x19, 0x7e, + 0x5e, 0x2c, 0x3e, 0x49, 0xa9, 0xa8, 0xb1, 0x26, 0x5f, 0xa3, 0x21, 0x96, + 0xee, 0x66, 0x2d, 0x27, 0x8d, 0x36, 0xaf, 0xe3, 0x80, 0x15, 0xce, 0x8c, + 0xff, 0xa8, 0xd4, 0x7a, 0x7f, 0x28, 0x99, 0x8, 0xe9, 0x13, 0x3, 0x2e, + 0x83, 0x26, 0xa4, 0x36, 0x3d, 0x1f, 0xcf, 0x2, 0x5c, 0x7b, 0x0, 0x3c, + 0xb, 0x18, 0xa2, 0xe4, 0x1b, 0x13, 0xbf, 0x67, 0x61, 0x7d, 0x27, 0x6c, + 0xbf, 0xa, 0xfd, 0xcf, 0x74, 0xa8, 0x74, 0x3a, 0xdd, 0xe3, 0x81, 0xb9, + 0x2f, 0xda, 0x95, 0xd, 0xfa, 0xf7, 0x7c, 0xd7, 0xf6, 0xc6, 0xca, 0x7a, + 0x2d, 0xf2, 0xe1, 0xd9, 0xf5, 0xcd, 0xff, 0x75, 0x79, 0x32, 0xe7, 0xb1, + 0x6e, 0xf4, 0xa9, 0xe4, 0xbd, 0xdc, 0xf2, 0xcd, 0xa4, 0xaf, 0xa5, 0xa7, + 0xf2, 0x27, 0xc1, 0x1d, 0x70, 0x0, 0xa7, 0xa6, 0xf3, 0x6b, 0x2c, 0xef, + 0x84, 0x59, 0xba, 0xfc, 0x4e, 0x92, 0xe, 0x29, 0x5e, 0xfa, 0x96, 0x5f, + 0xde, 0x1b, 0x34, 0x1a, 0x58, 0x2f, 0xfd, 0x62, 0x22, 0xb9, 0xdd, 0x38, + 0xf0, 0x70, 0x9, 0x30, 0x47, 0x5b, 0x3a, 0x38, 0x49, 0x77, 0x44, 0xc, + 0x22, 0x5c, 0xb0, 0x5f, 0x17, 0x52, 0x50, 0xd8, 0x51, 0x7e, 0x96, 0xcc, + 0x3d, 0xea, 0x7f, 0x25, 0x6d, 0xdb, 0x39, 0x97, 0x71, 0xc3, 0xea, 0xbd, + 0x71, 0x92, 0x2f, 0x4d, 0xe9, 0x5d, 0xac, 0x26, 0x41, 0x71, 0x42, 0xfa, + 0xe3, 0x8c, 0x22, 0xfa, 0x85, 0xc5, 0x21, 0xca, 0x85, 0x70, 0xc9, 0x69, + 0xbf, 0x48, 0x95, 0x6, 0x7a, 0x33, 0x77, 0xf3, 0x76, 0x7a, 0x9b, 0x4e, + 0xf3, 0xd2, 0xd1, 0x8f, 0xbd, 0x3c, 0xe2, 0xa8, 0xe7, 0x7b, 0xde, 0xa, + 0xaf, 0x3e, 0x6e, 0x21, 0x96, 0xe, 0x52, 0x93, 0x75, 0x97, 0x6b, 0x6, + 0xbf, 0x9e, 0x50, 0x51, 0xa, 0xdc, 0x96, 0x15, 0x62, 0x1, 0x94, 0x2d, + 0x44, 0x2a, 0xc0, 0xc0, 0xf, 0x8c, 0xd6, 0x63, 0x74, 0x73, 0x99, 0xe5, + 0x49, 0xad, 0xf5, 0xb4, 0x41, 0x97, 0x6, 0xbc, 0x81, 0x6c, 0x40, 0xd7, + 0x45, 0x6f, 0x72, 0xa5, 0x51, 0xf8, 0xc0, 0xa1, 0x4e, 0xce, 0x75, 0x93, + 0x85, 0x5f, 0xe8, 0x8b, 0x5e, 0x6b, 0x48, 0xc1, 0xf8, 0x55, 0xea, 0xc6, + 0xc5, 0x7, 0x83, 0x33, 0xcc, 0x1f, 0x55, 0xe1, 0xc9, 0xe4, 0x6d, 0x31, + 0x3c, 0x41, 0x5c, 0xa8, 0xec, 0x82, 0xfa, 0x30, 0x87, 0xfa, 0x16, 0x90, + 0x16, 0x29, 0xb5, 0x4b, 0x7e, 0xb9, 0xc5, 0x32, 0xc8, 0xb2, 0xa6, 0x59, + 0xfa, 0x80, 0x26, 0x1, 0xfb, 0x3c, 0xe4, 0x3b, 0xb5, 0x2, 0x7b, 0xd, + 0xf7, 0x5a, 0xaa, 0x8, 0x51, 0xa0, 0x54, 0x7d, 0x1, 0x28, 0x31, 0x14, + 0x3b, 0x24, 0x1f, 0x25, 0x9e, 0xd5, 0x51, 0x2a, 0x1f, 0xad, 0xd7, 0x34, + 0x46, 0x95, 0x74, 0x48, 0xa4, 0x1e, 0x62, 0xd1, 0x29, 0x84, 0xfc, 0x7b, + 0x75, 0x36, 0xfe, 0xa1, 0x41, 0xda, 0x6c, 0xe9, 0x59, 0xf8, 0xd0, 0x68, + 0x7a, 0x4b, 0x93, 0x26, 0xb9, 0x28, 0xf5, 0xdd, 0x7a, 0xd7, 0xb6, 0x69, + 0xae, 0xd0, 0x4c, 0xc3, 0x98, 0xca, 0x12, 0xc, 0x55, 0x59, 0x96, 0x59, + 0xde, 0xad, 0xac, 0xbd, 0xe3, 0xb, 0x48, 0x3c, 0x13, 0x80, 0xbf, 0x49, + 0x59, 0xfa, 0x38, 0x82, 0x9b, 0x9, 0x33, 0xbc, 0x9c, 0x17, 0x93, 0x93, + 0xad, 0x8e, 0x58, 0x3f, 0x5, 0x40, 0x75, 0x3f, 0xf7, 0xcd, 0x54, 0x8d, + 0x52, 0x8d, 0xf6, 0xeb, 0xbc, 0x31, 0x4a, 0xce, 0xb2, 0x3f, 0xc8, 0x8e, + 0x52, 0x7a, 0xa4, 0x46, 0xea, 0x1e, 0x9a, 0xa, 0x69, 0x20, 0x98, 0x98, + 0x45, 0xb0, 0xed, 0xa2, 0x6b, 0x65, 0xec, 0x6d, 0x53, 0xba, 0xaf, 0xb1, + 0xe7, 0xf7, 0x41, 0xbf, 0x35, 0x97, 0xc1, 0xb7, 0xa2, 0xe4, 0x8e, 0x93, + 0xea, 0x1b, 0xb1, 0xb5, 0xe3, 0x65, 0xab, 0xd1, 0x28, 0xd8, 0x50, 0x86, + 0x33, 0x86, 0x60, 0x26, 0xf4, 0x56, 0x48, 0xe5, 0x54, 0x6a, 0x17, 0x44, + 0x46, 0x76, 0x55, 0x4f, 0x43, 0xaf, 0x28, 0x99, 0x7b, 0x96, 0x6e, 0x7c, + 0xcb, 0xb9, 0xcc, 0x1c, 0xf, 0x84, 0x4a, 0x80, 0x53, 0x4c, 0x42, 0xcd, + 0xf0, 0x23, 0x2d, 0x3f, 0x8d, 0x2, 0x79, 0xc0, 0x7d, 0xce, 0x7d, 0xe5, + 0xfb, 0xe4, 0x7b, 0x65, 0x65, 0x6, 0x30, 0x44, 0x4e, 0x36, 0x85, 0x44, + 0x5a, 0x32, 0x47, 0x23, 0xe5, 0x98, 0x80, 0xb2, 0xb8, 0x5a, 0x1c, 0x84, + 0x86, 0x2, 0x71, 0x6d, 0xbe, 0x99, 0x88, 0xd, 0x26, 0x2e, 0x95, 0x1d, + 0xde, 0xb8, 0x2d, 0x40, 0xd5, 0xec, 0x7a, 0xb1, 0x8b, 0x6b, 0x67, 0xf4, + 0x2a, 0x93, 0xb4, 0xcb, 0xef, 0xab, 0x24, 0x13, 0x2b, 0xa1, 0x34, 0x18, + 0xa0, 0x28, 0xfe, 0xb3, 0x5, 0x3, 0x92, 0x49, 0x9, 0xa, 0xf2, 0x63, + 0xde, 0xd1, 0xf9, 0xfb, 0x50, 0xc1, 0x4, 0x26, 0xc8, 0x8b, 0xf2, 0x20, + 0x8, 0xb4, 0xbb, 0x45, 0x15, 0x3a, 0x27, 0xb4, 0xd3, 0x27, 0x85, 0xbc, + 0x8, 0x8f, 0xf1, 0xa2, 0x42, 0x16, 0x19, 0xb6, 0xc6, 0x11, 0x6f, 0x39, + 0x6c, 0x69, 0x53, 0xc, 0x31, 0x9e, 0x57, 0x4, 0x71, 0xf5, 0xf7, 0xff, + 0x11, 0xc4, 0x65, 0xde, 0x22, 0x11, 0x37, 0x3, 0x4c, 0x56, 0x4d, 0xf8, + 0x40, 0x34, 0x32, 0x69, 0x2, 0x54, 0xaf, 0x96, 0x10, 0x18, 0xd9, 0x35, + 0xf, 0x53, 0x53, 0x69, 0x9c, 0x36, 0x95, 0x62, 0x57, 0xf9, 0xed, 0xf0, + 0x41, 0x97, 0x72, 0xdb, 0x1c, 0xb6, 0xda, 0xab, 0x7a, 0x24, 0xac, 0x89, + 0x97, 0x15, 0x37, 0x6e, 0xfe, 0xef, 0x3c, 0xfc, 0x16, 0x91, 0x4b, 0xf0, + 0x57, 0x4a, 0xbc, 0x48, 0xe, 0x8, 0xe, 0x81, 0xe8, 0x8e, 0x98, 0x29, + 0x6, 0x58, 0xfc, 0xc1, 0x80, 0x1c, 0x63, 0x3c, 0x6a, 0xa7, 0xe4, 0x78, + 0x13, 0x53, 0xb6, 0x4b, 0xb2, 0x67, 0xc9, 0xfd, 0x3b, 0x6e, 0xaf, 0xd0, + 0xd5, 0x2b, 0x38, 0xf9, 0xc0, 0x0, 0x4, 0xc4, 0x25, 0xf9, 0xd2, 0x2a, + 0x83, 0xec, 0x1d, 0x49, 0x27, 0xda, 0xf8, 0xd1, 0x9e, 0x8e, 0x37, 0x73, + 0x6e, 0xb6, 0x25, 0x65, 0x39, 0xf9, 0xef, 0x74, 0xb6, 0xd3, 0x16, 0x94, + 0x9c, 0x6e, 0xac, 0xc6, 0x8b, 0x13, 0xc, 0xcf, 0x28, 0x94, 0xe9, 0xed, + 0x2e, 0xe4, 0x75, 0xc4, 0xe7, 0x1e, 0xc9, 0xd3, 0xad, 0xa9, 0x35, 0x7f, + 0x23, 0x8a, 0x88, 0x6, 0x3b, 0x89, 0xcc, 0x6, 0xc0, 0xc1, 0x79, 0x5e, + 0x70, 0x6c, 0xc2, 0x9b, 0x76, 0x22, 0x99, 0x5c, 0xbe, 0xcf, 0x16, 0x2a, + 0x47, 0x98, 0xfb, 0xe6, 0x83, 0x83, 0x8c, 0xab, 0x27, 0xc6, 0xb2, 0x5e, + 0x76, 0x2, 0x85, 0xf, 0x91, 0x19, 0x38, 0x57, 0xbc, 0x6f, 0xd9, 0x5, + 0xac, 0xf3, 0x7e, 0xfc, 0x68, 0x3, 0xb3, 0x4f, 0x96, 0xab, 0x84, 0x71, + 0x58, 0xce, 0xd9, 0x61, 0xfe, 0xd6, 0x1c, 0xd1, 0xcc, 0xb2, 0x7e, 0xc8, + 0x3a, 0x41, 0x9d, 0x5b, 0x64, 0xc2, 0xf2, 0xd8, 0xa1, 0x9e, 0xfa, 0xec, + 0xea, 0xf9, 0x1c, 0x35, 0x71, 0xe5, 0x42, 0xec, 0x8e, 0x46, 0x17, 0x9b, + 0x8e, 0xdc, 0x7e, 0x81, 0x1, 0x1b, 0xab, 0x2e, 0x9d, 0xea, 0xe0, 0x28, + 0xe7, 0x70, 0xdd, 0x8d, 0xf7, 0x19, 0x4f, 0xb, 0x60, 0x2e, 0xca, 0x7d, + 0x7a, 0x11, 0x2d, 0x1e, 0xa2, 0xe, 0x9f, 0x15, 0x8b, 0x8a, 0x58, 0x9d, + 0xd0, 0x0, 0xe, 0xc9, 0x6b, 0xde, 0x94, 0x88, 0xcf, 0x1d, 0x71, 0x44, + 0x9c, 0x1, 0x74, 0x69, 0x71, 0x14, 0xf9, 0x62, 0x7, 0x9e, 0xa2, 0x87, + 0xa6, 0x4f, 0xa6, 0x5, 0xe, 0xfd, 0x1e, 0xf5, 0xa6, 0xe4, 0x30, 0x9b, + 0x39, 0x91, 0xe0, 0x3c, 0xbd, 0x72, 0x30, 0x84, 0x85, 0xb5, 0x67, 0xad, + 0xf, 0x87, 0x88, 0xf8, 0x83, 0x1, 0x3c, 0x14, 0x7f, 0x72, 0xee, 0x58, + 0x62, 0xa1, 0xf0, 0x46, 0x65, 0x7e, 0x74, 0xbf, 0xc6, 0xee, 0x74, 0x85, + 0x46, 0xe, 0x82, 0x8c, 0x48, 0x40, 0x66, 0x99, 0x6d, 0x97, 0x7d, 0x35, + 0x5b, 0x2a, 0x48, 0x77, 0xd2, 0xd2, 0x32, 0x35, 0x7e, 0xa1, 0x4c, 0xa8, + 0x64, 0x8d, 0x30, 0xa4, 0xe3, 0xe0, 0x9a, 0x4, 0x73, 0x9a, 0xef, 0x46, + 0x82, 0x38, 0x7b, 0x58, 0x6e, 0xaf, 0xe5, 0x38, 0x13, 0xa1, 0xe0, 0x65, + 0x6a, 0xda, 0x88, 0x47, 0xde, 0xf3, 0xc4, 0x4c, 0xca, 0xdb, 0xf9, 0x6e, + 0x4e, 0xe8, 0xd9, 0x8, 0x8a, 0x84, 0x90, 0x8f, 0x7b, 0xc0, 0x9e, 0x86, + 0x29, 0x38, 0xbc, 0xf0, 0x13, 0xb4, 0xee, 0xc8, 0xb2, 0xc6, 0xb4, 0xdf, + 0x22, 0x68, 0x27, 0x9d, 0x6, 0x76, 0x65, 0xfd, 0xe0, 0xbf, 0xe9, 0x0, + 0xe9, 0x17, 0x29, 0x7f, 0xf1, 0x8c, 0xf1, 0xc, 0x21, 0xe3, 0xa2, 0x8d, + 0xc8, 0xf1, 0x36, 0x62, 0x60, 0x98, 0xd9, 0x24, 0xc2, 0xba, 0x2c, 0x83, + 0x99, 0x1, 0xcc, 0x73, 0xd, 0x52, 0x14, 0x98, 0xd6, 0xf3, 0x6c, 0x48, + 0x44, 0x83, 0xe6, 0x5c, 0xfa, 0x41, 0x1d, 0xb8, 0x1c, 0xf6, 0xf6, 0x89, + 0xab, 0xbd, 0x7c, 0x45, 0x87, 0xed, 0xc6, 0x2b, 0x94, 0x22, 0x8b, 0xfd, + 0xa4, 0x7a, 0x64, 0xf7, 0xab, 0x29, 0xb7, 0x2, 0xb7, 0xc4, 0xba, 0xa2, + 0x15, 0x15, 0x26, 0x19, 0x82, 0x89, 0x52, 0x73, 0x32, 0xb4, 0xd6, 0xae, + 0x3b, 0x42, 0xb, 0xbe, 0x4c, 0xff, 0x3c, 0xe4, 0xa3, 0x98, 0x77, 0x32, + 0x3e, 0x3b, 0x7f, 0x98, 0x40, 0x7e, 0x5f, 0xa2, 0x24, 0x39, 0xfd, 0x25, + 0x93, 0x51, 0xe3, 0x1b, 0x47, 0xe2, 0xce, 0xc7, 0x3d, 0x8d, 0x4a, 0x96, + 0xd7, 0x13, 0xf0, 0x39, 0x28, 0xc7, 0xbd, 0xfd, 0x68, 0xee, 0x31, 0x4d, + 0x9e, 0xaa, 0xc2, 0x7, 0x7a, 0x6d, 0xfc, 0x66, 0x80, 0x7a, 0xca, 0xe5, + 0xff, 0x78, 0x28, 0xca, 0xe5, 0xa, 0x1, 0x52, 0x2, 0xf4, 0x3d, 0x37, + 0x3c, 0x3f, 0x72, 0xa5, 0x7f, 0x2a, 0xa2, 0x4d, 0x63, 0x65, 0x60, 0xe9, + 0x51, 0x18, 0xdb, 0x59, 0x3d, 0xb2, 0xe3, 0xb0, 0x3f, 0xf0, 0x97, 0x9b, + 0xc4, 0x51, 0x7f, 0x88, 0xfb, 0x85, 0x61, 0xea, 0xaa, 0xb3, 0x6e, 0xd6, + 0x8f, 0x1b, 0x1e, 0xb7, 0x8d, 0x25, 0xed, 0x7c, 0x59, 0xd4, 0xd5, 0x14, + 0x95, 0xc, 0x2f, 0x8e, 0xa5, 0x48, 0xfa, 0x14, 0xf1, 0x7b, 0x2a, 0x21, + 0xd5, 0xc4, 0x75, 0x2, 0xe4, 0x49, 0xd, 0x9b, 0x2e, 0x83, 0x13, 0x22, + 0xe6, 0xdf, 0xf2, 0xfc, 0xf8, 0xa7, 0x5a, 0xd2, 0xe1, 0x7a, 0x27, 0xe9, + 0x8b, 0x3, 0xa1, 0xde, 0xe1, 0x27, 0xd8, 0xfc, 0x2c, 0x6a, 0x67, 0x85, + 0xdc, 0x1d, 0x1f, 0x59, 0x10, 0x99, 0xce, 0x2e, 0x48, 0x86, 0xf6, 0x9c, + 0xf6, 0x79, 0x79, 0x7c, 0xdf, 0x8e, 0xa3, 0x14, 0x9a, 0xa3, 0xe5, 0xf3, + 0x74, 0x62, 0x62, 0x37, 0x83, 0x89, 0xf2, 0xd7, 0xda, 0xdd, 0x5, 0x11, + 0xaf, 0xc1, 0xe4, 0x2a, 0xaa, 0xa7, 0xc0, 0xa6, 0x2a, 0xc5, 0x17, 0xa7, + 0xea, 0x23, 0x56, 0xea, 0x3d, 0x52, 0x32, 0x31, 0x16, 0xb1, 0x4d, 0xa8, + 0x0, 0x44, 0x59, 0x7a, 0xf7, 0x6b, 0x5, 0x4d, 0x5c, 0xf8, 0xe, 0xa, + 0x48, 0x63, 0xe5, 0x94, 0xef, 0x74, 0x8e, 0x47, 0x3e, 0xd9, 0xb1, 0x2d, + 0x15, 0xaf, 0x52, 0x6e, 0x63, 0xe6, 0x88, 0x5d, 0xcd, 0xc0, 0x8a, 0xd2, + 0xa, 0x96, 0x24, 0x1, 0xe5, 0xe6, 0xad, 0xf1, 0xee, 0xe6, 0xbb, 0xa1, + 0x5f, 0x50, 0x63, 0x1d, 0xa, 0xec, 0xda, 0xb1, 0xff, 0x7a, 0x4d, 0x83, + 0x24, 0xcd, 0xde, 0x38, 0x31, 0x7f, 0xe5, 0x93, 0x2d, 0x3e, 0x3c, 0xa8, + 0x55, 0x81, 0x7b, 0xa2, 0x5f, 0xfb, 0xa7, 0xa7, 0x1b, 0x27, 0xd9, 0x22, + 0x19, 0xce, 0x66, 0xc6, 0x59, 0x60, 0xeb, 0xdc, 0x45, 0x6, 0xe2, 0xf3, + 0xfd, 0x43, 0x3d, 0x5e, 0x72, 0xd, 0x62, 0x70, 0xfd, 0x61, 0x43, 0xe4, + 0x2f, 0xc5, 0x58, 0x70, 0x18, 0xa2, 0xee, 0xb9, 0xaa, 0x20, 0x3c, 0x4d, + 0x7f, 0xf5, 0xc3, 0x29, 0x4d, 0x43, 0x20, 0xb1, 0x50, 0x84, 0x38, 0x56, + 0xb4, 0x94, 0xa2, 0x5, 0xa3, 0x84, 0xae, 0x41, 0x17, 0x53, 0x51, 0xe1, + 0x2f, 0x4a, 0xa6, 0xa7, 0x8b, 0x5, 0x4b, 0x2f, 0x50, 0xfd, 0xaa, 0xa0, + 0xe1, 0x59, 0xe6, 0x1b, 0x94, 0x46, 0x17, 0x29, 0x4f, 0xdc, 0x4e, 0x46, + 0xff, 0xd1, 0xa9, 0x6a, 0x3f, 0xa7, 0x33, 0x13, 0x85, 0x8, 0xd1, 0x40, + 0xdc, 0x95, 0xe0, 0x53, 0xdc, 0x6c, 0xf4, 0xee, 0xd4, 0x90, 0x76, 0x64, + 0xc, 0x43, 0x54, 0x44, 0x2d, 0x73, 0xed, 0x63, 0x99, 0xe3, 0x2, 0xad, + 0x4e, 0x10, 0xc, 0x8f, 0x31, 0x6b, 0x53, 0xeb, 0xc7, 0x6f, 0xfd, 0x3a, + 0xfe, 0xb2, 0x78, 0x35, 0xc, 0x2b, 0x34, 0xeb, 0x9a, 0x9d, 0xf9, 0x93, + 0x18, 0xcf, 0xeb, 0x43, 0xb5, 0xaa, 0x89, 0xdd, 0xec, 0x80, 0xd4, 0xbc, + 0x4a, 0x45, 0xea, 0x56, 0x2, 0xb2, 0xb5, 0xe9, 0xb3, 0x8a, 0x5e, 0x30, + 0xf7, 0x76, 0xeb, 0xf0, 0x25, 0x4c, 0x5d, 0xe9, 0x76, 0x9, 0x5f, 0x7f, + 0x54, 0xe5, 0xd0, 0xa0, 0xf, 0xb4, 0xcc, 0x27, 0x1, 0xa4, 0x95, 0x15, + 0x4, 0xc0, 0xc8, 0x0, 0x16, 0xb6, 0x78, 0xe7, 0x79, 0xd1, 0x1a, 0x5e, + 0xfc, 0xaa, 0x2a, 0xc4, 0xb3, 0xc3, 0x62, 0x39, 0xde, 0x4c, 0xb7, 0x4b, + 0x4f, 0x5c, 0xe1, 0x58, 0x7f, 0x4c, 0x7e, 0x81, 0x9a, 0xbc, 0x57, 0xbd, + 0x1d, 0xae, 0xc7, 0x5a, 0x6f, 0xf8, 0xa7, 0x8c, 0x64, 0xee, 0xb6, 0x88, + 0x7d, 0xaf, 0x96, 0xfb, 0xf2, 0x60, 0xae, 0xdc, +}; +const uint8_t kAltGameImages2xF[] = { + 0xc2, 0xff, 0x83, 0xa7, 0x7c, 0xe3, 0x9f, 0xd0, 0x89, 0xac, 0xe8, 0x95, + 0x5a, 0xc4, 0xf7, 0xb0, 0x8, 0x8d, 0xb, 0xc, 0x42, 0xf3, 0x6b, 0xb6, + 0x72, 0xa4, 0xba, 0x25, 0x21, 0x64, 0x7b, 0xac, 0x29, 0xa3, 0xa8, 0xaa, + 0x9c, 0x8a, 0xfe, 0x4, 0xe6, 0xc8, 0x54, 0xf6, 0x2b, 0xa1, 0x37, 0xe8, + 0xc1, 0x94, 0xe1, 0xdb, 0x36, 0x75, 0xce, 0xc5, 0x42, 0xa6, 0x31, 0xb, + 0x5a, 0x1d, 0xfe, 0x74, 0x44, 0xeb, 0x75, 0xc4, 0xd, 0x40, 0x68, 0xe6, + 0x1, 0x76, 0xfa, 0x61, 0x5e, 0x9d, 0x1d, 0x1b, 0x84, 0xb6, 0xa4, 0x9, + 0x5, 0xe0, 0x92, 0x93, 0x79, 0xed, 0xa1, 0x37, 0x42, 0xdd, 0xeb, 0xbc, + 0x80, 0xaa, 0x2e, 0xe6, 0xa8, 0x5c, 0xa3, 0x9a, 0xaf, 0x14, 0x61, 0xaa, + 0xf4, 0x79, 0x1c, 0x2c, 0xd7, 0x1b, 0xcb, 0x22, 0x11, 0x3d, 0xd9, 0x41, + 0x9d, 0xb8, 0x56, 0xf3, 0x62, 0xd0, 0x6e, 0xef, 0xbb, 0xcd, 0x9d, 0xdf, + 0x9e, 0xaa, 0x38, 0xd3, 0x93, 0xaa, 0x92, 0xb2, 0x95, 0x7, 0x98, 0x8f, + 0xb6, 0x3f, 0x9a, 0xc7, 0x2b, 0x95, 0x4, 0x94, 0xbe, 0xe4, 0x9b, 0x1d, + 0x4e, 0x62, 0x2b, 0xb9, 0x39, 0x17, 0x6, 0xdb, 0x57, 0x86, 0xdd, 0x22, + 0x27, 0xa5, 0x82, 0x16, 0x7a, 0xd6, 0xc7, 0xa5, 0x56, 0x46, 0x44, 0xc8, + 0x68, 0xd8, 0x30, 0xe7, 0xbd, 0xea, 0xb5, 0x74, 0x3, 0x9d, 0x57, 0x1c, + 0x8e, 0xe2, 0x17, 0x4d, 0xa3, 0x2b, 0xb7, 0xab, 0x21, 0xe0, 0x33, 0xe, + 0x20, 0x2c, 0xb1, 0x2f, 0x1, 0x8e, 0xaf, 0x36, 0x4, 0x77, 0x42, 0x4, + 0xb0, 0x39, 0xc0, 0x11, 0x59, 0xd1, 0xba, 0x8d, 0xf0, 0xfd, 0x37, 0xcf, + 0xec, 0xe9, 0xb9, 0x87, 0xe, 0xda, 0xd4, 0xbf, 0xe1, 0x9e, 0xe9, 0xd1, + 0x29, 0xb0, 0xcf, 0xb0, 0xdf, 0xbe, 0x14, 0x7, 0xe5, 0xe0, 0x20, 0xe5, + 0x6f, 0x39, 0x6d, 0x53, 0x35, 0xa8, 0x4d, 0x4a, 0x30, 0x54, 0xfb, 0x96, + 0x80, 0x4d, 0x44, 0xb6, 0x87, 0x66, 0x72, 0xcd, 0x63, 0x61, 0xf1, 0x2d, + 0xb1, 0x9c, 0x7, 0x51, 0x48, 0xc1, 0x53, 0x40, 0x0, 0x4f, 0x42, 0x4b, + 0xbc, 0x3c, 0x7e, 0x3d, 0xc2, 0xaf, 0xe4, 0x36, 0x95, 0x3a, 0x7c, 0xf6, + 0x14, 0xa0, 0xd4, 0x3d, 0x89, 0xb7, 0xa0, 0x4d, 0x57, 0x41, 0x9e, 0xa4, + 0x33, 0x6f, 0x28, 0x5a, 0x76, 0x17, 0x0, 0xd2, 0xe0, 0x88, 0xc, 0x43, + 0x42, 0xc8, 0xb4, 0xdc, 0x24, 0xc3, 0xd7, 0x8, 0x48, 0xe1, 0x76, 0xb8, + 0x6c, 0xbd, 0x7c, 0x72, 0xb2, 0x9d, 0xf, 0x7, 0x62, 0x3a, 0xf4, 0xd7, + 0x7b, 0xee, 0x8e, 0xba, 0x1, 0x45, 0x15, 0xfa, 0x55, 0xbd, 0x25, 0xba, + 0x7a, 0xfe, 0x83, 0x22, 0x9c, 0xca, 0x7b, 0x46, 0xb8, 0xcf, 0xfa, 0x16, + 0x1c, 0x74, 0x57, 0x75, 0x43, 0x26, 0x10, 0xad, 0x57, 0xff, 0xd4, 0xa7, + 0xe9, 0xfa, 0xeb, 0x84, 0x9f, 0xdc, 0x34, 0x63, 0x5e, 0x5, 0x8d, 0xc2, + 0xa6, 0x2e, 0x13, 0x8d, 0x33, 0xcc, 0x25, 0x2f, 0x4, 0xfb, 0x95, 0xcd, + 0x8d, 0x29, 0xd5, 0x9e, 0xaa, 0x14, 0x7b, 0xa3, 0xda, 0x1b, 0xa3, 0xc4, + 0x24, 0x75, 0xf1, 0x95, 0xbd, 0xb8, 0x1f, 0x8c, 0xe9, 0xb0, 0x78, 0xee, + 0x6b, 0x3a, 0x9a, 0x70, 0x1, 0x8, 0xf, 0x5f, 0xde, 0xdf, 0xd5, 0x2c, + 0x22, 0xbf, 0xc2, 0xbf, 0xcf, 0x7b, 0x7f, 0x58, 0x5c, 0x1e, 0xdf, 0xcd, + 0xe7, 0x4a, 0x52, 0xf7, 0x3d, 0xba, 0x2f, 0x3f, 0x55, 0x45, 0x7b, 0x9b, + 0xfc, 0xd0, 0xd4, 0xd3, 0xe0, 0x92, 0xa5, 0x9c, 0x1f, 0xd1, 0xef, 0xbb, + 0x93, 0xd3, 0x6b, 0x48, 0x59, 0xf1, 0xba, 0xf3, 0xf1, 0x4a, 0x29, 0x83, + 0xa8, 0x65, 0x8f, 0x46, 0x60, 0xb0, 0x8c, 0x10, 0xaa, 0xd1, 0xf5, 0xa0, + 0x1, 0xd5, 0x38, 0xeb, 0x14, 0x88, 0x60, 0x95, 0x17, 0xdc, 0x1f, 0xb9, + 0x55, 0xff, 0x9a, 0x5d, 0x46, 0x67, 0xa2, 0xa0, 0x7b, 0xd9, 0x7b, 0xdb, + 0x8f, 0xac, 0x43, 0x94, 0xa8, 0xdf, 0xc2, 0xc2, 0xa1, 0xec, 0xf0, 0x8c, + 0x6e, 0x35, 0x3f, 0xd3, 0x39, 0xcf, 0xee, 0x80, 0x23, 0xa, 0x73, 0x74, + 0x78, 0x1f, 0x19, 0x5d, 0xb, 0x88, 0xae, 0x3c, 0x67, 0x60, 0x85, 0xdd, + 0x2, 0x46, 0x51, 0x5c, 0x55, 0xba, 0x15, 0x24, 0xd2, 0x98, 0x70, 0x14, + 0x19, 0xa, 0x31, 0x3f, 0x38, 0x80, 0x85, 0x48, 0xde, 0xc2, 0xd, 0x67, + 0xc1, 0x46, 0xd3, 0x93, 0x49, 0x22, 0xa0, 0x4, 0xfe, 0xe6, 0xaa, 0x6f, + 0xa0, 0x2f, 0x7c, 0x22, 0x5, 0x49, 0xdf, 0xee, 0x2, 0x4d, 0x35, 0x4c, + 0xd1, 0x5d, 0x6d, 0xe3, 0xe2, 0x5a, 0xc4, 0x5e, 0x43, 0x1e, 0x47, 0x41, + 0xf9, 0xb7, 0x0, 0x53, 0x3a, 0xc3, 0x5e, 0xa5, 0x81, 0x36, 0x22, 0xe9, + 0x25, 0x38, 0xfe, 0x3a, 0x7d, 0xf2, 0xee, 0x33, 0x30, 0x72, 0x6e, 0x81, + 0xa1, 0x7, 0x1b, 0xc4, 0x83, 0x68, 0xde, 0x8e, 0x90, 0xde, 0x43, 0x73, + 0xda, 0xb2, 0x75, 0x7a, 0xfd, 0x0, 0x21, 0xd2, 0x15, 0x58, 0x45, 0x65, + 0x10, 0x26, 0x7a, 0x68, 0xfe, 0x9b, 0x31, 0xb5, 0xaa, 0xad, 0x9a, 0x92, + 0x2e, 0x77, 0x68, 0xc5, 0x90, 0x4, 0xd6, 0x18, 0x6d, 0xf6, 0x99, 0x33, + 0x99, 0xcd, 0x2, 0xc7, 0x20, 0x4b, 0x1f, 0x18, 0xc0, 0x6d, 0x4f, 0xe3, + 0x41, 0x79, 0xcd, 0x7f, 0x11, 0xe, 0xdd, 0xee, 0x9a, 0x3f, 0x9, 0xa0, + 0xc, 0x1f, 0xe1, 0x83, 0x3d, 0xd6, 0x8f, 0xb, 0xb6, 0x12, 0x47, 0x9f, + 0x7e, 0x4b, 0xaa, 0x23, 0x13, 0xed, 0xee, 0xbb, 0x3d, 0x72, 0xab, 0xfe, + 0xd2, 0xed, 0x7b, 0xc7, 0xf9, 0xeb, 0xb3, 0x3f, 0x72, 0xd0, 0x15, 0xb8, + 0x98, 0xb8, 0x60, 0xd9, 0x5f, 0x3, 0x4d, 0x9, 0xfe, 0x28, 0x68, 0xdb, + 0x2, 0x4d, 0xd7, 0xc5, 0xbd, 0x7a, 0xf6, 0x16, 0x1a, 0xd0, 0xc5, 0x32, + 0x42, 0x17, 0x7f, 0x3b, 0x67, 0x1a, 0xa5, 0x44, 0x2a, 0xb3, 0x17, 0x81, + 0x94, 0x75, 0x38, 0x30, 0xa7, 0x31, 0xa2, 0xfa, 0x92, 0x25, 0xcb, 0x1a, + 0x39, 0x58, 0xdc, 0x3f, 0x5c, 0xb5, 0xa0, 0xbd, 0xdf, 0xa6, 0xe8, 0x8e, + 0x9f, 0x2e, 0x2d, 0xa2, 0x3e, 0x3e, 0x37, 0xcc, 0x8d, 0x4e, 0x82, 0x44, + 0xc, 0xac, 0x80, 0xf7, 0xd6, 0x19, 0x71, 0xf6, 0xcb, 0x28, 0x40, 0x68, + 0x98, 0xee, 0xec, 0x2b, 0x9e, 0x4, 0xcd, 0xa1, 0xbf, 0x4c, 0xa5, 0x1b, + 0x47, 0xea, 0x43, 0xf5, 0xb0, 0xc4, 0x64, 0xba, 0x54, 0x89, 0x1b, 0x67, + 0xd9, 0x12, 0x6f, 0x6d, 0x3, 0x42, 0xb4, 0xe4, 0x2d, 0x1f, 0x45, 0x50, + 0x87, 0x5d, 0x6a, 0xd6, 0xf9, 0xf8, 0xc1, 0xa6, 0xc5, 0x99, 0x8b, 0xc3, + 0x2d, 0xac, 0x29, 0xee, 0x31, 0x75, 0xcf, 0xd1, 0xb0, 0x4e, 0x67, 0xa2, + 0x56, 0x42, 0xc5, 0x3b, 0x42, 0x9b, 0x2b, 0xa7, 0xe3, 0x4e, 0x92, 0xa4, + 0xd3, 0xf8, 0xf9, 0x6c, 0x64, 0x64, 0x9e, 0xd7, 0x74, 0x67, 0xbb, 0xa3, + 0x4e, 0x24, 0xf, 0x90, 0xbf, 0x92, 0x24, 0xa0, 0xb0, 0x4c, 0x7b, 0xb7, + 0x9f, 0x8e, 0x76, 0x5e, 0x45, 0x51, 0xe2, 0xdc, 0x69, 0xb0, 0x4d, 0x9e, + 0xd6, 0xb0, 0x45, 0x48, 0x64, 0x17, 0x1e, 0xad, 0xbb, 0x24, 0xf8, 0x12, + 0xf5, 0x94, 0x3c, 0xdc, 0xf9, 0xf8, 0x7f, 0x51, 0x3b, 0x80, 0xad, 0x6f, + 0x1b, 0xe3, 0x98, 0x60, 0x6e, 0xf5, 0xd1, 0x4a, 0x6a, 0xf8, 0x66, 0x26, + 0xf8, 0xa, 0xb6, 0x3f, 0xd9, 0x91, 0x7c, 0x79, 0xb1, 0x2b, 0xa8, 0x2c, + 0x77, 0x7d, 0xa2, 0x2e, 0x85, 0x80, 0x9c, 0xcc, 0xb9, 0x67, 0xc7, 0x56, + 0xaf, 0xcc, 0x49, 0xee, 0x3c, 0x47, 0xf1, 0x6d, 0xb, 0xe4, 0x2c, 0xd3, + 0xbc, 0xfc, 0x6, 0xa7, 0x44, 0xc5, 0xbe, 0x87, 0x7f, 0xbc, 0x17, 0xb, + 0x41, 0x9e, 0x6b, 0x78, 0xeb, 0xeb, 0xae, 0x5a, 0x60, 0x8f, 0x6f, 0x7c, + 0x45, 0x4b, 0xd1, 0x99, 0x67, 0x6b, 0x43, 0x1d, 0xb9, 0x52, 0x95, 0x98, + 0x17, 0x2a, 0xd6, 0xdf, 0x40, 0x8d, 0x5c, 0x52, 0x13, 0x19, 0x57, 0xbf, + 0x10, 0x35, 0x9e, 0xda, 0x70, 0xe6, 0x27, 0x4b, 0xc4, 0x36, 0xb7, 0x74, + 0xe9, 0xf8, 0x85, 0x17, 0x8c, 0x1a, 0x84, 0x85, 0xfb, 0x56, 0xbd, 0x70, + 0xfc, 0xb5, 0x70, 0xba, 0x79, 0x91, 0x8a, 0x20, 0x54, 0x26, 0x56, 0x8d, + 0xff, 0xa0, 0xc1, 0x4c, 0x9f, 0x9b, 0x97, 0xc5, 0xf, 0xb6, 0x79, 0x14, + 0x2e, 0x57, 0x92, 0xdb, 0x89, 0x87, 0x5e, 0x21, 0xb8, 0xa1, 0x60, 0x6f, + 0xfe, 0xab, 0x49, 0x96, 0x2c, 0xd, 0x64, 0x31, 0xe6, 0x47, 0xd6, 0x5d, + 0x18, 0x1b, 0xeb, 0xdc, 0x35, 0xcc, 0x61, 0x84, 0x9c, 0xe8, 0xb9, 0x15, + 0x34, 0x86, 0x6f, 0xfc, 0x15, 0x7d, 0xb9, 0xa3, 0xb4, 0xdf, 0x2, 0x1c, + 0x25, 0x67, 0xfc, 0x75, 0x5f, 0xb9, 0x1b, 0x9a, 0xc8, 0xf3, 0xdd, 0x8c, + 0x6f, 0xb8, 0xab, 0x30, 0x57, 0x80, 0xc5, 0x63, 0x5, 0x63, 0xbe, 0x74, + 0x73, 0xe4, 0xd6, 0xfe, 0xea, 0x53, 0xc2, 0x55, 0xe8, 0xcd, 0xc7, 0xbc, + 0x72, 0xb4, 0xb, 0xf1, 0xb1, 0xde, 0xdf, 0x17, 0xe4, 0xd, 0xba, 0xfb, + 0x83, 0x71, 0xdf, 0xe7, 0xdb, 0x26, 0x3b, 0xc3, 0x0, 0x57, 0xcb, 0x17, + 0x94, 0xb5, 0x8, 0x1b, 0xb5, 0xf3, 0x48, 0xf7, 0x95, 0x8f, 0x78, 0x1d, + 0xb4, 0xf9, 0x38, 0x6e, 0x2f, 0x59, 0xe8, 0x52, 0x4, 0x8b, 0x80, 0x1b, + 0xa4, 0xd6, 0x44, 0x43, 0xd6, 0x55, 0xd2, 0x5c, 0x51, 0x67, 0x6d, 0xb7, + 0x70, 0xb3, 0xad, 0x45, 0xe3, 0x4d, 0x71, 0x57, 0x86, 0x8c, 0xc3, 0x6d, + 0xf7, 0x8b, 0xd8, 0xc4, 0x3e, 0x78, 0x91, 0x28, 0x4d, 0xf7, 0x55, 0x60, + 0x3f, 0xcb, 0x97, 0x4f, 0xc9, 0x9f, 0x9, 0x6c, 0x97, 0x9f, 0xc, 0xc, + 0xdf, 0xb0, 0x33, 0xf2, 0xf, 0x48, 0xcf, 0x52, 0xe8, 0x38, 0x35, 0x84, + 0x6b, 0x33, 0x48, 0x92, 0xba, 0xb0, 0xbf, 0x55, 0x85, 0xd8, 0xf6, 0x64, + 0xcb, 0x57, 0xcd, 0x6b, 0x52, 0xf4, 0xa5, 0x31, 0xf3, 0x5, 0x86, 0xa2, + 0x6b, 0x1f, 0xa2, 0x7, 0xb8, 0x20, 0x3d, 0xce, 0x6a, 0xf, 0xdc, 0xa, + 0x8a, 0x23, 0xb6, 0xfc, 0x76, 0x76, 0xb1, 0xac, 0x7c, 0xb, 0x23, 0x5b, + 0x7b, 0x90, 0xda, 0x3b, 0xf4, 0x43, 0x48, 0xa5, 0x2, 0x99, 0xe6, 0x21, + 0x7f, 0x3b, 0xe1, 0x63, 0xa8, 0xd7, 0x2e, 0x82, 0xc3, 0x40, 0xd1, 0x98, + 0xee, 0xb, 0x65, 0x67, 0x1d, 0xa, 0x51, 0x57, 0x80, 0x9f, 0xa3, 0xde, + 0x20, 0xa2, 0x79, 0x2b, 0x7d, 0xf4, 0xa5, 0xf4, 0x83, 0xeb, 0x63, 0x65, + 0xb7, 0x41, 0xbf, 0x69, 0xdb, 0x9d, 0x13, 0x15, 0xc0, 0xbc, 0x4d, 0x84, + 0xfe, 0x73, 0x21, 0xd9, 0x1d, 0xa0, 0x33, 0xaf, 0x4, 0x33, 0x9e, 0xf9, + 0xa8, 0xc1, 0xae, 0xaa, 0xa7, 0xc, 0xf4, 0x17, 0xda, 0x59, 0x6a, 0x31, + 0x6f, 0x16, 0xf0, 0xa, 0x0, 0x24, 0xc3, 0x6a, 0xa2, 0x50, 0x50, 0xc9, + 0xdf, 0xb, 0xb6, 0x1f, 0x6f, 0x5e, 0x78, 0x76, 0x29, 0x92, 0x62, 0x62, + 0x91, 0xbc, 0x49, 0x9a, 0xa1, 0xa7, 0x33, 0x3d, 0xf6, 0xdd, 0x68, 0xa3, + 0xf7, 0x42, 0x5a, 0x93, 0xda, 0xb0, 0xa6, 0x8, 0x8f, 0x69, 0x2c, 0x85, + 0xf, 0xf4, 0x96, 0x3, 0xd5, 0xa8, 0xba, 0x28, 0xaf, 0x63, 0xba, 0x55, + 0xbb, 0x97, 0xa4, 0x5b, 0xa, 0x26, 0xf1, 0x7b, 0x28, 0xb7, 0x1f, 0x27, + 0x4b, 0xa6, 0xbe, 0xe5, 0x78, 0x57, 0xf3, 0x77, 0x39, 0xba, 0xf, 0x69, + 0x24, 0x1e, 0x2e, 0x38, 0x9c, 0xba, 0xad, 0xa7, 0x86, 0xa0, 0xfd, 0x2e, + 0xe5, 0x63, 0xb5, 0xb6, 0x6d, 0x54, 0x55, 0xe0, 0xb0, 0x65, 0xb6, 0x34, + 0xce, 0xe, 0xf5, 0x2d, 0xc1, 0x26, 0x2e, 0xc8, 0xbc, 0x2b, 0x7c, 0xfe, + 0xd6, 0xee, 0xd9, 0xc, 0xf6, 0x5d, 0x60, 0xc5, 0x9b, 0xd5, 0xa3, 0xfe, + 0x83, 0x5f, 0x26, 0x7a, 0xcc, 0xb1, 0x5d, 0xe3, 0xad, 0x34, 0x8, 0x64, + 0x44, 0x95, 0x3b, 0xa9, 0xb3, 0x43, 0x3f, 0xec, 0x93, 0x39, 0xc1, 0xa8, + 0x27, 0x49, 0xca, 0xae, 0x70, 0xf, 0x11, 0x54, 0xb2, 0x6b, 0x64, 0x3b, + 0x9d, 0x7a, 0xf5, 0x2c, 0x9a, 0x43, 0x7d, 0xc6, 0x54, 0x9a, 0xfa, 0x9e, + 0xad, 0xcd, 0x94, 0x15, 0xfc, 0x89, 0x89, 0xbe, 0xaa, 0x9e, 0x8f, 0xbb, + 0x6, 0x22, 0x42, 0x5, 0xa0, 0x61, 0xb5, 0x58, 0xd7, 0x58, 0xa2, 0xb8, + 0xfd, 0x4, 0xf3, 0x64, 0x3f, 0x9b, 0x69, 0xcc, 0xc, 0x7a, 0x34, 0x88, + 0x13, 0xeb, 0x90, 0x8e, 0x33, 0x27, 0xe, 0x65, 0xcd, 0x81, 0xe0, 0x0, + 0xbf, 0xa1, 0x94, 0x3e, 0x91, 0xbf, 0x54, 0x3f, 0x2f, 0xc6, 0x30, 0xee, + 0xc1, 0x39, 0xf7, 0x4a, 0xbe, 0xbd, 0xb3, 0xcb, 0x91, 0x16, 0xad, 0xc4, + 0xb6, 0x3e, 0xc8, 0x6c, 0xc1, 0xb5, 0x66, 0x1b, 0xa0, 0x97, 0x2a, 0x30, + 0x6c, 0x20, 0xe5, 0xec, 0x4e, 0xd7, 0xe3, 0xea, 0x3a, 0xd5, 0x41, 0x99, + 0xd0, 0x95, 0xe3, 0x8b, 0x19, 0xee, 0x92, 0x11, 0x84, 0x13, 0xa7, 0x1e, + 0x65, 0xb5, 0xc8, 0x23, 0x3d, 0xb3, 0x89, 0x30, 0xda, 0xdd, 0x1f, 0xe9, + 0x55, 0x3c, 0x22, 0xee, 0x18, 0xa, 0x92, 0x5c, 0x61, 0xc7, 0x39, 0xd, + 0xea, 0x1b, 0xe4, 0xb, 0x5, 0x6e, 0x7b, 0x8e, 0xd0, 0xd5, 0xa5, 0x6b, + 0x3, 0xaf, 0x8b, 0xb7, 0x75, 0x24, 0xc7, 0xf9, 0x1d, 0x32, 0xea, 0xa9, + 0xe5, 0xa5, 0x1a, 0x41, 0x82, 0xdd, 0xc8, 0x86, 0x82, 0x85, 0xcd, 0xe, + 0x89, 0xa4, 0x4a, 0xe0, 0x6a, 0xf4, 0xe, 0x26, 0x33, 0x33, 0xa1, 0x3a, + 0xd2, 0xde, 0xff, 0x2f, 0xa6, 0x8a, 0x7a, 0x9e, 0x44, 0xab, 0xed, 0x53, + 0x30, 0xdf, 0xfd, 0x95, 0xac, 0x6d, 0x82, 0xd, 0x5e, 0x35, 0xc8, 0x3b, + 0xb6, 0x59, 0x93, 0x1d, 0x6b, 0x8c, 0x27, 0x5e, 0x2, 0xa9, 0xa1, 0x64, + 0x65, 0xe3, 0xbf, 0x52, 0x87, 0x26, 0x10, 0x6, 0x5a, 0xaf, 0x7c, 0x10, + 0x44, 0x7e, 0x46, 0xfa, 0xc, 0x85, 0xe5, 0x74, 0x92, 0xf6, 0xd8, 0x8, + 0x59, 0xe8, 0x46, 0xc3, 0x5b, 0x2c, 0x3, 0xda, 0xb3, 0x17, 0xbf, 0x71, + 0x3e, 0xbd, 0xe3, 0x41, 0x1f, 0xad, 0xa4, 0x9f, 0x31, 0x8d, 0x38, 0x5f, + 0x83, 0x92, 0x26, 0x8f, 0xe, 0xe4, 0xcc, 0xdb, 0xf4, 0x83, 0x62, 0x34, + 0xd7, 0xb9, 0xd0, 0x29, 0xa9, 0x4a, 0xba, 0xf2, 0xe2, 0x18, 0x23, 0x30, + 0x27, 0x10, 0xf, 0x2e, 0xad, 0x40, 0xab, 0xed, 0xda, 0x76, 0xd6, 0x4e, + 0x60, 0x80, 0x2a, 0xe3, 0x23, 0x79, 0x27, 0xaa, 0xc8, 0xa4, 0xce, 0x1f, + 0x4f, 0x88, 0x5b, 0x55, 0x83, 0x47, 0x88, 0x56, 0xd4, 0xe9, 0x79, 0x9b, + 0x7d, 0x83, 0x83, 0x4d, 0x26, 0xe3, 0x90, 0xdf, 0xbf, 0x6c, 0xa0, 0x4f, + 0x78, 0x7f, 0x69, 0x86, 0xe7, 0x54, 0xfd, 0x4b, 0x24, 0xe9, 0xb6, 0x46, + 0xf3, 0xdc, 0xae, 0x5e, 0x2c, 0x21, 0x8e, 0xd5, 0x4d, 0x30, 0x25, 0xfa, + 0xcd, 0xb, 0x4b, 0x8, 0x4b, 0x7e, 0x15, 0x60, 0x30, 0xba, 0x75, 0xbd, + 0xfb, 0xe2, 0x49, 0x1, 0xcb, 0xff, 0x3f, 0x23, 0xde, 0xdb, 0xc4, 0xb9, + 0x26, 0x36, 0xb5, 0xc1, 0xd9, 0xc8, 0x63, 0xe0, 0x48, 0xd9, 0xe0, 0xd2, + 0x52, 0xf7, 0x15, 0x94, 0xf2, 0x1c, 0xc, 0x32, 0xe0, 0xfe, 0xf0, 0xb5, + 0x3, 0xa6, 0x50, 0xbd, 0xf3, 0x13, 0x95, 0x92, 0xe9, 0x11, 0xd9, 0x75, + 0xe5, 0xef, 0x94, 0x20, 0xff, 0xff, 0x79, 0xb1, 0x45, 0x27, 0xec, 0x69, + 0xf7, 0xe3, 0x2d, 0x9e, 0x36, 0x7a, 0xec, 0xcc, 0xcb, 0x57, 0xce, 0x11, + 0xcb, 0x60, 0x95, 0x19, 0x49, 0x32, 0x7d, 0xd4, 0x5d, 0x1b, 0x97, 0x3d, + 0xde, 0xd5, 0xb4, 0x4b, 0x8a, 0x31, 0x52, 0x10, 0xb4, 0xe1, 0x35, 0x3a, + 0x10, 0xb5, 0x4b, 0xf8, 0x83, 0xff, 0x7e, 0x90, 0xb6, 0x37, 0x61, 0x4a, + 0xad, 0x80, 0x80, 0x78, 0x67, 0xcf, 0xcb, 0x70, 0x5d, 0xcf, 0x78, 0x46, + 0x1a, 0xa2, 0xfe, 0x68, 0xe3, 0x0, 0x27, 0xc, 0x3a, 0x1, 0xed, 0x89, + 0x11, 0x7, 0xc7, 0x77, 0xa4, 0xe8, 0x6e, 0x7b, 0xaa, 0x7c, 0x20, 0x86, + 0xaf, 0xe2, 0x45, 0x45, 0x9f, 0xb6, 0x65, 0xbe, 0x82, 0x5f, 0xdb, 0xce, + 0x1a, 0x43, 0x15, 0xeb, 0x90, 0x1a, 0x7e, 0xce, 0x5f, 0x0, 0x45, 0xd7, + 0x5e, 0x58, 0xa, 0xde, 0xab, 0xf, 0xca, 0x46, 0x8e, 0x4a, 0x18, 0xc4, + 0xc9, 0x5a, 0xdb, 0x13, 0x2, 0xc8, 0x83, 0xaf, 0x1f, 0xd6, 0xa, 0x29, + 0xae, 0x9e, 0x5d, 0xbe, 0x8f, 0xd0, 0xb0, 0x9e, 0x68, 0x84, 0xd6, 0x4b, + 0x8, 0xa2, 0x59, 0x6d, 0x34, 0x9e, 0x0, 0x5b, 0x83, 0xbf, 0x3, 0x70, + 0x43, 0x3a, 0x15, 0xa6, 0xb0, 0x5e, 0x67, 0xf3, 0xfb, 0x4c, 0xe5, 0x2b, + 0xc1, 0x4f, 0xd5, 0x69, 0xfb, 0x71, 0x62, 0x27, 0x12, 0x35, 0x5b, 0x6e, + 0x32, 0xb4, 0xb2, 0x22, 0x3a, 0xb0, 0x4c, 0xbd, 0xf5, 0x63, 0x89, 0x70, + 0x92, 0xcb, 0x29, 0xca, 0xb7, 0xd9, 0xfe, 0xc5, 0xdb, 0xa3, 0xe3, 0xb3, + 0x36, 0xbf, 0xa8, 0x49, 0xe1, 0x72, 0x61, 0x44, 0x44, 0x21, 0xdb, 0x71, + 0x3a, 0xf2, 0x7a, 0x5c, 0x21, 0x2, 0x64, 0x38, 0xe4, 0xb9, 0xee, 0x98, + 0xd7, 0xa8, 0xde, 0xd0, 0xe1, 0x7e, 0x38, 0x55, 0x79, 0xe1, 0x9a, 0x34, + 0x82, 0xeb, 0x34, 0xd1, 0x45, 0x48, 0xa8, 0xc, 0xc8, 0xf, 0x6a, 0x40, + 0x38, 0x36, 0x92, 0xa0, 0x25, 0x4d, 0xe1, 0x4b, 0x43, 0xe5, 0x17, 0x79, + 0xdb, 0x48, 0xf7, 0x8b, 0x25, 0x4a, 0x61, 0x62, 0x59, 0x71, 0x27, 0xca, + 0x3b, 0x96, 0xe4, 0x54, 0xd8, 0x33, 0x84, 0x90, 0xf, 0x30, 0x1d, 0x10, + 0x4b, 0x99, 0x51, 0x1a, 0x6f, 0x39, 0xb, 0x14, 0xa, 0x74, 0xfe, 0x65, + 0x6a, 0x74, 0xa2, 0x63, 0xc0, 0xbd, 0x97, 0x6e, 0xd6, 0xd3, 0x21, 0x3, + 0xa9, 0x65, 0x39, 0xcf, 0x87, 0x93, 0x37, 0xdc, 0x60, 0x53, 0xbf, 0x79, + 0x6d, 0x37, 0x1b, 0x6d, 0x76, 0xc9, 0x5c, 0xc8, 0xd5, 0x51, 0xdb, 0x4a, + 0xa3, 0x54, 0x0, 0x99, 0x15, 0xab, 0xac, 0x46, 0xae, 0x45, 0xb3, 0xf8, + 0x7e, 0x98, 0x42, 0xf6, 0x95, 0x9e, 0xb5, 0x19, 0x92, 0x79, 0xf4, 0x25, + 0x9c, 0xd7, 0xec, 0xd7, 0x7a, 0x2f, 0xef, 0x82, 0x8a, 0xe0, 0x2d, 0xee, + 0x77, 0xab, 0x81, 0x39, 0x75, 0x44, 0x2b, 0xa4, 0x4b, 0x1c, 0x73, 0x8a, + 0x23, 0x8e, 0xc0, 0x1f, 0x69, 0xbd, 0x53, 0x88, 0x3e, 0xaa, 0x32, 0x1a, + 0xa, 0x93, 0xc0, 0x81, 0x8d, 0x37, 0x5e, 0xd1, 0x4, 0x1d, 0xbb, 0x3a, + 0x56, 0x47, 0xe6, 0x30, 0x7a, 0x6a, 0x6a, 0x9d, 0x4b, 0xb6, 0x4d, 0xce, + 0x26, 0x69, 0x5b, 0x5, 0x57, 0xdc, 0x33, 0x99, 0x68, 0xca, 0xca, 0xe4, + 0x42, 0xfe, 0xad, 0xa, 0x1c, 0xf2, 0xe0, 0xa5, 0x43, 0xb, 0xa4, 0xd9, + 0x9, 0xdc, 0xa1, 0xe, 0x28, 0x77, 0xab, 0xc6, 0x17, 0xc8, 0x47, 0x5e, + 0x4f, 0x3f, 0x6, 0x78, 0x70, 0x12, 0x69, 0xc9, 0x4a, 0x57, 0x87, 0x49, + 0xeb, 0x8d, 0x66, 0xb1, 0x13, 0x13, 0x6c, 0x63, 0x96, 0x6c, 0x29, 0x5e, + 0xce, 0x21, 0x1f, 0xe3, 0x8a, 0xdf, 0xac, 0x5f, 0x9b, 0x34, 0x74, 0x6, + 0x93, 0x9f, 0x4b, 0xf1, 0x50, 0x17, 0x5, 0x1c, 0xf2, 0xcb, 0x1d, 0xc6, + 0x85, 0x30, 0xf8, 0xa4, 0x2f, 0xeb, 0xaa, 0x41, 0xb3, 0xa5, 0x42, 0xfb, + 0x21, 0x4e, 0x4c, 0x4d, 0xc5, 0xda, 0xc8, 0x13, 0xb1, 0x42, 0xba, 0xfe, + 0x2, 0x39, 0x7d, 0xd, 0xcc, 0x7a, 0x18, 0x6b, 0x79, 0x19, 0x11, 0x2b, + 0x25, 0xe2, 0x4c, 0xba, 0x83, 0xb3, 0x13, 0xe9, 0x15, 0x7e, 0x3b, 0x7b, + 0x5b, 0xa3, 0xd, 0x72, 0x70, 0x54, 0xdc, 0x2c, 0xbf, 0xfa, 0x46, 0xc5, + 0xeb, 0xba, 0xb, 0x2c, 0xa1, 0xd6, 0x5a, 0xdd, 0xc8, 0xc4, 0xd, 0x58, + 0x8b, 0x94, 0x2f, 0x5f, 0x4e, 0x8c, 0xa0, 0x48, 0x5c, 0x3a, 0x9b, 0xa5, + 0xbb, 0xa3, 0x88, 0xa8, 0xa2, 0x9a, 0x9, 0xe5, 0x7c, 0x3e, 0x2b, 0x65, + 0xf8, 0x73, 0x92, 0x9e, 0x6c, 0xe7, 0x14, 0x33, 0xc1, 0xa3, 0xec, 0x90, + 0xa6, 0xc2, 0xa5, 0xe8, 0xd9, 0xf8, 0x80, 0xa4, 0xe0, 0x28, 0x36, 0x55, + 0x6b, 0xfd, 0x50, 0xc, 0x4, 0xdb, 0x87, 0xdc, 0xc8, 0x91, 0x76, 0x2c, + 0xec, 0xc4, 0xd3, 0xe1, 0x8a, 0x94, 0xe5, 0xd5, 0x4f, 0x7b, 0xd0, 0xca, + 0xa2, 0x3a, 0x33, 0xa1, 0x1f, 0x62, 0x68, 0x9b, 0x82, 0x9a, 0xd7, 0x43, + 0xcf, 0x62, 0x16, 0x40, 0xe8, 0x4d, 0x69, 0x85, 0x33, 0xad, 0x27, 0x2c, + 0xe2, 0xbb, 0x91, 0x94, 0xf4, 0x2c, 0xa9, 0x9b, 0x2, 0x2, 0xe1, 0x22, + 0x79, 0x65, 0x65, 0xac, 0xf6, 0x4e, 0x29, 0x90, 0x97, 0xf5, 0x69, 0x10, + 0x4a, 0xb1, 0xd6, 0x11, 0xfa, 0xed, 0x33, 0xab, 0x28, 0x76, 0xe8, 0x80, + 0x7f, 0xfb, 0x39, 0x20, 0xe0, 0x34, 0x4c, 0x3f, 0x15, 0x2, 0xac, 0x88, + 0x5d, 0x2d, 0x68, 0x88, 0x4e, 0x53, 0xe9, 0xac, 0x1, 0x9f, 0x73, 0x93, + 0x25, 0x3f, 0x6a, 0x56, 0x52, 0x84, 0x53, 0xf5, 0x4, 0x32, 0xea, 0xc9, + 0x75, 0xa8, 0x4d, 0x2b, 0xd7, 0x85, 0x51, 0xcd, 0x7d, 0x5e, 0xe6, 0x86, + 0xb7, 0x2d, 0x8a, 0x4, 0xce, 0x64, 0xea, 0x6, 0x34, 0x29, 0x62, 0xda, + 0x32, 0xe3, 0xb0, 0x79, 0xd3, 0xf8, 0x8e, 0xc5, 0xf, 0x56, 0x43, 0xec, + 0xc, 0x16, 0x91, 0x77, 0x3d, 0xf0, 0x77, 0x9d, 0x7, 0xb3, 0xa5, 0xc0, + 0x3a, 0x14, 0xf5, 0xc5, 0x96, 0x6c, 0x6b, 0xc9, 0xad, 0xc8, 0x66, 0xe8, + 0x6a, 0xab, 0xaa, 0x40, 0xed, 0x31, 0x8a, 0x2c, 0xf4, 0xa0, 0x41, 0x7b, + 0x28, 0x6f, 0xad, 0x30, 0x6, 0xc0, 0xff, 0xd7, 0xd5, 0x8b, 0xd0, 0x57, + 0x64, 0xc1, 0xbb, 0x76, 0x57, 0xef, 0xed, 0x3f, 0x87, 0xe5, 0x99, 0xca, + 0xd8, 0x41, 0xfd, 0x40, 0xa8, 0x1d, 0xb9, 0x4b, 0xca, 0x29, 0xe2, 0xd1, + 0xcc, 0x4b, 0x31, 0x1, 0x84, 0xe9, 0x14, 0x76, 0xb9, 0xe1, 0x28, 0x75, + 0xae, 0x56, 0x50, 0xec, 0x75, 0xd1, 0x98, 0x98, 0xa2, 0x1c, 0xea, 0xd1, + 0x35, 0xfd, 0x2f, 0x1a, 0xbf, 0x4a, 0x55, 0xa7, 0xb2, 0xc2, 0xef, 0x45, + 0x8c, 0x41, 0x40, 0x89, 0x46, 0xec, 0xab, 0x13, 0x21, 0xe8, 0x66, 0x80, + 0x57, 0x61, 0x78, 0x5f, 0x15, 0x40, 0xe2, 0xc0, 0xd0, 0x89, 0xd5, 0x9a, + 0x66, 0x16, 0x8d, 0xaa, 0x4e, 0xa1, 0x6e, 0xb7, 0xf9, 0x6c, 0xdf, 0xc9, + 0x86, 0x5e, 0x7d, 0x40, 0x76, 0xfa, 0xa6, 0x16, 0x6c, 0x49, 0x2c, 0xcc, + 0x64, 0x85, 0x92, 0xe1, 0x16, 0x67, 0xd, 0x10, 0xff, 0x4d, 0x9b, 0xc8, + 0x3f, 0x9d, 0xae, 0x84, 0x49, 0x6d, 0xb8, 0xe3, 0x8f, 0x5b, 0x3c, 0x21, + 0xf1, 0x94, 0xf5, 0x9d, 0x4, 0x90, 0x3a, 0x2e, 0xf8, 0xde, 0x32, 0xbb, + 0x4d, 0xcb, 0xdd, 0xb3, 0x47, 0xe, 0xef, 0x0, 0x39, 0x60, 0x63, 0x3d, + 0xd9, 0x2f, 0x6e, 0xfd, 0x45, 0x2e, 0xf2, 0x90, 0x37, 0xe2, 0x1b, 0x57, + 0x20, 0xa4, 0x16, 0x6d, 0x0, 0x5b, 0xe7, 0x93, 0xcf, 0x5b, 0x17, 0x22, + 0xd5, 0x44, 0x12, 0x93, 0xdc, 0x91, 0x6e, 0xa9, 0x27, 0xa6, 0x95, 0xe3, + 0xd9, 0xec, 0x95, 0x66, 0xc5, 0x9e, 0x70, 0x7f, 0x89, 0xe5, 0xcb, 0x22, + 0xb2, 0x50, 0x82, 0xc8, 0x10, 0x9e, 0xb3, 0x61, 0x75, 0xcd, 0x14, 0x3e, + 0xd2, 0xd1, 0x27, 0xfa, 0x48, 0xc3, 0x38, 0x45, 0x3d, 0xb8, 0xb2, 0x36, + 0xc9, 0xda, 0x91, 0x8c, 0x35, 0x45, 0x2c, 0x21, 0x85, 0x76, 0xad, 0x67, + 0x3f, 0xf2, 0x1a, 0x6d, 0x16, 0x58, 0x83, 0xf8, 0x15, 0x66, 0x6b, 0xdf, + 0xf8, 0x27, 0x98, 0x8, 0x9f, 0x50, 0xc0, 0x3e, 0xee, 0xf, 0x38, 0x53, + 0x41, 0x33, 0xc6, 0x61, 0x50, 0xc5, 0x49, 0x1b, 0x67, 0x57, 0xac, 0xe1, + 0x67, 0x7c, 0xe0, 0x6a, 0x80, 0x5e, 0x5d, 0xf5, 0xb3, 0xc1, 0xb, 0x27, + 0xdf, 0x72, 0xce, 0xbf, 0xaa, 0x3e, 0x9a, 0x31, 0xf9, 0xcd, 0xbf, 0x29, + 0xb4, 0x3a, 0x7, 0x81, 0x1e, 0x47, 0x1b, 0xd8, 0xf3, 0x82, 0xef, 0x13, + 0xc8, 0xf0, 0xb6, 0x13, 0x5b, 0x4c, 0xb5, 0x2f, 0x5f, 0xa4, 0xc1, 0x52, + 0xb8, 0xe, 0x90, 0x43, 0xc5, 0xa7, 0xc2, 0x36, 0x90, 0x4a, 0xdf, 0x5d, + 0xc8, 0xb7, 0x60, 0x10, 0x38, 0xd6, 0xde, 0x10, 0x7b, 0x5b, 0x76, 0x92, + 0x82, 0xc7, 0x10, 0xc3, 0xc2, 0xb8, 0xf, 0xc, 0x19, 0xaa, 0xdc, 0x15, + 0x55, 0x51, 0x55, 0xe4, 0x7d, 0x61, 0x3f, 0xaf, 0xee, 0x40, 0x53, 0x8e, + 0x7a, 0x63, 0xfe, 0xc9, 0xd6, 0xdb, 0xe3, 0x20, 0xb7, 0xd8, 0x7c, 0x90, + 0x8d, 0xad, 0x6d, 0x82, 0x1c, 0xba, 0xf3, 0xbc, 0x87, 0x1d, 0x18, 0xdc, + 0xea, 0x99, 0x70, 0xa4, +}; +const uint8_t* kAltGameImages2x[] = { + kAltGameImages2xA, kAltGameImages2xB, kAltGameImages2xC, + kAltGameImages2xD, kAltGameImages2xE, kAltGameImages2xF, }; const size_t kAltGameImages2xLength[] = { - 752, 3968, 4288, 4576, 2432, 3280, + base::size(kAltGameImages2xA), base::size(kAltGameImages2xB), + base::size(kAltGameImages2xC), base::size(kAltGameImages2xD), + base::size(kAltGameImages2xE), base::size(kAltGameImages2xF), }; -constexpr int kAltGameImagesCount = 6; +static_assert(base::size(kAltGameImages2x) == kAltGameImagesCount, ""); +static_assert(base::size(kAltGameImages2xLength) == kAltGameImagesCount, ""); std::string DecryptImage(const std::string& image_ciphertext, crypto::SymmetricKey* key) { @@ -2797,9 +2808,11 @@ return false; if (scale == 1) - *image = std::string(kAltGameImages1x[id], kAltGameImages1xLength[id]); + *image = std::string(reinterpret_cast<const char*>(kAltGameImages1x[id]), + kAltGameImages1xLength[id]); else if (scale == 2) - *image = std::string(kAltGameImages2x[id], kAltGameImages2xLength[id]); + *image = std::string(reinterpret_cast<const char*>(kAltGameImages2x[id]), + kAltGameImages2xLength[id]); else return false; return true;
diff --git a/components/feed/core/v2/BUILD.gn b/components/feed/core/v2/BUILD.gn index 960c770..94b2882 100644 --- a/components/feed/core/v2/BUILD.gn +++ b/components/feed/core/v2/BUILD.gn
@@ -212,6 +212,7 @@ "//components/prefs:test_support", "//components/signin/public/identity_manager", "//components/signin/public/identity_manager:test_support", + "//components/variations:test_support", "//components/version_info:channel", "//net:test_support", "//services/network:test_support",
diff --git a/components/feed/core/v2/feed_network_impl_unittest.cc b/components/feed/core/v2/feed_network_impl_unittest.cc index d55b2b7..28382d4 100644 --- a/components/feed/core/v2/feed_network_impl_unittest.cc +++ b/components/feed/core/v2/feed_network_impl_unittest.cc
@@ -24,6 +24,7 @@ #include "components/feed/core/v2/test/callback_receiver.h" #include "components/prefs/testing_pref_service.h" #include "components/signin/public/identity_manager/identity_test_environment.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "net/http/http_util.h" @@ -212,6 +213,8 @@ private: signin::IdentityTestEnvironment identity_test_env_; TestDelegate delegate_{&identity_test_env_}; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<FeedNetwork> feed_network_; network::TestURLLoaderFactory test_factory_; scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
diff --git a/components/feedback/BUILD.gn b/components/feedback/BUILD.gn index 7dd3bcb..c9388cc4 100644 --- a/components/feedback/BUILD.gn +++ b/components/feedback/BUILD.gn
@@ -65,6 +65,7 @@ "//components/prefs:test_support", "//components/sync_preferences:test_support", "//components/user_prefs", + "//components/variations:test_support", "//components/variations/net", "//net:test_support", "//services/network:test_support",
diff --git a/components/feedback/feedback_uploader_dispatch_unittest.cc b/components/feedback/feedback_uploader_dispatch_unittest.cc index 414b806..5e951b5 100644 --- a/components/feedback/feedback_uploader_dispatch_unittest.cc +++ b/components/feedback/feedback_uploader_dispatch_unittest.cc
@@ -15,6 +15,7 @@ #include "base/test/bind.h" #include "base/test/task_environment.h" #include "components/variations/net/variations_http_headers.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_associated_data.h" #include "components/variations/variations_ids_provider.h" #include "net/http/http_util.h" @@ -96,6 +97,8 @@ private: base::test::TaskEnvironment task_environment_; base::ScopedTempDir scoped_temp_dir_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_; @@ -104,9 +107,7 @@ TEST_F(FeedbackUploaderDispatchTest, VariationHeaders) { // Register a trial and variation id, so that there is data in variations - // headers. Also, the variations header provider may have been registered to - // observe some other field trial list, so reset it. - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); + // headers. CreateFieldTrialWithId("Test", "Group1", 123); FeedbackUploader uploader(/*is_off_the_record=*/false, state_path(), @@ -120,8 +121,6 @@ QueueReport(&uploader, "test"); base::RunLoop().RunUntilIdle(); - - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); } // Test that the bearer token is present if there is an email address present in
diff --git a/components/full_restore/arc_read_handler.cc b/components/full_restore/arc_read_handler.cc index 847b72c..a3a2197 100644 --- a/components/full_restore/arc_read_handler.cc +++ b/components/full_restore/arc_read_handler.cc
@@ -23,10 +23,16 @@ } void ArcReadHandler::AddArcWindowCandidate(aura::Window* window) { - // If the ARC task is not created yet, add |window| to - // |arc_window_candidates_| to wait for the task to be created. if (!base::Contains(task_id_to_window_id_, window->GetProperty(::full_restore::kWindowIdKey))) { + // Check `session_id` to see whether this is a ghost window. + int32_t session_id = + window->GetProperty(::full_restore::kGhostWindowSessionIdKey); + if (session_id >= kArcSessionIdOffsetForRestoredLaunching) + return; + + // If the task hasn't been created, and this is not a ghost window, add + // `window` to `arc_window_candidates_` to wait for the task to be created. arc_window_candidates_.insert(window); } }
diff --git a/components/full_restore/arc_save_handler.cc b/components/full_restore/arc_save_handler.cc index 51f28af3..bc9804a 100644 --- a/components/full_restore/arc_save_handler.cc +++ b/components/full_restore/arc_save_handler.cc
@@ -34,28 +34,78 @@ // Save |app_launch_info| to |session_id_to_app_launch_info_|, and wait for // the ARC task to be created. int32_t session_id = app_launch_info->arc_session_id.value(); + + // If the ghost window has been created for `session_id`, add + // `app_launch_info` to the restore data. + if (base::Contains(ghost_window_session_id_to_app_id_, session_id)) { + app_launch_info->window_id = session_id; + FullRestoreSaveHandler::GetInstance()->AddAppLaunchInfo( + profile_path_, std::move(app_launch_info)); + return; + } + session_id_to_app_launch_info_[session_id] = std::make_pair(std::move(app_launch_info), base::TimeTicks::Now()); MaybeStartCheckTimer(); } -void ArcSaveHandler::ModifyWindowInfo(int task_id, - const WindowInfo& window_info) { - auto it = task_id_to_app_id_.find(task_id); - if (it == task_id_to_app_id_.end()) - return; +void ArcSaveHandler::ModifyWindowInfo(const WindowInfo& window_info) { + aura::Window* window = window_info.window; - FullRestoreSaveHandler::GetInstance()->ModifyWindowInfo( - profile_path_, it->second, task_id, window_info); + int32_t task_id = window->GetProperty(::full_restore::kWindowIdKey); + auto task_it = task_id_to_app_id_.find(task_id); + if (task_it != task_id_to_app_id_.end()) { + FullRestoreSaveHandler::GetInstance()->ModifyWindowInfo( + profile_path_, task_it->second, task_id, window_info); + return; + } + + // For the ghost window, modify the window info with `session_id` as the + // window id. + int32_t session_id = + window->GetProperty(::full_restore::kGhostWindowSessionIdKey); + auto it = ghost_window_session_id_to_app_id_.find(session_id); + if (it != ghost_window_session_id_to_app_id_.end()) { + FullRestoreSaveHandler::GetInstance()->ModifyWindowInfo( + profile_path_, it->second, session_id, window_info); + } } void ArcSaveHandler::OnWindowInitialized(aura::Window* window) { int32_t task_id = window->GetProperty(::full_restore::kWindowIdKey); if (!base::Contains(task_id_to_app_id_, task_id)) { - // If the task hasn't been created, add |window| to - // |arc_window_candidates_| to wait the task to be created. - arc_window_candidates_.insert(window); + // Check `session_id` to see whether this is a ghost window. + int32_t session_id = + window->GetProperty(::full_restore::kGhostWindowSessionIdKey); + if (session_id < kArcSessionIdOffsetForRestoredLaunching) { + // If the task hasn't been created, and this is not a ghost window, add + // `window` to `arc_window_candidates_` to wait for the task to be + // created. + arc_window_candidates_.insert(window); + return; + } + + // Save `session_id` for the ghost window, to wait for the task created to + // replace the window id with the task id in the restore data. + const std::string* app_id = window->GetProperty(::full_restore::kAppIdKey); + DCHECK(app_id); + ghost_window_session_id_to_app_id_[session_id] = *app_id; + + auto it = session_id_to_app_launch_info_.find(session_id); + if (it == session_id_to_app_launch_info_.end()) + return; + + // If there is `app_launch_info`, add it to the restore data using + // `session_id` as `window_id`. + auto app_launch_info = std::move(it->second.first); + session_id_to_app_launch_info_.erase(it); + if (session_id_to_app_launch_info_.empty()) + check_timer_.Stop(); + + app_launch_info->window_id = session_id; + FullRestoreSaveHandler::GetInstance()->AddAppLaunchInfo( + profile_path_, std::move(app_launch_info)); return; } @@ -70,19 +120,40 @@ int32_t task_id = window->GetProperty(::full_restore::kWindowIdKey); auto task_it = task_id_to_app_id_.find(task_id); - if (task_it == task_id_to_app_id_.end()) + if (task_it != task_id_to_app_id_.end()) { + FullRestoreSaveHandler::GetInstance()->RemoveWindowInfo( + profile_path_, task_it->second, task_id); return; + } - FullRestoreSaveHandler::GetInstance()->RemoveWindowInfo( - profile_path_, task_it->second, task_id); + // If the ghost window has been created for `session_id`, remove + // `app_launch_info` from the restore data with `session_id` as the window id. + int32_t session_id = + window->GetProperty(::full_restore::kGhostWindowSessionIdKey); + auto it = ghost_window_session_id_to_app_id_.find(session_id); + if (it != ghost_window_session_id_to_app_id_.end()) { + FullRestoreSaveHandler::GetInstance()->RemoveWindowInfo( + profile_path_, it->second, session_id); + ghost_window_session_id_to_app_id_.erase(it); + } } void ArcSaveHandler::OnTaskCreated(const std::string& app_id, int32_t task_id, int32_t session_id) { auto it = session_id_to_app_launch_info_.find(session_id); - if (it == session_id_to_app_launch_info_.end()) + if (it == session_id_to_app_launch_info_.end()) { + auto session_it = ghost_window_session_id_to_app_id_.find(session_id); + if (session_it == ghost_window_session_id_to_app_id_.end()) + return; + + // For the ghost window, modify the window id from `session_id` to + // `task_id`. + FullRestoreSaveHandler::GetInstance()->ModifyWindowId( + profile_path_, session_it->second, session_id, task_id); + ghost_window_session_id_to_app_id_.erase(session_it); return; + } task_id_to_app_id_[task_id] = app_id;
diff --git a/components/full_restore/arc_save_handler.h b/components/full_restore/arc_save_handler.h index f340dc6..ff04942 100644 --- a/components/full_restore/arc_save_handler.h +++ b/components/full_restore/arc_save_handler.h
@@ -41,8 +41,8 @@ // for the ARC task to be created. void SaveAppLaunchInfo(AppLaunchInfoPtr app_launch_info); - // Saves |window_info| for |task_id|. - void ModifyWindowInfo(int task_id, const WindowInfo& window_info); + // Saves |window_info|. + void ModifyWindowInfo(const WindowInfo& window_info); // Invoked when |window| is initialized. void OnWindowInitialized(aura::Window* window); @@ -89,6 +89,10 @@ // property. This map is used to find the app id when save the window info. std::map<int32_t, std::string> task_id_to_app_id_; + // The map from the session id to the app id for ghost windows, so that we can + // save the restore data, once the ghost window is created. + std::map<int32_t, std::string> ghost_window_session_id_to_app_id_; + // ARC app tasks could be created after the window initialized. // |arc_window_candidates_| is used to record those initialized ARC app // windows, whose tasks have not been created. Once the task for the window is
diff --git a/components/full_restore/full_restore_save_handler.cc b/components/full_restore/full_restore_save_handler.cc index a180050..ebc16dc 100644 --- a/components/full_restore/full_restore_save_handler.cc +++ b/components/full_restore/full_restore_save_handler.cc
@@ -175,16 +175,16 @@ if (!window_info.window) return; - int32_t window_id = - window_info.window->GetProperty(::full_restore::kWindowIdKey); - if (window_info.window->GetProperty(aura::client::kAppType) == static_cast<int>(ash::AppType::ARC_APP)) { if (arc_save_handler_) - arc_save_handler_->ModifyWindowInfo(window_id, window_info); + arc_save_handler_->ModifyWindowInfo(window_info); return; } + int32_t window_id = + window_info.window->GetProperty(::full_restore::kWindowIdKey); + if (!SessionID::IsValidValue(window_id)) return;
diff --git a/components/full_restore/full_restore_utils.cc b/components/full_restore/full_restore_utils.cc index 3ddde78..cc5d344 100644 --- a/components/full_restore/full_restore_utils.cc +++ b/components/full_restore/full_restore_utils.cc
@@ -19,6 +19,7 @@ DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kWindowIdKey, 0) DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kRestoreWindowIdKey, 0) +DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kGhostWindowSessionIdKey, 0) DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kAppIdKey, nullptr) DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(int32_t, kActivationIndexKey, nullptr) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kParentToHiddenContainerKey, false)
diff --git a/components/full_restore/full_restore_utils.h b/components/full_restore/full_restore_utils.h index 14d2e376..b75af79 100644 --- a/components/full_restore/full_restore_utils.h +++ b/components/full_restore/full_restore_utils.h
@@ -49,6 +49,11 @@ COMPONENT_EXPORT(FULL_RESTORE) extern const ui::ClassProperty<int32_t>* const kRestoreWindowIdKey; +// A property key to indicate the session id for the ARC ghost window from +// RestoreData. +COMPONENT_EXPORT(FULL_RESTORE) +extern const ui::ClassProperty<int32_t>* const kGhostWindowSessionIdKey; + // A property key to store the app id. COMPONENT_EXPORT(FULL_RESTORE) extern const ui::ClassProperty<std::string*>* const kAppIdKey;
diff --git a/components/history_clusters/core/history_clusters_service_unittest.cc b/components/history_clusters/core/history_clusters_service_unittest.cc index fad27f26..5372d093 100644 --- a/components/history_clusters/core/history_clusters_service_unittest.cc +++ b/components/history_clusters/core/history_clusters_service_unittest.cc
@@ -101,13 +101,16 @@ const std::u16string title, history::VisitID visit_id, base::Time visit_time, - int page_end_reason) { + int page_end_reason, + absl::optional<history::VisitID> referring_visit_id) { history::AnnotatedVisit visit; visit.url_row.set_id(url_id); visit.url_row.set_url(url); visit.url_row.set_title(title); visit.visit_row.visit_id = visit_id; visit.visit_row.visit_time = visit_time; + if (referring_visit_id) + visit.visit_row.referring_visit = *referring_visit_id; visit.context_annotations.page_end_reason = page_end_reason; AddVisit(visit); } @@ -160,6 +163,7 @@ visit->set_origin("https://github.com/"); visit->set_page_end_reason(5); visit->set_url("https://github.com/"); + visit->set_referring_visit_id(2); std::string encoded; base::Base64Encode(request.SerializeAsString(), &encoded); @@ -221,8 +225,10 @@ std::string experiment_name = "someExperiment"; EnableMemoriesWithEndpoint(kFakeEndpoint, experiment_name); - AddVisit(0, GURL{"https://google.com"}, u"Google title", 2, IntToTime(2), 3); - AddVisit(0, GURL{"https://github.com"}, u"Github title", 4, IntToTime(4), 5); + AddVisit(0, GURL{"https://google.com"}, u"Google title", 2, IntToTime(2), 3, + absl::nullopt); + AddVisit(0, GURL{"https://github.com"}, u"Github title", 4, IntToTime(4), 5, + 2); struct TestData { std::string query; @@ -522,8 +528,9 @@ // Must not be too old otherwise the history layer will ignore the visit. const auto visit_time = base::Time::Now() - base::TimeDelta::FromDays(1); - AddVisit(1, GURL{"https://google.com"}, u"Google title", 1, visit_time, 3); - AddVisit(2, GURL{"https://github.com"}, u"Github title", 2, visit_time, 5); + AddVisit(1, GURL{"https://google.com"}, u"Google title", 1, visit_time, 3, + absl::nullopt); + AddVisit(2, GURL{"https://github.com"}, u"Github title", 2, visit_time, 5, 2); EXPECT_FALSE(test_url_loader_factory_.IsPending(kFakeEndpoint)); @@ -592,8 +599,9 @@ // Must not be too old otherwise the history layer will ignore the visit. const auto visit_time = base::Time::Now() - base::TimeDelta::FromDays(1); - AddVisit(1, GURL{"https://google.com"}, u"Google title", 1, visit_time, 3); - AddVisit(2, GURL{"https://github.com"}, u"Github title", 2, visit_time, 5); + AddVisit(1, GURL{"https://google.com"}, u"Google title", 1, visit_time, 3, + absl::nullopt); + AddVisit(2, GURL{"https://github.com"}, u"Github title", 2, visit_time, 5, 2); EXPECT_FALSE(test_url_loader_factory_.IsPending(kFakeEndpoint)); history_clusters_service_->QueryMemories( @@ -752,8 +760,10 @@ TEST_F(HistoryClustersServiceTest, DoesQueryMatchAnyCluster) { EnableMemoriesWithEndpoint(); - AddVisit(0, GURL{"https://google.com"}, u"Google title", 2, IntToTime(2), 3); - AddVisit(0, GURL{"https://github.com"}, u"Github title", 4, IntToTime(4), 5); + AddVisit(0, GURL{"https://google.com"}, u"Google title", 2, IntToTime(2), 3, + absl::nullopt); + AddVisit(0, GURL{"https://github.com"}, u"Github title", 4, IntToTime(4), 5, + 2); // Verify that initially, the test keyword doesn't match anything, but this // query should have kicked off a cache population request.
diff --git a/components/history_clusters/core/memories_remote_model_helper.cc b/components/history_clusters/core/memories_remote_model_helper.cc index 19fac31..05022b6 100644 --- a/components/history_clusters/core/memories_remote_model_helper.cc +++ b/components/history_clusters/core/memories_remote_model_helper.cc
@@ -42,6 +42,7 @@ visit.context_annotations.page_end_reason); request_visit->set_page_transition( static_cast<int>(visit.visit_row.transition)); + request_visit->set_referring_visit_id(visit.visit_row.referring_visit); if (debug_logger) { base::DictionaryValue debug_visit;
diff --git a/components/history_clusters/core/proto/clusters.proto b/components/history_clusters/core/proto/clusters.proto index 54e2093b..13db6dc2 100644 --- a/components/history_clusters/core/proto/clusters.proto +++ b/components/history_clusters/core/proto/clusters.proto
@@ -41,6 +41,8 @@ int64 page_transition = 8; // Whether the page load originated from Google Search. bool is_from_google_search = 9; + // The visit ID that referred this visit, if not a new navigation. + int64 referring_visit_id = 10; } message Cluster {
diff --git a/components/live_caption/views/caption_bubble.cc b/components/live_caption/views/caption_bubble.cc index f3b6b3b..c5707b4 100644 --- a/components/live_caption/views/caption_bubble.cc +++ b/components/live_caption/views/caption_bubble.cc
@@ -30,6 +30,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/button/button.h" @@ -773,10 +774,10 @@ views::SetImageFromVectorIcon(collapse_button_, vector_icons::kCaretUpIcon, kButtonDip, text_color); - back_to_tab_button_->ink_drop()->SetBaseColor(text_color); - close_button_->ink_drop()->SetBaseColor(text_color); - expand_button_->ink_drop()->SetBaseColor(text_color); - collapse_button_->ink_drop()->SetBaseColor(text_color); + views::InkDrop::Get(back_to_tab_button_)->SetBaseColor(text_color); + views::InkDrop::Get(close_button_)->SetBaseColor(text_color); + views::InkDrop::Get(expand_button_)->SetBaseColor(text_color); + views::InkDrop::Get(collapse_button_)->SetBaseColor(text_color); } void CaptionBubble::SetBackgroundColor() {
diff --git a/components/media_router/browser/presentation/web_contents_presentation_manager.h b/components/media_router/browser/presentation/web_contents_presentation_manager.h index 806130e2..ee88921b 100644 --- a/components/media_router/browser/presentation/web_contents_presentation_manager.h +++ b/components/media_router/browser/presentation/web_contents_presentation_manager.h
@@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "components/media_router/common/mojom/media_router.mojom.h" namespace content {
diff --git a/components/ntp_snippets/remote/json_request_unittest.cc b/components/ntp_snippets/remote/json_request_unittest.cc index 7919eaf..2ebc66a 100644 --- a/components/ntp_snippets/remote/json_request_unittest.cc +++ b/components/ntp_snippets/remote/json_request_unittest.cc
@@ -19,6 +19,7 @@ #include "components/ntp_snippets/ntp_snippets_constants.h" #include "components/ntp_snippets/remote/request_params.h" #include "components/prefs/testing_pref_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" @@ -115,6 +116,8 @@ private: base::test::ScopedFeatureList scoped_feature_list_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<TestingPrefServiceSimple> pref_service_; scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_; std::unique_ptr<base::ThreadTaskRunnerHandle> mock_runner_handle_;
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc index 4ecb9b1..927bed86 100644 --- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc +++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -31,6 +31,7 @@ #include "components/prefs/testing_pref_service.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/variations/entropy_provider.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/http/http_util.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -265,6 +266,8 @@ private: test::RemoteSuggestionsTestUtils utils_; base::test::ScopedFeatureList scoped_feature_list_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<RemoteSuggestionsFetcherImpl> fetcher_; std::unique_ptr<UserClassifier> user_classifier_; MockSnippetsAvailableCallback mock_callback_;
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn index f6dc975..62ef6cab 100644 --- a/components/omnibox/browser/BUILD.gn +++ b/components/omnibox/browser/BUILD.gn
@@ -579,6 +579,7 @@ "//components/sync_preferences:test_support", "//components/url_formatter", "//components/variations", + "//components/variations:test_support", "//components/variations/net:net", "//services/network:test_support", "//sql",
diff --git a/components/omnibox/browser/document_suggestions_service_unittest.cc b/components/omnibox/browser/document_suggestions_service_unittest.cc index 3f3bd0b..81b3597 100644 --- a/components/omnibox/browser/document_suggestions_service_unittest.cc +++ b/components/omnibox/browser/document_suggestions_service_unittest.cc
@@ -15,6 +15,7 @@ #include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/variations/net/variations_http_headers.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_associated_data.h" #include "components/variations/variations_ids_provider.h" #include "services/network/public/cpp/resource_request.h" @@ -51,7 +52,6 @@ identity_test_env_.SetAutomaticIssueOfAccessTokens(true); // Set up a variation. - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); variations::AssociateGoogleVariationID( variations::GOOGLE_WEB_PROPERTIES_ANY_CONTEXT, "trial name", "group name", kVariationID); @@ -63,6 +63,8 @@ const DocumentSuggestionsServiceTest&) = delete; base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_; sync_preferences::TestingPrefServiceSyncable prefs_;
diff --git a/components/omnibox/browser/favicon_cache_unittest.cc b/components/omnibox/browser/favicon_cache_unittest.cc index 42df5e0..4ef4c0f 100644 --- a/components/omnibox/browser/favicon_cache_unittest.cc +++ b/components/omnibox/browser/favicon_cache_unittest.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "components/favicon/core/test/mock_favicon_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -130,6 +131,8 @@ .Times(calls); } + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; favicon_base::FaviconImageCallback favicon_service_a_site_response_; favicon_base::FaviconImageCallback favicon_service_b_site_response_; favicon_base::FaviconRawBitmapCallback
diff --git a/components/omnibox/browser/location_bar_model_impl.cc b/components/omnibox/browser/location_bar_model_impl.cc index 0efffc14..1709f26 100644 --- a/components/omnibox/browser/location_bar_model_impl.cc +++ b/components/omnibox/browser/location_bar_model_impl.cc
@@ -91,19 +91,6 @@ ~url_formatter::kFormatUrlOmitHTTP; } - // Prevent scheme/trivial subdomain elision when simplified domain field - // trials are enabled. In these field trials, OmniboxViewViews handles elision - // of scheme and trivial subdomains because they are shown/hidden based on - // user interactions with the omnibox. - if (base::FeatureList::IsEnabled( - omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover) || - base::FeatureList::IsEnabled( - omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction)) { - format_types &= ~url_formatter::kFormatUrlOmitHTTP; - format_types &= ~url_formatter::kFormatUrlOmitHTTPS; - format_types &= ~url_formatter::kFormatUrlOmitTrivialSubdomains; - } - GURL url(GetURL()); #if defined(OS_IOS)
diff --git a/components/omnibox/browser/location_bar_model_impl_unittest.cc b/components/omnibox/browser/location_bar_model_impl_unittest.cc index 06abaf8e..51b6a530 100644 --- a/components/omnibox/browser/location_bar_model_impl_unittest.cc +++ b/components/omnibox/browser/location_bar_model_impl_unittest.cc
@@ -104,114 +104,6 @@ LocationBarModelImpl model_; }; -// A test fixture that enables the -// #omnibox-ui-reveal-steady-state-url-path-query-and-ref-on-hover field trial. -class LocationBarModelImplRevealOnHoverTest : public LocationBarModelImplTest { - public: - LocationBarModelImplRevealOnHoverTest() = default; - LocationBarModelImplRevealOnHoverTest( - const LocationBarModelImplRevealOnHoverTest&) = delete; - LocationBarModelImplRevealOnHoverTest& operator=( - const LocationBarModelImplRevealOnHoverTest&) = delete; - - protected: - // testing::Test: - void SetUp() override { - scoped_feature_list_.InitAndEnableFeature( - omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover); - LocationBarModelImplTest::SetUp(); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -// A test fixture that enables the -// #omnibox-ui-hide-steady-state-url-path-query-and-ref-on-interaction field -// trial. -class LocationBarModelImplHideOnInteractionTest - : public LocationBarModelImplTest { - public: - LocationBarModelImplHideOnInteractionTest() = default; - LocationBarModelImplHideOnInteractionTest( - const LocationBarModelImplHideOnInteractionTest&) = delete; - LocationBarModelImplHideOnInteractionTest& operator=( - const LocationBarModelImplHideOnInteractionTest&) = delete; - - protected: - // testing::Test: - void SetUp() override { - scoped_feature_list_.InitAndEnableFeature( - omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction); - LocationBarModelImplTest::SetUp(); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -// Tests that in the -// #omnibox-ui-reveal-steady-state-url-path-query-and-ref-on-hover, the display -// URL does not elide scheme or trivial subdomains. -TEST_F(LocationBarModelImplRevealOnHoverTest, DisplayUrl) { - delegate()->SetURL(GURL("http://www.example.test/foo")); -#if defined(OS_IOS) - EXPECT_EQ(u"http://www.example.test/TestSuffix", model()->GetURLForDisplay()); -#else // #!defined(OS_IOS) - EXPECT_EQ(u"http://www.example.test/foo/TestSuffix", - model()->GetURLForDisplay()); -#endif // #!defined(OS_IOS) - EXPECT_EQ(u"http://www.example.test/foo/TestSuffix", - model()->GetFormattedFullURL()); - - delegate()->SetURL(GURL("https://www.example.test/foo")); -#if defined(OS_IOS) - EXPECT_EQ(u"https://www.example.test/TestSuffix", - model()->GetURLForDisplay()); -#else // #!defined(OS_IOS) - EXPECT_EQ(u"https://www.example.test/foo/TestSuffix", - model()->GetURLForDisplay()); -#endif // #!defined(OS_IOS) - EXPECT_EQ(u"https://www.example.test/foo/TestSuffix", - model()->GetFormattedFullURL()); -} - -// Tests that in the -// #omnibox-ui-hide-steady-state-url-path-query-and-ref-on-interaction, the -// display URL does not elide scheme or trivial subdomains. -TEST_F(LocationBarModelImplHideOnInteractionTest, DisplayUrl) { - delegate()->SetURL(GURL("http://www.example.test/foo")); -#if defined(OS_IOS) - EXPECT_EQ(u"http://www.example.test/TestSuffix", model()->GetURLForDisplay()); -#else // #!defined(OS_IOS) - EXPECT_EQ(u"http://www.example.test/foo/TestSuffix", - model()->GetURLForDisplay()); -#endif // #!defined(OS_IOS) - EXPECT_EQ(u"http://www.example.test/foo/TestSuffix", - model()->GetFormattedFullURL()); - - delegate()->SetURL(GURL("https://www.example.test/foo")); -#if defined(OS_IOS) - EXPECT_EQ(u"https://www.example.test/TestSuffix", - model()->GetURLForDisplay()); -#else // #!defined(OS_IOS) - EXPECT_EQ(u"https://www.example.test/foo/TestSuffix", - model()->GetURLForDisplay()); -#endif // #!defined(OS_IOS) - EXPECT_EQ(u"https://www.example.test/foo/TestSuffix", - model()->GetFormattedFullURL()); -} - -TEST_F(LocationBarModelImplTest, - DisplayUrlAppliesFormattedStringWithEquivalentMeaning) { - delegate()->SetURL(GURL("http://www.google.com/")); - - // Verify that both the full formatted URL and the display URL add the test - // suffix. - EXPECT_EQ(u"www.google.com/TestSuffix", model()->GetFormattedFullURL()); - EXPECT_EQ(u"google.com/TestSuffix", model()->GetURLForDisplay()); -} - TEST_F(LocationBarModelImplTest, FormatsReaderModeUrls) { const GURL http_url("http://www.example.com/article.html"); // Get the real article's URL shown to the user.
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index dbe0c21..8c7d23d 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -700,28 +700,6 @@ return demote_mode; } -bool OmniboxFieldTrial::ShouldRevealPathQueryRefOnHover() { - return base::FeatureList::IsEnabled( - omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover); -} - -bool OmniboxFieldTrial::ShouldHidePathQueryRefOnInteraction() { - return base::FeatureList::IsEnabled( - omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction); -} - -bool OmniboxFieldTrial::ShouldMaybeElideToRegistrableDomain() { - return base::FeatureList::IsEnabled(omnibox::kMaybeElideToRegistrableDomain); -} - -int OmniboxFieldTrial::UnelideURLOnHoverThresholdMs() { - const int kDefaultThresholdMs = 250; - int threshold = base::GetFieldTrialParamByFeatureAsInt( - omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover, - kOmniboxUIUnelideURLOnHoverThresholdMsParam, kDefaultThresholdMs); - return threshold < 0 ? kDefaultThresholdMs : threshold; -} - bool OmniboxFieldTrial::ShouldDisableCGIParamMatching() { return base::FeatureList::IsEnabled(omnibox::kDisableCGIParamMatching); } @@ -815,9 +793,6 @@ int OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs = 100; -const char OmniboxFieldTrial::kOmniboxUIUnelideURLOnHoverThresholdMsParam[] = - "OmniboxUIUnelideURLOnHoverThresholdMsdMs"; - namespace OmniboxFieldTrial { // Rich autocompletion.
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index 9531411..0bfc776f 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -391,14 +391,6 @@ // Function only works in non-incognito when server suggestions are available. std::string OnDeviceHeadSuggestDemoteMode(); -// Experiment to hide components of the URL in the steady state. -bool ShouldRevealPathQueryRefOnHover(); -bool ShouldHidePathQueryRefOnInteraction(); -// If true, the above two features elide subdomains beyond the registrable -// domain, as well as the path, query, and ref. -bool ShouldMaybeElideToRegistrableDomain(); -int UnelideURLOnHoverThresholdMs(); - // Returns true if CGI parameter names should not be considered when scoring // suggestions. bool ShouldDisableCGIParamMatching();
diff --git a/components/omnibox/browser/omnibox_popup_model.h b/components/omnibox/browser/omnibox_popup_model.h index 21e459b..00edd06a 100644 --- a/components/omnibox/browser/omnibox_popup_model.h +++ b/components/omnibox/browser/omnibox_popup_model.h
@@ -10,7 +10,6 @@ #include <string> #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "build/build_config.h" #include "components/omnibox/browser/autocomplete_controller.h" #include "components/omnibox/browser/autocomplete_result.h"
diff --git a/components/omnibox/browser/remote_suggestions_service_unittest.cc b/components/omnibox/browser/remote_suggestions_service_unittest.cc index f095b733..04cf7ff 100644 --- a/components/omnibox/browser/remote_suggestions_service_unittest.cc +++ b/components/omnibox/browser/remote_suggestions_service_unittest.cc
@@ -13,6 +13,7 @@ #include "base/test/test_mock_time_task_runner.h" #include "components/omnibox/common/omnibox_features.h" #include "components/search_engines/template_url_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/base/load_flags.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -42,6 +43,8 @@ protected: scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; network::TestURLLoaderFactory test_url_loader_factory_; };
diff --git a/components/omnibox/browser/scored_history_match_unittest.cc b/components/omnibox/browser/scored_history_match_unittest.cc index e49a300..54173a1 100644 --- a/components/omnibox/browser/scored_history_match_unittest.cc +++ b/components/omnibox/browser/scored_history_match_unittest.cc
@@ -19,6 +19,7 @@ #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/common/omnibox_features.h" #include "components/search_engines/search_terms_data.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -73,6 +74,10 @@ const WordStarts term_word_starts, const GURL& url, const std::u16string& title); + + private: + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; }; history::URLRow ScoredHistoryMatchTest::MakeURLRow(const char* url,
diff --git a/components/omnibox/browser/zero_suggest_provider_unittest.cc b/components/omnibox/browser/zero_suggest_provider_unittest.cc index 32bfa6f..149f27f 100644 --- a/components/omnibox/browser/zero_suggest_provider_unittest.cc +++ b/components/omnibox/browser/zero_suggest_provider_unittest.cc
@@ -28,6 +28,7 @@ #include "components/search_engines/template_url.h" #include "components/search_engines/template_url_service.h" #include "components/variations/entropy_provider.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_associated_data.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" @@ -97,12 +98,6 @@ // AutocompleteProviderListener: void OnProviderUpdate(bool updated_matches) override; - base::test::SingleThreadTaskEnvironment task_environment_; - std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; - - std::unique_ptr<FakeAutocompleteProviderClient> client_; - scoped_refptr<ZeroSuggestProvider> provider_; - network::TestURLLoaderFactory* test_loader_factory() { return client_->test_url_loader_factory(); } @@ -126,6 +121,13 @@ input.set_focus_type(OmniboxFocusType::ON_FOCUS); return input; } + + base::test::SingleThreadTaskEnvironment task_environment_; + std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; + std::unique_ptr<FakeAutocompleteProviderClient> client_; + scoped_refptr<ZeroSuggestProvider> provider_; }; void ZeroSuggestProviderTest::SetUp() {
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index 8d3d7da0..d58e681c 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -301,27 +301,6 @@ "OmniboxUpdatedConnectionSecurityIndicators", base::FEATURE_DISABLED_BY_DEFAULT}; -// Feature used to reveal the path, query and ref from steady state URLs -// on hover. -const base::Feature kRevealSteadyStateUrlPathQueryAndRefOnHover{ - "OmniboxUIExperimentRevealSteadyStateUrlPathQueryAndRefOnHover", - base::FEATURE_DISABLED_BY_DEFAULT}; - -// Feature used to hide the path, query and ref from steady state URLs -// on interaction with the page. -const base::Feature kHideSteadyStateUrlPathQueryAndRefOnInteraction{ - "OmniboxUIExperimentHideSteadyStateUrlPathQueryAndRefOnInteraction", - base::FEATURE_DISABLED_BY_DEFAULT}; - -// Feature used to possibly elide not just the path, query, and ref from steady -// state URLs, but also subdomains beyond the registrable domain, depending on -// whether the hostname fails lookalike checks. Has no effect unless -// kRevealSteadyStateUrlPathQueryAndRefOnHover and/or -// kHideSteadyStateUrlPathQueryAndRefOnInteraction are enabled. -const base::Feature kMaybeElideToRegistrableDomain{ - "OmniboxUIExperimentElideToRegistrableDomain", - base::FEATURE_DISABLED_BY_DEFAULT}; - // Feature used to default typed navigations to use HTTPS instead of HTTP. // This only applies to navigations that don't have a scheme such as // "example.com". Presently, typing "example.com" in a clean browsing profile
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h index 36ae0d1..82b287395f 100644 --- a/components/omnibox/common/omnibox_features.h +++ b/components/omnibox/common/omnibox_features.h
@@ -80,12 +80,6 @@ // Experiment to introduce new security indicators for HTTPS. extern const base::Feature kUpdatedConnectionSecurityIndicators; -// Path-hiding experiments - these hide the path and other URL components in -// some circumstances in the steady-state omnibox. -extern const base::Feature kRevealSteadyStateUrlPathQueryAndRefOnHover; -extern const base::Feature kHideSteadyStateUrlPathQueryAndRefOnInteraction; -extern const base::Feature kMaybeElideToRegistrableDomain; - // Navigation experiments. extern const base::Feature kDefaultTypedNavigationsToHttps; extern const char kDefaultTypedNavigationsToHttpsTimeoutParam[];
diff --git a/components/optimization_guide/core/BUILD.gn b/components/optimization_guide/core/BUILD.gn index 2a42a4c..07351447 100644 --- a/components/optimization_guide/core/BUILD.gn +++ b/components/optimization_guide/core/BUILD.gn
@@ -194,6 +194,7 @@ "//components/sync_preferences:test_support", "//components/ukm:test_support", "//components/unified_consent", + "//components/variations:test_support", "//net:test_support", "//services/network:network_service", "//services/network:test_support",
diff --git a/components/optimization_guide/core/hints_fetcher_unittest.cc b/components/optimization_guide/core/hints_fetcher_unittest.cc index dc4a5533..14d136c 100644 --- a/components/optimization_guide/core/hints_fetcher_unittest.cc +++ b/components/optimization_guide/core/hints_fetcher_unittest.cc
@@ -21,6 +21,7 @@ #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/prefs/testing_pref_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/base/url_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -163,6 +164,8 @@ base::RunLoop().RunUntilIdle(); } + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; bool hints_fetched_ = false; base::test::TaskEnvironment task_environment_;
diff --git a/components/optimization_guide/core/prediction_model_fetcher_unittest.cc b/components/optimization_guide/core/prediction_model_fetcher_unittest.cc index ec4ba40..20294002 100644 --- a/components/optimization_guide/core/prediction_model_fetcher_unittest.cc +++ b/components/optimization_guide/core/prediction_model_fetcher_unittest.cc
@@ -17,6 +17,7 @@ #include "base/test/task_environment.h" #include "components/optimization_guide/core/optimization_guide_features.h" #include "components/optimization_guide/proto/models.pb.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/base/url_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -104,6 +105,8 @@ bool models_fetched_ = false; base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<PredictionModelFetcher> prediction_model_fetcher_;
diff --git a/components/page_info/BUILD.gn b/components/page_info/BUILD.gn index 1de931e..17371dc 100644 --- a/components/page_info/BUILD.gn +++ b/components/page_info/BUILD.gn
@@ -20,6 +20,7 @@ "//components/browsing_data/content", "//components/content_settings/browser", "//components/content_settings/core/browser", + "//components/omnibox/common", "//components/password_manager/core/browser", "//components/permissions", "//components/prefs",
diff --git a/components/page_info/DEPS b/components/page_info/DEPS index 2eeb337..c100747d 100644 --- a/components/page_info/DEPS +++ b/components/page_info/DEPS
@@ -7,6 +7,7 @@ "+components/prefs", "+components/resources", "+components/safe_browsing", + "+components/omnibox/common", "+components/security_interstitials", "+components/security_state", "+components/signin",
diff --git a/components/page_info/page_info_ui.cc b/components/page_info/page_info_ui.cc index 96f6941..38ebccd5 100644 --- a/components/page_info/page_info_ui.cc +++ b/components/page_info/page_info_ui.cc
@@ -13,6 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" +#include "components/omnibox/common/omnibox_features.h" #include "components/page_info/features.h" #include "components/page_info/page_info_ui_delegate.h" #include "components/permissions/permission_manager.h" @@ -402,10 +403,13 @@ IDS_PAGE_INFO_LEGACY_TLS_DETAILS, SecurityDescriptionType::CONNECTION); default: - return CreateSecurityDescription(SecuritySummaryColor::GREEN, - IDS_PAGE_INFO_SECURE_SUMMARY, - IDS_PAGE_INFO_SECURE_DETAILS, - SecurityDescriptionType::CONNECTION); + return CreateSecurityDescription( + SecuritySummaryColor::GREEN, IDS_PAGE_INFO_SECURE_SUMMARY, + base::FeatureList::IsEnabled( + omnibox::kUpdatedConnectionSecurityIndicators) + ? IDS_PAGE_INFO_SECURE_DETAILS_V2 + : IDS_PAGE_INFO_SECURE_DETAILS, + SecurityDescriptionType::CONNECTION); } case PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM: case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN:
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp index a081335..d3159004 100644 --- a/components/page_info_strings.grdp +++ b/components/page_info_strings.grdp
@@ -84,6 +84,9 @@ <message name="IDS_PAGE_INFO_SECURE_DETAILS" desc="A short paragraph explaining a secure site to the user."> Your information (for example, passwords or credit card numbers) is private when it is sent to this site. </message> + <message name="IDS_PAGE_INFO_SECURE_DETAILS_V2" desc="A short paragraph explaining a secure site to the user."> + The site's connection is secure unless Chrome tells you otherwise. + </message> <message name="IDS_PAGE_INFO_MIXED_CONTENT_DETAILS" desc="A short paragraph explaining a partially insecure site to the user."> Attackers might be able to see the images you’re looking at on this site and trick you by modifying them. </message>
diff --git a/components/page_info_strings_grdp/IDS_PAGE_INFO_SECURE_DETAILS_V2.png.sha1 b/components/page_info_strings_grdp/IDS_PAGE_INFO_SECURE_DETAILS_V2.png.sha1 new file mode 100644 index 0000000..1664c011 --- /dev/null +++ b/components/page_info_strings_grdp/IDS_PAGE_INFO_SECURE_DETAILS_V2.png.sha1
@@ -0,0 +1 @@ +3ca31640ad34466c40404674282935ff9493d380 \ No newline at end of file
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn index ed70dbf..188e803 100644 --- a/components/password_manager/core/browser/BUILD.gn +++ b/components/password_manager/core/browser/BUILD.gn
@@ -740,6 +740,7 @@ "//components/sync_preferences:test_support", "//components/ukm:test_support", "//components/url_formatter", + "//components/variations:test_support", "//google_apis:google_apis", "//net:test_support", "//services/metrics/public/cpp:ukm_builders",
diff --git a/components/password_manager/core/browser/DEPS b/components/password_manager/core/browser/DEPS index d508df0..d7529fda 100644 --- a/components/password_manager/core/browser/DEPS +++ b/components/password_manager/core/browser/DEPS
@@ -16,6 +16,7 @@ "+components/sync_preferences", "+components/ukm", "+components/url_formatter", + "+components/variations", "+components/webdata/common", "+components/variations/net", "+crypto", @@ -34,24 +35,6 @@ "hsts_query_unittest\.cc": [ "+services/network", ], - "new_password_form_manager_unittest\.cc": [ - "+components/ukm", - ], - "password_autofill_manager_unittest\.cc": [ - "+components/ukm", - ], - "password_form_manager_unittest\.cc": [ - "+components/ukm", - ], - "password_form_metrics_recorder_unittest\.cc": [ - "+components/ukm", - ], - "password_manager_metrics_recorder_unittest\.cc": [ - "+components/ukm", - ], - "password_manager_unittest\.cc": [ - "+components/ukm", - ], "http_credentials_cleaner_unittest\.cc": [ "+services/network", ],
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc index 5e7e437..c5018e6 100644 --- a/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc +++ b/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
@@ -24,6 +24,7 @@ #include "components/password_manager/core/browser/android_affiliation/facet_manager.h" #include "components/password_manager/core/browser/android_affiliation/fake_affiliation_api.h" #include "components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_network_connection_tracker.h" @@ -366,6 +367,8 @@ base::MakeRefCounted<base::TestMockTimeTaskRunner>(); scoped_refptr<base::TestSimpleTaskRunner> consumer_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>(); + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; base::FilePath db_path_; std::unique_ptr<AffiliationBackend> backend_;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc index 3ea45ef..c549dea 100644 --- a/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc +++ b/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
@@ -18,6 +18,7 @@ #include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher_interface.h" #include "components/password_manager/core/browser/android_affiliation/mock_affiliation_fetcher_delegate.h" #include "components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/base/url_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -107,6 +108,8 @@ private: base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ = base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
diff --git a/components/password_manager/core/browser/android_affiliation/android_affiliation_service_unittest.cc b/components/password_manager/core/browser/android_affiliation/android_affiliation_service_unittest.cc index 636ff4d..a4a68889 100644 --- a/components/password_manager/core/browser/android_affiliation/android_affiliation_service_unittest.cc +++ b/components/password_manager/core/browser/android_affiliation/android_affiliation_service_unittest.cc
@@ -22,6 +22,7 @@ #include "components/password_manager/core/browser/android_affiliation/affiliation_backend.h" #include "components/password_manager/core/browser/android_affiliation/fake_affiliation_api.h" #include "components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_network_connection_tracker.h" @@ -100,6 +101,8 @@ background_task_runner_->RunUntilIdle(); } + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; scoped_refptr<base::TestMockTimeTaskRunner> background_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); network::TestURLLoaderFactory test_url_loader_factory_;
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc index 80863ea..640d1db 100644 --- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc +++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
@@ -20,14 +20,12 @@ #include "components/signin/public/identity_manager/identity_manager.h" #include "crypto/sha2.h" #include "google_apis/gaia/core_account_id.h" +#include "google_apis/gaia/gaia_constants.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace password_manager { namespace { -constexpr char kAPIScope[] = - "https://www.googleapis.com/auth/identity.passwords.leak.check"; - // Returns a Google account that can be used for getting a token. CoreAccountId GetAccountForRequest( const signin::IdentityManager* identity_manager) { @@ -171,8 +169,9 @@ signin::AccessTokenFetcher::TokenCallback callback) { return identity_manager->CreateAccessTokenFetcherForAccount( GetAccountForRequest(identity_manager), - /*oauth_consumer_name=*/"leak_detection_service", {kAPIScope}, - std::move(callback), signin::AccessTokenFetcher::Mode::kImmediate); + /*oauth_consumer_name=*/"leak_detection_service", + {GaiaConstants::kPasswordsLeakCheckOAuth2Scope}, std::move(callback), + signin::AccessTokenFetcher::Mode::kImmediate); } } // namespace password_manager
diff --git a/components/password_manager/core/browser/mock_bulk_leak_check_service.h b/components/password_manager/core/browser/mock_bulk_leak_check_service.h index 5e3a702a..40f89e79 100644 --- a/components/password_manager/core/browser/mock_bulk_leak_check_service.h +++ b/components/password_manager/core/browser/mock_bulk_leak_check_service.h
@@ -9,7 +9,6 @@ #include <vector> #include "base/memory/scoped_refptr.h" -#include "base/observer_list.h" #include "components/keyed_service/core/keyed_service.h" #include "components/password_manager/core/browser/bulk_leak_check_service_interface.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h index 285bcb4..1f7450b 100644 --- a/components/password_manager/core/browser/password_manager.h +++ b/components/password_manager/core/browser/password_manager.h
@@ -13,7 +13,6 @@ #include "base/callback.h" #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/observer_list.h" #include "build/build_config.h" #include "components/autofill/core/common/password_form_fill_data.h" #include "components/autofill/core/common/password_generation_util.h"
diff --git a/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl_unittest.cc b/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl_unittest.cc index 57fba510..44e3625 100644 --- a/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl_unittest.cc +++ b/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl_unittest.cc
@@ -12,6 +12,7 @@ #include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher_interface.h" #include "components/password_manager/core/browser/android_affiliation/mock_affiliation_fetcher_delegate.h" #include "components/password_manager/core/common/password_manager_features.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" @@ -49,6 +50,8 @@ private: base::test::ScopedFeatureList feature_list_; base::test::TaskEnvironment task_env_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ = base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
diff --git a/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher_unittest.cc b/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher_unittest.cc index 3d1ffe8..11c4b989 100644 --- a/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher_unittest.cc +++ b/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher_unittest.cc
@@ -12,6 +12,7 @@ #include "base/test/task_environment.h" #include "components/password_manager/core/browser/android_affiliation/affiliation_api.pb.h" #include "components/password_manager/core/browser/android_affiliation/mock_affiliation_fetcher_delegate.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" #include "services/network/test/test_utils.h" @@ -48,6 +49,8 @@ private: base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ = base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
diff --git a/components/performance_manager/tab_helper_frame_node_source.h b/components/performance_manager/tab_helper_frame_node_source.h index 7930e33..ef56892 100644 --- a/components/performance_manager/tab_helper_frame_node_source.h +++ b/components/performance_manager/tab_helper_frame_node_source.h
@@ -8,7 +8,6 @@ #include "components/performance_manager/frame_node_source.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "base/scoped_multi_source_observation.h" #include "components/performance_manager/performance_manager_tab_helper.h"
diff --git a/components/policy/core/browser/BUILD.gn b/components/policy/core/browser/BUILD.gn index 0e8afdd..5077b51 100644 --- a/components/policy/core/browser/BUILD.gn +++ b/components/policy/core/browser/BUILD.gn
@@ -35,6 +35,8 @@ "policy_error_map.h", "proxy_policy_handler.cc", "proxy_policy_handler.h", + "url_allowlist_policy_handler.cc", + "url_allowlist_policy_handler.h", "url_blocklist_manager.cc", "url_blocklist_manager.h", "url_blocklist_policy_handler.cc", @@ -129,6 +131,7 @@ "configuration_policy_pref_store_unittest.cc", "policy_error_map_unittest.cc", "proxy_policy_handler_unittest.cc", + "url_allowlist_policy_handler_unittest.cc", "url_blocklist_manager_unittest.cc", "url_blocklist_policy_handler_unittest.cc", "url_util_unittest.cc",
diff --git a/components/policy/core/browser/url_allowlist_policy_handler.cc b/components/policy/core/browser/url_allowlist_policy_handler.cc new file mode 100644 index 0000000..b4aadc9 --- /dev/null +++ b/components/policy/core/browser/url_allowlist_policy_handler.cc
@@ -0,0 +1,79 @@ +// Copyright 2021 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/policy/core/browser/url_allowlist_policy_handler.h" + +#include <memory> +#include <utility> +#include <vector> + +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/values.h" +#include "components/policy/core/browser/policy_error_map.h" +#include "components/policy/core/browser/url_util.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_pref_names.h" +#include "components/policy/policy_constants.h" +#include "components/prefs/pref_value_map.h" +#include "components/strings/grit/components_strings.h" + +namespace policy { + +URLAllowlistPolicyHandler::URLAllowlistPolicyHandler(const char* policy_name) + : TypeCheckingPolicyHandler(policy_name, base::Value::Type::LIST) {} + +URLAllowlistPolicyHandler::~URLAllowlistPolicyHandler() = default; + +bool URLAllowlistPolicyHandler::CheckPolicySettings(const PolicyMap& policies, + PolicyErrorMap* errors) { + const base::Value* url_allowlist = policies.GetValue(policy_name()); + if (!url_allowlist) + return true; + + if (!url_allowlist->is_list()) { + errors->AddError(policy_name(), IDS_POLICY_TYPE_ERROR, + base::Value::GetTypeName(base::Value::Type::LIST)); + + return true; + } + + // Filters more than |url_util::kMaxFiltersPerPolicy| are ignored, add a + // warning message. + if (url_allowlist->GetList().size() > url_util::GetMaxFiltersPerPolicy()) { + errors->AddError(policy_name(), + IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING, + base::NumberToString(url_util::GetMaxFiltersPerPolicy())); + } + + for (const auto& policy_iter : url_allowlist->GetList()) { + if (!policy_iter.is_string()) { + errors->AddError(policy_name(), IDS_POLICY_TYPE_ERROR, + base::Value::GetTypeName(base::Value::Type::STRING)); + return true; + } + } + + return true; +} + +void URLAllowlistPolicyHandler::ApplyPolicySettings(const PolicyMap& policies, + PrefValueMap* prefs) { + const base::Value* url_allowlist = policies.GetValue(policy_name()); + if (!url_allowlist || !url_allowlist->is_list()) { + return; + } + + std::vector<base::Value> filtered_url_allowlist; + for (const auto& entry : url_allowlist->GetList()) { + if (entry.is_string()) + filtered_url_allowlist.push_back(entry.Clone()); + } + + prefs->SetValue(policy_prefs::kUrlAllowlist, + base::Value(std::move(filtered_url_allowlist))); +} + +} // namespace policy
diff --git a/components/policy/core/browser/url_allowlist_policy_handler.h b/components/policy/core/browser/url_allowlist_policy_handler.h new file mode 100644 index 0000000..28558691 --- /dev/null +++ b/components/policy/core/browser/url_allowlist_policy_handler.h
@@ -0,0 +1,33 @@ +// Copyright 2021 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_POLICY_CORE_BROWSER_URL_ALLOWLIST_POLICY_HANDLER_H_ +#define COMPONENTS_POLICY_CORE_BROWSER_URL_ALLOWLIST_POLICY_HANDLER_H_ + +#include "base/compiler_specific.h" +#include "components/policy/core/browser/configuration_policy_handler.h" +#include "components/policy/policy_export.h" + +namespace policy { + +// Handles URLAllowlist policy. +class POLICY_EXPORT URLAllowlistPolicyHandler + : public TypeCheckingPolicyHandler { + public: + URLAllowlistPolicyHandler(const URLAllowlistPolicyHandler&) = delete; + void operator=(const URLAllowlistPolicyHandler&) = delete; + + explicit URLAllowlistPolicyHandler(const char* policy_name); + ~URLAllowlistPolicyHandler() override; + + // ConfigurationPolicyHandler methods: + bool CheckPolicySettings(const PolicyMap& policies, + PolicyErrorMap* errors) override; + void ApplyPolicySettings(const PolicyMap& policies, + PrefValueMap* prefs) override; +}; + +} // namespace policy + +#endif // COMPONENTS_POLICY_CORE_BROWSER_URL_ALLOWLIST_POLICY_HANDLER_H_
diff --git a/components/policy/core/browser/url_allowlist_policy_handler_unittest.cc b/components/policy/core/browser/url_allowlist_policy_handler_unittest.cc new file mode 100644 index 0000000..4ac04e7 --- /dev/null +++ b/components/policy/core/browser/url_allowlist_policy_handler_unittest.cc
@@ -0,0 +1,168 @@ +// Copyright 2021 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/policy/core/browser/url_allowlist_policy_handler.h" + +#include <memory> +#include <utility> + +#include "base/strings/string_number_conversions.h" +#include "base/values.h" +#include "components/policy/core/browser/policy_error_map.h" +#include "components/policy/core/browser/url_util.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_pref_names.h" +#include "components/policy/core/common/policy_types.h" +#include "components/policy/policy_constants.h" +#include "components/prefs/pref_value_map.h" +#include "components/strings/grit/components_strings.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" + +namespace policy { + +namespace { + +const char kTestAllowlistValue[] = "kTestAllowlistValue"; + +} // namespace + +class URLAllowlistPolicyHandlerTest : public testing::Test { + public: + void SetUp() override { + handler_ = std::make_unique<URLAllowlistPolicyHandler>(key::kURLAllowlist); + } + + protected: + void SetPolicy(const std::string& key, base::Value value) { + policies_.Set(key, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_CLOUD, std::move(value), nullptr); + } + bool CheckPolicy(const std::string& key, base::Value value) { + SetPolicy(key, std::move(value)); + return handler_->CheckPolicySettings(policies_, &errors_); + } + void ApplyPolicies() { handler_->ApplyPolicySettings(policies_, &prefs_); } + base::Value GetURLAllowlistPolicyValueWithEntries(size_t len) { + std::vector<base::Value> allowlist(len); + for (auto& entry : allowlist) + entry = base::Value(kTestAllowlistValue); + return base::Value(std::move(allowlist)); + } + + std::unique_ptr<URLAllowlistPolicyHandler> handler_; + PolicyErrorMap errors_; + PolicyMap policies_; + PrefValueMap prefs_; +}; + +TEST_F(URLAllowlistPolicyHandlerTest, CheckPolicySettings_WrongType) { + // The policy expects a list. Give it a boolean. + EXPECT_TRUE(CheckPolicy(key::kURLAllowlist, base::Value(false))); + EXPECT_EQ(1U, errors_.size()); + const std::string expected = key::kURLAllowlist; + const std::string actual = errors_.begin()->first; + EXPECT_EQ(expected, actual); +} + +TEST_F(URLAllowlistPolicyHandlerTest, ApplyPolicySettings_NothingSpecified) { + ApplyPolicies(); + EXPECT_FALSE(prefs_.GetValue(policy_prefs::kUrlAllowlist, nullptr)); +} + +TEST_F(URLAllowlistPolicyHandlerTest, ApplyPolicySettings_WrongType) { + // The policy expects a list. Give it a boolean. + SetPolicy(key::kURLAllowlist, base::Value(false)); + ApplyPolicies(); + EXPECT_FALSE(prefs_.GetValue(policy_prefs::kUrlAllowlist, nullptr)); +} + +TEST_F(URLAllowlistPolicyHandlerTest, ApplyPolicySettings_Empty) { + SetPolicy(key::kURLAllowlist, base::Value(base::Value::Type::LIST)); + ApplyPolicies(); + base::Value* out; + EXPECT_TRUE(prefs_.GetValue(policy_prefs::kUrlAllowlist, &out)); + base::ListValue* out_list; + EXPECT_TRUE(out->GetAsList(&out_list)); + EXPECT_EQ(0U, out_list->GetSize()); +} + +TEST_F(URLAllowlistPolicyHandlerTest, ApplyPolicySettings_WrongElementType) { + // The policy expects string-valued elements. Give it booleans. + base::Value in(base::Value::Type::LIST); + in.Append(false); + SetPolicy(key::kURLAllowlist, std::move(in)); + ApplyPolicies(); + + // The element should be skipped. + base::Value* out; + EXPECT_TRUE(prefs_.GetValue(policy_prefs::kUrlAllowlist, &out)); + base::ListValue* out_list; + EXPECT_TRUE(out->GetAsList(&out_list)); + EXPECT_EQ(0U, out_list->GetSize()); +} + +TEST_F(URLAllowlistPolicyHandlerTest, ApplyPolicySettings_Successful) { + base::Value in_url_allowlist(base::Value::Type::LIST); + in_url_allowlist.Append(kTestAllowlistValue); + SetPolicy(key::kURLAllowlist, std::move(in_url_allowlist)); + ApplyPolicies(); + + base::Value* out; + EXPECT_TRUE(prefs_.GetValue(policy_prefs::kUrlAllowlist, &out)); + base::ListValue* out_list; + EXPECT_TRUE(out->GetAsList(&out_list)); + EXPECT_EQ(1U, out_list->GetSize()); + + std::string out_string; + EXPECT_TRUE(out_list->GetString(0U, &out_string)); + EXPECT_EQ(kTestAllowlistValue, out_string); +} + +TEST_F(URLAllowlistPolicyHandlerTest, + ApplyPolicySettings_CheckPolicySettingsMaxFiltersLimitOK) { + size_t max_filters_per_policy = url_util::GetMaxFiltersPerPolicy(); + base::Value urls = + GetURLAllowlistPolicyValueWithEntries(max_filters_per_policy); + + EXPECT_TRUE(CheckPolicy(key::kURLAllowlist, std::move(urls))); + EXPECT_EQ(0U, errors_.size()); + + ApplyPolicies(); + + base::Value* out; + EXPECT_TRUE(prefs_.GetValue(policy_prefs::kUrlAllowlist, &out)); + base::ListValue* out_list; + EXPECT_TRUE(out->GetAsList(&out_list)); + EXPECT_EQ(max_filters_per_policy, out_list->GetSize()); +} + +// Test that the warning message, mapped to +// |IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING|, is added to +// |errors_| when URLAllowlist entries exceed the max filters per policy limit. +TEST_F(URLAllowlistPolicyHandlerTest, + ApplyPolicySettings_CheckPolicySettingsMaxFiltersLimitExceeded) { + size_t max_filters_per_policy = url_util::GetMaxFiltersPerPolicy(); + base::Value urls = + GetURLAllowlistPolicyValueWithEntries(max_filters_per_policy + 1); + + EXPECT_TRUE(CheckPolicy(key::kURLAllowlist, std::move(urls))); + EXPECT_EQ(1U, errors_.size()); + + ApplyPolicies(); + + auto error_str = errors_.GetErrors(key::kURLAllowlist); + auto expected_str = l10n_util::GetStringFUTF16( + IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING, + base::NumberToString16(max_filters_per_policy)); + EXPECT_TRUE(error_str.find(expected_str) != std::wstring::npos); + + base::Value* out; + EXPECT_TRUE(prefs_.GetValue(policy_prefs::kUrlAllowlist, &out)); + base::ListValue* out_list; + EXPECT_TRUE(out->GetAsList(&out_list)); + EXPECT_EQ(max_filters_per_policy + 1, out_list->GetSize()); +} + +} // namespace policy
diff --git a/components/policy/core/browser/url_blocklist_policy_handler.cc b/components/policy/core/browser/url_blocklist_policy_handler.cc index 8d49b18e..8b5ef94 100644 --- a/components/policy/core/browser/url_blocklist_policy_handler.cc +++ b/components/policy/core/browser/url_blocklist_policy_handler.cc
@@ -9,6 +9,7 @@ #include <vector> #include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/values.h" #include "components/policy/core/browser/policy_error_map.h" @@ -28,12 +29,17 @@ bool URLBlocklistPolicyHandler::CheckPolicySettings(const PolicyMap& policies, PolicyErrorMap* errors) { + size_t disabled_schemes_entries = 0; // This policy is deprecated but still supported so check it first. const base::Value* disabled_schemes = policies.GetValue(key::kDisabledSchemes); - if (disabled_schemes && !disabled_schemes->is_list()) { - errors->AddError(key::kDisabledSchemes, IDS_POLICY_TYPE_ERROR, - base::Value::GetTypeName(base::Value::Type::LIST)); + if (disabled_schemes) { + if (!disabled_schemes->is_list()) { + errors->AddError(key::kDisabledSchemes, IDS_POLICY_TYPE_ERROR, + base::Value::GetTypeName(base::Value::Type::LIST)); + } else { + disabled_schemes_entries = disabled_schemes->GetList().size(); + } } const base::Value* url_blocklist = policies.GetValue(policy_name()); @@ -47,6 +53,15 @@ return true; } + // Filters more than |url_util::kMaxFiltersPerPolicy| are ignored, add a + // warning message. + if (url_blocklist->GetList().size() + disabled_schemes_entries > + url_util::GetMaxFiltersPerPolicy()) { + errors->AddError(policy_name(), + IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING, + base::NumberToString(url_util::GetMaxFiltersPerPolicy())); + } + bool type_error = false; std::string policy; std::vector<std::string> invalid_policies;
diff --git a/components/policy/core/browser/url_blocklist_policy_handler_unittest.cc b/components/policy/core/browser/url_blocklist_policy_handler_unittest.cc index 4dc1ba6b..352f3b5e 100644 --- a/components/policy/core/browser/url_blocklist_policy_handler_unittest.cc +++ b/components/policy/core/browser/url_blocklist_policy_handler_unittest.cc
@@ -7,14 +7,18 @@ #include <memory> #include <utility> +#include "base/strings/string_number_conversions.h" #include "base/values.h" #include "components/policy/core/browser/policy_error_map.h" +#include "components/policy/core/browser/url_util.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_pref_names.h" #include "components/policy/core/common/policy_types.h" #include "components/policy/policy_constants.h" #include "components/prefs/pref_value_map.h" +#include "components/strings/grit/components_strings.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" // Note: this file should move to components/policy/core/browser, but the // components_unittests runner does not load the ResourceBundle as @@ -49,6 +53,12 @@ bool ValidatePolicy(const std::string& policy) { return handler_->ValidatePolicy(policy); } + base::Value GetURLBlocklistPolicyValueWithEntries(size_t len) { + std::vector<base::Value> blocklist(len); + for (auto& entry : blocklist) + entry = base::Value(kTestBlocklistValue); + return base::Value(std::move(blocklist)); + } std::unique_ptr<URLBlocklistPolicyHandler> handler_; PolicyErrorMap errors_; @@ -225,6 +235,83 @@ EXPECT_EQ(kTestBlocklistValue, out2); } +TEST_F(URLBlocklistPolicyHandlerTest, + ApplyPolicySettings_CheckPolicySettingsMaxFiltersLimitOK) { + size_t max_filters_per_policy = url_util::GetMaxFiltersPerPolicy(); + base::Value urls = + GetURLBlocklistPolicyValueWithEntries(max_filters_per_policy); + + EXPECT_TRUE(CheckPolicy(key::kURLBlocklist, std::move(urls))); + EXPECT_EQ(0U, errors_.size()); + + ApplyPolicies(); + + base::Value* out; + EXPECT_TRUE(prefs_.GetValue(policy_prefs::kUrlBlocklist, &out)); + base::ListValue* out_list; + EXPECT_TRUE(out->GetAsList(&out_list)); + EXPECT_EQ(max_filters_per_policy, out_list->GetSize()); +} + +// Test that the warning message, mapped to +// |IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING|, is added to +// |errors_| when URLBlocklist entries exceed the max filters per policy limit. +TEST_F(URLBlocklistPolicyHandlerTest, + ApplyPolicySettings_CheckPolicySettingsMaxFiltersLimitExceeded_1) { + size_t max_filters_per_policy = url_util::GetMaxFiltersPerPolicy(); + base::Value urls = + GetURLBlocklistPolicyValueWithEntries(max_filters_per_policy + 1); + + EXPECT_TRUE(CheckPolicy(key::kURLBlocklist, std::move(urls))); + EXPECT_EQ(1U, errors_.size()); + + ApplyPolicies(); + + auto error_str = errors_.GetErrors(key::kURLBlocklist); + auto expected_str = l10n_util::GetStringFUTF16( + IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING, + base::NumberToString16(max_filters_per_policy)); + EXPECT_TRUE(error_str.find(expected_str) != std::wstring::npos); + + base::Value* out; + EXPECT_TRUE(prefs_.GetValue(policy_prefs::kUrlBlocklist, &out)); + base::ListValue* out_list; + EXPECT_TRUE(out->GetAsList(&out_list)); + EXPECT_EQ(max_filters_per_policy + 1, out_list->GetSize()); +} + +// Test that the warning message, mapped to +// |IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING|, is added to +// |errors_| when URLBlocklist + DisabledScheme entries exceed the max filters +// per policy limit. +TEST_F(URLBlocklistPolicyHandlerTest, + ApplyPolicySettings_CheckPolicySettingsMaxFiltersLimitExceeded_2) { + base::Value in_disabled_schemes(base::Value::Type::LIST); + in_disabled_schemes.Append(kTestDisabledScheme); + SetPolicy(key::kDisabledSchemes, std::move(in_disabled_schemes)); + + size_t max_filters_per_policy = url_util::GetMaxFiltersPerPolicy(); + base::Value urls = + GetURLBlocklistPolicyValueWithEntries(max_filters_per_policy); + + EXPECT_TRUE(CheckPolicy(key::kURLBlocklist, std::move(urls))); + EXPECT_EQ(1U, errors_.size()); + + ApplyPolicies(); + + auto error_str = errors_.GetErrors(key::kURLBlocklist); + auto expected_str = l10n_util::GetStringFUTF16( + IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING, + base::NumberToString16(max_filters_per_policy)); + EXPECT_TRUE(error_str.find(expected_str) != std::wstring::npos); + + base::Value* out; + EXPECT_TRUE(prefs_.GetValue(policy_prefs::kUrlBlocklist, &out)); + base::ListValue* out_list; + EXPECT_TRUE(out->GetAsList(&out_list)); + EXPECT_EQ(max_filters_per_policy + 1, out_list->GetSize()); +} + TEST_F(URLBlocklistPolicyHandlerTest, ValidatePolicy) { EXPECT_TRUE(ValidatePolicy("http://*")); EXPECT_TRUE(ValidatePolicy("http:*"));
diff --git a/components/policy/core/browser/url_util.cc b/components/policy/core/browser/url_util.cc index 5bdbe32..32f9ea65 100644 --- a/components/policy/core/browser/url_util.cc +++ b/components/policy/core/browser/url_util.cc
@@ -228,6 +228,10 @@ return EmbeddedURLExtractor::GetInstance()->GetEmbeddedURL(url); } +size_t GetMaxFiltersPerPolicy() { + return kMaxFiltersPerPolicy; +} + FilterComponents::FilterComponents() : port(0), match_subdomains(true), allow(true) {} FilterComponents::~FilterComponents() = default;
diff --git a/components/policy/core/browser/url_util.h b/components/policy/core/browser/url_util.h index 3b1990da..dbd34ff9 100644 --- a/components/policy/core/browser/url_util.h +++ b/components/policy/core/browser/url_util.h
@@ -23,6 +23,9 @@ // a known format. POLICY_EXPORT GURL GetEmbeddedURL(const GURL& url); +// Gets maximum filters per policy. +POLICY_EXPORT size_t GetMaxFiltersPerPolicy(); + struct FilterComponents { FilterComponents(); FilterComponents(const FilterComponents&) = delete;
diff --git a/components/policy/resources/PRESUBMIT.py b/components/policy/resources/PRESUBMIT.py index 9a0dee4..3f6147d11 100644 --- a/components/policy/resources/PRESUBMIT.py +++ b/components/policy/resources/PRESUBMIT.py
@@ -9,6 +9,8 @@ from xml.dom import minidom from xml.parsers import expat +USE_PYTHON3 = True + def _GetPolicyTemplates(template_path): # Read list of policies in the template. eval() is used instead of a JSON # parser because policy_templates.json is not quite JSON, and uses some @@ -58,7 +60,7 @@ try: version_path = input_api.os_path.join(root, 'chrome', 'VERSION') with open(version_path, "rb") as f: - current_version = int(f.readline().split("=")[1]) + current_version = int(f.readline().split(b"=")[1]) print ('Checking policies against current version: ' + current_version) except: @@ -235,7 +237,7 @@ syntax_check_path = input_api.os_path.join( root, 'components', 'policy', 'tools', 'syntax_check_policy_template_json.py') - affected_files = input_api.AffectedFiles() + affected_files = input_api.change.AffectedFiles() results.extend(_CheckMissingPlaceholders(input_api, output_api, template_path))
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index b20e9b7..1c6b3edc 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -5187,6 +5187,37 @@ 'arc_support': '''This policy also controls access to Android Developer Options. If you set this policy to 'DeveloperToolsDisallowed' (value 2), users cannot access Developer Options. If you set this policy to another value or leave it unset, users can access Developer Options by tapping seven times on the build number in the Android settings app.''', }, { + 'name': 'RemoteDebuggingAllowed', + 'owners': ['file://components/policy/resources/OWNERS'], + 'type': 'main', + 'schema': { 'type': 'boolean' }, + 'items': [ + { + 'value': True, + 'caption': '''Allow use of the remote debugging''', + }, + { + 'value': False, + 'caption': '''Do not allow use of the remote debugging''', + }, + ], + 'supported_on': ['chrome.*:93-', 'chrome_os:93-'], + 'features': { + 'dynamic_refresh': False, + 'per_profile': False, + }, + 'example_value': True, + 'default': True, + 'id': 864, + 'caption': '''Allow remote debugging''', + 'tags': [], + 'desc': '''Controls whether users may use remote debugging. + + If this policy is set to Enabled or not set, users may use remote debugging by specifying --remote-debugging-port and --remote-debugging-pipe command line switches. + + If this policy is set to Disabled, users are not allowed to use remote debugging.''' + }, + { 'name': 'HeadlessMode', 'owners': ['file://headless/OWNERS'], 'type': 'int-enum', @@ -27043,6 +27074,6 @@ 'placeholders': [], 'deleted_policy_ids': [114, 115, 204, 205, 206, 412, 476, 544, 546, 562, 569, 578, 583, 585, 586, 587, 588, 589, 590, 591, 600, 668, 669], 'deleted_atomic_policy_group_ids': [19], - 'highest_id_currently_used': 863, + 'highest_id_currently_used': 864, 'highest_atomic_group_id_currently_used': 40 }
diff --git a/components/policy/tools/PRESUBMIT.py b/components/policy/tools/PRESUBMIT.py index c1c141c..b1aa269 100644 --- a/components/policy/tools/PRESUBMIT.py +++ b/components/policy/tools/PRESUBMIT.py
@@ -5,6 +5,9 @@ import os +USE_PYTHON3 = True + + def RunOtherPresubmit(function_name, input_api, output_api): # Apply the PRESUBMIT for components/policy/resources to run the syntax check component_resources_path = os.path.join('components', 'policy', 'resources')
diff --git a/components/policy/tools/generate_extension_admx.py b/components/policy/tools/generate_extension_admx.py index 48a0593..b6eb5e7d 100755 --- a/components/policy/tools/generate_extension_admx.py +++ b/components/policy/tools/generate_extension_admx.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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. @@ -15,7 +15,7 @@ Example: Download the managed bookmarks extension from - http://developer.chrome.com/extensions/examples/extensions/managed_bookmarks.zip + https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/mv2-archive/extensions/managed_bookmarks to obtain the schema.json file. generate_extension_admx.py --name 'Managed Bookmarks' @@ -32,7 +32,6 @@ from argparse import ArgumentParser from xml.dom import minidom - class AdmxGenerator(object): '''Generates ADMX and ADML templates''' @@ -233,7 +232,7 @@ elif ('$ref' in policy_schema): # Instantiate referenced schema. referenced_schema = self._schema_map[policy_schema['$ref']] - for key, value in referenced_schema.iteritems(): + for key, value in referenced_schema.items(): if not key in policy_schema: policy_schema[key] = value
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py index e59592e6..f582b5bf 100755 --- a/components/policy/tools/generate_policy_source.py +++ b/components/policy/tools/generate_policy_source.py
@@ -1,8 +1,8 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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. -'''python %prog [options] +'''python3 %(prog)s [options] Pass at least: --chrome-version-file <path to src/chrome/VERSION> or --all-chrome-versions @@ -11,8 +11,6 @@ --policy_templates <path to the policy_templates.json input file>.''' -from __future__ import with_statement - from argparse import ArgumentParser from collections import namedtuple from collections import OrderedDict
diff --git a/components/policy/tools/generate_policy_source_test.py b/components/policy/tools/generate_policy_source_test.py index ca2b1ec..c546839e 100755 --- a/components/policy/tools/generate_policy_source_test.py +++ b/components/policy/tools/generate_policy_source_test.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2016 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.
diff --git a/components/policy/tools/make_policy_zip.py b/components/policy/tools/make_policy_zip.py index 7c43af0..c9ab2fd 100755 --- a/components/policy/tools/make_policy_zip.py +++ b/components/policy/tools/make_policy_zip.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2011 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.
diff --git a/components/policy/tools/schema_validator.py b/components/policy/tools/schema_validator.py index d4c1898..5151d309 100644 --- a/components/policy/tools/schema_validator.py +++ b/components/policy/tools/schema_validator.py
@@ -135,7 +135,7 @@ # that their existence can be validated later on in ValidateSchema(schema). if '$ref' in schema: ref_id = schema['$ref'] - for name, value in schema.iteritems(): + for name, value in schema.items(): if name not in ALLOWED_REF_ATTRIBUTES_AND_TYPES: self._Error("Attribute '%s' is not allowed for schema with $ref '%s'." % (name, ref_id)) @@ -160,7 +160,7 @@ # Check that each schema only contains attributes that are allowed in their # respective type and that their values are of correct type. allowed_attributes = ALLOWED_ATTRIBUTES_AND_TYPES[schema_type] - for attribute_name, attribute_value in schema.iteritems(): + for attribute_name, attribute_value in schema.items(): if attribute_name in allowed_attributes: expected_type = allowed_attributes[attribute_name] if not isinstance(attribute_value, expected_type): @@ -271,7 +271,7 @@ if 'properties' in schema: has_any_properties = True properties = schema['properties'] - for property_name, property_schema in properties.iteritems(): + for property_name, property_schema in properties.items(): if not isinstance(property_name, str): self._Error("Property name must be a string.") if not property_name: @@ -280,7 +280,7 @@ if 'patternProperties' in schema: has_any_properties = True pattern_properties = schema['patternProperties'] - for property_pattern, property_schema in pattern_properties.iteritems(): + for property_pattern, property_schema in pattern_properties.items(): self._ValidatePattern(property_pattern) self._ValidateSchemaInternal(property_schema) if 'additionalProperties' in schema: @@ -354,14 +354,14 @@ if self.enforce_use_entire_schema: if self.expected_properties != self.used_properties: for schema_id, expected_properties \ - in self.expected_properties.iteritems(): + in self.expected_properties.items(): used_properties = self.used_properties.get(schema_id, set()) unused_properties = expected_properties.difference(used_properties) if unused_properties: self._Error("Unused properties: %s" % unused_properties) if self.expected_pattern_properties != self.used_pattern_properties: for schema_id, expected_properties \ - in self.expected_pattern_properties.iteritems(): + in self.expected_pattern_properties.items(): used_properties = self.used_pattern_properties.get(schema_id, set()) unused_properties = expected_properties.difference(used_properties) if unused_properties: @@ -393,7 +393,7 @@ pass # Boolean doesn't need any validation. elif schema_type == 'integer' and isinstance(value, int): self.ValidateIntegerValue(schema, value) - elif schema_type == 'string' and isinstance(value, (str, unicode)): + elif schema_type == 'string' and isinstance(value, (bytes, str)): self.ValidateStringValue(schema, value) elif schema_type == 'array' and isinstance(value, list): self.ValidateArrayValue(schema, value) @@ -482,16 +482,16 @@ # empty sets. schema_id = id(schema) if schema_id not in self.expected_properties: - self.expected_properties[schema_id] = set(properties.iterkeys()) + self.expected_properties[schema_id] = set(properties.keys()) self.expected_pattern_properties[schema_id] = set( - pattern_properties.iterkeys()) + pattern_properties.keys()) self.expected_additional_properties[schema_id] = ( 'additionalProperties' in schema) self.used_properties[schema_id] = set() self.used_pattern_properties[schema_id] = set() self.used_additional_properties[schema_id] = False - for property_key, property_value in value.iteritems(): + for property_key, property_value in value.items(): # Find property schema from either properties, patternProperties or # additionalProperties. property_schema = {} @@ -499,9 +499,9 @@ property_schema = properties[property_key] self.used_properties[schema_id].add(property_key) elif pattern_properties: - matched_pattern = next( - (pattern for pattern in pattern_properties.iterkeys() - if re.search(pattern, property_key)), "") + matched_pattern = next((pattern + for pattern in pattern_properties.keys() + if re.search(pattern, property_key)), "") property_schema = pattern_properties.get(matched_pattern, {}) self.used_pattern_properties[schema_id].add(matched_pattern) if not property_schema and additional_properties:
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py index e18b3d6..5f187b5 100755 --- a/components/policy/tools/syntax_check_policy_template_json.py +++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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. @@ -248,7 +248,7 @@ def _Warning(self, message): self.warning_count += 1 - print message + print(message) def _Error(self, message, @@ -259,9 +259,9 @@ error = '' if identifier is not None and parent_element is not None: error += 'In %s %s: ' % (parent_element, identifier) - print error + 'Error: ' + message + print(error + 'Error: ' + message) if offending_snippet is not None: - print ' Offending:', json.dumps(offending_snippet, indent=2) + print(' Offending:', json.dumps(offending_snippet, indent=2)) def _CheckContains(self, container, @@ -434,15 +434,14 @@ return any(self._AppearsToContainEmbeddedJson(v) for v in example_value) elif isinstance(example_value, dict): return any( - self._AppearsToContainEmbeddedJson(v) - for v in example_value.itervalues()) + self._AppearsToContainEmbeddedJson(v) for v in example_value.values()) # Checks that there are no duplicate proto paths in device_policy_proto_map. def _CheckDevicePolicyProtoMappingUniqueness(self, device_policy_proto_map, legacy_device_policy_proto_map): # Check that device_policy_proto_map does not have duplicate values. proto_paths = set() - for proto_path in device_policy_proto_map.itervalues(): + for proto_path in device_policy_proto_map.values(): if proto_path in proto_paths: self._Error( "Duplicate proto path '%s' in device_policy_proto_map. Did you set " @@ -755,7 +754,7 @@ # Each policy's description should be within the limit. desc = self._CheckContains(policy, 'desc', str) - if len(desc.decode("UTF-8")) > POLICY_DESCRIPTION_LENGTH_SOFT_LIMIT: + if len(desc) > POLICY_DESCRIPTION_LENGTH_SOFT_LIMIT: self._Error( 'Length of description is more than %d characters, which might ' 'exceed the limit of 4096 characters in one of its ' @@ -1630,7 +1629,7 @@ def _LineError(self, message, line_number): self.error_count += 1 - print 'In line %d: Error: %s' % (line_number, message) + print('In line %d: Error: %s' % (line_number, message)) def _LineWarning(self, message, line_number): self._Warning('In line %d: Warning: Automatically fixing formatting: %s' % @@ -1911,7 +1910,7 @@ (self.num_policies, self.num_policies_in_groups, self.num_groups, (1.0 * self.num_policies_in_groups / self.num_groups))) else: - print self.num_policies, 'policies, 0 policy groups.' + print(self.num_policies, 'policies, 0 policy groups.') if self.error_count > 0: return 1 return 0
diff --git a/components/policy/tools/template_writers/PRESUBMIT.py b/components/policy/tools/template_writers/PRESUBMIT.py index 66f6f82..e159b0d3 100755 --- a/components/policy/tools/template_writers/PRESUBMIT.py +++ b/components/policy/tools/template_writers/PRESUBMIT.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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. @@ -9,6 +9,9 @@ """ +USE_PYTHON3 = True + + def RunUnittests(input_api, output_api): return input_api.canned_checks.RunPythonUnitTests(input_api, output_api, ['test_suite_all'])
diff --git a/components/policy/tools/template_writers/__init__.py b/components/policy/tools/template_writers/__init__.py index 14d138a..abc9365 100755 --- a/components/policy/tools/template_writers/__init__.py +++ b/components/policy/tools/template_writers/__init__.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/policy_template_generator.py b/components/policy/tools/template_writers/policy_template_generator.py index 83059351..99a9e03 100755 --- a/components/policy/tools/template_writers/policy_template_generator.py +++ b/components/policy/tools/template_writers/policy_template_generator.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/policy_template_generator_unittest.py b/components/policy/tools/template_writers/policy_template_generator_unittest.py index 09d9cc5..5beb6082 100755 --- a/components/policy/tools/template_writers/policy_template_generator_unittest.py +++ b/components/policy/tools/template_writers/policy_template_generator_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/template_formatter.py b/components/policy/tools/template_writers/template_formatter.py index 7f22da6..9af8816 100755 --- a/components/policy/tools/template_writers/template_formatter.py +++ b/components/policy/tools/template_writers/template_formatter.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/test_suite_all.py b/components/policy/tools/template_writers/test_suite_all.py index 87b2317..8ca43de4 100755 --- a/components/policy/tools/template_writers/test_suite_all.py +++ b/components/policy/tools/template_writers/test_suite_all.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writer_configuration.py b/components/policy/tools/template_writers/writer_configuration.py index b3917d1c..a2c07c4c 100755 --- a/components/policy/tools/template_writers/writer_configuration.py +++ b/components/policy/tools/template_writers/writer_configuration.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/__init__.py b/components/policy/tools/template_writers/writers/__init__.py index df56f5c..fb050d1f 100755 --- a/components/policy/tools/template_writers/writers/__init__.py +++ b/components/policy/tools/template_writers/writers/__init__.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/adm_writer.py b/components/policy/tools/template_writers/writers/adm_writer.py index 4b480c45..7c20a5a 100755 --- a/components/policy/tools/template_writers/writers/adm_writer.py +++ b/components/policy/tools/template_writers/writers/adm_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/adm_writer_unittest.py b/components/policy/tools/template_writers/writers/adm_writer_unittest.py index 77992865..9d2b86d 100755 --- a/components/policy/tools/template_writers/writers/adm_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/adm_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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. @@ -1388,7 +1388,6 @@ ''') self.CompareOutputs(output, expected_output) - @unittest.skip("skipped due to https://crbug.com/1216996") def testRemovedPolicy(self): # Tests that a deprecated policy gets placed in the special # 'RemovedPolicies' group.
diff --git a/components/policy/tools/template_writers/writers/adml_writer.py b/components/policy/tools/template_writers/writers/adml_writer.py index 96af4b6..e40dcb1 100755 --- a/components/policy/tools/template_writers/writers/adml_writer.py +++ b/components/policy/tools/template_writers/writers/adml_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/adml_writer_unittest.py b/components/policy/tools/template_writers/writers/adml_writer_unittest.py index 6a34ccc..2f1afd1 100755 --- a/components/policy/tools/template_writers/writers/adml_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/adml_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/admx_writer.py b/components/policy/tools/template_writers/writers/admx_writer.py index 865558e..d6dbf4f 100755 --- a/components/policy/tools/template_writers/writers/admx_writer.py +++ b/components/policy/tools/template_writers/writers/admx_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/admx_writer_unittest.py b/components/policy/tools/template_writers/writers/admx_writer_unittest.py index 0ba159d..1543a01 100755 --- a/components/policy/tools/template_writers/writers/admx_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/admx_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/android_policy_writer.py b/components/policy/tools/template_writers/writers/android_policy_writer.py index 9466d8c..5536a41 100755 --- a/components/policy/tools/template_writers/writers/android_policy_writer.py +++ b/components/policy/tools/template_writers/writers/android_policy_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 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.
diff --git a/components/policy/tools/template_writers/writers/android_policy_writer_unittest.py b/components/policy/tools/template_writers/writers/android_policy_writer_unittest.py index b36a72a..a282bc5 100755 --- a/components/policy/tools/template_writers/writers/android_policy_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/android_policy_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 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.
diff --git a/components/policy/tools/template_writers/writers/chromeos_adml_writer.py b/components/policy/tools/template_writers/writers/chromeos_adml_writer.py index 6ae5309..72e4dfc 100755 --- a/components/policy/tools/template_writers/writers/chromeos_adml_writer.py +++ b/components/policy/tools/template_writers/writers/chromeos_adml_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/chromeos_adml_writer_unittest.py b/components/policy/tools/template_writers/writers/chromeos_adml_writer_unittest.py index 4cf97d3d..f07d2992 100755 --- a/components/policy/tools/template_writers/writers/chromeos_adml_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/chromeos_adml_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/chromeos_admx_writer.py b/components/policy/tools/template_writers/writers/chromeos_admx_writer.py index fa53e17..c9f1c2c 100755 --- a/components/policy/tools/template_writers/writers/chromeos_admx_writer.py +++ b/components/policy/tools/template_writers/writers/chromeos_admx_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/chromeos_admx_writer_unittest.py b/components/policy/tools/template_writers/writers/chromeos_admx_writer_unittest.py index 6208f02..b6b4f83 100755 --- a/components/policy/tools/template_writers/writers/chromeos_admx_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/chromeos_admx_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/doc_atomic_groups_writer.py b/components/policy/tools/template_writers/writers/doc_atomic_groups_writer.py index a98f1a6..9f92347 100755 --- a/components/policy/tools/template_writers/writers/doc_atomic_groups_writer.py +++ b/components/policy/tools/template_writers/writers/doc_atomic_groups_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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.
diff --git a/components/policy/tools/template_writers/writers/doc_writer.py b/components/policy/tools/template_writers/writers/doc_writer.py index b852d86..69ea6ed 100755 --- a/components/policy/tools/template_writers/writers/doc_writer.py +++ b/components/policy/tools/template_writers/writers/doc_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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. @@ -127,7 +127,11 @@ ''' dd = self._AddPolicyAttribute(parent, 'schema', None, ['.monospace', '.pre-wrap']) - schema_json = json.dumps(schema, indent=2, sort_keys=True) + # Explicitly specify separators since defaults depend on python version. + schema_json = json.dumps(schema, + indent=2, + sort_keys=True, + separators=(", ", ": ")) self.AddText(dd, schema_json) def _AddFeatures(self, parent, policy): @@ -141,8 +145,7 @@ ''' features = [] # The sorting is to make the order well-defined for testing. - keys = list(policy['features'].keys()) - keys.sort() + keys = sorted(policy['features'].keys()) for key in keys: key_name = self._FEATURE_MAP[key] if policy['features'][key]: @@ -325,7 +328,11 @@ self.AddElement(parent, 'dt', {}, os_header) element = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre-wrap']) key_name = self._GetRegistryKeyName(policy, is_win) - example = json.dumps(policy['example_value'], indent=2, sort_keys=True) + # Explicitly specify separators since defaults depend on python version. + example = json.dumps(policy['example_value'], + indent=2, + sort_keys=True, + separators=(", ", ": ")) self.AddText(element, '%s\\%s = %s' % (key_name, policy['name'], example)) def _AddDictionaryExampleAndroidLinux(self, parent, policy): @@ -339,7 +346,11 @@ ''' self.AddElement(parent, 'dt', {}, 'Android/Linux:') element = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre-wrap']) - example = json.dumps(policy['example_value'], indent=2, sort_keys=True) + # Explicitly specify separators since defaults depend on python version. + example = json.dumps(policy['example_value'], + indent=2, + sort_keys=True, + separators=(", ", ": ")) self.AddText(element, '%s: %s' % (policy['name'], example)) def _AddDictionaryExample(self, parent, policy):
diff --git a/components/policy/tools/template_writers/writers/doc_writer_unittest.py b/components/policy/tools/template_writers/writers/doc_writer_unittest.py index ed8de5c..e6d0172 100755 --- a/components/policy/tools/template_writers/writers/doc_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/doc_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/google_adml_writer.py b/components/policy/tools/template_writers/writers/google_adml_writer.py index 85d1f96..a126d34 100755 --- a/components/policy/tools/template_writers/writers/google_adml_writer.py +++ b/components/policy/tools/template_writers/writers/google_adml_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/google_adml_writer_unittest.py b/components/policy/tools/template_writers/writers/google_adml_writer_unittest.py index 8ca55155..3170f57f 100755 --- a/components/policy/tools/template_writers/writers/google_adml_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/google_adml_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/google_admx_writer.py b/components/policy/tools/template_writers/writers/google_admx_writer.py index 4e013a8..e1f885f 100755 --- a/components/policy/tools/template_writers/writers/google_admx_writer.py +++ b/components/policy/tools/template_writers/writers/google_admx_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/google_admx_writer_unittest.py b/components/policy/tools/template_writers/writers/google_admx_writer_unittest.py index f82e24c..f4f1e6dc 100755 --- a/components/policy/tools/template_writers/writers/google_admx_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/google_admx_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/gpo_editor_writer.py b/components/policy/tools/template_writers/writers/gpo_editor_writer.py index c6bdbb68..0d39d094 100755 --- a/components/policy/tools/template_writers/writers/gpo_editor_writer.py +++ b/components/policy/tools/template_writers/writers/gpo_editor_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2018 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -31,7 +31,7 @@ since_version = supported_on.get('since_version', None) - return not since_version or int(since_version) >= major_version + return not since_version or major_version >= int(since_version) def IsPolicyOnWin7Only(self, policy): ''' Returns true if the policy is supported on win7 only.'''
diff --git a/components/policy/tools/template_writers/writers/ios_app_config_writer.py b/components/policy/tools/template_writers/writers/ios_app_config_writer.py index 233d557..a5a61f9 100755 --- a/components/policy/tools/template_writers/writers/ios_app_config_writer.py +++ b/components/policy/tools/template_writers/writers/ios_app_config_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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.
diff --git a/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py b/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py index aadaf534..8774f2e 100755 --- a/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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.
diff --git a/components/policy/tools/template_writers/writers/jamf_writer.py b/components/policy/tools/template_writers/writers/jamf_writer.py index e87cd15..41fa458 100755 --- a/components/policy/tools/template_writers/writers/jamf_writer.py +++ b/components/policy/tools/template_writers/writers/jamf_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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. @@ -186,7 +186,8 @@ return if 'id' in obj: ids_in_ancestry.add(obj['id']) - for key, value in obj.items(): + # Make a copy of items since we are going to change |obj|. + for key, value in list(obj.items()): if type(value) is not dict: continue if '$ref' in value:
diff --git a/components/policy/tools/template_writers/writers/jamf_writer_unittest.py b/components/policy/tools/template_writers/writers/jamf_writer_unittest.py index 1ab69c4..35fc22b 100755 --- a/components/policy/tools/template_writers/writers/jamf_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/jamf_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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.
diff --git a/components/policy/tools/template_writers/writers/json_writer.py b/components/policy/tools/template_writers/writers/json_writer.py index 5943621..7d5d166c 100755 --- a/components/policy/tools/template_writers/writers/json_writer.py +++ b/components/policy/tools/template_writers/writers/json_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/json_writer_unittest.py b/components/policy/tools/template_writers/writers/json_writer_unittest.py index 3dacf25..5f7c3ad 100755 --- a/components/policy/tools/template_writers/writers/json_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/json_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/mock_writer.py b/components/policy/tools/template_writers/writers/mock_writer.py index bcb43ad..19e1d748 100755 --- a/components/policy/tools/template_writers/writers/mock_writer.py +++ b/components/policy/tools/template_writers/writers/mock_writer.py
@@ -1,9 +1,9 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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. -from template_writer import TemplateWriter +from .template_writer import TemplateWriter class MockWriter(TemplateWriter):
diff --git a/components/policy/tools/template_writers/writers/plist_helper.py b/components/policy/tools/template_writers/writers/plist_helper.py index 2f6d3d77..e69f00d 100755 --- a/components/policy/tools/template_writers/writers/plist_helper.py +++ b/components/policy/tools/template_writers/writers/plist_helper.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/plist_strings_writer.py b/components/policy/tools/template_writers/writers/plist_strings_writer.py index cb4d8482..adfbc6d 100755 --- a/components/policy/tools/template_writers/writers/plist_strings_writer.py +++ b/components/policy/tools/template_writers/writers/plist_strings_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/plist_writer.py b/components/policy/tools/template_writers/writers/plist_writer.py index acac7e2..e866648 100755 --- a/components/policy/tools/template_writers/writers/plist_writer.py +++ b/components/policy/tools/template_writers/writers/plist_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/plist_writer_unittest.py b/components/policy/tools/template_writers/writers/plist_writer_unittest.py index 05f7f6c9..92d75ee 100755 --- a/components/policy/tools/template_writers/writers/plist_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/plist_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/reg_writer.py b/components/policy/tools/template_writers/writers/reg_writer.py index 2e27978..3fbd0a6b 100755 --- a/components/policy/tools/template_writers/writers/reg_writer.py +++ b/components/policy/tools/template_writers/writers/reg_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/reg_writer_unittest.py b/components/policy/tools/template_writers/writers/reg_writer_unittest.py index e59777f..7278f76 100755 --- a/components/policy/tools/template_writers/writers/reg_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/reg_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/template_writer.py b/components/policy/tools/template_writers/writers/template_writer.py index 0ce8ed2..bc1c3489 100755 --- a/components/policy/tools/template_writers/writers/template_writer.py +++ b/components/policy/tools/template_writers/writers/template_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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. @@ -292,9 +292,9 @@ ''' for policy in policy_list: if policy['type'] == 'group': - child_policies = self._GetPoliciesForWriter(policy) - child_recommended_policies = filter(self.CanBeRecommended, - child_policies) + child_policies = list(self._GetPoliciesForWriter(policy)) + child_recommended_policies = list( + filter(self.CanBeRecommended, child_policies)) if child_policies: # Only write nonempty groups. self.BeginPolicyGroup(policy)
diff --git a/components/policy/tools/template_writers/writers/template_writer_unittest.py b/components/policy/tools/template_writers/writers/template_writer_unittest.py index 3d4988e2..d725cdfa 100755 --- a/components/policy/tools/template_writers/writers/template_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/template_writer_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/writer_unittest_common.py b/components/policy/tools/template_writers/writers/writer_unittest_common.py index b0fdf67..d96bb798 100755 --- a/components/policy/tools/template_writers/writers/writer_unittest_common.py +++ b/components/policy/tools/template_writers/writers/writer_unittest_common.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 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.
diff --git a/components/policy/tools/template_writers/writers/xml_formatted_writer.py b/components/policy/tools/template_writers/writers/xml_formatted_writer.py index c0db6faf..a8815370 100755 --- a/components/policy/tools/template_writers/writers/xml_formatted_writer.py +++ b/components/policy/tools/template_writers/writers/xml_formatted_writer.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy/tools/template_writers/writers/xml_writer_base_unittest.py b/components/policy/tools/template_writers/writers/xml_writer_base_unittest.py index 2b5df21..40c2ff5 100755 --- a/components/policy/tools/template_writers/writers/xml_writer_base_unittest.py +++ b/components/policy/tools/template_writers/writers/xml_writer_base_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 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.
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp index 3bd19eb..e7c3a1e 100644 --- a/components/policy_strings.grdp +++ b/components/policy_strings.grdp
@@ -175,6 +175,9 @@ <message name="IDS_POLICY_EXTENSION_SETTINGS_ORIGIN_LIMIT_WARNING" desc="The text displayed in the status column of the 'Extension Settings' policy when more than 100 origins are specified."> This field should not have more than <ph name="MAX_ITEMS_LIMIT">$1<ex>100</ex></ph> entries. All further entries will be discarded. </message> + <message name="IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING" desc="The text displayed in the status column of the URLAllowlist and URLBlocklist policies when the max number of filters is exceeded."> + This field should not have more than <ph name="MAX_ITEMS_LIMIT">$1<ex>1000</ex></ph> entries. All further entries will be ignored. + </message> <message name="IDS_POLICY_SUBKEY_ERROR" desc="The text displayed in the status column for errors in a subkey of a policy."> Key "<ph name="SUBKEY">$1<ex>ProxyMode</ex></ph>": <ph name="ERROR">$2<ex>Must be specified.</ex></ph> </message>
diff --git a/components/policy_strings_grdp/IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING.png.sha1 new file mode 100644 index 0000000..5d82254 --- /dev/null +++ b/components/policy_strings_grdp/IDS_POLICY_URL_ALLOW_BLOCK_LIST_MAX_FILTERS_LIMIT_WARNING.png.sha1
@@ -0,0 +1 @@ +d58121a8fede02fd87f1ee787afb9526d08f1a2f \ No newline at end of file
diff --git a/components/prefs/pref_service.h b/components/prefs/pref_service.h index 53532b0..6471f58e 100644 --- a/components/prefs/pref_service.h +++ b/components/prefs/pref_service.h
@@ -23,7 +23,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/observer_list.h" #include "base/sequence_checker.h" #include "base/time/time.h" #include "base/values.h"
diff --git a/components/query_tiles/internal/log_source.h b/components/query_tiles/internal/log_source.h index ac3b66f4..cbcc9f9a 100644 --- a/components/query_tiles/internal/log_source.h +++ b/components/query_tiles/internal/log_source.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_QUERY_TILES_INTERNAL_LOG_SOURCE_H_ #define COMPONENTS_QUERY_TILES_INTERNAL_LOG_SOURCE_H_ -#include "base/observer_list.h" #include "components/query_tiles/internal/log_sink.h" #include "components/query_tiles/internal/tile_group.h" #include "components/query_tiles/internal/tile_types.h"
diff --git a/components/reporting/proto/record_constants.proto b/components/reporting/proto/record_constants.proto index eab5c90..cb6c0f3 100644 --- a/components/reporting/proto/record_constants.proto +++ b/components/reporting/proto/record_constants.proto
@@ -48,6 +48,9 @@ // |DLP_EVENTS| events send from data leakage protection for Chrome OS DLP_EVENTS = 11; + + // |LOGIN_LOGOUT_EVENTS| is for login/logout events. + LOGIN_LOGOUT_EVENTS = 12; } // |Priority| is used to determine when items from the queue should be rate
diff --git a/components/safe_browsing/content/browser/client_side_detection_host.cc b/components/safe_browsing/content/browser/client_side_detection_host.cc index 7ada63d..4dcde9fc 100644 --- a/components/safe_browsing/content/browser/client_side_detection_host.cc +++ b/components/safe_browsing/content/browser/client_side_detection_host.cc
@@ -10,12 +10,15 @@ #include "base/bind.h" #include "base/check_op.h" +#include "base/command_line.h" +#include "base/guid.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/sequenced_task_runner_helpers.h" +#include "base/task/thread_pool.h" #include "base/time/default_tick_clock.h" #include "base/time/tick_clock.h" #include "components/prefs/pref_service.h" @@ -46,6 +49,35 @@ namespace safe_browsing { +namespace { + +// Command-line flag that can be used to write extracted CSD features to disk. +// This is also enables a few other behaviors that are useful for debugging. +const char kCsdDebugFeatureDirectoryFlag[] = "csd-debug-feature-directory"; + +void WriteFeaturesToDisk(const ClientPhishingRequest& features, + const base::FilePath& base_path) { + base::FilePath path = + base_path.AppendASCII(base::GUID::GenerateRandomV4().AsLowercaseString()); + base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); + if (!file.IsValid()) + return; + std::string serialized_features = features.SerializeAsString(); + file.WriteAtCurrentPos(serialized_features.data(), + serialized_features.size()); +} + +bool HasDebugFeatureDirectory() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + kCsdDebugFeatureDirectoryFlag); +} + +base::FilePath GetDebugFeatureDirectory() { + return base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( + kCsdDebugFeatureDirectoryFlag); +} +} // namespace + typedef base::OnceCallback<void(bool)> ShouldClassifyUrlCallback; // This class is instantiated each time a new toplevel URL loads, and @@ -192,6 +224,14 @@ void CheckSafeBrowsingDatabase(const GURL& url) { DCHECK_CURRENTLY_ON(BrowserThread::IO); PreClassificationCheckResult phishing_reason = NO_CLASSIFY_MAX; + + // When doing debug feature dumps, ignore the allowlist. + if (HasDebugFeatureDirectory()) { + OnAllowlistCheckDoneOnIO(url, NO_CLASSIFY_MAX, + /*match_allowlist=*/false); + return; + } + if (!database_manager_.get()) { // We cannot check the Safe Browsing allowlists so we stop here // for safety. @@ -234,8 +274,10 @@ } // If result is cached, we don't want to run classification again. // In that case we're just trying to show the warning. + // If we're dumping features for debugging, ignore the cache. bool is_phishing; - if (csd_service_->GetValidCachedResult(url_, &is_phishing)) { + if (!HasDebugFeatureDirectory() && + csd_service_->GetValidCachedResult(url_, &is_phishing)) { base::UmaHistogramBoolean("SBClientPhishing.RequestSatisfiedFromCache", true); // Since we are already on the UI thread, this is safe. @@ -249,7 +291,9 @@ // too many pages as phishing, but for those that we already think are // phishing we want to send a request to the server to give ourselves // a chance to fix misclassifications. - if (!csd_service_->IsInCache(url_) && + // If we're dumping features for debugging, allow us to exceed the report + // limit. + if (!HasDebugFeatureDirectory() && !csd_service_->IsInCache(url_) && csd_service_->OverPhishingReportLimit()) { DontClassifyForPhishing(NO_CLASSIFY_TOO_MANY_REPORTS); } @@ -468,6 +512,13 @@ VLOG(2) << "Phash Score: " << match.vision_matched_phash_score(); VLOG(2) << "EMD Score: " << match.vision_matched_emd_score(); } + + if (HasDebugFeatureDirectory()) { + base::ThreadPool::PostTask(FROM_HERE, {base::MayBlock()}, + base::BindOnce(&WriteFeaturesToDisk, *verdict, + GetDebugFeatureDirectory())); + } + if (!IsExtendedReportingEnabled(*delegate_->GetPrefs()) && !IsEnhancedProtectionEnabled(*delegate_->GetPrefs())) { // These fields should only be set for SBER users.
diff --git a/components/safe_browsing/content/triggers/BUILD.gn b/components/safe_browsing/content/triggers/BUILD.gn index 30be54c..74aa0f9c 100644 --- a/components/safe_browsing/content/triggers/BUILD.gn +++ b/components/safe_browsing/content/triggers/BUILD.gn
@@ -4,13 +4,50 @@ import("//build/config/features.gni") +source_set("triggers") { + sources = [ + "trigger_manager.cc", + "trigger_manager.h", + ] + public_deps = [ + "//components/security_interstitials/content:security_interstitial_page", + "//components/security_interstitials/core", + "//components/security_interstitials/core:unsafe_resource", + "//content/public/browser", + ] + deps = [ + ":trigger_throttler", + "//base:base", + "//components/prefs", + "//components/safe_browsing/content/browser", + "//components/safe_browsing/core:features", + "//components/safe_browsing/core/browser", + "//components/safe_browsing/core/browser:referrer_chain_provider", + "//components/safe_browsing/core/common:thread_utils", + "//net", + ] +} + +source_set("trigger_throttler") { + sources = [ + "trigger_throttler.cc", + "trigger_throttler.h", + ] + deps = [ + "//base", + "//components/prefs", + "//components/safe_browsing/core:features", + "//components/safe_browsing/core/common:safe_browsing_prefs", + ] +} + source_set("trigger_util") { sources = [ "trigger_util.cc", "trigger_util.h", ] deps = [ - "//components/safe_browsing/core/triggers", + ":triggers", "//content/public/browser", ] } @@ -21,11 +58,11 @@ "ad_popup_trigger.h", ] deps = [ + ":trigger_throttler", ":trigger_util", + ":triggers", "//base:base", "//components/safe_browsing/core:features", - "//components/safe_browsing/core/triggers", - "//components/safe_browsing/core/triggers:trigger_throttler", "//content/public/browser", ] } @@ -36,11 +73,11 @@ "ad_redirect_trigger.h", ] deps = [ + ":trigger_throttler", ":trigger_util", + ":triggers", "//base:base", "//components/safe_browsing/core:features", - "//components/safe_browsing/core/triggers", - "//components/safe_browsing/core/triggers:trigger_throttler", "//content/public/browser", "//content/public/common", ] @@ -52,11 +89,11 @@ "ad_sampler_trigger.h", ] deps = [ + ":trigger_throttler", ":trigger_util", + ":triggers", "//base:base", "//components/safe_browsing/core:features", - "//components/safe_browsing/core/triggers", - "//components/safe_browsing/core/triggers:trigger_throttler", "//content/public/browser", ] } @@ -67,12 +104,12 @@ "suspicious_site_trigger.h", ] deps = [ + ":trigger_throttler", + ":triggers", "//base:base", "//components/history/core/browser:browser", "//components/prefs:prefs", "//components/safe_browsing/core:features", - "//components/safe_browsing/core/triggers", - "//components/safe_browsing/core/triggers:trigger_throttler", "//content/public/browser", "//net:net", ] @@ -86,17 +123,22 @@ "mock_trigger_manager.cc", "mock_trigger_manager.h", "suspicious_site_trigger_unittest.cc", + "trigger_manager_unittest.cc", + "trigger_throttler_unittest.cc", ] deps = [ ":ad_popup_trigger", ":ad_sampler_trigger", ":suspicious_site_trigger", + ":trigger_throttler", + ":triggers", "//base", "//base/test:test_support", "//components/prefs:test_support", + "//components/safe_browsing/content/browser", "//components/safe_browsing/core:features", "//components/safe_browsing/core/browser:browser", - "//components/safe_browsing/core/triggers", + "//components/safe_browsing/core/common:test_support", "//components/subresource_filter/content/browser:test_support", "//content/public/browser:browser", "//content/test:test_support",
diff --git a/components/safe_browsing/content/triggers/ad_popup_trigger.cc b/components/safe_browsing/content/triggers/ad_popup_trigger.cc index 3080f0b..8a5ddd0f 100644 --- a/components/safe_browsing/content/triggers/ad_popup_trigger.cc +++ b/components/safe_browsing/content/triggers/ad_popup_trigger.cc
@@ -14,10 +14,10 @@ #include "base/rand_util.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "components/safe_browsing/content/triggers/trigger_util.h" #include "components/safe_browsing/core/features.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" -#include "components/safe_browsing/core/triggers/trigger_throttler.h" #include "components/security_interstitials/content/unsafe_resource_util.h" #include "components/security_interstitials/core/unsafe_resource.h" #include "content/public/browser/browser_task_traits.h"
diff --git a/components/safe_browsing/content/triggers/ad_redirect_trigger.cc b/components/safe_browsing/content/triggers/ad_redirect_trigger.cc index 7f49cd3..ead545d 100644 --- a/components/safe_browsing/content/triggers/ad_redirect_trigger.cc +++ b/components/safe_browsing/content/triggers/ad_redirect_trigger.cc
@@ -14,10 +14,10 @@ #include "base/rand_util.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "components/safe_browsing/content/triggers/trigger_util.h" #include "components/safe_browsing/core/features.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" -#include "components/safe_browsing/core/triggers/trigger_throttler.h" #include "components/security_interstitials/content/unsafe_resource_util.h" #include "components/security_interstitials/core/unsafe_resource.h" #include "content/public/browser/browser_task_traits.h"
diff --git a/components/safe_browsing/content/triggers/ad_sampler_trigger.cc b/components/safe_browsing/content/triggers/ad_sampler_trigger.cc index eb003d12..ecb803d 100644 --- a/components/safe_browsing/content/triggers/ad_sampler_trigger.cc +++ b/components/safe_browsing/content/triggers/ad_sampler_trigger.cc
@@ -14,10 +14,10 @@ #include "base/rand_util.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "components/safe_browsing/content/triggers/trigger_util.h" #include "components/safe_browsing/core/features.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" -#include "components/safe_browsing/core/triggers/trigger_throttler.h" #include "components/security_interstitials/content/unsafe_resource_util.h" #include "components/security_interstitials/core/unsafe_resource.h" #include "content/public/browser/browser_task_traits.h"
diff --git a/components/safe_browsing/content/triggers/mock_trigger_manager.h b/components/safe_browsing/content/triggers/mock_trigger_manager.h index 843e8f68..c2a86dfa 100644 --- a/components/safe_browsing/content/triggers/mock_trigger_manager.h +++ b/components/safe_browsing/content/triggers/mock_trigger_manager.h
@@ -6,7 +6,7 @@ #define COMPONENTS_SAFE_BROWSING_CONTENT_TRIGGERS_MOCK_TRIGGER_MANAGER_H_ #include "base/macros.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/safe_browsing/content/triggers/suspicious_site_trigger.cc b/components/safe_browsing/content/triggers/suspicious_site_trigger.cc index 8c0a5e1..a312869 100644 --- a/components/safe_browsing/content/triggers/suspicious_site_trigger.cc +++ b/components/safe_browsing/content/triggers/suspicious_site_trigger.cc
@@ -10,8 +10,8 @@ #include "base/single_thread_task_runner.h" #include "components/history/core/browser/history_service.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing/core/triggers/trigger_manager.h" -#include "components/safe_browsing/core/triggers/trigger_throttler.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "components/security_interstitials/content/unsafe_resource_util.h" #include "components/security_interstitials/core/unsafe_resource.h" #include "content/public/browser/browser_context.h"
diff --git a/components/safe_browsing/core/triggers/trigger_manager.cc b/components/safe_browsing/content/triggers/trigger_manager.cc similarity index 99% rename from components/safe_browsing/core/triggers/trigger_manager.cc rename to components/safe_browsing/content/triggers/trigger_manager.cc index 4bc1df4c..84cc078 100644 --- a/components/safe_browsing/core/triggers/trigger_manager.cc +++ b/components/safe_browsing/content/triggers/trigger_manager.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/safe_browsing/core/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" #include "base/bind.h" #include "base/containers/contains.h"
diff --git a/components/safe_browsing/core/triggers/trigger_manager.h b/components/safe_browsing/content/triggers/trigger_manager.h similarity index 96% rename from components/safe_browsing/core/triggers/trigger_manager.h rename to components/safe_browsing/content/triggers/trigger_manager.h index f7663cc9..8c72ea4 100644 --- a/components/safe_browsing/core/triggers/trigger_manager.h +++ b/components/safe_browsing/content/triggers/trigger_manager.h
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_SAFE_BROWSING_CORE_TRIGGERS_TRIGGER_MANAGER_H_ -#define COMPONENTS_SAFE_BROWSING_CORE_TRIGGERS_TRIGGER_MANAGER_H_ +#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_TRIGGERS_TRIGGER_MANAGER_H_ +#define COMPONENTS_SAFE_BROWSING_CONTENT_TRIGGERS_TRIGGER_MANAGER_H_ #include <unordered_map> #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "components/safe_browsing/core/browser/referrer_chain_provider.h" -#include "components/safe_browsing/core/triggers/trigger_throttler.h" #include "components/security_interstitials/core/base_safe_browsing_error_ui.h" #include "components/security_interstitials/core/unsafe_resource.h" #include "content/public/browser/web_contents.h" @@ -218,4 +218,4 @@ } // namespace safe_browsing -#endif // COMPONENTS_SAFE_BROWSING_CORE_TRIGGERS_TRIGGER_MANAGER_H_ +#endif // COMPONENTS_SAFE_BROWSING_CONTENT_TRIGGERS_TRIGGER_MANAGER_H_
diff --git a/components/safe_browsing/core/triggers/trigger_manager_unittest.cc b/components/safe_browsing/content/triggers/trigger_manager_unittest.cc similarity index 99% rename from components/safe_browsing/core/triggers/trigger_manager_unittest.cc rename to components/safe_browsing/content/triggers/trigger_manager_unittest.cc index fd14cca..83f1a9d9c 100644 --- a/components/safe_browsing/core/triggers/trigger_manager_unittest.cc +++ b/components/safe_browsing/content/triggers/trigger_manager_unittest.cc
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/safe_browsing/core/triggers/trigger_manager.h" +#include "components/safe_browsing/content/triggers/trigger_manager.h" #include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" #include "components/safe_browsing/content/browser/threat_details.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "components/safe_browsing/core/common/test_task_environment.h" #include "components/safe_browsing/core/features.h" -#include "components/safe_browsing/core/triggers/trigger_throttler.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_web_contents_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/components/safe_browsing/core/triggers/trigger_throttler.cc b/components/safe_browsing/content/triggers/trigger_throttler.cc similarity index 99% rename from components/safe_browsing/core/triggers/trigger_throttler.cc rename to components/safe_browsing/content/triggers/trigger_throttler.cc index 6a3a3da..ca186d2 100644 --- a/components/safe_browsing/core/triggers/trigger_throttler.cc +++ b/components/safe_browsing/content/triggers/trigger_throttler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/safe_browsing/core/triggers/trigger_throttler.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "base/containers/contains.h" #include "base/metrics/field_trial_params.h"
diff --git a/components/safe_browsing/core/triggers/trigger_throttler.h b/components/safe_browsing/content/triggers/trigger_throttler.h similarity index 94% rename from components/safe_browsing/core/triggers/trigger_throttler.h rename to components/safe_browsing/content/triggers/trigger_throttler.h index 93f2f80..b6a9e61b 100644 --- a/components/safe_browsing/core/triggers/trigger_throttler.h +++ b/components/safe_browsing/content/triggers/trigger_throttler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_SAFE_BROWSING_CORE_TRIGGERS_TRIGGER_THROTTLER_H_ -#define COMPONENTS_SAFE_BROWSING_CORE_TRIGGERS_TRIGGER_THROTTLER_H_ +#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_TRIGGERS_TRIGGER_THROTTLER_H_ +#define COMPONENTS_SAFE_BROWSING_CONTENT_TRIGGERS_TRIGGER_THROTTLER_H_ #include <memory> #include <unordered_map> @@ -117,4 +117,4 @@ } // namespace safe_browsing -#endif // COMPONENTS_SAFE_BROWSING_CORE_TRIGGERS_TRIGGER_THROTTLER_H_ +#endif // COMPONENTS_SAFE_BROWSING_CONTENT_TRIGGERS_TRIGGER_THROTTLER_H_
diff --git a/components/safe_browsing/core/triggers/trigger_throttler_unittest.cc b/components/safe_browsing/content/triggers/trigger_throttler_unittest.cc similarity index 99% rename from components/safe_browsing/core/triggers/trigger_throttler_unittest.cc rename to components/safe_browsing/content/triggers/trigger_throttler_unittest.cc index 3722a9d..ebe09fe 100644 --- a/components/safe_browsing/core/triggers/trigger_throttler_unittest.cc +++ b/components/safe_browsing/content/triggers/trigger_throttler_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/safe_browsing/core/triggers/trigger_throttler.h" +#include "components/safe_browsing/content/triggers/trigger_throttler.h" #include "base/strings/stringprintf.h" #include "base/test/scoped_feature_list.h"
diff --git a/components/safe_browsing/core/triggers/BUILD.gn b/components/safe_browsing/core/triggers/BUILD.gn deleted file mode 100644 index 921c97f..0000000 --- a/components/safe_browsing/core/triggers/BUILD.gn +++ /dev/null
@@ -1,65 +0,0 @@ -# Copyright 2017 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("//build/config/features.gni") - -source_set("triggers") { - sources = [ - "trigger_manager.cc", - "trigger_manager.h", - ] - public_deps = [ - "//components/security_interstitials/content:security_interstitial_page", - "//components/security_interstitials/core:core", - "//components/security_interstitials/core:unsafe_resource", - "//content/public/browser:browser", - ] - deps = [ - ":trigger_throttler", - "//base:base", - "//components/prefs:prefs", - "//components/safe_browsing/content/browser", - "//components/safe_browsing/core:features", - "//components/safe_browsing/core/browser:browser", - "//components/safe_browsing/core/browser:referrer_chain_provider", - "//components/safe_browsing/core/common:thread_utils", - "//net:net", - ] -} - -source_set("trigger_throttler") { - sources = [ - "trigger_throttler.cc", - "trigger_throttler.h", - ] - deps = [ - "//base:base", - "//components/prefs:prefs", - "//components/safe_browsing/core:features", - "//components/safe_browsing/core/common:safe_browsing_prefs", - ] -} - -source_set("unit_tests") { - testonly = true - sources = [ - "trigger_manager_unittest.cc", - "trigger_throttler_unittest.cc", - ] - deps = [ - ":trigger_throttler", - ":triggers", - "//base", - "//base/test:test_support", - "//components/prefs:test_support", - "//components/safe_browsing/content/browser", - "//components/safe_browsing/core:features", - "//components/safe_browsing/core/browser:browser", - "//components/safe_browsing/core/common:test_support", - "//content/public/browser:browser", - "//content/test:test_support", - "//testing/gmock", - "//testing/gtest", - ] -}
diff --git a/components/safe_browsing/core/triggers/DEPS b/components/safe_browsing/core/triggers/DEPS deleted file mode 100644 index 6b0d03f..0000000 --- a/components/safe_browsing/core/triggers/DEPS +++ /dev/null
@@ -1,5 +0,0 @@ -include_rules = [ - "+components/history/core/browser", - "+components/prefs", - "+content/public/test", -]
diff --git a/components/safe_browsing/core/triggers/OWNERS b/components/safe_browsing/core/triggers/OWNERS deleted file mode 100644 index c83e5caf..0000000 --- a/components/safe_browsing/core/triggers/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -lpz@chromium.org
diff --git a/components/safety_check/safety_check.h b/components/safety_check/safety_check.h index 6dcf7b3..ef19925 100644 --- a/components/safety_check/safety_check.h +++ b/components/safety_check/safety_check.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_SAFETY_CHECK_SAFETY_CHECK_H_ #define COMPONENTS_SAFETY_CHECK_SAFETY_CHECK_H_ -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "components/prefs/pref_service.h"
diff --git a/components/search/BUILD.gn b/components/search/BUILD.gn index d605086..df271d3 100644 --- a/components/search/BUILD.gn +++ b/components/search/BUILD.gn
@@ -49,6 +49,7 @@ "//components/signin/public/base:test_support", "//components/signin/public/identity_manager:test_support", "//components/variations", + "//components/variations:test_support", "//services/data_decoder/public/cpp:test_support", "//testing/gmock", "//testing/gtest",
diff --git a/components/search_engines/BUILD.gn b/components/search_engines/BUILD.gn index c2b09f07..6cd8400 100644 --- a/components/search_engines/BUILD.gn +++ b/components/search_engines/BUILD.gn
@@ -170,6 +170,7 @@ "//components/prefs", "//components/sync:test_support", "//components/sync_preferences:test_support", + "//components/variations:test_support", "//components/webdata/common", "//net:net", "//services/network:test_support",
diff --git a/components/search_engines/default_search_manager_unittest.cc b/components/search_engines/default_search_manager_unittest.cc index ef0c6d0..9933ff7f 100644 --- a/components/search_engines/default_search_manager_unittest.cc +++ b/components/search_engines/default_search_manager_unittest.cc
@@ -23,6 +23,7 @@ #include "components/search_engines/template_url_data_util.h" #include "components/search_engines/template_url_prepopulate_data.h" #include "components/sync_preferences/testing_pref_service_syncable.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -94,6 +95,8 @@ } private: + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> pref_service_; DISALLOW_COPY_AND_ASSIGN(DefaultSearchManagerTest);
diff --git a/components/signin/internal/identity_manager/account_tracker_service.h b/components/signin/internal/identity_manager/account_tracker_service.h index afe4c7a..4de08393 100644 --- a/components/signin/internal/identity_manager/account_tracker_service.h +++ b/components/signin/internal/identity_manager/account_tracker_service.h
@@ -14,7 +14,6 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/observer_list.h" #include "base/sequence_checker.h" #include "base/timer/timer.h" #include "build/build_config.h"
diff --git a/components/signin/internal/identity_manager/gaia_cookie_manager_service.h b/components/signin/internal/identity_manager/gaia_cookie_manager_service.h index 201bc6c..630826c 100644 --- a/components/signin/internal/identity_manager/gaia_cookie_manager_service.h +++ b/components/signin/internal/identity_manager/gaia_cookie_manager_service.h
@@ -15,7 +15,6 @@ #include "base/containers/circular_deque.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/timer/timer.h" #include "components/prefs/pref_registry_simple.h" #include "components/signin/internal/identity_manager/profile_oauth2_token_service.h"
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc index c1abe6c4..e987413a 100644 --- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc +++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -179,6 +179,10 @@ access_token_failure_ = error; } + std::string GetConsumerName() const override { + return "mutable_profile_oauth2_token_service_delegate_unittest"; + } + // ProfileOAuth2TokenServiceObserver implementation. void OnRefreshTokenAvailable(const CoreAccountId& account_id) override { ++token_available_count_;
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc index eff34b2..db3a004 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
@@ -22,9 +22,6 @@ namespace { -constexpr char kOAuthConsumerName[] = - "ProfileOAuth2TokenServiceDelegateChromeOS"; - // Values used from |MutableProfileOAuth2TokenServiceDelegate|. const net::BackoffEntry::Policy kBackoffPolicy = { 0 /* int num_errors_to_ignore */, @@ -193,13 +190,11 @@ consumer, backoff_error_); } - // TODO(https://crbug.com/1192668): use the consumer name that was passed to - // `IdentityManager::CreateAccessTokenFetcher`. return account_manager_facade_->CreateAccessTokenFetcher( account_manager::AccountKey{ account_tracker_service_->GetAccountInfo(account_id).gaia, account_manager::AccountType::kGaia} /* account_key */, - kOAuthConsumerName, consumer); + consumer->GetConsumerName(), consumer); } // Note: This method should use the same logic for filtering accounts as
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc index d2c1fcc..ab5cebb 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
@@ -60,6 +60,10 @@ ++num_access_token_fetch_failure_; } + std::string GetConsumerName() const override { + return "profile_oauth2_token_service_delegate_chromeos_unittest"; + } + int num_access_token_fetch_success_ = 0; int num_access_token_fetch_failure_ = 0;
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios_unittest.mm b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios_unittest.mm index 278a7268..016d758 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios_unittest.mm +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios_unittest.mm
@@ -66,6 +66,10 @@ last_access_token_error_ = error; } + std::string GetConsumerName() const override { + return "profile_oauth2_token_service_delegate_ios_unittest"; + } + // ProfileOAuth2TokenServiceObserver implementation. void OnRefreshTokenAvailable(const CoreAccountId& account_id) override { ++token_available_count_;
diff --git a/components/soda/soda_installer_impl_chromeos.h b/components/soda/soda_installer_impl_chromeos.h index cbcb13c..603c20cf 100644 --- a/components/soda/soda_installer_impl_chromeos.h +++ b/components/soda/soda_installer_impl_chromeos.h
@@ -10,11 +10,6 @@ #include "components/soda/soda_installer.h" class PrefService; -class OnDeviceSpeechRecognizerTest; - -namespace ash { -class DictationTest; -} // namespace ash namespace speech { @@ -43,10 +38,11 @@ bool IsLanguageInstalled( const std::string& locale_or_language) const override; - private: - friend class ::ash::DictationTest; - friend class ::OnDeviceSpeechRecognizerTest; + void set_soda_installed_for_test(bool installed) { + soda_installed_for_test_ = installed; + } + private: // SodaInstaller: void InstallSoda(PrefService* global_prefs) override; // Here "uninstall" is used in the DLC sense of the term: Uninstallation will
diff --git a/components/subresource_redirect/common/subresource_redirect_result.h b/components/subresource_redirect/common/subresource_redirect_result.h index 0454aeb3c..dae817b 100644 --- a/components/subresource_redirect/common/subresource_redirect_result.h +++ b/components/subresource_redirect/common/subresource_redirect_result.h
@@ -65,8 +65,11 @@ // got disabled. kIneligibleFirstKDisableSubresourceRedirect = 12, - kMaxValue = - SubresourceRedirectResult::kIneligibleFirstKDisableSubresourceRedirect + // Because the subresource redirection was disabled, where only metrics are + // recorded and the actual subresource redirection does not happen. + kIneligibleCompressionDisabled = 13, + + kMaxValue = SubresourceRedirectResult::kIneligibleCompressionDisabled }; } // namespace subresource_redirect
diff --git a/components/suggestions/BUILD.gn b/components/suggestions/BUILD.gn index d312075e..f3b54188 100644 --- a/components/suggestions/BUILD.gn +++ b/components/suggestions/BUILD.gn
@@ -51,6 +51,7 @@ "//components/signin/public/identity_manager:test_support", "//components/sync:test_support", "//components/sync_preferences:test_support", + "//components/variations:test_support", "//net:test_support", "//services/network:test_support", "//testing/gmock",
diff --git a/components/suggestions/suggestions_service_impl_unittest.cc b/components/suggestions/suggestions_service_impl_unittest.cc index 143c3196..be60b86 100644 --- a/components/suggestions/suggestions_service_impl_unittest.cc +++ b/components/suggestions/suggestions_service_impl_unittest.cc
@@ -21,6 +21,7 @@ #include "components/suggestions/suggestions_store.h" #include "components/sync/driver/sync_service.h" #include "components/sync/driver/test_sync_service.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/base/url_util.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" @@ -195,6 +196,8 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; private: + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; signin::IdentityTestEnvironment identity_test_env_; syncer::TestSyncService test_sync_service_; network::TestURLLoaderFactory url_loader_factory_;
diff --git a/components/suggestions/suggestions_store_unittest.cc b/components/suggestions/suggestions_store_unittest.cc index d2ff478..5f91e0c2 100644 --- a/components/suggestions/suggestions_store_unittest.cc +++ b/components/suggestions/suggestions_store_unittest.cc
@@ -13,6 +13,7 @@ #include "base/time/time.h" #include "components/suggestions/proto/suggestions.pb.h" #include "components/sync_preferences/testing_pref_service_syncable.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "testing/gtest/include/gtest/gtest.h" using sync_preferences::TestingPrefServiceSyncable; @@ -92,6 +93,8 @@ } protected: + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> pref_service_; std::unique_ptr<SuggestionsStore> suggestions_store_; base::SimpleTestClock test_clock_;
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn index c8575ba..1bddf1c 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn
@@ -237,6 +237,7 @@ "//components/sync/base:test_support", "//components/sync/driver:test_support", "//components/sync/invalidations:test_support", + "//components/variations:test_support", "//components/version_info", "//components/version_info:generate_version_info", "//components/version_info:version_string",
diff --git a/components/sync/driver/sync_service_crypto.cc b/components/sync/driver/sync_service_crypto.cc index 8985797a..49c2f250 100644 --- a/components/sync/driver/sync_service_crypto.cc +++ b/components/sync/driver/sync_service_crypto.cc
@@ -55,11 +55,6 @@ NOTREACHED(); } - void RemoveAllStoredKeys() override { - // Never invoked by SyncServiceCrypto. - NOTREACHED(); - } - void MarkKeysAsStale(const CoreAccountInfo& account_info, base::OnceCallback<void(bool)> cb) override { std::move(cb).Run(false);
diff --git a/components/sync/driver/sync_service_crypto_unittest.cc b/components/sync/driver/sync_service_crypto_unittest.cc index 8cc20ce9..f853f34 100644 --- a/components/sync/driver/sync_service_crypto_unittest.cc +++ b/components/sync/driver/sync_service_crypto_unittest.cc
@@ -218,13 +218,6 @@ } } - void RemoveAllStoredKeys() override { - gaia_id_to_cached_keys_.clear(); - for (Observer& observer : observer_list_) { - observer.OnTrustedVaultKeysChanged(); - } - } - void MarkKeysAsStale(const CoreAccountInfo& account_info, base::OnceCallback<void(bool)> cb) override { const std::string& gaia_id = account_info.gaia;
diff --git a/components/sync/driver/sync_service_impl.cc b/components/sync/driver/sync_service_impl.cc index 28b2dabb..b00c7e3c 100644 --- a/components/sync/driver/sync_service_impl.cc +++ b/components/sync/driver/sync_service_impl.cc
@@ -1467,10 +1467,6 @@ accounts_in_cookie_jar_info.signed_in_accounts, base::NullCallback()); } -void SyncServiceImpl::OnAccountsCookieDeletedByUserAction() { - sync_client_->GetTrustedVaultClient()->RemoveAllStoredKeys(); -} - void SyncServiceImpl::OnAccountsInCookieUpdatedWithCallback( const std::vector<gaia::ListedAccount>& signed_in_accounts, base::OnceClosure callback) {
diff --git a/components/sync/driver/sync_service_impl.h b/components/sync/driver/sync_service_impl.h index 8595f8f..a0282df 100644 --- a/components/sync/driver/sync_service_impl.h +++ b/components/sync/driver/sync_service_impl.h
@@ -184,7 +184,6 @@ void OnAccountsInCookieUpdated( const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info, const GoogleServiceAuthError& error) override; - void OnAccountsCookieDeletedByUserAction() override; // Similar to above but with a callback that will be invoked on completion. void OnAccountsInCookieUpdatedWithCallback(
diff --git a/components/sync/driver/trusted_vault_client.h b/components/sync/driver/trusted_vault_client.h index f2f46e7..ef923dcf 100644 --- a/components/sync/driver/trusted_vault_client.h +++ b/components/sync/driver/trusted_vault_client.h
@@ -11,7 +11,6 @@ #include "base/callback_forward.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" struct CoreAccountInfo; @@ -71,11 +70,6 @@ const std::vector<std::vector<uint8_t>>& keys, int last_key_version) = 0; - // Allows implementation to remove all previously stored keys. - // Implementations must erase all keys saved during StoreKeys() call. Used - // when accounts cookies deleted by the user action. - virtual void RemoveAllStoredKeys() = 0; - // Returns whether recoverability of the keys is degraded and user action is // required to add a new method. This may be called frequently and // implementations are responsible for implementing caching and possibly
diff --git a/components/sync/engine/net/http_bridge_unittest.cc b/components/sync/engine/net/http_bridge_unittest.cc index 0f5ff4efa..e846886 100644 --- a/components/sync/engine/net/http_bridge_unittest.cc +++ b/components/sync/engine/net/http_bridge_unittest.cc
@@ -19,6 +19,7 @@ #include "base/threading/thread.h" #include "build/build_config.h" #include "components/sync/engine/cancelation_signal.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -111,6 +112,8 @@ HttpBridge* bridge_for_race_test_; base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; // Separate thread for IO used by the HttpBridge. base::Thread io_thread_; };
diff --git a/components/sync/invalidations/fcm_registration_token_observer.h b/components/sync/invalidations/fcm_registration_token_observer.h index 8474a6cb..0e88b6f 100644 --- a/components/sync/invalidations/fcm_registration_token_observer.h +++ b/components/sync/invalidations/fcm_registration_token_observer.h
@@ -5,7 +5,7 @@ #ifndef COMPONENTS_SYNC_INVALIDATIONS_FCM_REGISTRATION_TOKEN_OBSERVER_H_ #define COMPONENTS_SYNC_INVALIDATIONS_FCM_REGISTRATION_TOKEN_OBSERVER_H_ -#include "base/observer_list.h" +#include "base/observer_list_types.h" namespace syncer {
diff --git a/components/sync/invalidations/invalidations_listener.h b/components/sync/invalidations/invalidations_listener.h index c61c61e7..e0bc955 100644 --- a/components/sync/invalidations/invalidations_listener.h +++ b/components/sync/invalidations/invalidations_listener.h
@@ -7,7 +7,7 @@ #include <string> -#include "base/observer_list.h" +#include "base/observer_list_types.h" namespace syncer {
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc index 6b2edf16..940a930 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl.cc +++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -12,6 +12,7 @@ #include "base/json/json_string_value_serializer.h" #include "base/location.h" #include "base/metrics/histogram_macros.h" +#include "base/observer_list.h" #include "components/sync/base/encryptor.h" #include "components/sync/base/passphrase_enums.h" #include "components/sync/base/sync_base_switches.h"
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h index c6503e6..908a47a 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl.h +++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -12,7 +12,6 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/sequence_checker.h" #include "base/time/time.h" #include "components/sync/engine/nigori/key_derivation_params.h"
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.h b/components/sync/trusted_vault/standalone_trusted_vault_backend.h index b93947f2..0508589 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_backend.h +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.h
@@ -81,7 +81,8 @@ // |account_info| will trigger a key download attempt. bool MarkKeysAsStale(const CoreAccountInfo& account_info); - // Removes all keys for all accounts from both memory and |file_path_|. + // Removes all keys for all accounts from both memory and |file_path_|. Called + // when accounts cookie deleted by the user action. void RemoveAllStoredKeys(); // Sets/resets |primary_account_|.
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_client.cc b/components/sync/trusted_vault/standalone_trusted_vault_client.cc index 4a142209..6cb4886 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_client.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_client.cc
@@ -42,36 +42,41 @@ return GURL(string_url); } -class PrimaryAccountObserver : public signin::IdentityManager::Observer { +class IdentityManagerObserver : public signin::IdentityManager::Observer { public: - PrimaryAccountObserver( + IdentityManagerObserver( scoped_refptr<base::SequencedTaskRunner> backend_task_runner, scoped_refptr<StandaloneTrustedVaultBackend> backend, + const base::RepeatingClosure& notify_keys_changed_callback, signin::IdentityManager* identity_manager); - PrimaryAccountObserver(const PrimaryAccountObserver& other) = delete; - PrimaryAccountObserver& operator=(const PrimaryAccountObserver& other) = + IdentityManagerObserver(const IdentityManagerObserver& other) = delete; + IdentityManagerObserver& operator=(const IdentityManagerObserver& other) = delete; - ~PrimaryAccountObserver() override; + ~IdentityManagerObserver() override; // signin::IdentityManager::Observer implementation. void OnPrimaryAccountChanged( const signin::PrimaryAccountChangeEvent& event) override; + void OnAccountsCookieDeletedByUserAction() override; private: void UpdatePrimaryAccountIfNeeded(); const scoped_refptr<base::SequencedTaskRunner> backend_task_runner_; const scoped_refptr<StandaloneTrustedVaultBackend> backend_; + const base::RepeatingClosure notify_keys_changed_callback_; signin::IdentityManager* const identity_manager_; CoreAccountInfo primary_account_; }; -PrimaryAccountObserver::PrimaryAccountObserver( +IdentityManagerObserver::IdentityManagerObserver( scoped_refptr<base::SequencedTaskRunner> backend_task_runner, scoped_refptr<StandaloneTrustedVaultBackend> backend, + const base::RepeatingClosure& notify_keys_changed_callback, signin::IdentityManager* identity_manager) : backend_task_runner_(backend_task_runner), backend_(backend), + notify_keys_changed_callback_(notify_keys_changed_callback), identity_manager_(identity_manager) { DCHECK(backend_task_runner_); DCHECK(backend_); @@ -81,16 +86,24 @@ UpdatePrimaryAccountIfNeeded(); } -PrimaryAccountObserver::~PrimaryAccountObserver() { +IdentityManagerObserver::~IdentityManagerObserver() { identity_manager_->RemoveObserver(this); } -void PrimaryAccountObserver::OnPrimaryAccountChanged( +void IdentityManagerObserver::OnPrimaryAccountChanged( const signin::PrimaryAccountChangeEvent& event) { UpdatePrimaryAccountIfNeeded(); } -void PrimaryAccountObserver::UpdatePrimaryAccountIfNeeded() { +void IdentityManagerObserver::OnAccountsCookieDeletedByUserAction() { + backend_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&StandaloneTrustedVaultBackend::RemoveAllStoredKeys, + backend_)); + notify_keys_changed_callback_.Run(); +} + +void IdentityManagerObserver::UpdatePrimaryAccountIfNeeded() { CoreAccountInfo primary_account = identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin); if (primary_account == primary_account_) { @@ -162,15 +175,21 @@ FROM_HERE, base::BindOnce(&StandaloneTrustedVaultBackend::ReadDataFromDisk, backend_)); - primary_account_observer_ = std::make_unique<PrimaryAccountObserver>( - backend_task_runner_, backend_, identity_manager); + // Using base::Unretained() is safe here, because |identity_manager_observer_| + // owned by |this|. + identity_manager_observer_ = std::make_unique<IdentityManagerObserver>( + backend_task_runner_, backend_, + base::BindRepeating( + &StandaloneTrustedVaultClient::NotifyTrustedVaultKeysChanged, + base::Unretained(this)), + identity_manager); } StandaloneTrustedVaultClient::~StandaloneTrustedVaultClient() { // |backend_| needs to be destroyed inside backend sequence, not the current - // one. Destroy |primary_account_observer_| that owns pointer to |backend_| + // one. Destroy |identity_manager_observer_| that owns pointer to |backend_| // as well and release |backend_| in |backend_task_runner_|. - primary_account_observer_.reset(); + identity_manager_observer_.reset(); backend_task_runner_->ReleaseSoon(FROM_HERE, std::move(backend_)); } @@ -204,21 +223,7 @@ backend_task_runner_->PostTask( FROM_HERE, base::BindOnce(&StandaloneTrustedVaultBackend::StoreKeys, backend_, gaia_id, keys, last_key_version)); - for (Observer& observer : observer_list_) { - observer.OnTrustedVaultKeysChanged(); - } -} - -void StandaloneTrustedVaultClient::RemoveAllStoredKeys() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(backend_); - backend_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&StandaloneTrustedVaultBackend::RemoveAllStoredKeys, - backend_)); - for (Observer& observer : observer_list_) { - observer.OnTrustedVaultKeysChanged(); - } + NotifyTrustedVaultKeysChanged(); } void StandaloneTrustedVaultClient::MarkKeysAsStale( @@ -301,6 +306,13 @@ std::move(callback)); } +void StandaloneTrustedVaultClient::NotifyTrustedVaultKeysChanged() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + for (Observer& observer : observer_list_) { + observer.OnTrustedVaultKeysChanged(); + } +} + void StandaloneTrustedVaultClient::NotifyRecoverabilityDegradedChanged() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); for (Observer& observer : observer_list_) {
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_client.h b/components/sync/trusted_vault/standalone_trusted_vault_client.h index a9933d0..a9525b6 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_client.h +++ b/components/sync/trusted_vault/standalone_trusted_vault_client.h
@@ -60,7 +60,6 @@ void StoreKeys(const std::string& gaia_id, const std::vector<std::vector<uint8_t>>& keys, int last_key_version) override; - void RemoveAllStoredKeys() override; void MarkKeysAsStale(const CoreAccountInfo& account_info, base::OnceCallback<void(bool)> cb) override; void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info, @@ -80,6 +79,7 @@ base::OnceCallback<void(const std::vector<uint8_t>&)> callback); private: + void NotifyTrustedVaultKeysChanged(); void NotifyRecoverabilityDegradedChanged(); const scoped_refptr<base::SequencedTaskRunner> backend_task_runner_; @@ -96,9 +96,9 @@ // |backend_task_runner_|. scoped_refptr<StandaloneTrustedVaultBackend> backend_; - // Observes changes of primary account and populates them into |backend_|. + // Observes changes of accounts state and populates them into |backend_|. // Holds references to |backend_| and |backend_task_runner_|. - std::unique_ptr<signin::IdentityManager::Observer> primary_account_observer_; + std::unique_ptr<signin::IdentityManager::Observer> identity_manager_observer_; base::WeakPtrFactory<StandaloneTrustedVaultClient> weak_ptr_factory_{this}; };
diff --git a/components/sync_bookmarks/bookmark_model_merger_unittest.cc b/components/sync_bookmarks/bookmark_model_merger_unittest.cc index d083b7c..425919ec 100644 --- a/components/sync_bookmarks/bookmark_model_merger_unittest.cc +++ b/components/sync_bookmarks/bookmark_model_merger_unittest.cc
@@ -958,10 +958,10 @@ bookmark_model->bookmark_bar_node(); const bookmarks::BookmarkNode* folder1 = bookmark_model->AddFolder( /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16(kTitle1), - /*meta_info=*/nullptr, kGuid1); + /*meta_info=*/nullptr, /*creation_time=*/base::Time::Now(), kGuid1); const bookmarks::BookmarkNode* folder2 = bookmark_model->AddFolder( /*parent=*/folder1, /*index=*/0, base::UTF8ToUTF16(kTitle2), - /*meta_info=*/nullptr, kGuid2); + /*meta_info=*/nullptr, /*creation_time=*/base::Time::Now(), kGuid2); ASSERT_TRUE(folder1); ASSERT_TRUE(folder2); ASSERT_THAT(bookmark_bar_node->children(), ElementRawPointersAre(folder1)); @@ -1083,7 +1083,8 @@ bookmark_model->bookmark_bar_node(); const bookmarks::BookmarkNode* folder = bookmark_model->AddFolder( /*parent=*/bookmark_bar_node, /*index=*/0, - base::UTF8ToUTF16(kOriginalTitle), /*meta_info=*/nullptr, kGuid1); + base::UTF8ToUTF16(kOriginalTitle), /*meta_info=*/nullptr, + /*creation_time=*/base::Time::Now(), kGuid1); const bookmarks::BookmarkNode* bookmark = bookmark_model->AddURL( /*parent=*/folder, /*index=*/0, u"Bookmark Title", GURL("http://foo.com/")); @@ -1165,7 +1166,8 @@ bookmark_model->bookmark_bar_node(); const bookmarks::BookmarkNode* folder = bookmark_model->AddFolder( /*parent=*/bookmark_bar_node, /*index=*/0, - base::UTF8ToUTF16(kOriginalTitle), /*meta_info=*/nullptr, kGuid1); + base::UTF8ToUTF16(kOriginalTitle), /*meta_info=*/nullptr, + /*creation_time=*/base::Time::Now(), kGuid1); const bookmarks::BookmarkNode* bookmark = bookmark_model->AddURL( /*parent=*/folder, /*index=*/0, u"Bookmark Title", GURL("http://foo.com/")); @@ -1339,10 +1341,10 @@ bookmark_model->bookmark_bar_node(); const bookmarks::BookmarkNode* folder = bookmark_model->AddFolder( /*parent=*/bookmark_bar_node, /*index=*/0, u"Folder Title", - /*meta_info=*/nullptr, kGuid1); + /*meta_info=*/nullptr, /*creation_time=*/base::Time::Now(), kGuid1); const bookmarks::BookmarkNode* bookmark = bookmark_model->AddURL( /*parent=*/folder, /*index=*/0, u"Foo's title", GURL("http://foo.com"), - /*meta_info=*/nullptr, base::Time::Now(), kGuid2); + /*meta_info=*/nullptr, /*creation_time=*/base::Time::Now(), kGuid2); ASSERT_TRUE(folder); ASSERT_TRUE(bookmark); ASSERT_THAT(bookmark_bar_node->children(), ElementRawPointersAre(folder));
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc index 5f016d4..bdefa80 100644 --- a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc +++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -1885,7 +1885,7 @@ bookmark_model()->bookmark_bar_node(); const bookmarks::BookmarkNode* node = bookmark_model()->AddFolder( bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16(kFolderTitle), - /*meta_info=*/nullptr, kGuid); + /*meta_info=*/nullptr, /*creation_time=*/base::Time::Now(), kGuid); sync_pb::BookmarkModelMetadata model_metadata = CreateMetadataForPermanentNodes(bookmark_model()); sync_pb::BookmarkMetadata* node_metadata =
diff --git a/components/sync_bookmarks/bookmark_specifics_conversions.cc b/components/sync_bookmarks/bookmark_specifics_conversions.cc index 7c5ee5f..1c61b31 100644 --- a/components/sync_bookmarks/bookmark_specifics_conversions.cc +++ b/components/sync_bookmarks/bookmark_specifics_conversions.cc
@@ -294,21 +294,20 @@ bookmarks::BookmarkNode::MetaInfoMap metainfo = GetBookmarkMetaInfo(specifics); + const int64_t creation_time_us = specifics.creation_time_us(); + const base::Time creation_time = base::Time::FromDeltaSinceWindowsEpoch( + // Use FromDeltaSinceWindowsEpoch because creation_time_us has + // always used the Windows epoch. + base::TimeDelta::FromMicroseconds(creation_time_us)); + if (is_folder) { - // TODO(crbug.com/1214840): Folders should propagate the creation time into - // BookmarkModel, just like non-folders. return model->AddFolder(parent, index, NodeTitleFromSpecifics(specifics), - &metainfo, guid); + &metainfo, creation_time, guid); } - const int64_t create_time_us = specifics.creation_time_us(); - base::Time create_time = base::Time::FromDeltaSinceWindowsEpoch( - // Use FromDeltaSinceWindowsEpoch because create_time_us has - // always used the Windows epoch. - base::TimeDelta::FromMicroseconds(create_time_us)); const bookmarks::BookmarkNode* node = model->AddURL(parent, index, NodeTitleFromSpecifics(specifics), - GURL(specifics.url()), &metainfo, create_time, guid); + GURL(specifics.url()), &metainfo, creation_time, guid); SetBookmarkFaviconFromSpecifics(specifics, node, favicon_service); return node; @@ -350,9 +349,9 @@ const bookmarks::BookmarkNode* new_node = nullptr; if (node->is_folder()) { - new_node = - model->AddFolder(node->parent(), node->parent()->GetIndexOf(node), - node->GetTitle(), node->GetMetaInfoMap(), guid); + new_node = model->AddFolder( + node->parent(), node->parent()->GetIndexOf(node), node->GetTitle(), + node->GetMetaInfoMap(), node->date_added(), guid); } else { new_node = model->AddURL(node->parent(), node->parent()->GetIndexOf(node), node->GetTitle(), node->url(),
diff --git a/components/translate/core/browser/BUILD.gn b/components/translate/core/browser/BUILD.gn index b3464b3..c9415a0 100644 --- a/components/translate/core/browser/BUILD.gn +++ b/components/translate/core/browser/BUILD.gn
@@ -129,6 +129,7 @@ "//components/ukm", "//components/ukm:test_support", "//components/variations", + "//components/variations:test_support", "//net:test_support", "//services/metrics/public/cpp:metrics_cpp", "//services/metrics/public/cpp:ukm_builders",
diff --git a/components/translate/core/browser/mock_translate_driver.cc b/components/translate/core/browser/mock_translate_driver.cc index 86cdd0a..945318e 100644 --- a/components/translate/core/browser/mock_translate_driver.cc +++ b/components/translate/core/browser/mock_translate_driver.cc
@@ -10,8 +10,6 @@ namespace testing { -const std::string kHtmlMimeType = "text/html"; - MockTranslateDriver::MockTranslateDriver() : is_incognito_(false), on_is_page_translated_changed_called_(false), @@ -49,7 +47,7 @@ } const std::string& MockTranslateDriver::GetContentsMimeType() { - return kHtmlMimeType; + return page_mime_type_; } const GURL& MockTranslateDriver::GetLastCommittedURL() { @@ -76,6 +74,11 @@ last_committed_url_ = url; } +void MockTranslateDriver::SetPageMimeType( + const std::string& mime_type) { + page_mime_type_ = mime_type; +} + } // namespace testing } // namespace translate
diff --git a/components/translate/core/browser/mock_translate_driver.h b/components/translate/core/browser/mock_translate_driver.h index f0025d2e..cb1a52e 100644 --- a/components/translate/core/browser/mock_translate_driver.h +++ b/components/translate/core/browser/mock_translate_driver.h
@@ -56,6 +56,8 @@ void SetLastCommittedURL(const GURL& url); + void SetPageMimeType(const std::string& mime_type); + private: bool is_incognito_; bool on_is_page_translated_changed_called_; @@ -63,6 +65,7 @@ bool translate_page_is_called_; LanguageState language_state_; GURL last_committed_url_; + std::string page_mime_type_ = "text/html"; }; } // namespace testing
diff --git a/components/translate/core/browser/translate_browser_metrics.h b/components/translate/core/browser/translate_browser_metrics.h index 19b2997..213a0ac6 100644 --- a/components/translate/core/browser/translate_browser_metrics.h +++ b/components/translate/core/browser/translate_browser_metrics.h
@@ -94,7 +94,7 @@ kTranslateDisabled, kNetworkOffline, kApiKeysMissing, - kMHTMLPage, + kMIMETypeUnsupported, kURLNotTranslatable, kTargetLangUnknown, kNotAllowedByPolicy,
diff --git a/components/translate/core/browser/translate_browser_metrics_unittest.cc b/components/translate/core/browser/translate_browser_metrics_unittest.cc index 5a00dcb..d807d48 100644 --- a/components/translate/core/browser/translate_browser_metrics_unittest.cc +++ b/components/translate/core/browser/translate_browser_metrics_unittest.cc
@@ -176,7 +176,7 @@ void CheckMenuTranslationUnavailableReason(int expected_kTranslate_disabled, int expected_network_offline, int expected_api_keys_missing, - int expected_mhtml_page, + int expected_unsupported_mimetype_page, int expected_url_not_translatable, int expected_target_lang_unknown, int expected_not_allowed_by_policy, @@ -195,10 +195,10 @@ GetCountWithoutSnapshot(static_cast<int>( translate::TranslateBrowserMetrics:: MenuTranslationUnavailableReason::kApiKeysMissing))); - EXPECT_EQ(expected_mhtml_page, + EXPECT_EQ(expected_unsupported_mimetype_page, GetCountWithoutSnapshot(static_cast<int>( translate::TranslateBrowserMetrics:: - MenuTranslationUnavailableReason::kMHTMLPage))); + MenuTranslationUnavailableReason::kMIMETypeUnsupported))); EXPECT_EQ(expected_url_not_translatable, GetCountWithoutSnapshot(static_cast<int>( translate::TranslateBrowserMetrics:: @@ -334,7 +334,7 @@ recorder.CheckMenuTranslationUnavailableReason(1, 1, 1, 0, 0, 0, 0, 0); translate::TranslateBrowserMetrics::ReportMenuTranslationUnavailableReason( translate::TranslateBrowserMetrics::MenuTranslationUnavailableReason:: - kMHTMLPage); + kMIMETypeUnsupported); recorder.CheckMenuTranslationUnavailableReason(1, 1, 1, 1, 0, 0, 0, 0); translate::TranslateBrowserMetrics::ReportMenuTranslationUnavailableReason( translate::TranslateBrowserMetrics::MenuTranslationUnavailableReason::
diff --git a/components/translate/core/browser/translate_language_list_unittest.cc b/components/translate/core/browser/translate_language_list_unittest.cc index bce23d4..eb57d31 100644 --- a/components/translate/core/browser/translate_language_list_unittest.cc +++ b/components/translate/core/browser/translate_language_list_unittest.cc
@@ -15,6 +15,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_url_util.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" @@ -22,9 +23,16 @@ namespace translate { +class TranslateLanguageListTest : public testing::Test { + public: + private: + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; +}; + // Test that the supported languages can be explicitly set using // SetSupportedLanguages(). -TEST(TranslateLanguageListTest, SetSupportedLanguages) { +TEST_F(TranslateLanguageListTest, SetSupportedLanguages) { const std::string language_list( "{" "\"sl\":{\"en\":\"English\",\"ja\":\"Japanese\"}," @@ -52,7 +60,7 @@ // Test that the language code back-off of locale is done correctly (where // required). -TEST(TranslateLanguageListTest, GetLanguageCode) { +TEST_F(TranslateLanguageListTest, GetLanguageCode) { TranslateLanguageList language_list; EXPECT_EQ("en", language_list.GetLanguageCode("en")); // Test backoff of unsupported locale. @@ -64,7 +72,7 @@ // Test that the translation URL is correctly generated, and that the // translate-security-origin command-line flag correctly overrides the default // value. -TEST(TranslateLanguageListTest, TranslateLanguageUrl) { +TEST_F(TranslateLanguageListTest, TranslateLanguageUrl) { TranslateLanguageList language_list; // Test default security origin. @@ -85,7 +93,7 @@ // Test that IsSupportedLanguage() is true for languages that should be // supported, and false for invalid languages. -TEST(TranslateLanguageListTest, IsSupportedLanguage) { +TEST_F(TranslateLanguageListTest, IsSupportedLanguage) { TranslateLanguageList language_list; EXPECT_TRUE(language_list.IsSupportedLanguage("en")); EXPECT_TRUE(language_list.IsSupportedLanguage("zh-CN")); @@ -96,7 +104,7 @@ // languages should be large (> 100) and must contain very common languages. // If either of these tests are not true, the default language configuration is // likely to be incorrect. -TEST(TranslateLanguageListTest, GetSupportedLanguages) { +TEST_F(TranslateLanguageListTest, GetSupportedLanguages) { TranslateLanguageList language_list; std::vector<std::string> languages; language_list.GetSupportedLanguages(true /* translate_allowed */, &languages); @@ -113,7 +121,7 @@ // Check that we contact the translate server to update the supported language // list when translate is enabled by policy. -TEST(TranslateLanguageListTest, GetSupportedLanguagesFetch) { +TEST_F(TranslateLanguageListTest, GetSupportedLanguagesFetch) { // Set up fake network environment. base::test::TaskEnvironment task_environment; network::TestURLLoaderFactory test_url_loader_factory; @@ -166,7 +174,7 @@ // Check that we don't send any network data when translate is disabled by // policy. -TEST(TranslateLanguageListTest, GetSupportedLanguagesNoFetch) { +TEST_F(TranslateLanguageListTest, GetSupportedLanguagesNoFetch) { // Set up fake network environment. base::test::TaskEnvironment task_environment; network::TestURLLoaderFactory test_url_loader_factory;
diff --git a/components/translate/core/browser/translate_manager.cc b/components/translate/core/browser/translate_manager.cc index 44ea9f56..b7d937e 100644 --- a/components/translate/core/browser/translate_manager.cc +++ b/components/translate/core/browser/translate_manager.cc
@@ -47,6 +47,7 @@ #include "components/translate/core/common/translate_switches.h" #include "components/variations/variations_associated_data.h" #include "google_apis/google_api_keys.h" +#include "net/base/mime_util.h" #include "net/base/network_change_notifier.h" #include "net/base/url_util.h" #include "net/http/http_status_code.h" @@ -257,12 +258,14 @@ can_translate = false; } - // MHTML pages currently cannot be translated (crbug.com/217945). - if (translate_driver_->GetContentsMimeType() == "multipart/related") { + // not supported MIME type pages currently cannot be translated. + // See bug: 217945, 1208340. + if (!IsMimeTypeSupported(translate_driver_->GetContentsMimeType())) { if (!menuLogging) return false; TranslateBrowserMetrics::ReportMenuTranslationUnavailableReason( - TranslateBrowserMetrics::MenuTranslationUnavailableReason::kMHTMLPage); + TranslateBrowserMetrics::MenuTranslationUnavailableReason:: + kMIMETypeUnsupported); can_translate = false; } @@ -334,6 +337,15 @@ return can_translate; } +bool TranslateManager::IsMimeTypeSupported(const std::string& mime_type) { + if (net::MatchesMimeType("image/*", mime_type)) + return false; + if (mime_type == "multipart/related") + return false; + + return true; +} + void TranslateManager::InitiateManualTranslation(bool auto_translate, bool triggered_from_menu) { // If a translation is in progress, do nothing. @@ -904,9 +916,9 @@ TriggerDecision::kDisabledMissingAPIKey); } - // MHTML pages currently cannot be translated. - // See bug: 217945. - if (translate_driver_->GetContentsMimeType() == "multipart/related") { + // not supported MIME type pages currently cannot be translated. + // See bug: 217945, 1208340. + if (!IsMimeTypeSupported(translate_driver_->GetContentsMimeType())) { decision->PreventAllTriggering(); decision->initiation_statuses.push_back( TranslateBrowserMetrics::INITIATION_STATUS_MIME_TYPE_IS_NOT_SUPPORTED);
diff --git a/components/translate/core/browser/translate_manager.h b/components/translate/core/browser/translate_manager.h index 43c3e936..faae855 100644 --- a/components/translate/core/browser/translate_manager.h +++ b/components/translate/core/browser/translate_manager.h
@@ -142,6 +142,8 @@ // translate menu item. bool CanManuallyTranslate(bool menuLogging = false); + bool IsMimeTypeSupported(const std::string& mime_type); + // Shows the after translate or error infobar depending on the details. void PageTranslated(const std::string& source_lang, const std::string& target_lang,
diff --git a/components/translate/core/browser/translate_manager_unittest.cc b/components/translate/core/browser/translate_manager_unittest.cc index bc36ac2..a2addfd 100644 --- a/components/translate/core/browser/translate_manager_unittest.cc +++ b/components/translate/core/browser/translate_manager_unittest.cc
@@ -32,6 +32,7 @@ #include "components/translate/core/browser/translate_pref_names.h" #include "components/translate/core/browser/translate_prefs.h" #include "components/translate/core/common/translate_constants.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_associated_data.h" #include "net/base/mock_network_change_notifier.h" #include "net/base/network_change_notifier.h" @@ -210,6 +211,9 @@ // uses ObserverListThreadSafe. base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; + sync_preferences::TestingPrefServiceSyncable prefs_; ProfilePrefRegistration registration_; // TODO(groby): request TranslatePrefs from |mock_translate_client_| instead. @@ -1113,6 +1117,22 @@ metrics::INITIATION_STATUS_SHOW_UI_PREDEFINED_TARGET_LANGUAGE, 1))); } +TEST_F(TranslateManagerTest, CanManuallyTranslate_ImagePage) { + TranslateManager::SetIgnoreMissingKeyForTesting(true); + translate_manager_ = std::make_unique<translate::TranslateManager>( + &mock_translate_client_, &mock_translate_ranker_, &mock_language_model_); + + network_notifier_.SimulateOnline(); + ON_CALL(mock_translate_client_, IsTranslatableURL(GURL::EmptyGURL())) + .WillByDefault(Return(true)); + + translate_manager_->GetLanguageState()->LanguageDetermined("de", true); + driver_.SetPageMimeType("image/png"); + + EXPECT_FALSE(translate_manager_->CanManuallyTranslate()); + EXPECT_FALSE(translate_manager_->CanManuallyTranslate(true)); +} + TEST_F(TranslateManagerTest, PredefinedTargetLanguage_HonourUserSettings) { TranslateManager::SetIgnoreMissingKeyForTesting(true); translate_manager_ = std::make_unique<translate::TranslateManager>(
diff --git a/components/translate/core/browser/translate_script_unittest.cc b/components/translate/core/browser/translate_script_unittest.cc index 27b43785..a96bd9e 100644 --- a/components/translate/core/browser/translate_script_unittest.cc +++ b/components/translate/core/browser/translate_script_unittest.cc
@@ -14,6 +14,7 @@ #include "build/build_config.h" #include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/common/translate_switches.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_ids_provider.h" #include "net/base/load_flags.h" #include "net/base/url_util.h" @@ -34,7 +35,6 @@ protected: void SetUp() override { - variations::VariationsIdsProvider::GetInstance()->ResetForTesting(); script_ = std::make_unique<TranslateScript>(); auto* translate_download_manager = TranslateDownloadManager::GetInstance(); translate_download_manager->set_application_locale("en"); @@ -69,6 +69,9 @@ // Sets up the task scheduling/task-runner environment for each test. base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; + // The translate script. std::unique_ptr<TranslateScript> script_;
diff --git a/components/translate/core/browser/translate_ui_delegate_unittest.cc b/components/translate/core/browser/translate_ui_delegate_unittest.cc index c1cd78a1..f5d5b4cb 100644 --- a/components/translate/core/browser/translate_ui_delegate_unittest.cc +++ b/components/translate/core/browser/translate_ui_delegate_unittest.cc
@@ -27,6 +27,7 @@ #include "components/translate/core/browser/translate_manager.h" #include "components/translate/core/browser/translate_pref_names.h" #include "components/translate/core/browser/translate_prefs.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_associated_data.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -80,6 +81,8 @@ // Do not reorder. These are ordered for dependency on creation/destruction. MockTranslateDriver driver_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> pref_service_; std::unique_ptr<MockTranslateClient> client_; std::unique_ptr<MockTranslateRanker> ranker_;
diff --git a/components/unified_consent/unified_consent_service.h b/components/unified_consent/unified_consent_service.h index 762a19bc..0779331 100644 --- a/components/unified_consent/unified_consent_service.h +++ b/components/unified_consent/unified_consent_service.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "base/values.h" #include "components/keyed_service/core/keyed_service.h" #include "components/prefs/pref_change_registrar.h"
diff --git a/components/variations/BUILD.gn b/components/variations/BUILD.gn index 714422a..5a86672 100644 --- a/components/variations/BUILD.gn +++ b/components/variations/BUILD.gn
@@ -161,6 +161,8 @@ static_library("test_support") { testonly = true sources = [ + "scoped_variations_ids_provider.cc", + "scoped_variations_ids_provider.h", "variations_params_manager.cc", "variations_params_manager.h", "variations_test_utils.cc",
diff --git a/components/variations/scoped_variations_ids_provider.cc b/components/variations/scoped_variations_ids_provider.cc new file mode 100644 index 0000000..0d5418d --- /dev/null +++ b/components/variations/scoped_variations_ids_provider.cc
@@ -0,0 +1,18 @@ +// Copyright 2021 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/variations/scoped_variations_ids_provider.h" + +namespace variations { + +ScopedVariationsIdsProvider::ScopedVariationsIdsProvider( + VariationsIdsProvider::Mode mode) { + VariationsIdsProvider::CreateInstanceForTesting(mode); +} + +ScopedVariationsIdsProvider::~ScopedVariationsIdsProvider() { + VariationsIdsProvider::DestroyInstanceForTesting(); +} + +} // namespace variations
diff --git a/components/variations/scoped_variations_ids_provider.h b/components/variations/scoped_variations_ids_provider.h new file mode 100644 index 0000000..dd65d933 --- /dev/null +++ b/components/variations/scoped_variations_ids_provider.h
@@ -0,0 +1,23 @@ +// Copyright 2021 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_VARIATIONS_SCOPED_VARIATIONS_IDS_PROVIDER_H_ +#define COMPONENTS_VARIATIONS_SCOPED_VARIATIONS_IDS_PROVIDER_H_ + +#include "components/variations/variations_ids_provider.h" + +namespace variations { + +class ScopedVariationsIdsProvider { + public: + explicit ScopedVariationsIdsProvider(VariationsIdsProvider::Mode mode); + ScopedVariationsIdsProvider(const ScopedVariationsIdsProvider&) = delete; + ScopedVariationsIdsProvider& operator=(const ScopedVariationsIdsProvider&) = + delete; + ~ScopedVariationsIdsProvider(); +}; + +} // namespace variations + +#endif // COMPONENTS_VARIATIONS_SCOPED_VARIATIONS_IDS_PROVIDER_H_
diff --git a/components/variations/service/BUILD.gn b/components/variations/service/BUILD.gn index 963203db..78e39ab 100644 --- a/components/variations/service/BUILD.gn +++ b/components/variations/service/BUILD.gn
@@ -75,6 +75,7 @@ "//components/metrics:test_support", "//components/prefs:test_support", "//components/variations", + "//components/variations:test_support", "//components/variations/proto", "//components/web_resource:test_support", "//net",
diff --git a/components/variations/service/variations_field_trial_creator_unittest.cc b/components/variations/service/variations_field_trial_creator_unittest.cc index 86c6d0cd..445d2ff8 100644 --- a/components/variations/service/variations_field_trial_creator_unittest.cc +++ b/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -23,6 +23,7 @@ #include "components/variations/platform_field_trials.h" #include "components/variations/pref_names.h" #include "components/variations/proto/variations_seed.pb.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/service/safe_seed_manager.h" #include "components/variations/service/variations_service.h" #include "components/variations/service/variations_service_client.h" @@ -305,6 +306,8 @@ TestingPrefServiceSimple prefs_; private: + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; // The global feature list, which is ignored by tests in this suite. std::unique_ptr<base::FeatureList> global_feature_list_; @@ -318,7 +321,7 @@ // seed state. const base::Time now = base::Time::Now(); const base::Time recent_time = now - base::TimeDelta::FromMinutes(17); - testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ::testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); EXPECT_CALL( @@ -352,7 +355,7 @@ // With a valid seed on first run, the safe seed manager should be informed of // the active seed state. The last fetch time in this case is expected to be // inferred to be recent. - testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ::testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); const base::Time start_time = base::Time::Now(); @@ -387,7 +390,7 @@ // With an expired seed, there should be no field trials created, and hence no // active state should be passed to the safe seed manager. - testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ::testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _)).Times(0); @@ -419,7 +422,7 @@ // With a valid safe seed, the safe seed manager should *not* be informed of // the active seed state. This is an optimization to avoid saving a safe seed // when already running in safe mode. - testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ::testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true)); EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _)).Times(0); @@ -454,7 +457,7 @@ // active seed state. const base::Time now = base::Time::Now(); const base::Time recent_time = now - base::TimeDelta::FromMinutes(17); - testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ::testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true)); EXPECT_CALL( safe_seed_manager, @@ -500,7 +503,7 @@ TestVariationsServiceClient variations_service_client; TestPlatformFieldTrials platform_field_trials; - testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ::testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); @@ -536,7 +539,7 @@ // Tests that the hardware class is set on Android. TEST_F(FieldTrialCreatorTest, ClientFilterableState_HardwareClass) { - testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ::testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false));
diff --git a/components/variations/service/variations_service_unittest.cc b/components/variations/service/variations_service_unittest.cc index 422ef639..1ea19b6 100644 --- a/components/variations/service/variations_service_unittest.cc +++ b/components/variations/service/variations_service_unittest.cc
@@ -34,6 +34,7 @@ #include "components/variations/pref_names.h" #include "components/variations/proto/study.pb.h" #include "components/variations/proto/variations_seed.pb.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/web_resource/resource_request_allowed_notifier_test_util.h" #include "net/base/mock_network_change_notifier.h" #include "net/base/url_util.h" @@ -329,6 +330,8 @@ private: base::test::TaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; std::unique_ptr<metrics::TestEnabledStateProvider> enabled_state_provider_; std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager_;
diff --git a/components/variations/variations_ids_provider.cc b/components/variations/variations_ids_provider.cc index 2b64ee3..3e420c1f 100644 --- a/components/variations/variations_ids_provider.cc +++ b/components/variations/variations_ids_provider.cc
@@ -8,20 +8,32 @@ #include "base/base64.h" #include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/synchronization/lock.h" #include "components/variations/proto/client_variations.pb.h" #include "components/variations/variations_client.h" #include "components/variations/variations_features.h" namespace variations { +namespace { // Range of low entropy source values (8000) as variation ids for the // X-Client-Data header. This range is reserved in cl/333331461 (internal CL). const int kLowEntropySourceVariationIdRangeMin = 3320978; const int kLowEntropySourceVariationIdRangeMax = 3328977; +VariationsIdsProvider* g_instance = nullptr; + +base::Lock& GetInstanceLock() { + static base::NoDestructor<base::Lock> lock; + return *lock; +} + +} // namespace + bool VariationsHeaderKey::operator<(const VariationsHeaderKey& other) const { if (is_signed_in != other.is_signed_in) return is_signed_in < other.is_signed_in; @@ -42,9 +54,18 @@ // function variations::CreateSimpleURLLoaderWithVariationsHeader(). // static +VariationsIdsProvider* VariationsIdsProvider::Create(Mode mode) { + base::AutoLock lock(GetInstanceLock()); + DCHECK(!g_instance); + g_instance = new VariationsIdsProvider(mode); + return g_instance; +} + +// static VariationsIdsProvider* VariationsIdsProvider::GetInstance() { - static base::NoDestructor<VariationsIdsProvider> instance; - return instance.get(); + base::AutoLock lock(GetInstanceLock()); + DCHECK(g_instance); + return g_instance; } variations::mojom::VariationsHeadersPtr @@ -53,6 +74,9 @@ // transmit it. InitVariationIDsCacheIfNeeded(); + if (mode_ == Mode::kIgnoreSignedInState) + is_signed_in = true; + std::string first_party_header_copy; std::string any_context_header_copy; { @@ -186,13 +210,27 @@ variations_headers_map_.clear(); } -VariationsIdsProvider::VariationsIdsProvider() - : variation_ids_cache_initialized_(false) {} +VariationsIdsProvider::VariationsIdsProvider(Mode mode) + : mode_(mode), variation_ids_cache_initialized_(false) {} VariationsIdsProvider::~VariationsIdsProvider() { base::FieldTrialList::RemoveObserver(this); } +// static +void VariationsIdsProvider::CreateInstanceForTesting(Mode mode) { + base::AutoLock lock(GetInstanceLock()); + delete g_instance; + g_instance = new VariationsIdsProvider(mode); +} + +// static +void VariationsIdsProvider::DestroyInstanceForTesting() { + base::AutoLock lock(GetInstanceLock()); + delete g_instance; + g_instance = nullptr; +} + void VariationsIdsProvider::OnFieldTrialGroupFinalized( const std::string& trial_name, const std::string& group_name) {
diff --git a/components/variations/variations_ids_provider.h b/components/variations/variations_ids_provider.h index 3242b90..afe774e 100644 --- a/components/variations/variations_ids_provider.h +++ b/components/variations/variations_ids_provider.h
@@ -57,8 +57,25 @@ virtual ~Observer() {} }; + enum class Mode { + // Indicates the signed-in parameter supplied to GetClientDataHeaders() is + // honored. + kUseSignedInState, + + // Indicates the signed-in parameter supplied to GetClientDataHeaders() is + // treated as true, regardless of what is supplied. This is intended for + // embedders (such as WebLayer) that do not have the notion of signed-in. + kIgnoreSignedInState, + }; + + // Creates the VariationsIdsProvider instance. This must be called before + // GetInstance(). Only one instance of VariationsIdsProvider may be created. + static VariationsIdsProvider* Create(Mode mode); + static VariationsIdsProvider* GetInstance(); + Mode mode() const { return mode_; } + // Returns the X-Client-Data headers corresponding to |is_signed_in|: a header // that may be sent in first-party requests and a header that may be sent in // third-party requests. For more details, see IsFirstPartyContext() in @@ -66,7 +83,9 @@ // // If |is_signed_in| is false, VariationIDs that should be sent for only // signed in users (i.e. GOOGLE_WEB_PROPERTIES_SIGNED_IN entries) are not - // included. Also, computes and caches the header if necessary. + // included. Also, computes and caches the header if necessary. |is_signed_in| + // is impacted by the Mode supplied when VariationsIdsProvider is created. + // See Mode for details. variations::mojom::VariationsHeadersPtr GetClientDataHeaders( bool is_signed_in); @@ -129,10 +148,10 @@ void ResetForTesting(); private: - friend class base::NoDestructor<VariationsIdsProvider>; - typedef std::pair<VariationID, IDCollectionKey> VariationIDEntry; + friend class ScopedVariationsIdsProvider; + FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest, ForceVariationIds_Valid); FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest, ForceVariationIds_ValidCommandLine); @@ -156,9 +175,12 @@ GetVariationsVectorForWebPropertiesKeys); FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest, GetVariationsVectorImpl); - VariationsIdsProvider(); + explicit VariationsIdsProvider(Mode mode); ~VariationsIdsProvider() override; + static void CreateInstanceForTesting(Mode mode); + static void DestroyInstanceForTesting(); + // Returns a space-separated string containing the list of current active // variations (as would be reported in the |variation_id| repeated field of // the ClientVariations proto) for a given ID collection. @@ -221,6 +243,8 @@ std::vector<VariationID> GetVariationsVectorImpl( const std::set<IDCollectionKey>& key); + const Mode mode_; + // Guards access to variables below. base::Lock lock_;
diff --git a/components/variations/variations_ids_provider_unittest.cc b/components/variations/variations_ids_provider_unittest.cc index 9da42b1..38aee5a 100644 --- a/components/variations/variations_ids_provider_unittest.cc +++ b/components/variations/variations_ids_provider_unittest.cc
@@ -54,7 +54,8 @@ }; TEST_F(VariationsIdsProviderTest, ForceVariationIds_Valid) { - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); // Valid experiment ids. EXPECT_EQ(VariationsIdsProvider::ForceIdsResult::SUCCESS, @@ -75,7 +76,8 @@ } TEST_F(VariationsIdsProviderTest, ForceVariationIds_ValidCommandLine) { - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); // Valid experiment ids. EXPECT_EQ(VariationsIdsProvider::ForceIdsResult::SUCCESS, @@ -97,7 +99,8 @@ } TEST_F(VariationsIdsProviderTest, ForceVariationIds_Invalid) { - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); // Invalid experiment ids. EXPECT_EQ(VariationsIdsProvider::ForceIdsResult::INVALID_VECTOR_ENTRY, @@ -119,7 +122,8 @@ } TEST_F(VariationsIdsProviderTest, ForceDisableVariationIds_ValidCommandLine) { - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); // Valid experiment ids. EXPECT_EQ(VariationsIdsProvider::ForceIdsResult::SUCCESS, @@ -146,7 +150,8 @@ } TEST_F(VariationsIdsProviderTest, ForceDisableVariationIds_Invalid) { - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); // Invalid command-line ids. EXPECT_FALSE(provider.ForceDisableVariationIds("abc")); @@ -161,7 +166,8 @@ TEST_P(VariationsIdsProviderTestWithRestrictedVisibility, LowEntropySourceValue_Valid) { - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); absl::optional<int> valid_low_entropy_source_value = 5; provider.SetLowEntropySourceValue(valid_low_entropy_source_value); @@ -198,7 +204,8 @@ TEST_P(VariationsIdsProviderTestWithRestrictedVisibility, LowEntropySourceValue_Null) { - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); absl::optional<int> null_low_entropy_source_value = absl::nullopt; provider.SetLowEntropySourceValue(null_low_entropy_source_value); @@ -243,7 +250,8 @@ TEST_P(VariationsIdsProviderTestWithRestrictedVisibility, OnFieldTrialGroupFinalized) { - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); provider.InitVariationIDsCacheIfNeeded(); const std::string default_name = "default"; @@ -384,7 +392,8 @@ // GOOGLE_APP ids should be included. CreateTrialAndAssociateId("t6", "g6", GOOGLE_APP, 126); - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); provider.ForceVariationIds({"100", "200"}, ""); EXPECT_EQ(" 126 ", provider.GetGoogleAppVariationsString()); } @@ -406,7 +415,8 @@ // GOOGLE_APP ids shouldn't be included. CreateTrialAndAssociateId("t6", "g6", GOOGLE_APP, 126); - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); provider.ForceVariationIds({"100", "200"}, ""); EXPECT_EQ(" 100 123 124 200 ", provider.GetVariationsString()); } @@ -421,7 +431,8 @@ CreateTrialAndAssociateId("t6", "g6", GOOGLE_WEB_PROPERTIES_SIGNED_IN, 125); CreateTrialAndAssociateId("t7", "g7", GOOGLE_APP, 126); - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); provider.ForceVariationIds({"100", "200", "t101"}, ""); EXPECT_EQ((std::vector<VariationID>{100, 121, 200}), @@ -459,7 +470,8 @@ // GOOGLE_APP ids shouldn't be included. CreateTrialAndAssociateId("t6", "g6", GOOGLE_APP, 126); - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); provider.ForceVariationIds({"100", "t101"}, ""); EXPECT_EQ((std::vector<VariationID>{100, 101, 121, 122, 123, 124, 125}), provider.GetVariationsVectorForWebPropertiesKeys()); @@ -475,7 +487,8 @@ CreateTrialAndAssociateId("t5", "g5", GOOGLE_WEB_PROPERTIES_SIGNED_IN, 125); CreateTrialAndAssociateId("t6", "g6", GOOGLE_APP, 125); // Duplicate. - VariationsIdsProvider provider; + VariationsIdsProvider provider( + VariationsIdsProvider::Mode::kUseSignedInState); provider.ForceVariationIds({"100", "200", "t101"}, ""); EXPECT_EQ(
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index 2ff8732..7692a2a 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -96,6 +96,8 @@ "display/render_pass_id_remapper.h", "display/renderer_utils.cc", "display/renderer_utils.h", + "display/resolved_frame_data.cc", + "display/resolved_frame_data.h", "display/resource_fence.h", "display/scoped_gpu_memory_buffer_texture.cc", "display/scoped_gpu_memory_buffer_texture.h", @@ -539,6 +541,7 @@ "display/frame_rate_decider_unittest.cc", "display/layer_quad_unittest.cc", "display/renderer_pixeltest.cc", + "display/resolved_frame_data_unittest.cc", "display/shader_unittest.cc", "display/skia_readback_pixeltest.cc", "display/software_renderer_unittest.cc",
diff --git a/components/viz/service/display/resolved_frame_data.cc b/components/viz/service/display/resolved_frame_data.cc new file mode 100644 index 0000000..d0943d2 --- /dev/null +++ b/components/viz/service/display/resolved_frame_data.cc
@@ -0,0 +1,91 @@ +// Copyright 2021 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/viz/service/display/resolved_frame_data.h" + +#include <utility> + +#include "components/viz/service/surfaces/surface.h" + +namespace viz { + +ResolvedQuadData::ResolvedQuadData(const DrawQuad& quad) + : remapped_resources(quad.resources) {} + +ResolvedPassData::ResolvedPassData() = default; +ResolvedPassData::~ResolvedPassData() = default; +ResolvedPassData::ResolvedPassData(ResolvedPassData&& other) = default; +ResolvedPassData& ResolvedPassData::operator=(ResolvedPassData&& other) = + default; + +ResolvedFrameData::ResolvedFrameData(const SurfaceId& surface_id, + Surface* surface) + : surface_id_(surface_id), surface_(surface) {} + +ResolvedFrameData::~ResolvedFrameData() = default; + +void ResolvedFrameData::UpdateResolvedPassData( + std::vector<ResolvedPassData> resolved_passes) { + DCHECK(!resolved_passes.empty()); + + frame_index_ = surface_->GetActiveFrameIndex(); + DCHECK_NE(frame_index_, 0u); + + resolved_passes_ = std::move(resolved_passes); + + // Build a map from render pass id to data. + std::vector<std::pair<CompositorRenderPassId, ResolvedPassData*>> entries; + entries.reserve(resolved_passes_.size()); + for (auto& resolved_pass : resolved_passes_) + entries.emplace_back(resolved_pass.render_pass->id, &resolved_pass); + render_pass_id_map_ = + base::flat_map<CompositorRenderPassId, ResolvedPassData*>( + std::move(entries)); + + valid_ = true; +} + +void ResolvedFrameData::SetInvalid() { + frame_index_ = surface_->GetActiveFrameIndex(); + render_pass_id_map_.clear(); + resolved_passes_.clear(); + valid_ = false; +} + +size_t ResolvedFrameData::RenderPassCount() const { + DCHECK(valid_); + return resolved_passes_.size(); +} + +ResolvedPassData& ResolvedFrameData::GetRenderPassDataById( + CompositorRenderPassId render_pass_id) { + DCHECK(valid_); + + // TODO(kylechar): We need to validate that RenderPassDrawQuads only refer to + // CompositorRenderPassIds that exist. + auto iter = render_pass_id_map_.find(render_pass_id); + DCHECK(iter != render_pass_id_map_.end()); + return *iter->second; +} + +ResolvedPassData& ResolvedFrameData::GetRenderPassDataByIndex(size_t index) { + DCHECK(valid_); + return resolved_passes_[index]; +} + +ResolvedPassData& ResolvedFrameData::GetRootRenderPassData() { + DCHECK(valid_); + return resolved_passes_.back(); +} + +bool ResolvedFrameData::MarkAsUsed() { + // Returns true the first time this is called after reset. + return !std::exchange(used_, true); +} + +bool ResolvedFrameData::CheckIfUsedAndReset() { + return std::exchange(used_, false); +} + +} // namespace viz
diff --git a/components/viz/service/display/resolved_frame_data.h b/components/viz/service/display/resolved_frame_data.h new file mode 100644 index 0000000..3353115 --- /dev/null +++ b/components/viz/service/display/resolved_frame_data.h
@@ -0,0 +1,97 @@ +// Copyright 2021 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_VIZ_SERVICE_DISPLAY_RESOLVED_FRAME_DATA_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_RESOLVED_FRAME_DATA_H_ + +#include <vector> + +#include "base/containers/flat_map.h" +#include "components/viz/common/quads/compositor_render_pass.h" +#include "components/viz/common/quads/draw_quad.h" +#include "components/viz/common/surfaces/surface_id.h" +#include "components/viz/service/viz_service_export.h" + +namespace viz { + +class Surface; + +// Data associated with a DrawQuad in a resolved frame. +struct VIZ_SERVICE_EXPORT ResolvedQuadData { + explicit ResolvedQuadData(const DrawQuad& quad); + + // Remapped display ResourceIds. + DrawQuad::Resources remapped_resources; +}; + +// Data associated with a CompositorRenderPass in a resolved frame. +struct VIZ_SERVICE_EXPORT ResolvedPassData { + ResolvedPassData(); + ~ResolvedPassData(); + ResolvedPassData(ResolvedPassData&& other); + ResolvedPassData& operator=(ResolvedPassData&& other); + + CompositorRenderPass* render_pass; + std::vector<ResolvedQuadData> draw_quads; + + // Tracks if prewalk is visiting this render pass to avoid cycles. + bool is_visited = false; +}; + +// Holds computed information for a particular Surface+CompositorFrame. The +// CompositorFrame computed information will be updated whenever the active +// frame for the surface has changed. +class VIZ_SERVICE_EXPORT ResolvedFrameData { + public: + ResolvedFrameData(const SurfaceId& surface_id, Surface* surface); + ~ResolvedFrameData(); + ResolvedFrameData(ResolvedFrameData&& other) = delete; + ResolvedFrameData& operator=(ResolvedFrameData&& other) = delete; + + const SurfaceId& surface_id() const { return surface_id_; } + Surface* surface() { return surface_; } + bool is_valid() const { return valid_; } + uint64_t frame_index() const { return frame_index_; } + + // Update the list of resolved pass data. This will set frame index and mark + // as valid. + void UpdateResolvedPassData(std::vector<ResolvedPassData> resolved_passes); + + // Sets frame index and marks as invalid. This also clears any existing + // resolved pass data. + void SetInvalid(); + + // RenderPassData accessors. These should only be used if is_valid() returns + // true. + size_t RenderPassCount() const; + ResolvedPassData& GetRenderPassDataById( + CompositorRenderPassId render_pass_id); + ResolvedPassData& GetRenderPassDataByIndex(size_t index); + ResolvedPassData& GetRootRenderPassData(); + + // Marks this as used and returns true if this was the first time MarkAsUsed() + // was called since last reset. + bool MarkAsUsed(); + + // Returns true if MarkAsUsed() was called since last reset and then resets + // used to false. + bool CheckIfUsedAndReset(); + + private: + const SurfaceId surface_id_; + Surface* const surface_; + + // Data associated with CompositorFrame with |frame_index_|. + bool valid_ = false; + uint64_t frame_index_ = 0; + std::vector<ResolvedPassData> resolved_passes_; + base::flat_map<CompositorRenderPassId, ResolvedPassData*> render_pass_id_map_; + + // Track if the this resolved frame was used this frame. + bool used_ = false; +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_RESOLVED_FRAME_DATA_H_
diff --git a/components/viz/service/display/resolved_frame_data_unittest.cc b/components/viz/service/display/resolved_frame_data_unittest.cc new file mode 100644 index 0000000..c2ae2ce --- /dev/null +++ b/components/viz/service/display/resolved_frame_data_unittest.cc
@@ -0,0 +1,102 @@ +// Copyright 2021 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/viz/service/display/resolved_frame_data.h" + +#include <memory> +#include <utility> +#include <vector> + +#include "components/viz/common/quads/compositor_render_pass.h" +#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" +#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" +#include "components/viz/service/surfaces/surface.h" +#include "components/viz/test/compositor_frame_helpers.h" +#include "components/viz/test/test_surface_id_allocator.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace viz { +namespace { + +TEST(ResolvedFrameDataTest, ResolvedRenderPassData) { + constexpr gfx::Rect output_rect(100, 100); + TestSurfaceIdAllocator surface_id(FrameSinkId(1, 1)); + + ServerSharedBitmapManager shared_bitmap_manager; + FrameSinkManagerImpl frame_sink_manager(&shared_bitmap_manager); + auto support = std::make_unique<CompositorFrameSinkSupport>( + nullptr, &frame_sink_manager, surface_id.frame_sink_id(), + /*is_root=*/true); + + { + // Create a CompositorFrame and submit it to |surface_id| so there is a + // fully populated Surface with an active CompositorFrame. + CompositorRenderPassList render_passes; + for (int i = 0; i < 3; ++i) { + auto render_pass = CompositorRenderPass::Create(); + render_pass->SetNew(CompositorRenderPassId::FromUnsafeValue(i + 100), + output_rect, output_rect, gfx::Transform()); + render_passes.push_back(std::move(render_pass)); + } + + auto frame = CompositorFrameBuilder() + .SetRenderPassList(std::move(render_passes)) + .Build(); + support->SubmitCompositorFrame(surface_id.local_surface_id(), + std::move(frame)); + } + + Surface* surface = + frame_sink_manager.surface_manager()->GetSurfaceForId(surface_id); + EXPECT_TRUE(surface); + EXPECT_TRUE(surface->HasActiveFrame()); + + ResolvedFrameData resolved_frame(surface_id, surface); + + // The resolved frame should be false immediately. + EXPECT_FALSE(resolved_frame.is_valid()); + + std::vector<ResolvedPassData> resolved_passes; + for (auto& render_pass : surface->GetActiveFrame().render_pass_list) { + resolved_passes.emplace_back(); + resolved_passes.back().render_pass = render_pass.get(); + } + + // Resolved frame data should be valid after adding resolved render pass data. + resolved_frame.UpdateResolvedPassData(std::move(resolved_passes)); + EXPECT_TRUE(resolved_frame.is_valid()); + + // Looking up ResolvedPassData by CompositorRenderPassId should work. + for (auto& render_pass : surface->GetActiveFrame().render_pass_list) { + ResolvedPassData& resolved_pass = + resolved_frame.GetRenderPassDataById(render_pass->id); + EXPECT_EQ(resolved_pass.render_pass, render_pass.get()); + } + + // Check invalidation also works. + resolved_frame.SetInvalid(); + EXPECT_FALSE(resolved_frame.is_valid()); +} + +TEST(ResolvedFrameDataTest, MarkAsUsed) { + TestSurfaceIdAllocator surface_id(FrameSinkId(1, 1)); + ResolvedFrameData resolved_frame(surface_id, nullptr); + + EXPECT_TRUE(resolved_frame.MarkAsUsed()); + EXPECT_FALSE(resolved_frame.MarkAsUsed()); + EXPECT_FALSE(resolved_frame.MarkAsUsed()); + + // MarkAsUsed() was called so return true. + EXPECT_TRUE(resolved_frame.CheckIfUsedAndReset()); + + // MarkAsUsed() wasn't called so return false. + EXPECT_FALSE(resolved_frame.CheckIfUsedAndReset()); + + // First usage after reset returns true then false again. + EXPECT_TRUE(resolved_frame.MarkAsUsed()); + EXPECT_FALSE(resolved_frame.MarkAsUsed()); +} + +} // namespace +} // namespace viz
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc index b55b43b2..b8f8303 100644 --- a/components/viz/service/display/surface_aggregator.cc +++ b/components/viz/service/display/surface_aggregator.cc
@@ -8,11 +8,13 @@ #include <algorithm> #include <map> +#include <utility> #include "base/auto_reset.h" #include "base/bind.h" #include "base/check_op.h" #include "base/containers/adapters.h" +#include "base/logging.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/numerics/ranges.h" @@ -137,20 +139,6 @@ bool is_fast_rounded_corner; }; -struct SurfaceAggregator::RenderPassMapEntry { - explicit RenderPassMapEntry(CompositorRenderPass* render_pass) - : render_pass(render_pass) {} - - // Make this move-only. - RenderPassMapEntry(RenderPassMapEntry&&) = default; - RenderPassMapEntry(const RenderPassMapEntry&) = delete; - RenderPassMapEntry& operator=(RenderPassMapEntry&&) = default; - RenderPassMapEntry& operator=(const RenderPassMapEntry&) = delete; - - CompositorRenderPass* render_pass; - bool is_visited = false; -}; - SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager, DisplayResourceProvider* provider, bool aggregate_only_damaged, @@ -171,32 +159,6 @@ ProcessAddedAndRemovedSurfaces(); } -// static -base::flat_map<CompositorRenderPassId, SurfaceAggregator::RenderPassMapEntry> -SurfaceAggregator::GenerateRenderPassMap( - const CompositorRenderPassList& render_pass_list, - bool is_root_surface) { - const auto* root_pass_in_root_surface = - is_root_surface ? render_pass_list.back().get() : nullptr; - // This data is created once and typically small or empty. Collect all items - // and pass to a flat_map to sort once. - std::vector<std::pair<CompositorRenderPassId, RenderPassMapEntry>> - render_pass_data; - render_pass_data.reserve(render_pass_list.size()); - for (const auto& render_pass : render_pass_list) { - if (render_pass->backdrop_filters.HasFilterThatMovesPixels()) { - DCHECK_NE(render_pass.get(), root_pass_in_root_surface) - << "The root render pass on the root surface can not have backdrop " - "affecting filters"; - } - render_pass_data.emplace_back(std::piecewise_construct, - std::forward_as_tuple(render_pass->id), - std::forward_as_tuple(render_pass.get())); - } - return base::flat_map<CompositorRenderPassId, RenderPassMapEntry>( - std::move(render_pass_data)); -} - // Create a clip rect for an aggregated quad from the original clip rect and // the clip rect from the surface it's on. absl::optional<gfx::Rect> SurfaceAggregator::CalculateClipRect( @@ -466,6 +428,70 @@ sqs->de_jelly_delta_y == 0; } +ResolvedFrameData* SurfaceAggregator::GetResolvedFrame( + const SurfaceRange& range) { + // Find latest in flight surface and cache that result for the duration of + // this aggregation, then find ResolvedFrameData for that surface. + auto iter = resolved_surface_ranges_.find(range); + if (iter == resolved_surface_ranges_.end()) { + iter = resolved_surface_ranges_ + .emplace(range, manager_->GetLatestInFlightSurface(range)) + .first; + } + + return GetResolvedFrame(iter->second); +} + +ResolvedFrameData* SurfaceAggregator::GetResolvedFrame( + const SurfaceId& surface_id) { + return GetResolvedFrame(manager_->GetSurfaceForId(surface_id)); +} + +ResolvedFrameData* SurfaceAggregator::GetResolvedFrame(Surface* surface) { + if (!surface || !surface->HasActiveFrame()) { + // If there is no resolved surface or the surface has no active frame there + // is no resolved frame data to return. + return nullptr; + } + + auto iter = resolved_frames_.find(surface); + if (iter == resolved_frames_.end()) { + iter = + resolved_frames_ + .emplace(std::piecewise_construct, std::forward_as_tuple(surface), + std::forward_as_tuple(surface->surface_id(), surface)) + .first; + } + + ResolvedFrameData& resolved_frame = iter->second; + DCHECK_EQ(resolved_frame.surface(), surface); + + // Verify that a new surface wasn't created at the same address as a deleted + // surface with a different SurfaceId. + // TODO(kylechar): Invalidate cached resolved frame data when + // SurfaceObserver signals the surface has been destroyed instead. + if (resolved_frame.surface_id() != surface->surface_id()) { + resolved_frames_.erase(iter); + return GetResolvedFrame(surface); + } + + // Mark the frame as used this aggregation so it persists. + bool first_use = resolved_frame.MarkAsUsed(); + + if (first_use) { + // If there is a new CompositorFrame for `surface` compute resolved frame + // data for the new resolved CompositorFrame. + if (resolved_frame.frame_index() != surface->GetActiveFrameIndex() || + surface->HasSurfaceAnimationDamage()) { + base::ElapsedTimer timer; + ProcessResolvedFrame(resolved_frame); + stats_->declare_resources_time += timer.Elapsed(); + } + } + + return &resolved_frame; +} + void SurfaceAggregator::HandleSurfaceQuad( const SurfaceDrawQuad* surface_quad, float parent_device_scale_factor, @@ -477,15 +503,15 @@ bool* damage_rect_in_quad_space_valid, const MaskFilterInfoExt& mask_filter_info) { SurfaceId primary_surface_id = surface_quad->surface_range.end(); - Surface* latest_surface = - manager_->GetLatestInFlightSurface(surface_quad->surface_range); + ResolvedFrameData* resolved_frame = + GetResolvedFrame(surface_quad->surface_range); // If a new surface is going to be emitted, add the surface_quad rect to // |surface_damage_rect_list_| for overlays. The whole quad is considered // damaged. if (needs_surface_damage_rect_list_ && - (!latest_surface || !latest_surface->HasActiveFrame() || - (latest_surface->surface_id() != primary_surface_id))) { + (!resolved_frame || + (resolved_frame->surface_id() != primary_surface_id))) { gfx::Transform transform( target_transform, surface_quad->shared_quad_state->quad_to_target_transform); @@ -497,19 +523,18 @@ // If there's no fallback surface ID available, then simply emit a // SolidColorDrawQuad with the provided default background color. This // can happen after a Viz process crash. - if (!latest_surface || !latest_surface->HasActiveFrame()) { + if (!resolved_frame) { EmitDefaultBackgroundColorQuad(surface_quad, target_transform, clip_rect, dest_pass, mask_filter_info); return; } - if (latest_surface->surface_id() != primary_surface_id && + if (resolved_frame->surface_id() != primary_surface_id && !surface_quad->stretch_content_to_fill_bounds) { const CompositorFrame& fallback_frame = - latest_surface->GetActiveOrInterpolatedFrame(); + resolved_frame->surface()->GetActiveOrInterpolatedFrame(); - gfx::Rect fallback_rect( - latest_surface->GetActiveOrInterpolatedFrame().size_in_pixels()); + gfx::Rect fallback_rect(fallback_frame.size_in_pixels()); float scale_ratio = parent_device_scale_factor / fallback_frame.device_scale_factor(); @@ -524,14 +549,14 @@ dest_pass, mask_filter_info); } - EmitSurfaceContent(latest_surface, parent_device_scale_factor, surface_quad, + EmitSurfaceContent(*resolved_frame, parent_device_scale_factor, surface_quad, target_transform, clip_rect, dest_pass, ignore_undamaged, damage_rect_in_quad_space, damage_rect_in_quad_space_valid, mask_filter_info); } void SurfaceAggregator::EmitSurfaceContent( - Surface* surface, + ResolvedFrameData& resolved_frame, float parent_device_scale_factor, const SurfaceDrawQuad* surface_quad, const gfx::Transform& target_transform, @@ -541,6 +566,8 @@ gfx::Rect* damage_rect_in_quad_space, bool* damage_rect_in_quad_space_valid, const MaskFilterInfoExt& mask_filter_info) { + Surface* surface = resolved_frame.surface(); + // If this surface's id is already in our referenced set then it creates // a cycle in the graph and should be dropped. SurfaceId surface_id = surface->surface_id(); @@ -607,8 +634,7 @@ } referenced_surfaces_.insert(surface_id); - const auto& child_to_parent_map = - provider_->GetChildToParentMap(ChildIdForSurface(surface)); + gfx::Transform combined_transform = scaled_quad_to_target_transform; combined_transform.ConcatTransform(target_transform); @@ -658,12 +684,14 @@ surface->TakeDelegatedInkMetadata()); } - const CompositorRenderPassList& referenced_passes = render_pass_list; // TODO(fsamuel): Move this to a separate helper function. + size_t num_render_passes = resolved_frame.RenderPassCount(); size_t passes_to_copy = - merge_pass ? referenced_passes.size() - 1 : referenced_passes.size(); + merge_pass ? num_render_passes - 1 : num_render_passes; for (size_t j = 0; j < passes_to_copy; ++j) { - const CompositorRenderPass& source = *referenced_passes[j]; + const ResolvedPassData& resolved_pass = + resolved_frame.GetRenderPassDataByIndex(j); + const CompositorRenderPass& source = *resolved_pass.render_pass; size_t sqs_size = source.shared_quad_state_list.size(); size_t dq_size = source.quad_list.size(); @@ -697,9 +725,8 @@ copy_pass->transform_to_root_target.ConcatTransform( dest_pass->transform_to_root_target); - CopyQuadsToPass(source, copy_pass.get(), frame.device_scale_factor(), - child_to_parent_map, gfx::Transform(), {}, surface, - MaskFilterInfoExt()); + CopyQuadsToPass(resolved_pass, copy_pass.get(), frame.device_scale_factor(), + gfx::Transform(), {}, surface, MaskFilterInfoExt()); // If the render pass has copy requests, or should be cached, or has // moving-pixel filters, or in a moving-pixel surface, we should damage the @@ -730,8 +757,8 @@ !DamageRectForSurface(surface, last_pass, true).IsEmpty(); if (merge_pass) { - CopyQuadsToPass(last_pass, dest_pass, frame.device_scale_factor(), - child_to_parent_map, combined_transform, quads_clip, + CopyQuadsToPass(resolved_frame.GetRootRenderPassData(), dest_pass, + frame.device_scale_factor(), combined_transform, quads_clip, surface, mask_filter_info); } else { auto* shared_quad_state = CopyAndScaleSharedQuadState( @@ -1034,15 +1061,14 @@ } void SurfaceAggregator::CopyQuadsToPass( - const CompositorRenderPass& source_pass, + const ResolvedPassData& resolved_pass, AggregatedRenderPass* dest_pass, float parent_device_scale_factor, - const std::unordered_map<ResourceId, ResourceId, ResourceIdHasher>& - child_to_parent_map, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& clip_rect, const Surface* surface, const MaskFilterInfoExt& parent_mask_filter_info_ext) { + const CompositorRenderPass& source_pass = *resolved_pass.render_pass; const QuadList& source_quad_list = source_pass.quad_list; const SharedQuadState* last_copied_source_shared_quad_state = nullptr; @@ -1093,7 +1119,11 @@ } MaskFilterInfoExt new_mask_filter_info_ext = parent_mask_filter_info_ext; + + size_t quad_index = 0; for (auto* quad : source_quad_list) { + const ResolvedQuadData& quad_data = resolved_pass.draw_quads[quad_index++]; + // Both cannot be set at once. If this happens then a surface is being // merged when it should not. DCHECK(quad->shared_quad_state->mask_filter_info.IsEmpty() || @@ -1202,22 +1232,15 @@ } else { dest_quad = dest_pass->CopyFromAndAppendDrawQuad(quad); } - if (!child_to_parent_map.empty()) { - for (ResourceId& resource_id : dest_quad->resources) { - auto it = child_to_parent_map.find(resource_id); - DCHECK(it != child_to_parent_map.end()); - - DCHECK_EQ(it->first, resource_id); - ResourceId remapped_id = it->second; - resource_id = remapped_id; - } - } + dest_quad->resources = quad_data.remapped_resources; } } } -void SurfaceAggregator::CopyPasses(const CompositorFrame& frame, - Surface* surface) { +void SurfaceAggregator::CopyPasses(ResolvedFrameData& resolved_frame, + const CompositorFrame& frame) { + Surface* surface = resolved_frame.surface(); + // The root surface is allowed to have copy output requests, so grab them // off its render passes. This map contains a set of CopyOutputRequests // keyed by each RenderPass id. @@ -1231,9 +1254,6 @@ ++stats_->copied_surface_count; - const auto& child_to_parent_map = - provider_->GetChildToParentMap(ChildIdForSurface(surface)); - const gfx::Transform surface_transform = IsRootSurface(surface) ? root_surface_transform_ : gfx::Transform(); @@ -1300,8 +1320,8 @@ /*clip_rect=*/{}, &source, copy_pass.get(), surface); } - CopyQuadsToPass(source, copy_pass.get(), frame.device_scale_factor(), - child_to_parent_map, + CopyQuadsToPass(resolved_frame.GetRenderPassDataByIndex(i), copy_pass.get(), + frame.device_scale_factor(), apply_surface_transform_to_root_pass ? surface_transform : gfx::Transform(), {}, surface, MaskFilterInfoExt()); @@ -1340,21 +1360,22 @@ } gfx::Rect SurfaceAggregator::PrewalkRenderPass( - RenderPassMapEntry* render_pass_entry, - const Surface* surface, - base::flat_map<CompositorRenderPassId, RenderPassMapEntry>* render_pass_map, + ResolvedFrameData& resolved_frame, + ResolvedPassData& resolved_pass, bool will_draw, const gfx::Rect& damage_from_parent, const gfx::Transform& target_to_root_transform, bool in_moved_pixel_rp, PrewalkResult* result) { - if (render_pass_entry->is_visited) { + const Surface* surface = resolved_frame.surface(); + + if (resolved_pass.is_visited) { // This render pass is an ancestor of itself and is not supported. return gfx::Rect(); } - base::AutoReset<bool> reset_visited(&render_pass_entry->is_visited, true); - const CompositorRenderPass& render_pass = *render_pass_entry->render_pass; + base::AutoReset<bool> reset_visited(&resolved_pass.is_visited, true); + const CompositorRenderPass& render_pass = *resolved_pass.render_pass; if (render_pass.backdrop_filters.HasFilterThatMovesPixels()) { has_pixel_moving_backdrop_filter_ = true; @@ -1400,26 +1421,29 @@ gfx::Rect quad_damage_rect; if (quad->material == DrawQuad::Material::kSurfaceContent) { const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad); - Surface* child_surface = - manager_->GetLatestInFlightSurface(surface_quad->surface_range); + ResolvedFrameData* child_resolved_frame = + GetResolvedFrame(surface_quad->surface_range); + // If the primary surface is not available then we assume the damage is // the full size of the SurfaceDrawQuad because we might need to introduce // gutter. - if (!child_surface || - child_surface->surface_id() != surface_quad->surface_range.end()) { + if (!child_resolved_frame || child_resolved_frame->surface_id() != + surface_quad->surface_range.end()) { quad_damage_rect = quad->rect; } - if (child_surface) { + if (child_resolved_frame) { gfx::Rect child_rect; float x_scale = SK_Scalar1; float y_scale = SK_Scalar1; if (surface_quad->stretch_content_to_fill_bounds) { - if (!child_surface->size_in_pixels().IsEmpty()) { + const gfx::Size& child_size = + child_resolved_frame->surface()->size_in_pixels(); + if (!child_size.IsEmpty()) { x_scale = static_cast<float>(surface_quad->rect.width()) / - child_surface->size_in_pixels().width(); + child_size.width(); y_scale = static_cast<float>(surface_quad->rect.height()) / - child_surface->size_in_pixels().height(); + child_size.height(); } } // If the surface quad is to be merged potentially, the current @@ -1451,7 +1475,7 @@ inverse, accumulated_damage_in_child_space); } } - child_rect = PrewalkSurface(child_surface, in_moved_pixel_rp, + child_rect = PrewalkSurface(*child_resolved_frame, in_moved_pixel_rp, remapped_pass_id, will_draw, accumulated_damage_in_child_space, result); child_rect = gfx::ScaleToEnclosingRect(child_rect, x_scale, y_scale); @@ -1461,11 +1485,11 @@ auto* render_pass_quad = CompositorRenderPassDrawQuad::MaterialCast(quad); CompositorRenderPassId child_pass_id = render_pass_quad->render_pass_id; - auto child_it = render_pass_map->find(child_pass_id); - DCHECK(child_it != render_pass_map->end()); - RenderPassMapEntry& child_render_pass_entry = child_it->second; + + ResolvedPassData& child_resolved_pass = + resolved_frame.GetRenderPassDataById(child_pass_id); const CompositorRenderPass& child_render_pass = - *child_render_pass_entry.render_pass; + *child_resolved_pass.render_pass; gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect( quad->shared_quad_state->quad_to_target_transform, @@ -1543,8 +1567,8 @@ target_to_root_transform, quad->shared_quad_state->quad_to_target_transform); quad_damage_rect = PrewalkRenderPass( - &child_render_pass_entry, surface, render_pass_map, will_draw, - gfx::Rect(), child_to_root_transform, in_moved_pixel_rp, result); + resolved_frame, child_resolved_pass, will_draw, gfx::Rect(), + child_to_root_transform, in_moved_pixel_rp, result); } if (!quad_damage_rect.IsEmpty()) { @@ -1570,10 +1594,15 @@ return damage_rect; } -bool SurfaceAggregator::DeclareResourcesToProvider( - Surface* surface, - const std::vector<TransferableResource>& resource_list, - const CompositorRenderPassList& render_passes) { +void SurfaceAggregator::ProcessResolvedFrame( + ResolvedFrameData& resolved_frame) { + Surface* surface = resolved_frame.surface(); + const CompositorFrame& compositor_frame = + surface->GetActiveOrInterpolatedFrame(); + + auto& resource_list = compositor_frame.resource_list; + auto& render_passes = compositor_frame.render_pass_list; + int child_id = ChildIdForSurface(surface); // Ref the resources in the surface, and let the provider know we've received @@ -1590,26 +1619,43 @@ // is more efficient. std::vector<ResourceId> referenced_resources; referenced_resources.reserve(resource_list.size()); - const auto& child_to_parent_map = provider_->GetChildToParentMap(child_id); - for (const auto& render_pass : render_passes) { + + // Reset and compute new render pass / quad data for this frame. This stores + // remapped display resource ids. + std::vector<ResolvedPassData> resolved_pass_list(render_passes.size()); + for (size_t i = 0; i < render_passes.size(); ++i) { + auto& render_pass = render_passes[i]; + resolved_pass_list[i].render_pass = render_pass.get(); + + // Loop through the quads, remapping resource ids and storing them. + auto& draw_quads = resolved_pass_list[i].draw_quads; + draw_quads.reserve(render_pass->quad_list.size()); for (auto* quad : render_pass->quad_list) { - for (ResourceId resource_id : quad->resources) { + draw_quads.emplace_back(*quad); + for (ResourceId& resource_id : draw_quads.back().remapped_resources) { // If we're using a resource which was not declared in the // |resource_list| then this is an invalid frame, we can abort. - if (!child_to_parent_map.count(resource_id)) - return false; + auto iter = child_to_parent_map.find(resource_id); + if (iter == child_to_parent_map.end()) { + DLOG(ERROR) << "Invalid resource for " << resolved_frame.surface_id(); + resolved_frame.SetInvalid(); + return; + } + referenced_resources.push_back(resource_id); + resource_id = iter->second; } } } + resolved_frame.UpdateResolvedPassData(std::move(resolved_pass_list)); + // Declare the used resources to the provider. This will cause all resources // that were received but not used in the render passes to be unreferenced in // the surface, and returned to the child in the resource provider. ResourceIdSet resource_set(std::move(referenced_resources)); provider_->DeclareUsedResourcesFromChild(child_id, resource_set); - return true; } bool SurfaceAggregator::CheckFrameSinksChanged(const Surface* surface) { @@ -1624,35 +1670,27 @@ } gfx::Rect SurfaceAggregator::PrewalkSurface( - Surface* surface, + ResolvedFrameData& resolved_frame, bool in_moved_pixel_rp, AggregatedRenderPassId parent_pass_id, bool will_draw, const gfx::Rect& damage_from_parent, PrewalkResult* result) { + Surface* surface = resolved_frame.surface(); + DCHECK(surface->HasActiveFrame()); + if (referenced_surfaces_.count(surface->surface_id())) return gfx::Rect(); result->frame_sinks_changed |= CheckFrameSinksChanged(surface); - if (!surface->HasActiveFrame()) - return gfx::Rect(); - const CompositorFrame& frame = surface->GetActiveOrInterpolatedFrame(); auto remapped_pass_id = pass_id_remapper_.Remap( frame.render_pass_list.back()->id, surface->surface_id()); if (parent_pass_id) render_pass_dependencies_[parent_pass_id].insert(remapped_pass_id); - base::flat_map<CompositorRenderPassId, RenderPassMapEntry> render_pass_map = - GenerateRenderPassMap(frame.render_pass_list, IsRootSurface(surface)); - - base::ElapsedTimer timer; - bool valid_frame = DeclareResourcesToProvider(surface, frame.resource_list, - frame.render_pass_list); - stats_->declare_resources_time += timer.Elapsed(); - - if (!valid_frame) + if (!resolved_frame.is_valid()) return gfx::Rect(); valid_surfaces_.insert(surface->surface_id()); ++stats_->prewalked_surface_count; @@ -1664,13 +1702,9 @@ // |referenced_surfaces_|. referenced_surfaces_.insert(surface->surface_id()); - auto it = render_pass_map.find(frame.render_pass_list.back()->id); - DCHECK(it != render_pass_map.end()); - RenderPassMapEntry& entry = it->second; - damage_rect.Union(PrewalkRenderPass( - &entry, surface, &render_pass_map, will_draw, damage_from_parent, - gfx::Transform(), in_moved_pixel_rp, result)); + resolved_frame, resolved_frame.GetRootRenderPassData(), will_draw, + damage_from_parent, gfx::Transform(), in_moved_pixel_rp, result)); if (!damage_rect.IsEmpty()) { auto damage_rect_surface_space = damage_rect; @@ -1719,10 +1753,11 @@ for (const SurfaceId& surface_id : surface->active_referenced_surfaces()) { if (!contained_surfaces_.count(surface_id)) { result->undrawn_surfaces.insert(surface_id); - Surface* undrawn_surface = manager_->GetSurfaceForId(surface_id); - if (undrawn_surface) - PrewalkSurface(undrawn_surface, false, AggregatedRenderPassId(), + ResolvedFrameData* undrawn_surface = GetResolvedFrame(surface_id); + if (undrawn_surface) { + PrewalkSurface(*undrawn_surface, false, AggregatedRenderPassId(), /*will_draw=*/false, gfx::Rect(), result); + } } } @@ -1757,11 +1792,11 @@ for (size_t i = 0; i < surfaces_to_copy.size(); i++) { SurfaceId surface_id = surfaces_to_copy[i]; - Surface* surface = manager_->GetSurfaceForId(surface_id); - if (!surface) + ResolvedFrameData* resolved_frame = GetResolvedFrame(surface_id); + if (!resolved_frame) continue; - if (!surface->HasActiveFrame()) - continue; + + Surface* surface = resolved_frame->surface(); if (!surface->HasCopyOutputRequests()) { // Children are not necessarily included in undrawn_surfaces (because // they weren't referenced directly from a drawn surface), but may have @@ -1778,7 +1813,7 @@ } else { prewalk_result->undrawn_surfaces.erase(surface_id); referenced_surfaces_.insert(surface_id); - CopyPasses(surface->GetActiveOrInterpolatedFrame(), surface); + CopyPasses(*resolved_frame, surface->GetActiveOrInterpolatedFrame()); referenced_surfaces_.erase(surface_id); } } @@ -1863,8 +1898,12 @@ dest_pass_list_ = &frame.render_pass_list; surface_damage_rect_list_ = &frame.surface_damage_rect_list_; - const gfx::Size viewport_bounds = - root_surface_frame.render_pass_list.back()->output_rect.size(); + auto& root_render_pass = root_surface_frame.render_pass_list.back(); + + // The root render pass on the root surface can not have backdrop filters. + DCHECK(!root_render_pass->backdrop_filters.HasFilterThatMovesPixels()); + + const gfx::Size viewport_bounds = root_render_pass->output_rect.size(); root_surface_transform_ = gfx::OverlayTransformToTransform( display_transform, gfx::SizeF(viewport_bounds)); @@ -1875,8 +1914,11 @@ base::ElapsedTimer prewalk_timer; PrewalkResult prewalk_result; + // Get the resolved frame for the root surface after `prewalk_timer` is + // started so the work is counted in the same histograms as before. + ResolvedFrameData& resolved_frame = *GetResolvedFrame(surface); gfx::Rect surfaces_damage_rect = PrewalkSurface( - surface, /*in_moved_pixel_rp=*/false, + resolved_frame, /*in_moved_pixel_rp=*/false, /*parent_pass=*/AggregatedRenderPassId(), /*will_draw=*/true, /*damage_from_parent=*/gfx::Rect(), &prewalk_result); stats_->prewalk_time = prewalk_timer.Elapsed(); @@ -1911,7 +1953,7 @@ base::ElapsedTimer copy_timer; CopyUndrawnSurfaces(&prewalk_result); referenced_surfaces_.insert(surface_id); - CopyPasses(root_surface_frame, surface); + CopyPasses(resolved_frame, root_surface_frame); referenced_surfaces_.erase(surface_id); DCHECK(referenced_surfaces_.empty()); stats_->copy_time = copy_timer.Elapsed(); @@ -2015,11 +2057,17 @@ copy_request_passes_.clear(); contributing_content_damaged_passes_.clear(); render_pass_dependencies_.clear(); + resolved_surface_ranges_.clear(); pass_id_remapper_.ClearUnusedMappings(); contained_surfaces_.clear(); contained_frame_sinks_.clear(); display_trace_id_ = -1; video_capture_enabled_ = false; + + // Delete resolved frame data that wasn't used this frame. + base::EraseIf(resolved_frames_, [](auto& entry) { + return !entry.second.CheckIfUsedAndReset(); + }); } void SurfaceAggregator::ReleaseResources(const SurfaceId& surface_id) {
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h index fd547c37..02fa6f79 100644 --- a/components/viz/service/display/surface_aggregator.h +++ b/components/viz/service/display/surface_aggregator.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SURFACE_AGGREGATOR_H_ #define COMPONENTS_VIZ_SERVICE_DISPLAY_SURFACE_AGGREGATOR_H_ +#include <map> #include <memory> #include <unordered_map> #include <utility> @@ -21,6 +22,7 @@ #include "components/viz/common/surfaces/surface_range.h" #include "components/viz/service/display/aggregated_frame.h" #include "components/viz/service/display/render_pass_id_remapper.h" +#include "components/viz/service/display/resolved_frame_data.h" #include "components/viz/service/viz_service_export.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/delegated_ink_metadata.h" @@ -93,7 +95,6 @@ private: struct PrewalkResult; struct ChildSurfaceInfo; - struct RenderPassMapEntry; struct MaskFilterInfoExt; struct AggregateStatistics { @@ -106,11 +107,12 @@ base::TimeDelta declare_resources_time; }; - // Helper function that gets a list of render passes and returns a map from - // render pass ids to render passes. - static base::flat_map<CompositorRenderPassId, RenderPassMapEntry> - GenerateRenderPassMap(const CompositorRenderPassList& render_pass_list, - bool is_root_surface); + // Get resolved frame data for the resolved surfaces active frame. Returns + // null if there is no matching surface or the surface doesn't have an active + // CompositorFrame. + ResolvedFrameData* GetResolvedFrame(const SurfaceRange& range); + ResolvedFrameData* GetResolvedFrame(const SurfaceId& surface_id); + ResolvedFrameData* GetResolvedFrame(Surface* surface); absl::optional<gfx::Rect> CalculateClipRect( const absl::optional<gfx::Rect>& surface_clip, @@ -127,7 +129,7 @@ bool* damage_rect_in_quad_space_valid, const MaskFilterInfoExt& mask_filter_info_pair); - void EmitSurfaceContent(Surface* surface, + void EmitSurfaceContent(ResolvedFrameData& resolved_frame, float parent_device_scale_factor, const SurfaceDrawQuad* surface_quad, const gfx::Transform& target_transform, @@ -172,24 +174,21 @@ AggregatedRenderPass* dest_render_pass, const MaskFilterInfoExt& mask_filter_info_pair); - void CopyQuadsToPass( - const CompositorRenderPass& source_pass, - AggregatedRenderPass* dest_pass, - float parent_device_scale_factor, - const std::unordered_map<ResourceId, ResourceId, ResourceIdHasher>& - resource_to_child_map, - const gfx::Transform& target_transform, - const absl::optional<gfx::Rect>& clip_rect, - const Surface* surface, - const MaskFilterInfoExt& mask_filter_info_pair); + void CopyQuadsToPass(const ResolvedPassData& resolved_pass, + AggregatedRenderPass* dest_pass, + float parent_device_scale_factor, + const gfx::Transform& target_transform, + const absl::optional<gfx::Rect>& clip_rect, + const Surface* surface, + const MaskFilterInfoExt& mask_filter_info_pair); // Recursively walks through the render pass and updates the // |intersects_damage_under| flag on all RenderPassDrawQuads(RPDQ). // The function returns the damage rect of the render pass in its own content // space. - // - |render_pass_entry| specifies the render pass in the entry map to be - // prewalked - // - |surface| is the surface containing the render pass. + // - |resolved_frame| is the resolved frame containing the render pass. + // - |resolved_pass| contains the render pass data corresponding to the + // render pass to be walked. // - |render_pass_map| is a map that contains all render passes and their // entry data. // - |will_draw| indicates that the surface can be aggregated into the final @@ -212,38 +211,33 @@ // ancestor render pass with a pixel-moving foreground filter. // - |result| is the result of a prewalk of the surface that contains the // render pass. - gfx::Rect PrewalkRenderPass( - RenderPassMapEntry* render_pass_entry, - const Surface* surface, - base::flat_map<CompositorRenderPassId, RenderPassMapEntry>* - render_pass_map, - bool will_draw, - const gfx::Rect& damage_from_parent, - const gfx::Transform& target_to_root_transform, - bool in_moved_pixel_rp, - PrewalkResult* result); + gfx::Rect PrewalkRenderPass(ResolvedFrameData& resolved_frame, + ResolvedPassData& resolved_pass, + bool will_draw, + const gfx::Rect& damage_from_parent, + const gfx::Transform& target_to_root_transform, + bool in_moved_pixel_rp, + PrewalkResult* result); - // Walk the Surface tree from |surface|. Validate the resources of the + // Walk the Surface tree from |resolved_frame|. Validate the resources of the // current surface and its descendants, check if there are any copy requests, // and return the combined damage rect. - gfx::Rect PrewalkSurface(Surface* surface, + gfx::Rect PrewalkSurface(ResolvedFrameData& resolved_frame, bool in_moved_pixel_rp, AggregatedRenderPassId parent_pass, bool will_draw, const gfx::Rect& damage_from_parent, PrewalkResult* result); - // Declares all of the resources to the resource provider. Also declares - // resources that are used in the render_pass_list. Returns true if this seems - // to be a valid frame (all resources used in the render pass are present in - // the resource list). - bool DeclareResourcesToProvider( - Surface* surface, - const std::vector<TransferableResource>& resource_list, - const CompositorRenderPassList& render_pass_list); + // Processes a new resolved CompositorFrame. This declares all of the + // transferable resources plus what resources that are used in the + // render_pass_list to the resource provider. Also repopulates render pass and + // quad data in |resolved_frame| based on the active CompositorFrame. + void ProcessResolvedFrame(ResolvedFrameData& resolved_frame); void CopyUndrawnSurfaces(PrewalkResult* prewalk); - void CopyPasses(const CompositorFrame& frame, Surface* surface); + void CopyPasses(ResolvedFrameData& resolved_frame, + const CompositorFrame& frame); void AddColorConversionPass(); void AddDisplayTransformPass(); @@ -434,6 +428,9 @@ base::flat_map<AggregatedRenderPassId, base::flat_set<AggregatedRenderPassId>> render_pass_dependencies_; + // Map from SurfaceRange to Surface for current aggregation. + base::flat_map<SurfaceRange, Surface*> resolved_surface_ranges_; + // The root damage rect of the currently-aggregating frame. gfx::Rect root_damage_rect_; @@ -502,6 +499,9 @@ // Indicates whether video capture has been enabled for this frame. bool video_capture_enabled_ = false; + // Persistent storage for ResolvedFrameData. + std::map<Surface*, ResolvedFrameData> resolved_frames_; + // A helper class used to remap render pass IDs from the surface namespace to // a common space, to avoid collisions. RenderPassIdRemapper pass_id_remapper_;
diff --git a/components/webdata/common/web_database_service.h b/components/webdata/common/web_database_service.h index 092df83..3f1eb9c 100644 --- a/components/webdata/common/web_database_service.h +++ b/components/webdata/common/web_database_service.h
@@ -18,7 +18,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/ref_counted_delete_on_sequence.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/single_thread_task_runner.h" #include "components/webdata/common/web_data_service_base.h" #include "components/webdata/common/web_database.h"
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc index 8b557bde..7fe6909 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc
@@ -49,6 +49,7 @@ #include "components/discardable_memory/service/discardable_shared_memory_manager.h" #include "components/download/public/common/download_task_runner.h" #include "components/power_scheduler/power_mode_arbiter.h" +#include "components/variations/variations_ids_provider.h" #include "content/app/mojo/mojo_init.h" #include "content/app/mojo_ipc_support.h" #include "content/browser/browser_main.h" @@ -998,6 +999,12 @@ // as BrowserThread::UI in BrowserMainLoop::CreateMainMessageLoop). BrowserTaskExecutor::Create(); + auto* provider = delegate_->CreateVariationsIdsProvider(); + if (!provider) { + variations::VariationsIdsProvider::Create( + variations::VariationsIdsProvider::Mode::kUseSignedInState); + } + delegate_->PostEarlyInitialization(main_params.ui_task != nullptr); // The hang watcher needs to be started once the feature list is available
diff --git a/content/browser/accessibility/dump_accessibility_node_browsertest.cc b/content/browser/accessibility/dump_accessibility_node_browsertest.cc index 1f10791..a159c93 100644 --- a/content/browser/accessibility/dump_accessibility_node_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_node_browsertest.cc
@@ -762,6 +762,12 @@ } IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, + NameTextLabelledbyHiddenWithHiddenChild) { + RunAccNameTest( + FILE_PATH_LITERAL("name-text-labelledby-hidden-with-hidden-child.html")); +} + +IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextLabelledbyParagraphs) { RunAccNameTest(FILE_PATH_LITERAL("name-text-labelledby-paragraphs.html")); }
diff --git a/content/browser/code_cache/generated_code_cache.cc b/content/browser/code_cache/generated_code_cache.cc index f4d0844..fc15e1f 100644 --- a/content/browser/code_cache/generated_code_cache.cc +++ b/content/browser/code_cache/generated_code_cache.cc
@@ -4,9 +4,7 @@ #include "content/browser/code_cache/generated_code_cache.h" #include "base/bind.h" -#include "base/feature_list.h" #include "base/memory/ptr_util.h" -#include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "content/public/common/url_constants.h" @@ -94,22 +92,9 @@ // a given resource. Code that is larger than this limit will be stored under a // key derived from the code checksum, and each origin using a given resource // gets its own small entry under the key generated by |GetCacheKey| that holds -// the hash, enabling a two stage lookup. -constexpr size_t kLargeDataLimit = 64 * 1024; - -// crbug.com/936107: This is a study to determine a good size threshold to -// deduplicate JS and WebAssembly cache entries. -// TODO(bbudge): Remove this after the study finishes. -constexpr base::Feature kCodeCacheDeduplicationStudy{ - "CodeCacheDeduplicationStudy", base::FEATURE_DISABLED_BY_DEFAULT}; -constexpr base::FeatureParam<int> kCodeCacheDeduplicationThreshold{ - &kCodeCacheDeduplicationStudy, "size", kLargeDataLimit}; - -size_t GetLargeDataLimit() { - // The large data limit should be greater than or equal to kSmallDataLimit. - return std::max(kSmallDataLimit, base::saturated_cast<size_t>( - kCodeCacheDeduplicationThreshold.Get())); -} +// the hash, enabling a two stage lookup. This limit was determined empirically +// by a Finch experiment. +constexpr size_t kLargeDataLimit = 16384; // Checks that the header data in the small buffer is valid. We may read cache // entries that were written by a previous version of Chrome which use obsolete @@ -123,7 +108,7 @@ kDataSizeInBytes); if (data_size <= kSmallDataLimit) return buffer_size == kHeaderSizeInBytes + data_size; - if (data_size <= GetLargeDataLimit()) + if (data_size <= kLargeDataLimit) return buffer_size == kHeaderSizeInBytes; return buffer_size == kHeaderSizeInBytes + kSHAKeySizeInBytes; } @@ -371,7 +356,7 @@ memcpy(small_buffer->data() + kHeaderSizeInBytes, data.data(), data.size()); // Write 0 bytes and truncate stream 1 to clear any stale data. large_buffer = base::MakeRefCounted<BigIOBuffer>(mojo_base::BigBuffer()); - } else if (data_size <= GetLargeDataLimit()) { + } else if (data_size <= kLargeDataLimit) { // 2. Large // [stream0] response time, size // [stream1] data @@ -764,7 +749,7 @@ memcpy(data.data(), op->small_buffer()->data() + kHeaderSizeInBytes, data_size); op->TakeReadCallback().Run(response_time, std::move(data)); - } else if (data_size <= GetLargeDataLimit()) { + } else if (data_size <= kLargeDataLimit) { // Large data below the merging threshold. Return the large buffer. op->TakeReadCallback().Run(response_time, op->large_buffer()->TakeBuffer());
diff --git a/content/browser/conversions/conversion_storage_unittest.cc b/content/browser/conversions/conversion_storage_unittest.cc index 75505cd..265863a 100644 --- a/content/browser/conversions/conversion_storage_unittest.cc +++ b/content/browser/conversions/conversion_storage_unittest.cc
@@ -529,13 +529,68 @@ EXPECT_TRUE(ReportsEqual(first_call_reports, second_call_reports)); } -TEST_F(ConversionStorageTest, MaxImpressionsPerOrigin) { +TEST_F(ConversionStorageTest, MaxImpressionsPerOrigin_LimitsStorage) { delegate()->set_max_impressions_per_origin(2); - storage()->StoreImpression(ImpressionBuilder(clock()->Now()).Build()); - storage()->StoreImpression(ImpressionBuilder(clock()->Now()).Build()); - storage()->StoreImpression(ImpressionBuilder(clock()->Now()).Build()); - EXPECT_TRUE( - storage()->MaybeCreateAndStoreConversionReport(DefaultConversion())); + storage()->StoreImpression( + ImpressionBuilder(clock()->Now()).SetData(3).Build()); + storage()->StoreImpression( + ImpressionBuilder(clock()->Now()).SetData(5).Build()); + storage()->StoreImpression( + ImpressionBuilder(clock()->Now()).SetData(7).Build()); + + std::vector<StorableImpression> stored_impressions = + storage()->GetActiveImpressions(); + EXPECT_EQ(2u, stored_impressions.size()); + EXPECT_EQ(3u, stored_impressions[0].impression_data()); + EXPECT_EQ(5u, stored_impressions[1].impression_data()); +} + +TEST_F(ConversionStorageTest, MaxImpressionsPerOrigin_PerOriginNotSite) { + delegate()->set_max_impressions_per_origin(2); + storage()->StoreImpression(ImpressionBuilder(clock()->Now()) + .SetImpressionOrigin(url::Origin::Create( + GURL("https://foo.a.example"))) + .SetData(3) + .Build()); + storage()->StoreImpression(ImpressionBuilder(clock()->Now()) + .SetImpressionOrigin(url::Origin::Create( + GURL("https://foo.a.example"))) + .SetData(5) + .Build()); + storage()->StoreImpression(ImpressionBuilder(clock()->Now()) + .SetImpressionOrigin(url::Origin::Create( + GURL("https://bar.a.example"))) + .SetData(7) + .Build()); + + std::vector<StorableImpression> stored_impressions = + storage()->GetActiveImpressions(); + EXPECT_EQ(3u, stored_impressions.size()); + EXPECT_EQ(3u, stored_impressions[0].impression_data()); + EXPECT_EQ(5u, stored_impressions[1].impression_data()); + EXPECT_EQ(7u, stored_impressions[2].impression_data()); + + // This impression shouldn't be stored, because its origin has already hit the + // limit of 2. + storage()->StoreImpression(ImpressionBuilder(clock()->Now()) + .SetImpressionOrigin(url::Origin::Create( + GURL("https://foo.a.example"))) + .SetData(9) + .Build()); + // This impression should be stored, because its origin hasn't hit the limit + // of 2. + storage()->StoreImpression(ImpressionBuilder(clock()->Now()) + .SetImpressionOrigin(url::Origin::Create( + GURL("https://bar.a.example"))) + .SetData(11) + .Build()); + + stored_impressions = storage()->GetActiveImpressions(); + EXPECT_EQ(4u, stored_impressions.size()); + EXPECT_EQ(3u, stored_impressions[0].impression_data()); + EXPECT_EQ(5u, stored_impressions[1].impression_data()); + EXPECT_EQ(7u, stored_impressions[2].impression_data()); + EXPECT_EQ(11u, stored_impressions[3].impression_data()); } TEST_F(ConversionStorageTest, MaxConversionsPerOrigin) {
diff --git a/content/browser/interest_group/ad_auction_service_impl.h b/content/browser/interest_group/ad_auction_service_impl.h index 971d688..db52a96 100644 --- a/content/browser/interest_group/ad_auction_service_impl.h +++ b/content/browser/interest_group/ad_auction_service_impl.h
@@ -78,8 +78,6 @@ mojo::Remote<network::mojom::URLLoaderFactory> frame_url_loader_factory_; mojo::Remote<network::mojom::URLLoaderFactory> trusted_url_loader_factory_; - - base::WeakPtrFactory<AdAuctionServiceImpl> weak_ptr_factory_{this}; }; } // namespace content
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 1f92027b..b354fdd 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -13,7 +13,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/time/time.h" #include "cc/paint/element_id.h" #include "cc/trees/layer_tree_host_client.h"
diff --git a/content/browser/resources/BUILD.gn b/content/browser/resources/BUILD.gn index f7c84dd..0ac63ce 100644 --- a/content/browser/resources/BUILD.gn +++ b/content/browser/resources/BUILD.gn
@@ -7,6 +7,7 @@ if (enable_js_type_check) { group("closure_compile") { deps = [ + "conversions:closure_compile", "histograms:closure_compile", "process:closure_compile", ]
diff --git a/content/browser/resources/conversions/BUILD.gn b/content/browser/resources/conversions/BUILD.gn new file mode 100644 index 0000000..42abd887 --- /dev/null +++ b/content/browser/resources/conversions/BUILD.gn
@@ -0,0 +1,29 @@ +# Copyright 2021 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("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + closure_flags = + default_closure_args + mojom_js_args + [ + "js_module_root=" + rebase_path(".", root_build_dir), + "js_module_root=" + + rebase_path("$root_gen_dir/mojom-webui/content/browser/conversions", + root_build_dir), + ] + deps = [ ":conversions_internals" ] +} + +js_library("conversions_internals") { + sources = [ + # TODO(crbug.com/1217165): Fix Closure errors in .js and uncomment the line + # below. + # "conversion_internals.js" + ] + + deps = [ + "//content/browser/conversions:mojo_bindings_webui_js", + "//ui/webui/resources/js:util.m", + ] +}
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index f72f812..af8d522 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -91,7 +91,6 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" -#include "content/public/browser/render_widget_host_observer.h" #include "content/public/browser/site_isolation_policy.h" #include "content/public/common/content_client.h" #include "content/public/common/content_features.h" @@ -117,6 +116,7 @@ #include "content/test/content_browser_test_utils_internal.h" #include "content/test/did_commit_navigation_interceptor.h" #include "content/test/render_document_feature.h" +#include "content/test/render_widget_host_visibility_observer.h" #include "content/test/test_content_browser_client.h" #include "ipc/constants.mojom.h" #include "ipc/ipc_security_test_util.h" @@ -421,50 +421,6 @@ focus_observer.Wait(); } -class RenderWidgetHostVisibilityObserver : public RenderWidgetHostObserver { - public: - explicit RenderWidgetHostVisibilityObserver(RenderWidgetHostImpl* rwhi, - bool expected_visibility_state) - : expected_visibility_state_(expected_visibility_state), - was_observed_(false), - did_fail_(false), - render_widget_(rwhi) { - observation_.Observe(render_widget_); - message_loop_runner_ = new MessageLoopRunner; - } - - bool WaitUntilSatisfied() { - if (!was_observed_) - message_loop_runner_->Run(); - observation_.Reset(); - return !did_fail_; - } - - private: - void RenderWidgetHostVisibilityChanged(RenderWidgetHost* widget_host, - bool became_visible) override { - was_observed_ = true; - did_fail_ = expected_visibility_state_ != became_visible; - if (message_loop_runner_->loop_running()) - message_loop_runner_->Quit(); - } - - void RenderWidgetHostDestroyed(RenderWidgetHost* widget_host) override { - DCHECK(observation_.IsObservingSource(widget_host)); - observation_.Reset(); - } - - bool expected_visibility_state_; - scoped_refptr<MessageLoopRunner> message_loop_runner_; - base::ScopedObservation<RenderWidgetHost, RenderWidgetHostObserver> - observation_{this}; - bool was_observed_; - bool did_fail_; - RenderWidgetHost* render_widget_; - - DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostVisibilityObserver); -}; - bool ConvertJSONToPoint(const std::string& str, gfx::PointF* point) { absl::optional<base::Value> value = base::JSONReader::Read(str); if (!value.has_value()) @@ -576,27 +532,6 @@ rwh->ForwardGestureEvent(gesture_tap_down); } -// Helper class to wait for the next sad frame to be shown in a specific -// FrameTreeNode. This can be used to wait for sad frame visibility metrics to -// be logged. -class SadFrameShownObserver { - public: - explicit SadFrameShownObserver(FrameTreeNode* ftn) { - RenderFrameProxyHost* proxy_to_parent = - ftn->render_manager()->GetProxyToParent(); - proxy_to_parent->cross_process_frame_connector() - ->set_child_frame_crash_shown_closure_for_testing( - run_loop_.QuitClosure()); - } - - void Wait() { run_loop_.Run(); } - - private: - base::RunLoop run_loop_; - - DISALLOW_COPY_AND_ASSIGN(SadFrameShownObserver); -}; - } // namespace // Class to monitor incoming UpdateViewportIntersection messages. @@ -794,6 +729,11 @@ SitePerProcessProgrammaticScrollTest() : kInfinity(1000000U), kPositiveXYPlane(0, 0, kInfinity, kInfinity) {} + SitePerProcessProgrammaticScrollTest( + const SitePerProcessProgrammaticScrollTest&) = delete; + SitePerProcessProgrammaticScrollTest& operator=( + const SitePerProcessProgrammaticScrollTest&) = delete; + protected: const size_t kInfinity; const std::string kIframeOutOfViewHTML = "/iframe_out_of_view.html"; @@ -871,8 +811,6 @@ return {static_cast<int>(x), static_cast<int>(y), static_cast<int>(width), static_cast<int>(height)}; } - - DISALLOW_COPY_AND_ASSIGN(SitePerProcessProgrammaticScrollTest); }; // SitePerProcessWebBundleBrowserTest. @@ -14326,62 +14264,6 @@ } IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, - ChildFrameCrashMetrics_KilledWhileVisible) { - // Set-up a frame tree that helps verify what the metrics tracks: - // 1) frames (12 frames are affected if B process gets killed) or - // 2) crashes (simply 1 crash if B process gets killed)? - // 3) widgets (10 b widgets and 1 c widget are affected if B is killed, - // but a sad frame will appear only in 9 widgets - this excludes - // widgets for the b,c(b) part of the frame tree) or - GURL main_url(embedded_test_server()->GetURL( - "a.com", "/cross_site_iframe_factory.html?a(b(b,c(b)),b,b,b,b,b,b,b,b)")); - EXPECT_TRUE(NavigateToURL(shell(), main_url)); - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - - std::vector<std::unique_ptr<SadFrameShownObserver>> observers; - for (size_t i = 0U; i < root->child_count(); i++) { - // At this point, all b.com subframes should be considered visible. - RenderFrameProxyHost* proxy_to_parent = - root->child_at(i)->render_manager()->GetProxyToParent(); - CrossProcessFrameConnector* connector = - proxy_to_parent->cross_process_frame_connector(); - EXPECT_TRUE(connector->IsVisible()) - << " subframe " << i << " with URL " << root->child_at(i)->current_url() - << " is hidden"; - observers.push_back( - std::make_unique<SadFrameShownObserver>(root->child_at(i))); - } - - // Kill the child frame and wait for each of the subframe FrameTreeNodes to - // show a sad frame. - base::HistogramTester histograms; - RenderProcessHost* child_process = - root->child_at(0)->current_frame_host()->GetProcess(); - RenderProcessHostWatcher crash_observer( - child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); - child_process->Shutdown(0); - crash_observer.Wait(); - for (size_t i = 0U; i < root->child_count(); i++) { - SCOPED_TRACE(testing::Message() - << " Waiting for sad frame from subframe " << i - << " with URL:" << root->child_at(i)->current_url()); - observers[i]->Wait(); - } - - // Verify that the expected metrics got logged. - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.Visibility", - CrossProcessFrameConnector::CrashVisibility::kCrashedWhileVisible, 9); - - // Hide and show the web contents and verify that no more metrics got logged. - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.Visibility", - CrossProcessFrameConnector::CrashVisibility::kCrashedWhileVisible, 9); -} - -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ChildFrameCrashMetrics_KilledMainFrame) { GURL main_url(embedded_test_server()->GetURL( "a.com", "/cross_site_iframe_factory.html?a(a(b(b,c)))")); @@ -14400,107 +14282,6 @@ histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0); } -// Disable the feature to mark hidden tabs with sad frames for reload, for use -// in tests where this feature interferes with the behavior being tested. -class SitePerProcessBrowserTestWithoutSadFrameTabReload - : public SitePerProcessBrowserTest { - public: - SitePerProcessBrowserTestWithoutSadFrameTabReload() { - feature_list_.InitAndDisableFeature( - features::kReloadHiddenTabsWithCrashedSubframes); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -// This test is flaky on Win7. -// TODO(crbug.com/1179074): Deflake it and enable this test back. -#if defined(OS_WIN) -#define MAYBE_ChildFrameCrashMetrics_KilledWhileHiddenThenShown \ - DISABLED_ChildFrameCrashMetrics_KilledWhileHiddenThenShown -#else -#define MAYBE_ChildFrameCrashMetrics_KilledWhileHiddenThenShown \ - ChildFrameCrashMetrics_KilledWhileHiddenThenShown -#endif -IN_PROC_BROWSER_TEST_P( - SitePerProcessBrowserTestWithoutSadFrameTabReload, - MAYBE_ChildFrameCrashMetrics_KilledWhileHiddenThenShown) { - // Set-up a frame tree that helps verify what the metrics tracks: - // 1) frames (12 frames are affected if B process gets killed) or - // 2) widgets (10 b widgets and 1 c widget are affected if B is killed) or - // 3) crashes (1 crash if B process gets killed)? - GURL main_url(embedded_test_server()->GetURL( - "a.com", "/cross_site_iframe_factory.html?a(b(b,c),b,b,b,b,b,b,b,b,b)")); - EXPECT_TRUE(NavigateToURL(shell(), main_url)); - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - - // Hide the web contents (UpdateWebContentsVisibility is called twice to avoid - // hitting the |!did_first_set_visible_| case). Make sure all subframes are - // considered hidden at this point. - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - for (size_t i = 0U; i < root->child_count(); i++) { - RenderFrameProxyHost* proxy_to_parent = - root->child_at(i)->render_manager()->GetProxyToParent(); - CrossProcessFrameConnector* connector = - proxy_to_parent->cross_process_frame_connector(); - EXPECT_FALSE(connector->IsVisible()) - << " subframe " << i << " with URL " << root->child_at(i)->current_url() - << " is visible"; - } - - // Kill the subframe. - base::HistogramTester histograms; - RenderProcessHost* child_process = - root->child_at(0)->current_frame_host()->GetProcess(); - RenderProcessHostWatcher crash_observer( - child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); - child_process->Shutdown(0); - crash_observer.Wait(); - - // Verify that no child frame metrics got logged (yet - while WebContents are - // hidden). - histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0); - histograms.ExpectTotalCount( - "Stability.ChildFrameCrash.ShownAfterCrashingReason", 0); - - // Show the web contents, wait for each of the subframe FrameTreeNodes to - // show a sad frame, and verify that the expected metrics got logged. - std::vector<std::unique_ptr<SadFrameShownObserver>> observers; - for (size_t i = 0U; i < root->child_count(); i++) { - observers.push_back( - std::make_unique<SadFrameShownObserver>(root->child_at(i))); - } - - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - - for (size_t i = 0U; i < root->child_count(); i++) { - SCOPED_TRACE(testing::Message() - << " Waiting for sad frame from subframe " << i - << " with URL:" << root->child_at(i)->current_url()); - observers[i]->Wait(); - } - - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.Visibility", - CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 10); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.ShownAfterCrashingReason", - CrossProcessFrameConnector::ShownAfterCrashingReason::kTabWasShown, 10); - - // Hide and show the web contents again and verify that no more metrics got - // logged. - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.Visibility", - CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 10); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.ShownAfterCrashingReason", - CrossProcessFrameConnector::ShownAfterCrashingReason::kTabWasShown, 10); -} - IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ChildFrameCrashMetrics_NeverShown) { // Set-up a frame tree that helps verify what the metrics tracks: @@ -14528,9 +14309,8 @@ // Navigate away - this will trigger logging of the UMA. EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank"))); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.Visibility", - CrossProcessFrameConnector::CrashVisibility::kNeverVisibleAfterCrash, 10); + histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", + CrashVisibility::kNeverVisibleAfterCrash, 10); } IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, @@ -14595,387 +14375,6 @@ 1); } -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithoutSadFrameTabReload, - ChildFrameCrashMetrics_ScrolledIntoViewAfterTabIsShown) { - // Start on a page that has a single iframe, which is positioned out of - // view, and navigate that iframe cross-site. - GURL main_url( - embedded_test_server()->GetURL("a.com", "/iframe_out_of_view.html")); - EXPECT_TRUE(NavigateToURL(shell(), main_url)); - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - EXPECT_TRUE(NavigateToURLFromRenderer( - root->child_at(0), - embedded_test_server()->GetURL("b.com", "/title1.html"))); - - // Hide the web contents (UpdateWebContentsVisibility is called twice to avoid - // hitting the |!did_first_set_visible_| case). - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - - // Kill the child frame. - base::HistogramTester histograms; - RenderProcessHost* child_process = - root->child_at(0)->current_frame_host()->GetProcess(); - RenderProcessHostWatcher crash_observer( - child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); - child_process->Shutdown(0); - crash_observer.Wait(); - - // Verify that no child frame crash metrics got logged yet. - histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0); - histograms.ExpectTotalCount( - "Stability.ChildFrameCrash.ShownAfterCrashingReason", 0); - - // Show the web contents. The crash metrics still shouldn't be logged, since - // the crashed frame is out of view. - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0); - histograms.ExpectTotalCount( - "Stability.ChildFrameCrash.ShownAfterCrashingReason", 0); - - // Scroll the subframe into view and wait until the scrolled frame draws - // itself. - std::string scrolling_script = R"( - var frame = document.body.querySelector("iframe"); - frame.scrollIntoView(); - )"; - EXPECT_TRUE(ExecJs(root, scrolling_script)); - // This will ensure that browser has received the - // FrameHostMsg_UpdateViewportIntersection IPC message from the renderer main - // thread. - EXPECT_EQ(true, - EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true")); - - // Verify that the expected metrics got logged. - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.Visibility", - CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 1); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.ShownAfterCrashingReason", - CrossProcessFrameConnector::ShownAfterCrashingReason:: - kViewportIntersectionAfterTabWasShown, - 1); - - // Hide and show the web contents again and verify that no more metrics got - // logged. - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.Visibility", - CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 1); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.ShownAfterCrashingReason", - CrossProcessFrameConnector::ShownAfterCrashingReason:: - kViewportIntersectionAfterTabWasShown, - 1); -} - -class SitePerProcessBrowserTestWithSadFrameTabReload - : public SitePerProcessBrowserTest { - public: - SitePerProcessBrowserTestWithSadFrameTabReload() { - // Disable the feature to mark hidden tabs with sad frames for reload, since - // it makes the scenario for which this test collects metrics impossible. - feature_list_.InitAndEnableFeature( - features::kReloadHiddenTabsWithCrashedSubframes); - } - - void CrashProcess(FrameTreeNode* ftn) { - RenderProcessHost* process = ftn->current_frame_host()->GetProcess(); - RenderProcessHostWatcher crash_observer( - process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); - process->Shutdown(0); - crash_observer.Wait(); - EXPECT_FALSE(ftn->current_frame_host()->IsRenderFrameLive()); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -// Verify the feature where hidden tabs with a visible crashed subframe are -// marked for reload. This avoids showing crashed subframes if a hidden tab is -// eventually shown. See https://crbug.com/841572. -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, - ReloadHiddenTabWithCrashedSubframeInViewport) { - GURL main_url(embedded_test_server()->GetURL( - "a.com", "/cross_site_iframe_factory.html?a(b)")); - EXPECT_TRUE(NavigateToURL(shell(), main_url)); - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - - // Hide the WebContents (UpdateWebContentsVisibility is called twice to avoid - // hitting the |!did_first_set_visible_| case). - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - EXPECT_EQ(Visibility::HIDDEN, web_contents()->GetVisibility()); - - // Kill the b.com subframe's process. This should mark the hidden - // WebContents for reload. - { - base::HistogramTester histograms; - CrashProcess(root->child_at(0)); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.TabMarkedForReload", true, 1); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.TabMarkedForReload.Visibility", - blink::mojom::FrameVisibility::kRenderedInViewport, 1); - } - - // Show the WebContents. This should trigger a reload of the main frame. - { - base::HistogramTester histograms; - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - EXPECT_TRUE(WaitForLoadStop(web_contents())); - histograms.ExpectUniqueSample( - "Navigation.LoadIfNecessaryType", - NavigationControllerImpl::NeedsReloadType::kCrashedSubframe, 1); - } - - // Both frames should now have live renderer processes. - EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); - EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); -} - -// Verify that when a tab is reloaded because it was previously marked for -// reload due to having a sad frame, we log the sad frame as shown during a tab -// reload, rather than being shown to the user directly, since the sad frame is -// expected to go away shortly. See https://crbug.com/1132938. -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, - CrashedSubframeVisibilityMetricsDuringTabReload) { - GURL main_url(embedded_test_server()->GetURL( - "a.com", "/cross_site_iframe_factory.html?a(b,c)")); - EXPECT_TRUE(NavigateToURL(shell(), main_url)); - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - - // Hide the WebContents (UpdateWebContentsVisibility is called twice to avoid - // hitting the |!did_first_set_visible_| case). - RenderWidgetHostVisibilityObserver hide_observer( - root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), - false /* became_visible */); - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - EXPECT_EQ(Visibility::HIDDEN, web_contents()->GetVisibility()); - hide_observer.WaitUntilSatisfied(); - - // Kill the b.com subframe's process. This should mark the hidden - // WebContents for reload. - CrashProcess(root->child_at(0)); - auto& controller = static_cast<NavigationControllerImpl&>( - shell()->web_contents()->GetController()); - EXPECT_TRUE(controller.NeedsReload()); - EXPECT_EQ(1, controller.GetEntryCount()); - - // Show the WebContents. This should trigger a reload of the main frame. Sad - // frame visibility metrics should indicate that the sad frame is shown while - // the tab is being reloaded. Because the tab reload will wipe out the sad - // frame, this isn't as bad as kShownAfterCrashing. - { - base::HistogramTester histograms; - SadFrameShownObserver sad_frame_observer(root->child_at(0)); - TestNavigationManager manager(web_contents(), main_url); - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - EXPECT_TRUE(manager.WaitForRequestStart()); - sad_frame_observer.Wait(); - - histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", - CrashVisibility::kShownWhileAncestorIsLoading, - 1); - - // Ensure no new metrics are logged after the reload completes. - manager.WaitForNavigationFinished(); - EXPECT_TRUE(manager.was_successful()); - EXPECT_FALSE(controller.NeedsReload()); - EXPECT_EQ(1, controller.GetEntryCount()); - histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", - CrashVisibility::kShownWhileAncestorIsLoading, - 1); - } -} - -// Verify that a sad frame shown when its parent frame is loading is logged -// with appropriate metrics, namely as kShownWhileAncestorIsLoading rather than -// kShownAfterCrashing. See https://crbug.com/1132938. -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, - CrashedSubframeVisibilityMetricsDuringParentLoad) { - GURL main_url(embedded_test_server()->GetURL( - "a.com", "/cross_site_iframe_factory.html?a(b(c))")); - EXPECT_TRUE(NavigateToURL(shell(), main_url)); - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - FrameTreeNode* child = root->child_at(0); - FrameTreeNode* grandchild = child->child_at(0); - - // Hide the grandchild frame. - RenderWidgetHostVisibilityObserver hide_observer( - grandchild->current_frame_host()->GetRenderWidgetHost(), - false /* became_visible */); - EXPECT_TRUE( - ExecJs(child, "document.querySelector('iframe').style.display = 'none'")); - hide_observer.WaitUntilSatisfied(); - - // Kill the c.com grandchild process. - CrashProcess(grandchild); - - // Start a navigation in the b.com frame, but don't commit. - GURL url_d(embedded_test_server()->GetURL("d.com", "/title1.html")); - TestNavigationManager manager(web_contents(), url_d); - EXPECT_TRUE(ExecJs(child, JsReplace("location.href = $1", url_d))); - EXPECT_TRUE(manager.WaitForRequestStart()); - - // Make the grandchild iframe with the sad frame visible again. This should - // get logged as kShownWhileAncestorIsLoading, because its parent is - // currently loading. - { - base::HistogramTester histograms; - SadFrameShownObserver sad_frame_observer(grandchild); - EXPECT_TRUE(ExecJs( - child, "document.querySelector('iframe').style.display = 'block'")); - sad_frame_observer.Wait(); - - histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", - CrashVisibility::kShownWhileAncestorIsLoading, - 1); - - // Ensure no new metrics are logged after the navigation completes. - manager.WaitForNavigationFinished(); - EXPECT_TRUE(manager.was_successful()); - histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", - CrashVisibility::kShownWhileAncestorIsLoading, - 1); - } -} - -// Verify the feature where hidden tabs with crashed subframes are marked for -// reload. This avoids showing crashed subframes if a hidden tab is eventually -// shown. Similar to the test above, except that the crashed subframe is -// scrolled out of view. -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, - ReloadHiddenTabWithCrashedSubframeOutOfView) { - // Set WebContents to VISIBLE to avoid hitting the |!did_first_set_visible_| - // case when we hide it later. - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - - // Navigate to a page with an OOPIF that's scrolled out of view. - GURL out_of_view_url( - embedded_test_server()->GetURL("a.com", "/iframe_out_of_view.html")); - EXPECT_TRUE(NavigateToURL(shell(), out_of_view_url)); - EXPECT_EQ("LOADED", EvalJs(shell(), "notifyWhenLoaded();", - EXECUTE_SCRIPT_USE_MANUAL_REPLY)); - NavigateIframeToURL(web_contents(), "test_iframe", - embedded_test_server()->GetURL("b.com", "/title1.html")); - - // This will ensure that the layout has completed and visibility of the OOPIF - // has been updated in the browser process. - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - EXPECT_EQ(true, - EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true")); - - // Verify the OOPIF isn't visible at the moment. - RenderFrameProxyHost* proxy_to_parent = - root->child_at(0)->render_manager()->GetProxyToParent(); - CrossProcessFrameConnector* connector = - proxy_to_parent->cross_process_frame_connector(); - EXPECT_FALSE(connector->IsVisible()); - EXPECT_EQ(blink::mojom::FrameVisibility::kRenderedOutOfViewport, - connector->visibility()); - - // Hide the WebContents and crash the OOPIF. - { - base::HistogramTester histograms; - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - CrashProcess(root->child_at(0)); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.TabMarkedForReload", true, 1); - histograms.ExpectUniqueSample( - "Stability.ChildFrameCrash.TabMarkedForReload.Visibility", - blink::mojom::FrameVisibility::kRenderedOutOfViewport, 1); - } - - EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); - EXPECT_FALSE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); - - // Show the tab and ensure that it reloads. - { - base::HistogramTester histograms; - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - EXPECT_TRUE(WaitForLoadStop(web_contents())); - histograms.ExpectUniqueSample( - "Navigation.LoadIfNecessaryType", - NavigationControllerImpl::NeedsReloadType::kCrashedSubframe, 1); - } - - EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); - EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); -} - -// Verify that hidden tabs with a crashed subframe are not marked for reload -// when the crashed subframe is hidden with "display:none". -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, - DoNotReloadHiddenTabWithHiddenCrashedSubframe) { - // Set WebContents to VISIBLE to avoid hitting the |!did_first_set_visible_| - // case when we hide it later. - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - - GURL hidden_iframe_url( - embedded_test_server()->GetURL("a.com", "/page_with_hidden_iframe.html")); - EXPECT_TRUE(NavigateToURL(shell(), hidden_iframe_url)); - NavigateIframeToURL(web_contents(), "test_iframe", - embedded_test_server()->GetURL("b.com", "/title1.html")); - - // Ensure that the parent frame has propagated the OOPIF's hidden visibility - // to the browser process by forcing requestAnimationFrame and - // waiting for layout to finish. - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - EXPECT_EQ(true, - EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true")); - - // The OOPIF should be hidden at this point. - RenderFrameProxyHost* proxy_to_parent = - root->child_at(0)->render_manager()->GetProxyToParent(); - EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector()->IsHidden()); - - // Crashing a hidden OOPIF shouldn't mark the tab for reload. - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - base::HistogramTester histograms; - CrashProcess(root->child_at(0)); - histograms.ExpectUniqueSample("Stability.ChildFrameCrash.TabMarkedForReload", - false, 1); - - // Making the WebContents visible again should keep the sad frame and should - // not load anything new. - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - EXPECT_TRUE(WaitForLoadStop(web_contents())); - EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); - EXPECT_FALSE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); -} - -// Ensure that the sad frame reload policy doesn't trigger for a visible tab, -// even if it becomes hidden and then visible again. -IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, - DoNotReloadVisibleTabWithCrashedSubframe) { - // Set WebContents to VISIBLE to avoid hitting the |!did_first_set_visible_| - // case when we hide it later. - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - EXPECT_EQ(Visibility::VISIBLE, web_contents()->GetVisibility()); - - GURL main_url(embedded_test_server()->GetURL( - "a.com", "/cross_site_iframe_factory.html?a(b)")); - EXPECT_TRUE(NavigateToURL(shell(), main_url)); - FrameTreeNode* root = web_contents()->GetFrameTree()->root(); - base::HistogramTester histograms; - CrashProcess(root->child_at(0)); - histograms.ExpectUniqueSample("Stability.ChildFrameCrash.TabMarkedForReload", - false, 1); - - EXPECT_EQ(Visibility::VISIBLE, web_contents()->GetVisibility()); - web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); - web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); - EXPECT_TRUE(WaitForLoadStop(web_contents())); - EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); - EXPECT_FALSE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); - histograms.ExpectUniqueSample("Stability.ChildFrameCrash.TabMarkedForReload", - false, 1); -} - // Check that when a frame changes a subframe's size twice and then sends a // postMessage to the subframe, the subframe's onmessage handler sees the new // size. In particular, ensure that the postMessage won't get reordered with @@ -16916,12 +16315,6 @@ SitePerProcessBrowserTest, testing::ValuesIn(RenderDocumentFeatureLevelValues())); INSTANTIATE_TEST_SUITE_P(All, - SitePerProcessBrowserTestWithoutSadFrameTabReload, - testing::ValuesIn(RenderDocumentFeatureLevelValues())); -INSTANTIATE_TEST_SUITE_P(All, - SitePerProcessBrowserTestWithSadFrameTabReload, - testing::ValuesIn(RenderDocumentFeatureLevelValues())); -INSTANTIATE_TEST_SUITE_P(All, SitePerProcessBrowserTouchActionTest, testing::ValuesIn(RenderDocumentFeatureLevelValues())); INSTANTIATE_TEST_SUITE_P(All,
diff --git a/content/browser/site_per_process_sad_frame_browsertest.cc b/content/browser/site_per_process_sad_frame_browsertest.cc new file mode 100644 index 0000000..c1fa588 --- /dev/null +++ b/content/browser/site_per_process_sad_frame_browsertest.cc
@@ -0,0 +1,593 @@ +// Copyright 2021 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 "content/browser/site_per_process_browsertest.h" + +#include "build/build_config.h" +#include "content/browser/renderer_host/cross_process_frame_connector.h" +#include "content/browser/renderer_host/frame_tree.h" +#include "content/browser/renderer_host/render_frame_proxy_host.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/shell/browser/shell.h" +#include "content/test/render_document_feature.h" +#include "content/test/render_widget_host_visibility_observer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +namespace { + +// Helper class to wait for the next sad frame to be shown in a specific +// FrameTreeNode. This can be used to wait for sad frame visibility metrics to +// be logged. +class SadFrameShownObserver { + public: + explicit SadFrameShownObserver(FrameTreeNode* ftn) { + RenderFrameProxyHost* proxy_to_parent = + ftn->render_manager()->GetProxyToParent(); + proxy_to_parent->cross_process_frame_connector() + ->set_child_frame_crash_shown_closure_for_testing( + run_loop_.QuitClosure()); + } + + SadFrameShownObserver(const SadFrameShownObserver&) = delete; + SadFrameShownObserver& operator=(const SadFrameShownObserver&) = delete; + + void Wait() { run_loop_.Run(); } + + private: + base::RunLoop run_loop_; +}; + +} // namespace + +// Disable the feature to mark hidden tabs with sad frames for reload, for use +// in tests where this feature interferes with the behavior being tested. +class SitePerProcessBrowserTestWithoutSadFrameTabReload + : public SitePerProcessBrowserTest { + public: + SitePerProcessBrowserTestWithoutSadFrameTabReload() { + feature_list_.InitAndDisableFeature( + features::kReloadHiddenTabsWithCrashedSubframes); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// This test is flaky on Win7. +// TODO(crbug.com/1179074): Deflake it and enable this test back. +#if defined(OS_WIN) +#define MAYBE_ChildFrameCrashMetrics_KilledWhileHiddenThenShown \ + DISABLED_ChildFrameCrashMetrics_KilledWhileHiddenThenShown +#else +#define MAYBE_ChildFrameCrashMetrics_KilledWhileHiddenThenShown \ + ChildFrameCrashMetrics_KilledWhileHiddenThenShown +#endif +IN_PROC_BROWSER_TEST_P( + SitePerProcessBrowserTestWithoutSadFrameTabReload, + MAYBE_ChildFrameCrashMetrics_KilledWhileHiddenThenShown) { + // Set-up a frame tree that helps verify what the metrics tracks: + // 1) frames (12 frames are affected if B process gets killed) or + // 2) widgets (10 b widgets and 1 c widget are affected if B is killed) or + // 3) crashes (1 crash if B process gets killed)? + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b(b,c),b,b,b,b,b,b,b,b,b)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + + // Hide the web contents (UpdateWebContentsVisibility is called twice to avoid + // hitting the |!did_first_set_visible_| case). Make sure all subframes are + // considered hidden at this point. + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + for (size_t i = 0U; i < root->child_count(); i++) { + RenderFrameProxyHost* proxy_to_parent = + root->child_at(i)->render_manager()->GetProxyToParent(); + CrossProcessFrameConnector* connector = + proxy_to_parent->cross_process_frame_connector(); + EXPECT_FALSE(connector->IsVisible()) + << " subframe " << i << " with URL " << root->child_at(i)->current_url() + << " is visible"; + } + + // Kill the subframe. + base::HistogramTester histograms; + RenderProcessHost* child_process = + root->child_at(0)->current_frame_host()->GetProcess(); + RenderProcessHostWatcher crash_observer( + child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + child_process->Shutdown(0); + crash_observer.Wait(); + + // Verify that no child frame metrics got logged (yet - while WebContents are + // hidden). + histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0); + histograms.ExpectTotalCount( + "Stability.ChildFrameCrash.ShownAfterCrashingReason", 0); + + // Show the web contents, wait for each of the subframe FrameTreeNodes to + // show a sad frame, and verify that the expected metrics got logged. + std::vector<std::unique_ptr<SadFrameShownObserver>> observers; + for (size_t i = 0U; i < root->child_count(); i++) { + observers.push_back( + std::make_unique<SadFrameShownObserver>(root->child_at(i))); + } + + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + + for (size_t i = 0U; i < root->child_count(); i++) { + SCOPED_TRACE(testing::Message() + << " Waiting for sad frame from subframe " << i + << " with URL:" << root->child_at(i)->current_url()); + observers[i]->Wait(); + } + + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.Visibility", + CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 10); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.ShownAfterCrashingReason", + CrossProcessFrameConnector::ShownAfterCrashingReason::kTabWasShown, 10); + + // Hide and show the web contents again and verify that no more metrics got + // logged. + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.Visibility", + CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 10); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.ShownAfterCrashingReason", + CrossProcessFrameConnector::ShownAfterCrashingReason::kTabWasShown, 10); +} + +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithoutSadFrameTabReload, + ChildFrameCrashMetrics_ScrolledIntoViewAfterTabIsShown) { + // Start on a page that has a single iframe, which is positioned out of + // view, and navigate that iframe cross-site. + GURL main_url( + embedded_test_server()->GetURL("a.com", "/iframe_out_of_view.html")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + EXPECT_TRUE(NavigateToURLFromRenderer( + root->child_at(0), + embedded_test_server()->GetURL("b.com", "/title1.html"))); + + // Hide the web contents (UpdateWebContentsVisibility is called twice to avoid + // hitting the |!did_first_set_visible_| case). + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + + // Kill the child frame. + base::HistogramTester histograms; + RenderProcessHost* child_process = + root->child_at(0)->current_frame_host()->GetProcess(); + RenderProcessHostWatcher crash_observer( + child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + child_process->Shutdown(0); + crash_observer.Wait(); + + // Verify that no child frame crash metrics got logged yet. + histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0); + histograms.ExpectTotalCount( + "Stability.ChildFrameCrash.ShownAfterCrashingReason", 0); + + // Show the web contents. The crash metrics still shouldn't be logged, since + // the crashed frame is out of view. + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0); + histograms.ExpectTotalCount( + "Stability.ChildFrameCrash.ShownAfterCrashingReason", 0); + + // Scroll the subframe into view and wait until the scrolled frame draws + // itself. + std::string scrolling_script = R"( + var frame = document.body.querySelector("iframe"); + frame.scrollIntoView(); + )"; + EXPECT_TRUE(ExecJs(root, scrolling_script)); + // This will ensure that browser has received the + // FrameHostMsg_UpdateViewportIntersection IPC message from the renderer main + // thread. + EXPECT_EQ(true, + EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true")); + + // Verify that the expected metrics got logged. + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.Visibility", + CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 1); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.ShownAfterCrashingReason", + CrossProcessFrameConnector::ShownAfterCrashingReason:: + kViewportIntersectionAfterTabWasShown, + 1); + + // Hide and show the web contents again and verify that no more metrics got + // logged. + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.Visibility", + CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 1); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.ShownAfterCrashingReason", + CrossProcessFrameConnector::ShownAfterCrashingReason:: + kViewportIntersectionAfterTabWasShown, + 1); +} + +class SitePerProcessBrowserTestWithSadFrameTabReload + : public SitePerProcessBrowserTest { + public: + SitePerProcessBrowserTestWithSadFrameTabReload() { + // Disable the feature to mark hidden tabs with sad frames for reload, since + // it makes the scenario for which this test collects metrics impossible. + feature_list_.InitAndEnableFeature( + features::kReloadHiddenTabsWithCrashedSubframes); + } + + void CrashProcess(FrameTreeNode* ftn) { + RenderProcessHost* process = ftn->current_frame_host()->GetProcess(); + RenderProcessHostWatcher crash_observer( + process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + process->Shutdown(0); + crash_observer.Wait(); + EXPECT_FALSE(ftn->current_frame_host()->IsRenderFrameLive()); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Verify the feature where hidden tabs with a visible crashed subframe are +// marked for reload. This avoids showing crashed subframes if a hidden tab is +// eventually shown. See https://crbug.com/841572. +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, + ReloadHiddenTabWithCrashedSubframeInViewport) { + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + + // Hide the WebContents (UpdateWebContentsVisibility is called twice to avoid + // hitting the |!did_first_set_visible_| case). + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + EXPECT_EQ(Visibility::HIDDEN, web_contents()->GetVisibility()); + + // Kill the b.com subframe's process. This should mark the hidden + // WebContents for reload. + { + base::HistogramTester histograms; + CrashProcess(root->child_at(0)); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.TabMarkedForReload", true, 1); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.TabMarkedForReload.Visibility", + blink::mojom::FrameVisibility::kRenderedInViewport, 1); + } + + // Show the WebContents. This should trigger a reload of the main frame. + { + base::HistogramTester histograms; + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + EXPECT_TRUE(WaitForLoadStop(web_contents())); + histograms.ExpectUniqueSample( + "Navigation.LoadIfNecessaryType", + NavigationControllerImpl::NeedsReloadType::kCrashedSubframe, 1); + } + + // Both frames should now have live renderer processes. + EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); + EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); +} + +// Verify that when a tab is reloaded because it was previously marked for +// reload due to having a sad frame, we log the sad frame as shown during a tab +// reload, rather than being shown to the user directly, since the sad frame is +// expected to go away shortly. See https://crbug.com/1132938. +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, + CrashedSubframeVisibilityMetricsDuringTabReload) { + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b,c)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + + // Hide the WebContents (UpdateWebContentsVisibility is called twice to avoid + // hitting the |!did_first_set_visible_| case). + RenderWidgetHostVisibilityObserver hide_observer( + root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), + false /* became_visible */); + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + EXPECT_EQ(Visibility::HIDDEN, web_contents()->GetVisibility()); + hide_observer.WaitUntilSatisfied(); + + // Kill the b.com subframe's process. This should mark the hidden + // WebContents for reload. + CrashProcess(root->child_at(0)); + auto& controller = static_cast<NavigationControllerImpl&>( + shell()->web_contents()->GetController()); + EXPECT_TRUE(controller.NeedsReload()); + EXPECT_EQ(1, controller.GetEntryCount()); + + // Show the WebContents. This should trigger a reload of the main frame. Sad + // frame visibility metrics should indicate that the sad frame is shown while + // the tab is being reloaded. Because the tab reload will wipe out the sad + // frame, this isn't as bad as kShownAfterCrashing. + { + base::HistogramTester histograms; + SadFrameShownObserver sad_frame_observer(root->child_at(0)); + TestNavigationManager manager(web_contents(), main_url); + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + EXPECT_TRUE(manager.WaitForRequestStart()); + sad_frame_observer.Wait(); + + histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", + CrashVisibility::kShownWhileAncestorIsLoading, + 1); + + // Ensure no new metrics are logged after the reload completes. + manager.WaitForNavigationFinished(); + EXPECT_TRUE(manager.was_successful()); + EXPECT_FALSE(controller.NeedsReload()); + EXPECT_EQ(1, controller.GetEntryCount()); + histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", + CrashVisibility::kShownWhileAncestorIsLoading, + 1); + } +} + +// Verify that a sad frame shown when its parent frame is loading is logged +// with appropriate metrics, namely as kShownWhileAncestorIsLoading rather than +// kShownAfterCrashing. See https://crbug.com/1132938. +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, + CrashedSubframeVisibilityMetricsDuringParentLoad) { + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b(c))")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + FrameTreeNode* child = root->child_at(0); + FrameTreeNode* grandchild = child->child_at(0); + + // Hide the grandchild frame. + RenderWidgetHostVisibilityObserver hide_observer( + grandchild->current_frame_host()->GetRenderWidgetHost(), + false /* became_visible */); + EXPECT_TRUE( + ExecJs(child, "document.querySelector('iframe').style.display = 'none'")); + hide_observer.WaitUntilSatisfied(); + + // Kill the c.com grandchild process. + CrashProcess(grandchild); + + // Start a navigation in the b.com frame, but don't commit. + GURL url_d(embedded_test_server()->GetURL("d.com", "/title1.html")); + TestNavigationManager manager(web_contents(), url_d); + EXPECT_TRUE(ExecJs(child, JsReplace("location.href = $1", url_d))); + EXPECT_TRUE(manager.WaitForRequestStart()); + + // Make the grandchild iframe with the sad frame visible again. This should + // get logged as kShownWhileAncestorIsLoading, because its parent is + // currently loading. + { + base::HistogramTester histograms; + SadFrameShownObserver sad_frame_observer(grandchild); + EXPECT_TRUE(ExecJs( + child, "document.querySelector('iframe').style.display = 'block'")); + sad_frame_observer.Wait(); + + histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", + CrashVisibility::kShownWhileAncestorIsLoading, + 1); + + // Ensure no new metrics are logged after the navigation completes. + manager.WaitForNavigationFinished(); + EXPECT_TRUE(manager.was_successful()); + histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility", + CrashVisibility::kShownWhileAncestorIsLoading, + 1); + } +} + +// Verify the feature where hidden tabs with crashed subframes are marked for +// reload. This avoids showing crashed subframes if a hidden tab is eventually +// shown. Similar to the test above, except that the crashed subframe is +// scrolled out of view. +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, + ReloadHiddenTabWithCrashedSubframeOutOfView) { + // Set WebContents to VISIBLE to avoid hitting the |!did_first_set_visible_| + // case when we hide it later. + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + + // Navigate to a page with an OOPIF that's scrolled out of view. + GURL out_of_view_url( + embedded_test_server()->GetURL("a.com", "/iframe_out_of_view.html")); + EXPECT_TRUE(NavigateToURL(shell(), out_of_view_url)); + EXPECT_EQ("LOADED", EvalJs(shell(), "notifyWhenLoaded();", + EXECUTE_SCRIPT_USE_MANUAL_REPLY)); + NavigateIframeToURL(web_contents(), "test_iframe", + embedded_test_server()->GetURL("b.com", "/title1.html")); + + // This will ensure that the layout has completed and visibility of the OOPIF + // has been updated in the browser process. + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + EXPECT_EQ(true, + EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true")); + + // Verify the OOPIF isn't visible at the moment. + RenderFrameProxyHost* proxy_to_parent = + root->child_at(0)->render_manager()->GetProxyToParent(); + CrossProcessFrameConnector* connector = + proxy_to_parent->cross_process_frame_connector(); + EXPECT_FALSE(connector->IsVisible()); + EXPECT_EQ(blink::mojom::FrameVisibility::kRenderedOutOfViewport, + connector->visibility()); + + // Hide the WebContents and crash the OOPIF. + { + base::HistogramTester histograms; + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + CrashProcess(root->child_at(0)); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.TabMarkedForReload", true, 1); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.TabMarkedForReload.Visibility", + blink::mojom::FrameVisibility::kRenderedOutOfViewport, 1); + } + + EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); + EXPECT_FALSE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); + + // Show the tab and ensure that it reloads. + { + base::HistogramTester histograms; + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + EXPECT_TRUE(WaitForLoadStop(web_contents())); + histograms.ExpectUniqueSample( + "Navigation.LoadIfNecessaryType", + NavigationControllerImpl::NeedsReloadType::kCrashedSubframe, 1); + } + + EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); + EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); +} + +// Verify that hidden tabs with a crashed subframe are not marked for reload +// when the crashed subframe is hidden with "display:none". +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, + DoNotReloadHiddenTabWithHiddenCrashedSubframe) { + // Set WebContents to VISIBLE to avoid hitting the |!did_first_set_visible_| + // case when we hide it later. + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + + GURL hidden_iframe_url( + embedded_test_server()->GetURL("a.com", "/page_with_hidden_iframe.html")); + EXPECT_TRUE(NavigateToURL(shell(), hidden_iframe_url)); + NavigateIframeToURL(web_contents(), "test_iframe", + embedded_test_server()->GetURL("b.com", "/title1.html")); + + // Ensure that the parent frame has propagated the OOPIF's hidden visibility + // to the browser process by forcing requestAnimationFrame and + // waiting for layout to finish. + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + EXPECT_EQ(true, + EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true")); + + // The OOPIF should be hidden at this point. + RenderFrameProxyHost* proxy_to_parent = + root->child_at(0)->render_manager()->GetProxyToParent(); + EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector()->IsHidden()); + + // Crashing a hidden OOPIF shouldn't mark the tab for reload. + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + base::HistogramTester histograms; + CrashProcess(root->child_at(0)); + histograms.ExpectUniqueSample("Stability.ChildFrameCrash.TabMarkedForReload", + false, 1); + + // Making the WebContents visible again should keep the sad frame and should + // not load anything new. + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + EXPECT_TRUE(WaitForLoadStop(web_contents())); + EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); + EXPECT_FALSE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); +} + +// Ensure that the sad frame reload policy doesn't trigger for a visible tab, +// even if it becomes hidden and then visible again. +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithSadFrameTabReload, + DoNotReloadVisibleTabWithCrashedSubframe) { + // Set WebContents to VISIBLE to avoid hitting the |!did_first_set_visible_| + // case when we hide it later. + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + EXPECT_EQ(Visibility::VISIBLE, web_contents()->GetVisibility()); + + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + base::HistogramTester histograms; + CrashProcess(root->child_at(0)); + histograms.ExpectUniqueSample("Stability.ChildFrameCrash.TabMarkedForReload", + false, 1); + + EXPECT_EQ(Visibility::VISIBLE, web_contents()->GetVisibility()); + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + EXPECT_TRUE(WaitForLoadStop(web_contents())); + EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); + EXPECT_FALSE(root->child_at(0)->current_frame_host()->IsRenderFrameLive()); + histograms.ExpectUniqueSample("Stability.ChildFrameCrash.TabMarkedForReload", + false, 1); +} + +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, + ChildFrameCrashMetrics_KilledWhileVisible) { + // Set-up a frame tree that helps verify what the metrics tracks: + // 1) frames (12 frames are affected if B process gets killed) or + // 2) crashes (simply 1 crash if B process gets killed)? + // 3) widgets (10 b widgets and 1 c widget are affected if B is killed, + // but a sad frame will appear only in 9 widgets - this excludes + // widgets for the b,c(b) part of the frame tree) or + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b(b,c(b)),b,b,b,b,b,b,b,b)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + + std::vector<std::unique_ptr<SadFrameShownObserver>> observers; + for (size_t i = 0U; i < root->child_count(); i++) { + // At this point, all b.com subframes should be considered visible. + RenderFrameProxyHost* proxy_to_parent = + root->child_at(i)->render_manager()->GetProxyToParent(); + CrossProcessFrameConnector* connector = + proxy_to_parent->cross_process_frame_connector(); + EXPECT_TRUE(connector->IsVisible()) + << " subframe " << i << " with URL " << root->child_at(i)->current_url() + << " is hidden"; + observers.push_back( + std::make_unique<SadFrameShownObserver>(root->child_at(i))); + } + + // Kill the child frame and wait for each of the subframe FrameTreeNodes to + // show a sad frame. + base::HistogramTester histograms; + RenderProcessHost* child_process = + root->child_at(0)->current_frame_host()->GetProcess(); + RenderProcessHostWatcher crash_observer( + child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + child_process->Shutdown(0); + crash_observer.Wait(); + for (size_t i = 0U; i < root->child_count(); i++) { + SCOPED_TRACE(testing::Message() + << " Waiting for sad frame from subframe " << i + << " with URL:" << root->child_at(i)->current_url()); + observers[i]->Wait(); + } + + // Verify that the expected metrics got logged. + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.Visibility", + CrossProcessFrameConnector::CrashVisibility::kCrashedWhileVisible, 9); + + // Hide and show the web contents and verify that no more metrics got logged. + web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN); + web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE); + histograms.ExpectUniqueSample( + "Stability.ChildFrameCrash.Visibility", + CrossProcessFrameConnector::CrashVisibility::kCrashedWhileVisible, 9); +} + +INSTANTIATE_TEST_SUITE_P(All, + SitePerProcessBrowserTestWithoutSadFrameTabReload, + testing::ValuesIn(RenderDocumentFeatureLevelValues())); +INSTANTIATE_TEST_SUITE_P(All, + SitePerProcessBrowserTestWithSadFrameTabReload, + testing::ValuesIn(RenderDocumentFeatureLevelValues())); + +} // namespace content
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 04cdd66e..d0c260f 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -279,6 +279,8 @@ {wf::EnableSameSiteByDefaultCookies, net::features::kSameSiteByDefaultCookies}, {wf::EnableScrollUnification, features::kScrollUnification}, + {wf::EnableSecurePaymentConfirmationAPIV2, + features::kSecurePaymentConfirmationAPIV2}, {wf::EnableSecurePaymentConfirmationDebug, features::kSecurePaymentConfirmationDebug}, {wf::EnableSendBeaconThrowForBlobWithNonSimpleType, @@ -297,6 +299,8 @@ {wf::EnableTimerThrottlingForHiddenFrames, features::kTimerThrottlingForHiddenFrames}, {wf::EnableTransformInterop, blink::features::kTransformInterop}, + {wf::EnableBackfaceVisibilityInterop, + blink::features::kBackfaceVisibilityInterop}, {wf::EnableUserActivationSameOriginVisibility, features::kUserActivationSameOriginVisibility}, {wf::EnableVideoPlaybackQuality, features::kVideoPlaybackQuality},
diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc index 17d256b..8c71a57 100644 --- a/content/public/app/content_main_delegate.cc +++ b/content/public/app/content_main_delegate.cc
@@ -46,6 +46,11 @@ return true; } +variations::VariationsIdsProvider* +ContentMainDelegate::CreateVariationsIdsProvider() { + return nullptr; +} + ContentClient* ContentMainDelegate::CreateContentClient() { return new ContentClient(); }
diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h index dd16f2c..5e45724e 100644 --- a/content/public/app/content_main_delegate.h +++ b/content/public/app/content_main_delegate.h
@@ -12,6 +12,10 @@ #include "build/build_config.h" #include "content/common/content_export.h" +namespace variations { +class VariationsIdsProvider; +} + namespace content { class ContentBrowserClient; @@ -76,6 +80,11 @@ // created should override and return false. virtual bool ShouldCreateFeatureList(); + // Creates and returns the VariationsIdsProvider. If null is returned, + // a VariationsIdsProvider is created with a mode of `kUseSignedInState`. + // VariationsIdsProvider is a singleton. + virtual variations::VariationsIdsProvider* CreateVariationsIdsProvider(); + // Allows the embedder to perform initialization once field trials/FeatureList // initialization has completed if ShouldCreateFeatureList() returns true. // Otherwise, the embedder is responsible for calling this method once feature
diff --git a/content/public/browser/service_process_host.h b/content/public/browser/service_process_host.h index 5663b56..feec91a8 100644 --- a/content/public/browser/service_process_host.h +++ b/content/public/browser/service_process_host.h
@@ -13,7 +13,7 @@ #include "base/callback.h" #include "base/command_line.h" #include "base/macros.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "base/process/process_handle.h" #include "base/strings/string_piece.h" #include "content/common/content_export.h"
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 14042cf..1a93a109 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -627,6 +627,11 @@ #endif }; +// Used to enable API changes for Secure Payment Confirmation. +// TODO(crbug.com/1216464): Enable by default in M93. +const base::Feature kSecurePaymentConfirmationAPIV2{ + "SecurePaymentConfirmationAPIV2", base::FEATURE_DISABLED_BY_DEFAULT}; + // Used to control whether to remove the restriction that PaymentCredential in // WebAuthn and secure payment confirmation method in PaymentRequest API must // use a user verifying platform authenticator. When enabled, this allows using
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 62f90078..a9564a5e 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -147,6 +147,7 @@ kRunVideoCaptureServiceInBrowserProcess; CONTENT_EXPORT extern const base::Feature kSavePageAsWebBundle; CONTENT_EXPORT extern const base::Feature kSecurePaymentConfirmation; +CONTENT_EXPORT extern const base::Feature kSecurePaymentConfirmationAPIV2; CONTENT_EXPORT extern const base::Feature kSecurePaymentConfirmationDebug; CONTENT_EXPORT extern const base::Feature kSendBeaconThrowForBlobWithNonSimpleType;
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h index ff1e675..03fcde1 100644 --- a/content/public/common/url_constants.h +++ b/content/public/common/url_constants.h
@@ -5,13 +5,11 @@ #ifndef CONTENT_PUBLIC_COMMON_URL_CONSTANTS_H_ #define CONTENT_PUBLIC_COMMON_URL_CONSTANTS_H_ -#include "base/check_op.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "content/common/content_export.h" #include "url/url_constants.h" -#include "build/chromeos_buildflags.h" - // Contains constants for known URLs and portions thereof. namespace content {
diff --git a/content/public/renderer/render_view.h b/content/public/renderer/render_view.h index f88ac5e..a7c771a 100644 --- a/content/public/renderer/render_view.h +++ b/content/public/renderer/render_view.h
@@ -39,9 +39,6 @@ // Returns the RenderView containing the given WebView. static RenderView* FromWebView(blink::WebView* webview); - // Returns the number of live RenderView instances in this process. - static size_t GetRenderViewCount(); - // Visit all RenderViews with a live WebView (i.e., RenderViews that have // been closed but not yet destroyed are excluded). static void ForEach(RenderViewVisitor* visitor);
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index 83f5ed9c..29a8c717 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -41,6 +41,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "components/tracing/common/tracing_switches.h" +#include "components/variations/variations_ids_provider.h" #include "content/browser/browser_main_loop.h" #include "content/browser/browser_thread_impl.h" #include "content/browser/network_service_instance_impl.h" @@ -607,6 +608,13 @@ delegate->PreBrowserMain(); BrowserTaskExecutor::Create(); + + auto* provider = delegate->CreateVariationsIdsProvider(); + if (!provider) { + variations::VariationsIdsProvider::Create( + variations::VariationsIdsProvider::Mode::kUseSignedInState); + } + delegate->PostEarlyInitialization(/*is_running_tests=*/true); StartBrowserThreadPool();
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc index d078124c..d9d390d 100644 --- a/content/public/test/test_renderer_host.cc +++ b/content/public/test/test_renderer_host.cc
@@ -180,20 +180,34 @@ } RenderViewHost* RenderViewHostTestHarness::rvh() { - return web_contents()->GetMainFrame()->GetRenderViewHost(); + RenderViewHost* result = web_contents()->GetMainFrame()->GetRenderViewHost(); + CHECK_EQ(result, web_contents()->GetMainFrame()->GetRenderViewHost()); + return result; +} + +RenderViewHost* RenderViewHostTestHarness::pending_rvh() { + return pending_main_rfh() ? pending_main_rfh()->GetRenderViewHost() : nullptr; +} + +RenderViewHost* RenderViewHostTestHarness::active_rvh() { + return pending_rvh() ? pending_rvh() : rvh(); } RenderFrameHost* RenderViewHostTestHarness::main_rfh() { return web_contents()->GetMainFrame(); } +RenderFrameHost* RenderViewHostTestHarness::pending_main_rfh() { + return static_cast<TestWebContents*>(web_contents()) + ->GetSpeculativePrimaryMainFrame(); +} + BrowserContext* RenderViewHostTestHarness::browser_context() { return GetBrowserContext(); } MockRenderProcessHost* RenderViewHostTestHarness::process() { - auto* contents = static_cast<TestWebContents*>(web_contents()); - return contents->GetMainFrame()->GetProcess(); + return static_cast<MockRenderProcessHost*>(active_rvh()->GetProcess()); } void RenderViewHostTestHarness::DeleteContents() {
diff --git a/content/public/test/test_renderer_host.h b/content/public/test/test_renderer_host.h index abc7a007..287944c 100644 --- a/content/public/test/test_renderer_host.h +++ b/content/public/test/test_renderer_host.h
@@ -219,12 +219,21 @@ // web_contents()->GetRenderViewHost() RenderViewHost* rvh(); + // pending_rvh() is equivalent to: + // WebContentsTester::For(web_contents())->GetPendingRenderViewHost() + RenderViewHost* pending_rvh(); + + // active_rvh() is equivalent to pending_rvh() ? pending_rvh() : rvh() + RenderViewHost* active_rvh(); + // main_rfh() is equivalent to web_contents()->GetMainFrame() RenderFrameHost* main_rfh(); - BrowserContext* browser_context(); + // pending_main_rfh() is equivalent to: + // WebContentsTester::For(web_contents())->GetPendingMainFrame() + RenderFrameHost* pending_main_rfh(); - // Returns |main_rfh()|'s process. + BrowserContext* browser_context(); MockRenderProcessHost* process(); // Frees the current WebContents for tests that want to test destruction.
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 031f0522..d2a0ef4 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -4670,7 +4670,7 @@ RenderThreadImpl* render_thread_impl = RenderThreadImpl::current(); if (render_thread_impl) { // Can be NULL in tests. render_thread_impl->histogram_customizer()->RenderViewNavigatedToHost( - GetLoadingUrl().host(), RenderView::GetRenderViewCount()); + GetLoadingUrl().host(), blink::WebView::GetWebViewCount()); } }
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 32dd9d0..3a5834f 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -1395,11 +1395,11 @@ // Cache this result, as it can change while this code is running, and is used // as a divisor below. - size_t render_view_count = RenderView::GetRenderViewCount(); + size_t web_view_count = blink::WebView::GetWebViewCount(); - // If there are no render views it doesn't make sense to calculate metrics + // If there are no web views it doesn't make sense to calculate metrics // right now. - if (render_view_count == 0) + if (web_view_count == 0) return false; blink::WebMemoryStatistics blink_stats = blink::WebMemoryStatistics::Get(); @@ -1432,7 +1432,7 @@ memory_metrics->non_discardable_total_allocated_mb = (total_allocated - discardable_usage) / 1024 / 1024; memory_metrics->total_allocated_per_render_view_mb = - total_allocated / render_view_count / 1024 / 1024; + total_allocated / web_view_count / 1024 / 1024; return true; }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 9f02342..a229509d 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -194,11 +194,6 @@ return it == views->end() ? NULL : it->second; } -/* static */ -size_t RenderView::GetRenderViewCount() { - return g_view_map.Get().size(); -} - /*static*/ void RenderView::ForEach(RenderViewVisitor* visitor) { DCHECK(RenderThread::IsMainThread());
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 0c3a81a..954c172 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -341,6 +341,8 @@ "portal/portal_interceptor_for_testing.h", "render_document_feature.cc", "render_document_feature.h", + "render_widget_host_visibility_observer.cc", + "render_widget_host_visibility_observer.h", "storage_partition_test_helpers.cc", "storage_partition_test_helpers.h", "stub_render_view_host_delegate_view.h", @@ -423,6 +425,7 @@ "//build:chromeos_buildflags", "//cc:test_support", "//components/services/storage", + "//components/variations", "//components/viz/client", "//components/viz/host", "//content/app:for_content_tests", @@ -1220,6 +1223,7 @@ "../browser/site_per_process_browsertest.cc", "../browser/site_per_process_browsertest.h", "../browser/site_per_process_hit_test_browsertest.cc", + "../browser/site_per_process_sad_frame_browsertest.cc", "../browser/site_per_process_unload_browsertest.cc", "../browser/sms/sms_browsertest.cc", "../browser/snapshot_browsertest.cc",
diff --git a/content/test/data/accessibility/accname/name-text-labelledby-hidden-with-hidden-child-expected-blink.txt b/content/test/data/accessibility/accname/name-text-labelledby-hidden-with-hidden-child-expected-blink.txt new file mode 100644 index 0000000..0b6d4da --- /dev/null +++ b/content/test/data/accessibility/accname/name-text-labelledby-hidden-with-hidden-child-expected-blink.txt
@@ -0,0 +1,5 @@ +# If we interpret the spec literally the expectation should be "baz", but that +# does not match what Chrome and Firefox do and it is under discussion. See: +# https://github.com/w3c/accname/issues/57 +# TODO: set correct expectation after the issue is closed. +textField name='foobarbaz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-labelledby-hidden-with-hidden-child.html b/content/test/data/accessibility/accname/name-text-labelledby-hidden-with-hidden-child.html new file mode 100644 index 0000000..c3fb107 --- /dev/null +++ b/content/test/data/accessibility/accname/name-text-labelledby-hidden-with-hidden-child.html
@@ -0,0 +1,10 @@ +<!-- +@BLINK-DENY:description +--> +<!DOCTYPE html> +<html> +<body> + <input id="test" aria-labelledby="t1"> + <div id="t1" style="visibility:hidden"><span style="visibility:hidden">foo</span><span>bar</span>baz</div> +</body> +</html>
diff --git a/content/test/render_widget_host_visibility_observer.cc b/content/test/render_widget_host_visibility_observer.cc new file mode 100644 index 0000000..ed732bb --- /dev/null +++ b/content/test/render_widget_host_visibility_observer.cc
@@ -0,0 +1,43 @@ +// Copyright 2021 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 "content/test/render_widget_host_visibility_observer.h" + +namespace content { + +RenderWidgetHostVisibilityObserver::RenderWidgetHostVisibilityObserver( + RenderWidgetHostImpl* rwhi, + bool expected_visibility_state) + : expected_visibility_state_(expected_visibility_state), + was_observed_(false), + did_fail_(false), + render_widget_(rwhi) { + observation_.Observe(render_widget_); +} + +RenderWidgetHostVisibilityObserver::~RenderWidgetHostVisibilityObserver() = + default; + +bool RenderWidgetHostVisibilityObserver::WaitUntilSatisfied() { + if (!was_observed_) + run_loop_.Run(); + observation_.Reset(); + return !did_fail_; +} + +void RenderWidgetHostVisibilityObserver::RenderWidgetHostVisibilityChanged( + RenderWidgetHost* widget_host, + bool became_visible) { + was_observed_ = true; + did_fail_ = expected_visibility_state_ != became_visible; + run_loop_.Quit(); +} + +void RenderWidgetHostVisibilityObserver::RenderWidgetHostDestroyed( + RenderWidgetHost* widget_host) { + DCHECK(observation_.IsObservingSource(widget_host)); + observation_.Reset(); +} + +} // namespace content
diff --git a/content/test/render_widget_host_visibility_observer.h b/content/test/render_widget_host_visibility_observer.h new file mode 100644 index 0000000..f7223ea --- /dev/null +++ b/content/test/render_widget_host_visibility_observer.h
@@ -0,0 +1,49 @@ +// Copyright 2021 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 CONTENT_TEST_RENDER_WIDGET_HOST_VISIBILITY_OBSERVER_H_ +#define CONTENT_TEST_RENDER_WIDGET_HOST_VISIBILITY_OBSERVER_H_ + +#include "content/public/browser/render_widget_host_observer.h" + +#include "base/scoped_observation.h" +#include "content/browser/renderer_host/cross_process_frame_connector.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/public/test/test_utils.h" + +namespace content { + +using CrashVisibility = CrossProcessFrameConnector::CrashVisibility; + +class RenderWidgetHostVisibilityObserver : public RenderWidgetHostObserver { + public: + explicit RenderWidgetHostVisibilityObserver(RenderWidgetHostImpl* rwhi, + bool expected_visibility_state); + ~RenderWidgetHostVisibilityObserver() override; + + RenderWidgetHostVisibilityObserver( + const RenderWidgetHostVisibilityObserver&) = delete; + RenderWidgetHostVisibilityObserver& operator=( + const RenderWidgetHostVisibilityObserver&) = delete; + + bool WaitUntilSatisfied(); + + private: + // RenderWidgetHostObserver implementation. + void RenderWidgetHostVisibilityChanged(RenderWidgetHost* widget_host, + bool became_visible) override; + void RenderWidgetHostDestroyed(RenderWidgetHost* widget_host) override; + + bool expected_visibility_state_; + base::RunLoop run_loop_; + base::ScopedObservation<RenderWidgetHost, RenderWidgetHostObserver> + observation_{this}; + bool was_observed_; + bool did_fail_; + RenderWidgetHost* render_widget_; +}; + +} // namespace content + +#endif // CONTENT_TEST_RENDER_WIDGET_HOST_VISIBILITY_OBSERVER_H_
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc index 917f286..88bd15d 100644 --- a/content/test/test_render_view_host.cc +++ b/content/test/test_render_view_host.cc
@@ -376,6 +376,16 @@ return contents()->GetRenderViewHost(); } +TestRenderViewHost* RenderViewHostImplTestHarness::pending_test_rvh() { + return contents()->GetSpeculativePrimaryMainFrame() + ? contents()->GetSpeculativePrimaryMainFrame()->GetRenderViewHost() + : nullptr; +} + +TestRenderViewHost* RenderViewHostImplTestHarness::active_test_rvh() { + return static_cast<TestRenderViewHost*>(active_rvh()); +} + TestRenderFrameHost* RenderViewHostImplTestHarness::main_test_rfh() { return contents()->GetMainFrame(); }
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h index fb8cc12..5482020 100644 --- a/content/test/test_render_view_host.h +++ b/content/test/test_render_view_host.h
@@ -278,6 +278,21 @@ // prefer to use the GetMainFrame() method in tests. TestRenderViewHost* test_rvh(); + // pending_test_rvh() is equivalent to all of the following: + // contents()->GetPendingMainFrame()->GetRenderViewHost() [if frame exists] + // contents()->GetPendingRenderViewHost() + // static_cast<TestRenderViewHost*>(pending_rvh()) + // + // Since most functionality will eventually shift from RVH to RFH, you may + // prefer to use the GetPendingMainFrame() method in tests. + TestRenderViewHost* pending_test_rvh(); + + // active_test_rvh() is equivalent to: + // contents()->GetPendingRenderViewHost() ? + // contents()->GetPendingRenderViewHost() : + // contents()->GetRenderViewHost(); + TestRenderViewHost* active_test_rvh(); + // main_test_rfh() is equivalent to contents()->GetMainFrame() // TODO(nick): Replace all uses with contents()->GetMainFrame() TestRenderFrameHost* main_test_rfh();
diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h index f58f846a..0ce7b71 100644 --- a/device/bluetooth/bluetooth_adapter_mac.h +++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -17,7 +17,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/single_thread_task_runner.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_discovery_manager_mac.h"
diff --git a/device/bluetooth/bluetooth_classic_device_mac.h b/device/bluetooth/bluetooth_classic_device_mac.h index bf0a8852..88e45b2 100644 --- a/device/bluetooth/bluetooth_classic_device_mac.h +++ b/device/bluetooth/bluetooth_classic_device_mac.h
@@ -12,7 +12,6 @@ #include "base/mac/scoped_nsobject.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/time/time.h" #include "device/bluetooth/bluetooth_device_mac.h" #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/device/bluetooth/bluetooth_device_win.h b/device/bluetooth/bluetooth_device_win.h index 6690cdd..96bd8e9 100644 --- a/device/bluetooth/bluetooth_device_win.h +++ b/device/bluetooth/bluetooth_device_win.h
@@ -14,7 +14,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "base/sequenced_task_runner.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_export.h"
diff --git a/device/bluetooth/dbus/bluetooth_agent_manager_client.h b/device/bluetooth/dbus/bluetooth_agent_manager_client.h index f5f67b9..3684c24 100644 --- a/device/bluetooth/dbus/bluetooth_agent_manager_client.h +++ b/device/bluetooth/dbus/bluetooth_agent_manager_client.h
@@ -10,7 +10,7 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "dbus/object_path.h" #include "device/bluetooth/bluetooth_export.h" #include "device/bluetooth/dbus/bluez_dbus_client.h"
diff --git a/device/bluetooth/dbus/bluetooth_battery_client.cc b/device/bluetooth/dbus/bluetooth_battery_client.cc index 54e4bff..a84868c 100644 --- a/device/bluetooth/dbus/bluetooth_battery_client.cc +++ b/device/bluetooth/dbus/bluetooth_battery_client.cc
@@ -3,10 +3,12 @@ // found in the LICENSE file. #include "device/bluetooth/dbus/bluetooth_battery_client.h" + #include "base/bind.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/observer_list.h" #include "dbus/bus.h" #include "dbus/message.h" #include "dbus/object_manager.h"
diff --git a/device/bluetooth/dbus/bluetooth_battery_client.h b/device/bluetooth/dbus/bluetooth_battery_client.h index 794353a4..472ceac8 100644 --- a/device/bluetooth/dbus/bluetooth_battery_client.h +++ b/device/bluetooth/dbus/bluetooth_battery_client.h
@@ -12,7 +12,6 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/observer_list.h" #include "dbus/object_path.h" #include "dbus/property.h" #include "device/bluetooth/bluetooth_export.h"
diff --git a/device/bluetooth/dbus/bluetooth_device_client.cc b/device/bluetooth/dbus/bluetooth_device_client.cc index 1dab0bd..6600f7f 100644 --- a/device/bluetooth/dbus/bluetooth_device_client.cc +++ b/device/bluetooth/dbus/bluetooth_device_client.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/observer_list.h" #include "dbus/bus.h" #include "dbus/message.h" #include "dbus/object_manager.h"
diff --git a/device/bluetooth/dbus/bluetooth_device_client.h b/device/bluetooth/dbus/bluetooth_device_client.h index 8ee4cad..a7a28e6 100644 --- a/device/bluetooth/dbus/bluetooth_device_client.h +++ b/device/bluetooth/dbus/bluetooth_device_client.h
@@ -13,7 +13,6 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/observer_list.h" #include "dbus/object_path.h" #include "dbus/property.h" #include "device/bluetooth/bluetooth_export.h"
diff --git a/device/bluetooth/dbus/bluetooth_input_client.cc b/device/bluetooth/dbus/bluetooth_input_client.cc index 1ac48939..af417df6 100644 --- a/device/bluetooth/dbus/bluetooth_input_client.cc +++ b/device/bluetooth/dbus/bluetooth_input_client.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/check.h" #include "base/macros.h" +#include "base/observer_list.h" #include "dbus/bus.h" #include "dbus/message.h" #include "dbus/object_manager.h"
diff --git a/device/bluetooth/dbus/bluetooth_input_client.h b/device/bluetooth/dbus/bluetooth_input_client.h index 829e94ca..91ca166 100644 --- a/device/bluetooth/dbus/bluetooth_input_client.h +++ b/device/bluetooth/dbus/bluetooth_input_client.h
@@ -10,7 +10,6 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/observer_list.h" #include "dbus/object_path.h" #include "dbus/property.h" #include "device/bluetooth/bluetooth_export.h"
diff --git a/device/bluetooth/dbus/fake_bluetooth_agent_service_provider.h b/device/bluetooth/dbus/fake_bluetooth_agent_service_provider.h index 654e30a6..3d97ddb 100644 --- a/device/bluetooth/dbus/fake_bluetooth_agent_service_provider.h +++ b/device/bluetooth/dbus/fake_bluetooth_agent_service_provider.h
@@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/callback.h" -#include "base/observer_list.h" #include "dbus/object_path.h" #include "dbus/property.h" #include "device/bluetooth/bluetooth_export.h"
diff --git a/device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.h b/device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.h index e3a00c3..633b87c 100644 --- a/device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.h +++ b/device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.h
@@ -11,7 +11,6 @@ #include "base/bind.h" #include "base/callback.h" #include "base/macros.h" -#include "base/observer_list.h" #include "dbus/object_path.h" #include "dbus/property.h" #include "device/bluetooth/bluetooth_export.h"
diff --git a/device/bluetooth/dbus/fake_bluetooth_profile_manager_client.h b/device/bluetooth/dbus/fake_bluetooth_profile_manager_client.h index 18181e6..37bdc6f9 100644 --- a/device/bluetooth/dbus/fake_bluetooth_profile_manager_client.h +++ b/device/bluetooth/dbus/fake_bluetooth_profile_manager_client.h
@@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/callback.h" -#include "base/observer_list.h" #include "dbus/object_path.h" #include "dbus/property.h" #include "device/bluetooth/bluetooth_export.h"
diff --git a/docs/media/capture/README.md b/docs/media/capture/README.md new file mode 100644 index 0000000..29932a1 --- /dev/null +++ b/docs/media/capture/README.md
@@ -0,0 +1,186 @@ +# Media Capture + +In Chrome, "Media capture" refers to the features and user interfaces that +enable the browser to capture pixels and audio from itself or the underlying OS. +It also covers the Web APIs that allow Web applications to obtain captured +media. + +This is an index of media capture related documentation elsewhere, organized by +component/feature. This list is incomplete; additional documentation can be +found in code comments and/or Monorail issue threads in the components listed +below. + +# Features + +## Webcam capture + +* Code + * `//media/capture/video` + * `//services/video_capture` +* Issues + * `Internals>Media>CameraCapture` +* Docs + * [//services/video_capture/README.md](../../../services/video_capture/README.md) + + +## Microphone capture + +* Code + * `//media/audio` + * `//services/audio` +* Issues + * `Internals>Media>AudioCapture` +* Docs + * [//services/audio/README.md](../../../services/audio/README.md) + + +## System (desktop/window) capture + +* Code + * Windows/Linux: `//third_party/webrtc/modules/desktop_capture` + * Mac: `//content/browser/media/capture/desktop_capture_device_mac.cc` + * LaCrOS: `//content/browser/media/capture/desktop/desktop_capturer_lacros.cc` +* Issues + * `Internals>Media>ScreenCapture` +* Docs + * To be added later. + + +## System audio capture + +* Code + * Windows: `//media/audio/win/audio_low_latency_input_win.cc` + * ChromeOS: `//media/audio/cras/cras_input.cc` +* Issues + * `Internals>Media>Audio` +* Docs + * To be added later. + + +## Tab audio capture + +* Code + * `//services/audio/loopback_stream.cc` +* Issues + * `Internals>Media>Audio` +* Docs + * To be added later. + + +## Viz compositor surface capture + +Viz supports capture of Chrome tabs and windows on all platforms, and capture +of the desktop on ChromeOS. + +Familiarity with [Viz](../../../components/viz/README.md), the Chrome compositor, +is a prerequisite to understanding how surface capture works. + +* Code + * `//content/browser/media/capture/web_contents_video_capture_device.cc` + * `//components/viz/service/frame_sinks/video_capture` + * `//components/viz/common/frame_sinks/copy_output_request.cc` +* Issues + * `Internals>Media>SurfaceCapture` +* Docs + * [//components/viz/common/frame_sinks/README.md](../../../components/viz/common/frame_sinks/README.md) + + +# User interfaces + +## Screen capture target chooser + +Allows the user to select a tab/window/desktop in response to a getDisplayMedia +request. + +* Code + * `//chrome/browser/media/webrtc` + * `//chrome/browser/ui/views/desktop_capture` +* Issues + * `UI>Browser>MediaCapture` +* Docs + * To be added later. + + +## Screen capture indicator + +Widget that tells the user when the desktop is being captured. + +* Code + * `//chrome/browser/ui/screen_capture_notification_ui.cc` + * `//chrome/browser/ui/views/screen_capture_notification_ui_views.cc` + * ChromeOS: `//chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc` +* Issues + * `UI>Browser>MediaCapture` +* Docs + * To be added later. + + +## Tab capture indicator/switcher + +Shows the user what tab is being captured and allows them to stop or switch tabs. + +* Code + * `//chrome/browser/media/webrtc/media_stream_capture_indicator.cc` + * `//chrome/browser/ui/tab_sharing` + * `//chrome/browser/ui/views/tab_sharing.cc` +* Issues + * `UI>Browser>MediaCapture` +* Docs + * To be added later. + + +## Capture device chooser + +Allows the user to switch the camera/microphone used for capture. + +* Code + * `//chrome/browser/ui/content_settings/content_settings_bubble_model.cc` +* Issues + * `UI>Browser>MediaCapture` +* Docs + * To be added later. + + +# APIs + +## getUserMedia() + +Web API for Web applications to capture camera and microphone input. + +* Code + * `//third_party/blink/renderer/modules/mediastream/` +* Issues + * `Blink>GetUserMedia` +* Docs + * To be added later. + + +## getDisplayMedia() + +Web API for Web applications to capture screen contents and system/tab audio. + +* Code + * `//third_party/blink/renderer/modules/mediastream/` +* Issues + * `Blink>GetDisplayMedia` +* Docs + * To be added later. + + +# Additional features + +Not all media capture features are listed above; here are some additional +capture capabilities in Chrome. For more information about these, contact +developers at the address below. + +* Tab casting to Chromecast +* Screen casting from the ChromeOS system tray +* Presentation API 1-UA mode +* MediaStream capture from HTML elements (`<video>`, `<canvas>`) +* Extension APIs for capture + + +# Contact information + +Questions about media capture features, APIs, or user interfaces can be sent to +[media-capture-dev@chromium.org](mailto:media-capture-dev@chromium.org).
diff --git a/docs/speed/metrics_changelog/2021_05_fid.md b/docs/speed/metrics_changelog/2021_05_fid.md index 778c0de..95aad550 100644 --- a/docs/speed/metrics_changelog/2021_05_fid.md +++ b/docs/speed/metrics_changelog/2021_05_fid.md
@@ -16,4 +16,4 @@ ## When were users affected? -Chrome 91 is currently scheduled to be released the week of July 20, 2021. +Chrome 91 is currently scheduled to be released the week of May 25, 2021.
diff --git a/docs/speed_metrics/README.md b/docs/speed_metrics/README.md index c926ff6..e51f2635 100644 --- a/docs/speed_metrics/README.md +++ b/docs/speed_metrics/README.md
@@ -94,6 +94,7 @@ * [Properties of a good metric](../speed/good_toplevel_metrics.md) * [Survey of current metrics](https://docs.google.com/document/d/1Ww487ZskJ-xBmJGwPO-XPz_QcJvw-kSNffm0nPhVpj8/edit) + * [Debugging CLS](http://bit.ly/debug-cls) ## Talks * [Lessons learned from performance monitoring in @@ -103,4 +104,4 @@ by Nicolás Peña Moreno. * [Understanding Cumulative Layout Shift](https://www.youtube.com/watch?v=zIJuY-JCjqw), by Annie Sullivan and - Steve Kobes. \ No newline at end of file + Steve Kobes.
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h index 15c56f1..89b42fa 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -54,9 +54,9 @@ InProgressRequest( WebRequestProxyingURLLoaderFactory* factory, uint64_t request_id, + int32_t network_service_request_id, int32_t view_routing_id, int32_t frame_routing_id, - int32_t network_service_request_id, uint32_t options, ukm::SourceIdObj ukm_source_id, const network::ResourceRequest& request,
diff --git a/google_apis/gaia/fake_oauth2_access_token_manager.cc b/google_apis/gaia/fake_oauth2_access_token_manager.cc index 3f3547f60..b7b5e85 100644 --- a/google_apis/gaia/fake_oauth2_access_token_manager.cc +++ b/google_apis/gaia/fake_oauth2_access_token_manager.cc
@@ -178,6 +178,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& client_id, const std::string& client_secret, + const std::string& consumer_name, const FakeOAuth2AccessTokenManager::ScopeSet& scopes) { PendingRequest pending_request; pending_request.account_id = account_id;
diff --git a/google_apis/gaia/fake_oauth2_access_token_manager.h b/google_apis/gaia/fake_oauth2_access_token_manager.h index 7feeafe..5820986 100644 --- a/google_apis/gaia/fake_oauth2_access_token_manager.h +++ b/google_apis/gaia/fake_oauth2_access_token_manager.h
@@ -87,6 +87,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& client_id, const std::string& client_secret, + const std::string& consumer_name, const OAuth2AccessTokenManager::ScopeSet& scopes) override; void InvalidateAccessTokenImpl(
diff --git a/google_apis/gaia/oauth2_access_token_consumer.h b/google_apis/gaia/oauth2_access_token_consumer.h index da788f1..9bffd7fe 100644 --- a/google_apis/gaia/oauth2_access_token_consumer.h +++ b/google_apis/gaia/oauth2_access_token_consumer.h
@@ -78,6 +78,10 @@ // Failure callback. virtual void OnGetTokenFailure(const GoogleServiceAuthError& error); + // Returns the OAuth token consumer name, should be used for logging only. + virtual std::string GetConsumerName() const = 0; + + private: DISALLOW_COPY_AND_ASSIGN(OAuth2AccessTokenConsumer); };
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc index ba33d32..648d241 100644 --- a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc +++ b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
@@ -54,12 +54,16 @@ class MockOAuth2AccessTokenConsumer : public OAuth2AccessTokenConsumer { public: - MockOAuth2AccessTokenConsumer() {} - ~MockOAuth2AccessTokenConsumer() override {} + MockOAuth2AccessTokenConsumer() = default; + ~MockOAuth2AccessTokenConsumer() override = default; MOCK_METHOD1(OnGetTokenSuccess, void(const OAuth2AccessTokenConsumer::TokenResponse&)); MOCK_METHOD1(OnGetTokenFailure, void(const GoogleServiceAuthError& error)); + + std::string GetConsumerName() const override { + return "oauth2_access_token_fetcher_impl_unittest"; + } }; class URLLoaderFactoryInterceptor {
diff --git a/google_apis/gaia/oauth2_access_token_manager.cc b/google_apis/gaia/oauth2_access_token_manager.cc index b798777..62e4c14 100644 --- a/google_apis/gaia/oauth2_access_token_manager.cc +++ b/google_apis/gaia/oauth2_access_token_manager.cc
@@ -148,6 +148,7 @@ const std::string& client_id, const std::string& client_secret, const ScopeSet& scopes, + const std::string& consumer_name, base::WeakPtr<RequestImpl> waiting_request); ~Fetcher() override; @@ -175,6 +176,7 @@ void OnGetTokenSuccess( const OAuth2AccessTokenConsumer::TokenResponse& token_response) override; void OnGetTokenFailure(const GoogleServiceAuthError& error) override; + std::string GetConsumerName() const override; private: Fetcher(OAuth2AccessTokenManager* oauth2_access_token_manager, @@ -183,6 +185,7 @@ const std::string& client_id, const std::string& client_secret, const ScopeSet& scopes, + const std::string& consumer_name, base::WeakPtr<RequestImpl> waiting_request); void Start(); void InformWaitingRequests(); @@ -203,6 +206,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; const CoreAccountId account_id_; const ScopeSet scopes_; + const std::string consumer_name_; std::vector<base::WeakPtr<RequestImpl>> waiting_requests_; int retry_number_; @@ -234,10 +238,12 @@ const std::string& client_id, const std::string& client_secret, const ScopeSet& scopes, + const std::string& consumer_name, base::WeakPtr<RequestImpl> waiting_request) { - std::unique_ptr<OAuth2AccessTokenManager::Fetcher> fetcher = base::WrapUnique( - new Fetcher(oauth2_access_token_manager, account_id, url_loader_factory, - client_id, client_secret, scopes, waiting_request)); + std::unique_ptr<OAuth2AccessTokenManager::Fetcher> fetcher = + base::WrapUnique(new Fetcher(oauth2_access_token_manager, account_id, + url_loader_factory, client_id, client_secret, + scopes, consumer_name, waiting_request)); fetcher->Start(); return fetcher; @@ -250,11 +256,13 @@ const std::string& client_id, const std::string& client_secret, const ScopeSet& scopes, + const std::string& consumer_name, base::WeakPtr<RequestImpl> waiting_request) : oauth2_access_token_manager_(oauth2_access_token_manager), url_loader_factory_(url_loader_factory), account_id_(account_id), scopes_(scopes), + consumer_name_(consumer_name), retry_number_(0), error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE), client_id_(client_id), @@ -315,6 +323,10 @@ InformWaitingRequestsAndDelete(); } +std::string OAuth2AccessTokenManager::Fetcher::GetConsumerName() const { + return consumer_name_; +} + // Returns an exponential backoff in milliseconds including randomness less than // 1000 ms when retrying fetching an OAuth2 access token. int64_t @@ -478,6 +490,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& client_id, const std::string& client_secret, + const std::string& consumer_name, const ScopeSet& scopes) { // If there is already a pending fetcher for |scopes| and |account_id|, // simply register this |request| for those results rather than starting @@ -490,9 +503,9 @@ return; } - pending_fetchers_[request_parameters] = - Fetcher::CreateAndStart(this, account_id, url_loader_factory, client_id, - client_secret, scopes, request->AsWeakPtr()); + pending_fetchers_[request_parameters] = Fetcher::CreateAndStart( + this, account_id, url_loader_factory, client_id, client_secret, scopes, + consumer_name, request->AsWeakPtr()); } void OAuth2AccessTokenManager::RegisterTokenResponse( @@ -660,7 +673,7 @@ // The token isn't in the cache and the delegate isn't fetching it: fetch it // ourselves! FetchOAuth2Token(request.get(), account_id, url_loader_factory, client_id, - client_secret, scopes); + client_secret, consumer->id(), scopes); } return std::move(request); }
diff --git a/google_apis/gaia/oauth2_access_token_manager.h b/google_apis/gaia/oauth2_access_token_manager.h index bde56c0..c60b11e 100644 --- a/google_apis/gaia/oauth2_access_token_manager.h +++ b/google_apis/gaia/oauth2_access_token_manager.h
@@ -226,6 +226,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& client_id, const std::string& client_secret, + const std::string& consumer_name, const ScopeSet& scopes); // Returns a currently valid OAuth2 access token for the given set of scopes,
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index d31551f..82fa77db 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -278,7 +278,11 @@ } bool IsGL_REDSupportedOnFBOs() { -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if defined(OS_MAC) + // The glTexImage2D call below can hang on Mac so skip this since it's only + // really needed to workaround a Mesa issue. See https://crbug.com/1158744. + return true; +#else DCHECK(glGetError() == GL_NO_ERROR); // Skia uses GL_RED with frame buffers, unfortunately, Mesa claims to support // GL_EXT_texture_rg, but it doesn't support it on frame buffers. To fix @@ -310,9 +314,7 @@ DCHECK(glGetError() == GL_NO_ERROR); return result; -#else - return true; -#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) +#endif // defined(OS_MAC) } void FeatureInfo::EnableCHROMIUMTextureStorageImage() {
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index 01f43c92..97098091 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -3185,6 +3185,7 @@ if (!needs_clear && !shared_image_->IsCleared()) { LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM", "SharedImage not cleared before use."); + shared_image_.reset(); return; }
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc index 83fe6efc..426210e 100644 --- a/gpu/command_buffer/service/shared_context_state.cc +++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -621,10 +621,8 @@ void SharedContextState::PurgeMemory( base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { - if (!gr_context_) { - DCHECK(!transfer_cache_); + if (!gr_context_) return; - } // Ensure the context is current before doing any GPU cleanup. if (!MakeCurrent(nullptr))
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index f551d341..eeba4aa 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc
@@ -677,7 +677,7 @@ .RetiresOnSaturation(); } -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if !defined(OS_MAC) if (gl_info.is_es3 || gl_info.is_desktop_core_profile || gfx::HasExtension(extension_set, "GL_EXT_texture_rg") || (gfx::HasExtension(extension_set, "GL_ARB_texture_rg"))) { @@ -736,7 +736,7 @@ .RetiresOnSaturation(); #endif } -#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) +#endif // !defined(OS_MAC) } void TestHelper::SetupExpectationsForClearingUniforms(::gl::MockGLInterface* gl,
diff --git a/headless/BUILD.gn b/headless/BUILD.gn index f53e48be..2b5bd5a1 100644 --- a/headless/BUILD.gn +++ b/headless/BUILD.gn
@@ -384,10 +384,14 @@ if (headless_use_policy) { sources += [ + "lib/browser/headless_pref_names.cc", + "lib/browser/headless_pref_names.h", "lib/browser/policy/headless_browser_policy_connector.cc", "lib/browser/policy/headless_browser_policy_connector.h", "lib/browser/policy/headless_mode_policy.cc", "lib/browser/policy/headless_mode_policy.h", + "lib/browser/policy/headless_policies.cc", + "lib/browser/policy/headless_policies.h", ] } @@ -483,7 +487,6 @@ "//components/security_state/content", "//gin", "//third_party/blink/public:blink", - "//third_party/blink/public:blink_headers", "//ui/gl", "//v8", ] @@ -684,6 +687,8 @@ "test/headless_client_browsertest.cc", "test/headless_devtools_client_browsertest.cc", "test/headless_origin_trials_browsertest.cc", + "test/headless_policy_browsertest.cc", + "test/headless_policy_browsertest.h", "test/headless_test_launcher.cc", "test/headless_web_contents_browsertest.cc", "test/test_network_interceptor.cc",
diff --git a/headless/lib/browser/headless_browser_main_parts.cc b/headless/lib/browser/headless_browser_main_parts.cc index 463bead..b6d0091 100644 --- a/headless/lib/browser/headless_browser_main_parts.cc +++ b/headless/lib/browser/headless_browser_main_parts.cc
@@ -4,6 +4,8 @@ #include "headless/lib/browser/headless_browser_main_parts.h" +#include <stdio.h> + #include "content/public/common/result_codes.h" #include "headless/app/headless_shell_switches.h" #include "headless/lib/browser/headless_browser_context_impl.h" @@ -21,8 +23,8 @@ #if defined(HEADLESS_USE_POLICY) #include "components/keyed_service/content/browser_context_dependency_manager.h" -#include "components/policy/core/browser/url_blocklist_manager.h" #include "headless/lib/browser/policy/headless_mode_policy.h" +#include "headless/lib/browser/policy/headless_policies.h" #endif #if defined(OS_MAC) @@ -51,10 +53,7 @@ #if defined(HEADLESS_USE_PREFS) CreatePrefService(); #endif - if (browser_->options()->DevtoolsServerEnabled()) { - StartLocalDevToolsHttpHandler(browser_); - devtools_http_handler_started_ = true; - } + MaybeStartLocalDevToolsHttpHandler(); browser_->PlatformInitialize(); browser_->RunOnStartCallback(); @@ -105,6 +104,26 @@ std::move(quit_main_message_loop_).Run(); } +void HeadlessBrowserMainParts::MaybeStartLocalDevToolsHttpHandler() { + if (!browser_->options()->DevtoolsServerEnabled()) + return; + +#if defined(HEADLESS_USE_POLICY) + const PrefService* pref_service = browser_->GetPrefs(); + if (!policy::IsRemoteDebuggingAllowed(pref_service)) { + // Follow content/browser/devtools/devtools_http_handler.cc that reports its + // remote debugging port on stderr for symmetry. + fputs("\nDevTools remote debugging is disallowed by the system admin.\n", + stderr); + fflush(stderr); + return; + } +#endif + + StartLocalDevToolsHttpHandler(browser_); + devtools_http_handler_started_ = true; +} + #if defined(HEADLESS_USE_PREFS) void HeadlessBrowserMainParts::CreatePrefService() { scoped_refptr<PersistentPrefStore> pref_store; @@ -127,8 +146,7 @@ PrefServiceFactory factory; #if defined(HEADLESS_USE_POLICY) - policy::HeadlessModePolicy::RegisterLocalPrefs(pref_registry.get()); - policy::URLBlocklistManager::RegisterProfilePrefs(pref_registry.get()); + policy::RegisterPrefs(pref_registry.get()); policy_connector_ = std::make_unique<policy::HeadlessBrowserPolicyConnector>();
diff --git a/headless/lib/browser/headless_browser_main_parts.h b/headless/lib/browser/headless_browser_main_parts.h index f2dc0d4..763c545 100644 --- a/headless/lib/browser/headless_browser_main_parts.h +++ b/headless/lib/browser/headless_browser_main_parts.h
@@ -62,9 +62,11 @@ #endif private: + void MaybeStartLocalDevToolsHttpHandler(); #if defined(HEADLESS_USE_PREFS) void CreatePrefService(); #endif + const content::MainFunctionParams parameters_; // For running browser tests. HeadlessBrowserImpl* browser_; // Not owned.
diff --git a/headless/lib/browser/headless_pref_names.cc b/headless/lib/browser/headless_pref_names.cc new file mode 100644 index 0000000..3d79a28 --- /dev/null +++ b/headless/lib/browser/headless_pref_names.cc
@@ -0,0 +1,20 @@ +// Copyright 2021 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 "headless/lib/browser/headless_pref_names.h" + +namespace headless { + +namespace prefs { + +// Defines administrator-set availability of developer tools remote debugging. +const char kDevToolsRemoteDebuggingAllowed[] = + "devtools.remote_debugging.allowed"; + +// Defines administrator-set availability of the headless mode. +const char kHeadlessMode[] = "headless.mode"; + +} // namespace prefs + +} // namespace headless
diff --git a/headless/lib/browser/headless_pref_names.h b/headless/lib/browser/headless_pref_names.h new file mode 100644 index 0000000..8089ef0 --- /dev/null +++ b/headless/lib/browser/headless_pref_names.h
@@ -0,0 +1,19 @@ +// Copyright 2021 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 HEADLESS_LIB_BROWSER_HEADLESS_PREF_NAMES_H_ +#define HEADLESS_LIB_BROWSER_HEADLESS_PREF_NAMES_H_ + +namespace headless { + +namespace prefs { + +extern const char kDevToolsRemoteDebuggingAllowed[]; +extern const char kHeadlessMode[]; + +} // namespace prefs + +} // namespace headless + +#endif // HEADLESS_LIB_BROWSER_HEADLESS_PREF_NAMES_H_
diff --git a/headless/lib/browser/policy/DEPS b/headless/lib/browser/policy/DEPS index a5b00af..7908ee54 100644 --- a/headless/lib/browser/policy/DEPS +++ b/headless/lib/browser/policy/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+components/policy", "+components/prefs", + "+components/pref_registry", ]
diff --git a/headless/lib/browser/policy/headless_browser_policy_connector.cc b/headless/lib/browser/policy/headless_browser_policy_connector.cc index 343cf07..bf8eaac 100644 --- a/headless/lib/browser/policy/headless_browser_policy_connector.cc +++ b/headless/lib/browser/policy/headless_browser_policy_connector.cc
@@ -14,11 +14,14 @@ #include "base/task/thread_pool.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "components/policy/core/browser/configuration_policy_handler.h" #include "components/policy/core/browser/url_blocklist_policy_handler.h" #include "components/policy/core/common/async_policy_provider.h" #include "components/policy/core/common/policy_pref_names.h" #include "components/policy/policy_constants.h" +#include "headless/lib/browser/headless_pref_names.h" #include "headless/lib/browser/policy/headless_mode_policy.h" +#include "headless/lib/browser/policy/headless_policies.h" #if defined(OS_WIN) #include "base/win/registry.h" @@ -54,6 +57,11 @@ key::kURLAllowlist, policy_prefs::kUrlAllowlist, base::Value::Type::LIST)); + handlers->AddHandler(std::make_unique<SimplePolicyHandler>( + key::kRemoteDebuggingAllowed, + headless::prefs::kDevToolsRemoteDebuggingAllowed, + base::Value::Type::BOOLEAN)); + return handlers; }
diff --git a/headless/lib/browser/policy/headless_browser_policy_connector.h b/headless/lib/browser/policy/headless_browser_policy_connector.h index b9b9d29..ee4697e4 100644 --- a/headless/lib/browser/policy/headless_browser_policy_connector.h +++ b/headless/lib/browser/policy/headless_browser_policy_connector.h
@@ -53,4 +53,4 @@ } // namespace policy -#endif // HEADLESS_LIB_BROWSER_POLICY_HEADLESS_BROWSER_POLICY_CONNECTOR_H_ \ No newline at end of file +#endif // HEADLESS_LIB_BROWSER_POLICY_HEADLESS_BROWSER_POLICY_CONNECTOR_H_
diff --git a/headless/lib/browser/policy/headless_mode_policy.cc b/headless/lib/browser/policy/headless_mode_policy.cc index 333d76e..9cbab048 100644 --- a/headless/lib/browser/policy/headless_mode_policy.cc +++ b/headless/lib/browser/policy/headless_mode_policy.cc
@@ -7,16 +7,13 @@ #include "components/policy/policy_constants.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" - -namespace prefs { -const char kHeadlessMode[] = "headless.mode"; -} +#include "headless/lib/browser/headless_pref_names.h" namespace policy { // static void HeadlessModePolicy::RegisterLocalPrefs(PrefRegistrySimple* registry) { - registry->RegisterIntegerPref(prefs::kHeadlessMode, + registry->RegisterIntegerPref(headless::prefs::kHeadlessMode, static_cast<int>(HeadlessMode::kDefaultValue)); } @@ -28,7 +25,7 @@ if (!pref_service) return HeadlessMode::kDefaultValue; - int value = pref_service->GetInteger(prefs::kHeadlessMode); + int value = pref_service->GetInteger(headless::prefs::kHeadlessMode); if (value < static_cast<int>(HeadlessMode::kMinValue) || value > static_cast<int>(HeadlessMode::kMaxValue)) { // This should never happen, because the |kHeadlessMode| pref is @@ -50,7 +47,7 @@ HeadlessModePolicyHandler::HeadlessModePolicyHandler() : IntRangePolicyHandler( key::kHeadlessMode, - prefs::kHeadlessMode, + headless::prefs::kHeadlessMode, static_cast<int>(HeadlessModePolicy::HeadlessMode::kMinValue), static_cast<int>(HeadlessModePolicy::HeadlessMode::kMaxValue), false) {}
diff --git a/headless/lib/browser/policy/headless_mode_policy.h b/headless/lib/browser/policy/headless_mode_policy.h index 89c796f..da2c8896 100644 --- a/headless/lib/browser/policy/headless_mode_policy.h +++ b/headless/lib/browser/policy/headless_mode_policy.h
@@ -11,10 +11,6 @@ class PrefService; class PrefRegistrySimple; -namespace prefs { -extern const char kHeadlessMode[]; -} - namespace policy { // Headless mode policy helpers.
diff --git a/headless/lib/browser/policy/headless_policies.cc b/headless/lib/browser/policy/headless_policies.cc new file mode 100644 index 0000000..f0edc59 --- /dev/null +++ b/headless/lib/browser/policy/headless_policies.cc
@@ -0,0 +1,34 @@ +// Copyright 2021 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 "headless/lib/browser/policy/headless_policies.h" + +#include "base/check.h" +#include "components/policy/core/browser/url_blocklist_manager.h" +#include "components/policy/policy_constants.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_service.h" +#include "headless/lib/browser/headless_pref_names.h" +#include "headless/lib/browser/policy/headless_mode_policy.h" + +namespace policy { + +void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry) { + DCHECK(registry); + registry->RegisterBooleanPref( + headless::prefs::kDevToolsRemoteDebuggingAllowed, true); + HeadlessModePolicy::RegisterLocalPrefs(registry); + URLBlocklistManager::RegisterProfilePrefs(registry); +} + +bool IsRemoteDebuggingAllowed(const PrefService* pref_service) { + // If preferences are not available, assume the default value. + if (!pref_service) + return true; + + return pref_service->GetBoolean( + headless::prefs::kDevToolsRemoteDebuggingAllowed); +} + +} // namespace policy
diff --git a/headless/lib/browser/policy/headless_policies.h b/headless/lib/browser/policy/headless_policies.h new file mode 100644 index 0000000..218673ad1 --- /dev/null +++ b/headless/lib/browser/policy/headless_policies.h
@@ -0,0 +1,24 @@ +// Copyright 2021 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 HEADLESS_LIB_BROWSER_POLICY_HEADLESS_POLICIES_H_ +#define HEADLESS_LIB_BROWSER_POLICY_HEADLESS_POLICIES_H_ + +class PrefService; + +namespace user_prefs { +class PrefRegistrySyncable; +} + +namespace policy { + +// Registers headless policies' prefs in |registry|. +void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry); + +// Returns positive if current policy in |pref_service| allows Remote Debugging. +bool IsRemoteDebuggingAllowed(const PrefService* pref_service); + +} // namespace policy + +#endif // HEADLESS_LIB_BROWSER_POLICY_HEADLESS_POLICIES_H_
diff --git a/headless/test/headless_browser_browsertest.cc b/headless/test/headless_browser_browsertest.cc index 5fd2643..f7f76a6 100644 --- a/headless/test/headless_browser_browsertest.cc +++ b/headless/test/headless_browser_browsertest.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include <memory> -#include <tuple> #include "base/bind.h" #include "base/command_line.h" @@ -766,129 +765,4 @@ EXPECT_TRUE(WaitForLoad(web_contents)); } -class HeadlessBrowserTestWithPolicy : public HeadlessBrowserTest { - protected: - // Implement to set policies before headless browser is instantiated. - virtual void SetPolicy() {} - - void SetUp() override { - mock_provider_ = - std::make_unique<policy::MockConfigurationPolicyProvider>(); - EXPECT_CALL(*mock_provider_.get(), IsInitializationComplete(testing::_)) - .WillRepeatedly(testing::Return(false)); - policy::BrowserPolicyConnectorBase::SetPolicyProviderForTesting( - mock_provider_.get()); - SetPolicy(); - HeadlessBrowserTest::SetUp(); - } - - void SetUpInProcessBrowserTestFixture() override { - HeadlessBrowserTest::SetUpInProcessBrowserTestFixture(); - CreateTempUserDir(); - } - - void TearDown() override { - HeadlessBrowserTest::TearDown(); - mock_provider_->Shutdown(); - policy::BrowserPolicyConnectorBase::SetPolicyProviderForTesting(nullptr); - } - - void CreateTempUserDir() { - ASSERT_TRUE(user_data_dir_.CreateUniqueTempDir()); - EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir())); - options()->user_data_dir = user_data_dir(); - } - - const base::FilePath& user_data_dir() const { - return user_data_dir_.GetPath(); - } - - PrefService* GetPrefs() { - return static_cast<HeadlessBrowserImpl*>(browser())->GetPrefs(); - } - - base::ScopedTempDir user_data_dir_; - std::unique_ptr<policy::MockConfigurationPolicyProvider> mock_provider_; -}; - -// The following enum values must match HeadlessMode policy template in -// components/policy/resources/policy_templates.json -enum { - kHeadlessModePolicyEnabled = 1, - kHeadlessModePolicyDisabled = 2, - kHeadlessModePolicyUnset = -1, // not in the template -}; - -class HeadlessBrowserTestWithHeadlessModePolicy - : public HeadlessBrowserTestWithPolicy, - public testing::WithParamInterface<std::tuple<int, bool>> { - protected: - void SetPolicy() override { - int headless_mode_policy = std::get<0>(GetParam()); - if (headless_mode_policy != kHeadlessModePolicyUnset) { - SetHeadlessModePolicy( - static_cast<policy::HeadlessModePolicy::HeadlessMode>( - headless_mode_policy)); - } - } - - void SetHeadlessModePolicy( - policy::HeadlessModePolicy::HeadlessMode headless_mode) { - policy::PolicyMap policy; - policy.Set("HeadlessMode", policy::POLICY_LEVEL_MANDATORY, - policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, - base::Value(static_cast<int>(headless_mode)), - /*external_data_fetcher=*/nullptr); - mock_provider_->UpdateChromePolicy(policy); - } - - bool expected_enabled() { return std::get<1>(GetParam()); } - bool actual_enabled() { - return !policy::HeadlessModePolicy::IsHeadlessDisabled(GetPrefs()); - } -}; - -INSTANTIATE_TEST_CASE_P( - HeadlessBrowserTestWithHeadlessModePolicy, - HeadlessBrowserTestWithHeadlessModePolicy, - testing::Values(std::make_tuple(kHeadlessModePolicyEnabled, true), - std::make_tuple(kHeadlessModePolicyDisabled, false), - std::make_tuple(kHeadlessModePolicyUnset, true))); - -IN_PROC_BROWSER_TEST_P(HeadlessBrowserTestWithHeadlessModePolicy, - HeadlessModePolicySettings) { - EXPECT_EQ(actual_enabled(), expected_enabled()); -} - -class HeadlessBrowserTestWithUrlBlockPolicy - : public HeadlessBrowserTestWithPolicy { - protected: - void SetPolicy() override { - base::Value::ListStorage storage; - storage.emplace_back("*/blocked.html"); - base::Value value(std::move(storage)); - - policy::PolicyMap policy; - policy.Set("URLBlocklist", policy::POLICY_LEVEL_MANDATORY, - policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, - std::move(value), /*external_data_fetcher=*/nullptr); - mock_provider_->UpdateChromePolicy(policy); - } -}; - -IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithUrlBlockPolicy, BlockUrl) { - EXPECT_TRUE(embedded_test_server()->Start()); - - HeadlessBrowserContext* browser_context = - browser()->CreateBrowserContextBuilder().Build(); - - GURL url = embedded_test_server()->GetURL("/blocked.html"); - HeadlessWebContents* web_contents = - browser_context->CreateWebContentsBuilder().SetInitialURL(url).Build(); - - net::Error error = net::OK; - EXPECT_FALSE(WaitForLoad(web_contents, &error)); - EXPECT_EQ(error, net::ERR_BLOCKED_BY_ADMINISTRATOR); -} - } // namespace headless
diff --git a/headless/test/headless_policy_browsertest.cc b/headless/test/headless_policy_browsertest.cc new file mode 100644 index 0000000..8d2beee12 --- /dev/null +++ b/headless/test/headless_policy_browsertest.cc
@@ -0,0 +1,259 @@ +// Copyright 2021 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 "headless/test/headless_policy_browsertest.h" + +#include <fcntl.h> + +#include <memory> +#include <string> +#include <tuple> +#include <vector> + +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "base/strings/pattern.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/threading/platform_thread.h" +#include "base/threading/thread_restrictions.h" +#include "build/build_config.h" +#include "content/public/test/browser_test.h" +#include "headless/lib/browser/policy/headless_mode_policy.h" +#include "headless/public/headless_browser.h" +#include "headless/test/headless_browser_test.h" +#include "net/base/host_port_pair.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if !defined(OS_WIN) +#include <unistd.h> +#endif + +namespace headless { + +// The following enum values must match HeadlessMode policy template in +// components/policy/resources/policy_templates.json +enum { + kHeadlessModePolicyEnabled = 1, + kHeadlessModePolicyDisabled = 2, + kHeadlessModePolicyUnset = -1, // not in the template +}; + +class HeadlessBrowserTestWithHeadlessModePolicy + : public HeadlessBrowserTestWithPolicy<HeadlessBrowserTest>, + public testing::WithParamInterface<std::tuple<int, bool>> { + protected: + void SetPolicy() override { + int headless_mode_policy = std::get<0>(GetParam()); + if (headless_mode_policy != kHeadlessModePolicyUnset) { + SetHeadlessModePolicy( + static_cast<policy::HeadlessModePolicy::HeadlessMode>( + headless_mode_policy)); + } + } + + void SetHeadlessModePolicy( + policy::HeadlessModePolicy::HeadlessMode headless_mode) { + policy::PolicyMap policy; + policy.Set("HeadlessMode", policy::POLICY_LEVEL_MANDATORY, + policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, + base::Value(static_cast<int>(headless_mode)), + /*external_data_fetcher=*/nullptr); + mock_provider_->UpdateChromePolicy(policy); + } + + bool expected_enabled() { return std::get<1>(GetParam()); } + bool actual_enabled() { + return !policy::HeadlessModePolicy::IsHeadlessDisabled(GetPrefs()); + } +}; + +INSTANTIATE_TEST_CASE_P( + HeadlessBrowserTestWithHeadlessModePolicy, + HeadlessBrowserTestWithHeadlessModePolicy, + testing::Values(std::make_tuple(kHeadlessModePolicyEnabled, true), + std::make_tuple(kHeadlessModePolicyDisabled, false), + std::make_tuple(kHeadlessModePolicyUnset, true))); + +IN_PROC_BROWSER_TEST_P(HeadlessBrowserTestWithHeadlessModePolicy, + HeadlessModePolicySettings) { + EXPECT_EQ(actual_enabled(), expected_enabled()); +} + +class HeadlessBrowserTestWithUrlBlockPolicy + : public HeadlessBrowserTestWithPolicy<HeadlessBrowserTest> { + protected: + void SetPolicy() override { + base::Value value(base::Value::Type::LIST); + value.Append("*/blocked.html"); + + policy::PolicyMap policy; + policy.Set("URLBlocklist", policy::POLICY_LEVEL_MANDATORY, + policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, + std::move(value), /*external_data_fetcher=*/nullptr); + mock_provider_->UpdateChromePolicy(policy); + } +}; + +IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithUrlBlockPolicy, BlockUrl) { + EXPECT_TRUE(embedded_test_server()->Start()); + + HeadlessBrowserContext* browser_context = + browser()->CreateBrowserContextBuilder().Build(); + + GURL url = embedded_test_server()->GetURL("/blocked.html"); + HeadlessWebContents* web_contents = + browser_context->CreateWebContentsBuilder().SetInitialURL(url).Build(); + + net::Error error = net::OK; + EXPECT_FALSE(WaitForLoad(web_contents, &error)); + EXPECT_EQ(error, net::ERR_BLOCKED_BY_ADMINISTRATOR); +} + +namespace { + +class CaptureStdErr { + public: + CaptureStdErr() { +#if defined(OS_WIN) + CHECK_EQ(_pipe(pipes_, 4096, O_BINARY), 0); +#else + CHECK_EQ(pipe(pipes_), 0); +#endif + stderr_ = dup(fileno(stderr)); + CHECK_NE(stderr_, -1); + } + + ~CaptureStdErr() { + StopCapture(); + close(pipes_[kReadPipe]); + close(pipes_[kWritePipe]); + close(stderr_); + } + + void StartCapture() { + if (capturing_) + return; + + fflush(stderr); + CHECK_NE(dup2(pipes_[kWritePipe], fileno(stderr)), -1); + + capturing_ = true; + } + + void StopCapture() { + if (!capturing_) + return; + + char eop = kPipeEnd; + CHECK_NE(write(pipes_[kWritePipe], &eop, sizeof(eop)), -1); + + fflush(stderr); + CHECK_NE(dup2(stderr_, fileno(stderr)), -1); + + capturing_ = false; + } + + std::string ReadCapturedData() { + CHECK(!capturing_); + + std::string captured_data; + for (;;) { + constexpr size_t kChunkSize = 256; + char buffer[kChunkSize]; + int bytes_read = read(pipes_[kReadPipe], buffer, kChunkSize); + CHECK_NE(bytes_read, -1); + captured_data.append(buffer, bytes_read); + if (captured_data.rfind(kPipeEnd) != std::string::npos) + break; + } + return captured_data; + } + + std::vector<std::string> ReadCapturedLines() { + return base::SplitString(ReadCapturedData(), "\n", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + } + + private: + enum { kReadPipe, kWritePipe }; + + static constexpr char kPipeEnd = '\xff'; + + base::ScopedAllowBlockingForTesting allow_blocking_calls_; + + bool capturing_ = false; + int pipes_[2] = {-1, -1}; + int stderr_ = -1; +}; + +} // namespace + +class HeadlessBrowserTestWithRemoteDebuggingAllowedPolicy + : public HeadlessBrowserTestWithPolicy<HeadlessBrowserTest>, + public testing::WithParamInterface<bool> { + protected: + void SetPolicy() override { + policy::PolicyMap policy; + policy.Set("RemoteDebuggingAllowed", policy::POLICY_LEVEL_MANDATORY, + policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, + base::Value(expect_remote_debugging_available()), + /*external_data_fetcher=*/nullptr); + mock_provider_->UpdateChromePolicy(policy); + } + + void SetUpInProcessBrowserTestFixture() override { + HeadlessBrowserTestWithPolicy< + HeadlessBrowserTest>::SetUpInProcessBrowserTestFixture(); + options()->devtools_endpoint = net::HostPortPair("localhost", 0); + capture_stderr_.StartCapture(); + } + + bool expect_remote_debugging_available() { return GetParam(); } + + CaptureStdErr capture_stderr_; +}; + +INSTANTIATE_TEST_CASE_P(HeadlessBrowserTestWithRemoteDebuggingAllowedPolicy, + HeadlessBrowserTestWithRemoteDebuggingAllowedPolicy, + testing::Values(true, false)); + +// Remote debugging with ephemeral port is not working on Fuchsia, see +// crbug.com/1209251. +#if defined(OS_FUCHSIA) +#define MAYBE_RemoteDebuggingDisallowed DISABLED_RemoteDebuggingDisallowed +#else +#define MAYBE_RemoteDebuggingDisallowed RemoteDebuggingDisallowed +#endif +IN_PROC_BROWSER_TEST_P(HeadlessBrowserTestWithRemoteDebuggingAllowedPolicy, + MAYBE_RemoteDebuggingDisallowed) { + // DevTools starts its remote debugging port listener asynchronously and + // there is no reliable way to know when it is started, so resort to an + // ugly wait then check captured stderr. + base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5)); + capture_stderr_.StopCapture(); + + enum { kUnknown, kDisallowed, kListening } remote_debugging_state = kUnknown; + for (const std::string& line : capture_stderr_.ReadCapturedLines()) { + LOG(INFO) << "stderr: " << line; + if (base::MatchPattern(line, "DevTools remote debugging is disallowed *")) { + EXPECT_EQ(remote_debugging_state, kUnknown); + remote_debugging_state = kDisallowed; + } else if (base::MatchPattern(line, "DevTools listening on *")) { + EXPECT_EQ(remote_debugging_state, kUnknown); + remote_debugging_state = kListening; + } + } + + EXPECT_NE(remote_debugging_state, kUnknown); + + if (expect_remote_debugging_available()) + EXPECT_EQ(remote_debugging_state, kListening); + else + EXPECT_EQ(remote_debugging_state, kDisallowed); +} + +} // namespace headless
diff --git a/headless/test/headless_policy_browsertest.h b/headless/test/headless_policy_browsertest.h new file mode 100644 index 0000000..1617f56 --- /dev/null +++ b/headless/test/headless_policy_browsertest.h
@@ -0,0 +1,67 @@ +// Copyright 2021 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 HEADLESS_TEST_HEADLESS_POLICY_BROWSERTEST_H_ +#define HEADLESS_TEST_HEADLESS_POLICY_BROWSERTEST_H_ + +#include <memory> + +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "components/policy/core/browser/browser_policy_connector_base.h" +#include "components/policy/core/common/mock_configuration_policy_provider.h" +#include "components/policy/core/common/policy_map.h" +#include "headless/lib/browser/headless_browser_impl.h" + +namespace headless { + +template <typename Base> +class HeadlessBrowserTestWithPolicy : public Base { + protected: + // Implement to set policies before headless browser is instantiated. + virtual void SetPolicy() {} + + void SetUp() override { + mock_provider_ = + std::make_unique<policy::MockConfigurationPolicyProvider>(); + EXPECT_CALL(*mock_provider_.get(), IsInitializationComplete(testing::_)) + .WillRepeatedly(testing::Return(false)); + policy::BrowserPolicyConnectorBase::SetPolicyProviderForTesting( + mock_provider_.get()); + SetPolicy(); + Base::SetUp(); + } + + void SetUpInProcessBrowserTestFixture() override { + Base::SetUpInProcessBrowserTestFixture(); + CreateTempUserDir(); + } + + void TearDown() override { + Base::TearDown(); + mock_provider_->Shutdown(); + policy::BrowserPolicyConnectorBase::SetPolicyProviderForTesting(nullptr); + } + + void CreateTempUserDir() { + ASSERT_TRUE(user_data_dir_.CreateUniqueTempDir()); + EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir())); + Base::options()->user_data_dir = user_data_dir(); + } + + const base::FilePath& user_data_dir() const { + return user_data_dir_.GetPath(); + } + + PrefService* GetPrefs() { + return static_cast<HeadlessBrowserImpl*>(Base::browser())->GetPrefs(); + } + + base::ScopedTempDir user_data_dir_; + std::unique_ptr<policy::MockConfigurationPolicyProvider> mock_provider_; +}; + +} // namespace headless + +#endif // HEADLESS_TEST_HEADLESS_POLICY_BROWSERTEST_H_
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 98ae310..947e71e 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg
@@ -61135,7 +61135,7 @@ properties_j: "$recipe_engine/resultdb/test_presentation:{\"column_keys\":[],\"grouping_keys\":[\"status\",\"v.test_suite\"]}" properties_j: "builder_group:\"tryserver.chromium.win\"" } - execution_timeout_secs: 14400 + execution_timeout_secs: 21600 expiration_secs: 7200 grace_period { seconds: 120
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star index 8876260..d42853c 100644 --- a/infra/config/subprojects/chromium/try.star +++ b/infra/config/subprojects/chromium/try.star
@@ -1814,6 +1814,7 @@ executable = "recipe:chromium_upload_clang", goma_backend = None, os = os.WINDOWS_ANY, + execution_timeout = 6 * time.hour, ) try_.chromium_win_builder(
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger_unittest.mm b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger_unittest.mm index 4785cb0..3de91b37 100644 --- a/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger_unittest.mm +++ b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger_unittest.mm
@@ -77,8 +77,7 @@ } // Tests that memory pressure events are logged by ApplicationBreadcrumbsLogger. -// TODO(crbug.com/1046588): This test is flaky. -TEST_F(ApplicationBreadcrumbsLoggerTest, DISABLED_MemoryPressure) { +TEST_F(ApplicationBreadcrumbsLoggerTest, MemoryPressure) { ASSERT_EQ(1U, breadcrumb_manager_.GetEvents(0).size()); // startup event base::MemoryPressureListener::SimulatePressureNotification( @@ -88,7 +87,9 @@ base::RunLoop().RunUntilIdle(); std::list<std::string> events = breadcrumb_manager_.GetEvents(0); - ASSERT_EQ(2ul, events.size()); + ASSERT_EQ(3ul, events.size()); + // Pop startup. + events.pop_front(); EXPECT_NE(std::string::npos, events.front().find("Moderate")); // Ensure UserAction events are labeled as such. EXPECT_NE(std::string::npos, events.front().find("Memory Pressure: "));
diff --git a/ios/chrome/browser/ios_chrome_main_parts.mm b/ios/chrome/browser/ios_chrome_main_parts.mm index 4cfde26..cb75d999 100644 --- a/ios/chrome/browser/ios_chrome_main_parts.mm +++ b/ios/chrome/browser/ios_chrome_main_parts.mm
@@ -340,6 +340,10 @@ base::SetRecordActionTaskRunner( base::CreateSingleThreadTaskRunner({web::WebThread::UI})); + // FeatureList requires VariationsIdsProvider to be created. + variations::VariationsIdsProvider::Create( + variations::VariationsIdsProvider::Mode::kUseSignedInState); + // Initialize FieldTrialList to support FieldTrials that use one-time // randomization. DCHECK(!field_trial_list_);
diff --git a/ios/chrome/browser/main/browser_list.h b/ios/chrome/browser/main/browser_list.h index a175489..827f924 100644 --- a/ios/chrome/browser/main/browser_list.h +++ b/ios/chrome/browser/main/browser_list.h
@@ -8,7 +8,6 @@ #include <set> #include "base/macros.h" -#include "base/observer_list.h" #include "components/keyed_service/core/keyed_service.h" class BrowserListObserver;
diff --git a/ios/chrome/browser/main/browser_list_impl.h b/ios/chrome/browser/main/browser_list_impl.h index f61c8ed..313d713 100644 --- a/ios/chrome/browser/main/browser_list_impl.h +++ b/ios/chrome/browser/main/browser_list_impl.h
@@ -5,6 +5,7 @@ #ifndef IOS_CHROME_BROWSER_MAIN_BROWSER_LIST_IMPL_H_ #define IOS_CHROME_BROWSER_MAIN_BROWSER_LIST_IMPL_H_ +#include "base/observer_list.h" #import "ios/chrome/browser/main/browser_list.h" #include "ios/chrome/browser/main/browser_list_observer.h" #import "ios/chrome/browser/main/browser_observer.h"
diff --git a/ios/chrome/browser/main/browser_list_impl_unittest.mm b/ios/chrome/browser/main/browser_list_impl_unittest.mm index 1c25bbc..cbc6da3 100644 --- a/ios/chrome/browser/main/browser_list_impl_unittest.mm +++ b/ios/chrome/browser/main/browser_list_impl_unittest.mm
@@ -161,8 +161,7 @@ // Check that an observer is informed of additions and removals to both the // regular and incognito browser lists. -// TODO(crbug.com/1043625): Fails on device and simulator -TEST_F(BrowserListImplTest, DISABLED_BrowserListObserver) { +TEST_F(BrowserListImplTest, BrowserListObserver) { TestBrowserListObserver* observer = new TestBrowserListObserver; browser_list_->AddObserver(observer);
diff --git a/ios/chrome/browser/main/test_browser_list_observer.h b/ios/chrome/browser/main/test_browser_list_observer.h index eb7afc96..6ed498e 100644 --- a/ios/chrome/browser/main/test_browser_list_observer.h +++ b/ios/chrome/browser/main/test_browser_list_observer.h
@@ -57,10 +57,10 @@ DISALLOW_COPY_AND_ASSIGN(TestBrowserListObserver); // Backing vars for the corresponding getter methods. - Browser* last_added_browser_; - Browser* last_removed_browser_; - Browser* last_added_incognito_browser_; - Browser* last_removed_incognito_browser_; + Browser* last_added_browser_ = nullptr; + Browser* last_removed_browser_ = nullptr; + Browser* last_added_incognito_browser_ = nullptr; + Browser* last_removed_incognito_browser_ = nullptr; std::set<Browser*> last_browsers_; std::set<Browser*> last_incognito_browsers_; };
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h b/ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h index 1291746..9543e7e9 100644 --- a/ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h +++ b/ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h
@@ -11,7 +11,6 @@ #include "base/containers/circular_deque.h" #include "base/macros.h" -#include "base/observer_list.h" #include "base/time/time.h" #include "ios/chrome/browser/main/browser_observer.h" #include "ios/chrome/browser/main/browser_user_data.h"
diff --git a/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm b/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm index 5d145af8..926f090 100644 --- a/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm +++ b/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm
@@ -356,13 +356,6 @@ base::FeatureList::IsEnabled(safe_browsing::kDelayedWarnings)); experiment.set_delayed_warnings_mouse_clicks_enabled( safe_browsing::kDelayedWarningsEnableMouseClicks.Get()); - // Actual URL display experiments: - experiment.set_reveal_on_hover(base::FeatureList::IsEnabled( - omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover)); - experiment.set_hide_on_interaction(base::FeatureList::IsEnabled( - omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction)); - experiment.set_elide_to_registrable_domain( - base::FeatureList::IsEnabled(omnibox::kMaybeElideToRegistrableDomain)); return experiment; }
diff --git a/ios/chrome/browser/sync/ios_trusted_vault_client.h b/ios/chrome/browser/sync/ios_trusted_vault_client.h index 9c49180..e85ed7b 100644 --- a/ios/chrome/browser/sync/ios_trusted_vault_client.h +++ b/ios/chrome/browser/sync/ios_trusted_vault_client.h
@@ -24,7 +24,6 @@ void StoreKeys(const std::string& gaia_id, const std::vector<std::vector<uint8_t>>& keys, int last_key_version) override; - void RemoveAllStoredKeys() override; void MarkKeysAsStale(const CoreAccountInfo& account_info, base::OnceCallback<void(bool)> callback) override; void GetIsRecoverabilityDegraded(
diff --git a/ios/chrome/browser/sync/ios_trusted_vault_client.mm b/ios/chrome/browser/sync/ios_trusted_vault_client.mm index 23e0c3b..679a06d 100644 --- a/ios/chrome/browser/sync/ios_trusted_vault_client.mm +++ b/ios/chrome/browser/sync/ios_trusted_vault_client.mm
@@ -61,11 +61,6 @@ NOTREACHED(); } -void IOSTrustedVaultClient::RemoveAllStoredKeys() { - // Not used on iOS. - NOTREACHED(); -} - void IOSTrustedVaultClient::MarkKeysAsStale( const CoreAccountInfo& account_info, base::OnceCallback<void(bool)> callback) {
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn index 1a97843c..753d9ea 100644 --- a/ios/chrome/browser/ui/authentication/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -117,6 +117,8 @@ "//components/sync/driver:test_support", "//components/sync_preferences", "//components/sync_preferences:test_support", + "//components/variations", + "//components/variations:test_support", "//components/version_info", "//ios/chrome/app/strings", "//ios/chrome/browser",
diff --git a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm index 4126708..f4ab01f 100644 --- a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/strings/sys_string_conversions.h" #include "components/signin/public/identity_manager/identity_test_environment.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/signin/authentication_service_delegate_fake.h" #include "ios/chrome/browser/signin/authentication_service_factory.h" @@ -58,6 +59,8 @@ web::WebTaskEnvironment::IO_MAINLOOP}; signin::IdentityTestEnvironment identity_test_env_; std::unique_ptr<TestChromeBrowserState> browser_state_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; }; // Tests that the signed in accounts view shouldn't be presented when the
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm index c960993..138b426 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
@@ -202,6 +202,10 @@ #pragma mark - ContentSuggestionsHeaderSynchronizing +- (BOOL)isOmniboxFocused { + return [self.headerController isOmniboxFocused]; +} + - (void)updateFakeOmniboxForScrollPosition { // Unfocus the omnibox when the scroll view is scrolled by the user (but not // when a scroll is triggered by layout/UIKit).
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h index 010aaef..f0323c2 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h
@@ -35,6 +35,9 @@ // Update any dynamic constraints. - (void)updateConstraints; +// Whether the omnibox is currently focused. +- (BOOL)isOmniboxFocused; + // Returns the Y value to use for the scroll view's contentOffset when scrolling // the omnibox to the top of the screen. - (CGFloat)pinnedOffsetY;
diff --git a/ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.h b/ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.h index 533bf68..9ff08cb6 100644 --- a/ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.h +++ b/ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.h
@@ -18,6 +18,10 @@ // feed. - (void)recordInfiniteFeedTriggered; +// Record metrics for when the user changes the device orientation with the feed +// visible. +- (void)recordDeviceOrientationChanged:(UIDeviceOrientation)orientation; + // Record metrics for when the user selects the 'Learn More' item in the feed // header menu. - (void)recordHeaderMenuLearnMoreTapped;
diff --git a/ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.mm b/ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.mm index a712cc8..faf418d 100644 --- a/ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.mm +++ b/ios/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.mm
@@ -54,6 +54,12 @@ const char kDiscoverFeedInfiniteFeedTriggered[] = "ContentSuggestions.Feed.LoadStreamStatus.LoadMore"; +// User action names for the device orientation having changed. +const char kDiscoverFeedHistogramDeviceOrientationChangedToPortrait[] = + "ContentSuggestions.Feed.DeviceOrientationChanged.Portrait"; +const char kDiscoverFeedHistogramDeviceOrientationChangedToLandscape[] = + "ContentSuggestions.Feed.DeviceOrientationChanged.Landscape"; + // Histogram name for the Discover feed user actions. const char kDiscoverFeedUserActionHistogram[] = "ContentSuggestions.Feed.UserActions"; @@ -208,6 +214,17 @@ base::UserMetricsAction(kDiscoverFeedUserActionInfiniteFeedTriggered)); } +- (void)recordDeviceOrientationChanged:(UIDeviceOrientation)orientation { + if (orientation == UIDeviceOrientationPortrait) { + base::RecordAction(base::UserMetricsAction( + kDiscoverFeedHistogramDeviceOrientationChangedToPortrait)); + } else if (orientation == UIDeviceOrientationLandscapeLeft || + orientation == UIDeviceOrientationLandscapeRight) { + base::RecordAction(base::UserMetricsAction( + kDiscoverFeedHistogramDeviceOrientationChangedToLandscape)); + } +} + - (void)recordHeaderMenuLearnMoreTapped { [self recordDiscoverFeedUserActionHistogram:FeedUserActionType:: kTappedLearnMore];
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm index b79eaee..e0df37d 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -219,6 +219,12 @@ // Tests that when loading an invalid URL, the NTP is still displayed. // Prevents regressions from https://crbug.com/1063154 . - (void)testInvalidURL { + if (@available(iOS 13, *)) { + } else { + // TODO(crbug.com/1217121): This test is failing on iOS 12.4. + EARL_GREY_TEST_DISABLED(@"Disabled on iOS 12.4 as it is failing."); + } + NSString* URL = @"app-settings://test-test-test/"; // The URL needs to be typed to trigger the bug. @@ -241,6 +247,12 @@ // Tests that the fake omnibox width is correctly updated after a rotation. - (void)testOmniboxWidthRotation { + if (@available(iOS 13, *)) { + } else { + // TODO(crbug.com/1217121): This test is failing on iOS 12.4. + EARL_GREY_TEST_DISABLED(@"Disabled on iOS 12.4 as it is failing."); + } + // TODO(crbug.com/652465): Enable the test for iPad when rotation bug is // fixed. if ([ChromeEarlGrey isIPadIdiom]) { @@ -281,6 +293,12 @@ // Tests that the fake omnibox width is correctly updated after a rotation done // while the settings screen is shown. - (void)testOmniboxWidthRotationBehindSettings { + if (@available(iOS 13, *)) { + } else { + // TODO(crbug.com/1217121): This test is failing on iOS 12.4. + EARL_GREY_TEST_DISABLED(@"Disabled on iOS 12.4 as it is failing."); + } + // TODO(crbug.com/652465): Enable the test for iPad when rotation bug is // fixed. if ([ChromeEarlGrey isRegularXRegularSizeClass]) { @@ -705,7 +723,8 @@ // Test to ensure that initial position and content are maintained when rotating // the device back and forth. -- (void)testInitialPositionAndOrientationChange { +// TODO(crbug.com/1217121): This test is failing on iOS 14.5 and iOS 12.4. +- (void)DISABLED_testInitialPositionAndOrientationChange { UICollectionView* collectionView = [NewTabPageAppInterface collectionView]; [self testNTPInitialPositionAndContent:collectionView];
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.mm b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.mm index cf53939..3f15792 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.mm +++ b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler.mm
@@ -152,20 +152,13 @@ if (self.currentPromoReason != PromoReasonNone) { return; } - // This assumes that the currently active webstate is the one that the paste - // occured in. - web::WebState* activeWebState = self.webStateList->GetActiveWebState(); - // There should always be an active web state when pasting in the omnibox. - if (!activeWebState) { - return; - } self.currentPromoReason = PromoReasonExternalLink; self.promoTypeForMetrics = NonModalPromoTriggerType::kGrowthKitOpen; // Store the current web state, so when that web state's page load finishes, // the promo can be shown. - self.webStateToListenTo = activeWebState; + self.webStateToListenTo = self.webStateList->GetActiveWebState(); } - (void)logPromoWasDismissed {
diff --git a/ios/chrome/browser/ui/first_run/first_run_screen_view_controller.mm b/ios/chrome/browser/ui/first_run/first_run_screen_view_controller.mm index 2eabbeb6..76290ec9 100644 --- a/ios/chrome/browser/ui/first_run/first_run_screen_view_controller.mm +++ b/ios/chrome/browser/ui/first_run/first_run_screen_view_controller.mm
@@ -33,7 +33,6 @@ constexpr CGFloat kActionsBottomMargin = 10; constexpr CGFloat kTallBannerMultiplier = 0.35; constexpr CGFloat kDefaultBannerMultiplier = 0.25; -constexpr CGFloat kSubtitleBottomMarginViewHeight = 0.05; constexpr CGFloat kContentWidthMultiplier = 0.65; constexpr CGFloat kContentMaxWidth = 327; constexpr CGFloat kMoreArrowMargin = 4; @@ -189,8 +188,7 @@ [subtitleMarginLayoutGuide.topAnchor constraintEqualToAnchor:self.subtitleLabel.bottomAnchor], [subtitleMarginLayoutGuide.heightAnchor - constraintEqualToAnchor:self.view.heightAnchor - multiplier:kSubtitleBottomMarginViewHeight], + constraintEqualToConstant:kDefaultMargin], [self.specificContentView.topAnchor constraintEqualToAnchor:subtitleMarginLayoutGuide.bottomAnchor], [self.specificContentView.leadingAnchor
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn index 5aa21116..b2f7a40 100644 --- a/ios/chrome/browser/ui/location_bar/BUILD.gn +++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -156,6 +156,7 @@ "//base/test:test_support", "//components/omnibox/browser:test_support", "//components/variations", + "//components/variations:test_support", "//ios/chrome/app/strings", "//ios/chrome/browser", "//ios/chrome/browser/autocomplete",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm index 697888f86..dcaa0632 100644 --- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm
@@ -10,6 +10,7 @@ #include "base/files/scoped_temp_dir.h" #include "components/omnibox/browser/test_location_bar_model.h" +#include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/variations_ids_provider.h" #include "ios/chrome/browser/autocomplete/autocomplete_classifier_factory.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" @@ -121,8 +122,6 @@ // Started coordinator has to be stopped before WebStateList destruction. [coordinator_ stop]; - VariationsIdsProvider::GetInstance()->ResetForTesting(); - PlatformTest::TearDown(); } @@ -132,6 +131,8 @@ base::ScopedTempDir state_dir_; web::WebTaskEnvironment task_environment_; + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; LocationBarCoordinator* coordinator_; std::unique_ptr<TestChromeBrowserState> browser_state_; FakeWebStateListDelegate web_state_list_delegate_;
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index 05260f0..d1a4815 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -88,7 +88,6 @@ #import "ios/chrome/browser/ui/first_run/location_permissions_coordinator.h" #import "ios/chrome/browser/ui/first_run/location_permissions_field_trial.h" #import "ios/chrome/browser/ui/first_run/orientation_limiting_navigation_controller.h" -#import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h" #include "ios/chrome/browser/ui/history/history_coordinator.h" #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h" #import "ios/chrome/browser/ui/main/browser_interface_provider.h" @@ -261,9 +260,6 @@ @property(nonatomic, strong) NSDictionary<NSString*, NSString*>* specificProductData; -@property(nonatomic, weak) - WelcomeToChromeViewController* welcomeToChromeController; - @end @implementation SceneController @@ -354,8 +350,7 @@ - (BOOL)isSettingsViewPresented { return self.settingsNavigationController || - self.signinCoordinator.isSettingsViewPresented || - self.welcomeToChromeController; + self.signinCoordinator.isSettingsViewPresented; } - (void)setStartupParameters:(AppStartupParameters*)parameters { @@ -2538,7 +2533,6 @@ - (void)closeSettingsAnimated:(BOOL)animated completion:(ProceduralBlock)completion { if (self.settingsNavigationController) { - DCHECK(!self.welcomeToChromeController); ProceduralBlock dismissSettings = ^() { [self.settingsNavigationController cleanUpSettings]; UIViewController* presentingViewController = @@ -2559,12 +2553,6 @@ } else if (dismissSettings) { dismissSettings(); } - } else if (self.welcomeToChromeController) { - DCHECK(!self.signinCoordinator); - // If kSSOAccountCreationInChromeTab is set, the FRE has to be interrupted, - // to open the account creation URL. - [self.welcomeToChromeController - interruptSigninCoordinatorWithCompletion:completion]; } else if (self.signinCoordinator) { // |self.signinCoordinator| can also present settings, like // the advanced sign-in settings navigation controller. If the settings has
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm index 1d13752f..30243aa 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
@@ -86,6 +86,7 @@ - (void)dealloc { [self.overscrollActionsController invalidate]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)viewDidLoad { @@ -99,8 +100,7 @@ UIView* discoverFeedView = self.discoverFeedWrapperViewController.view; - self.discoverFeedWrapperViewController.feedCollectionView - .accessibilityIdentifier = kNTPCollectionViewIdentifier; + self.collectionView.accessibilityIdentifier = kNTPCollectionViewIdentifier; [self.discoverFeedWrapperViewController willMoveToParentViewController:self]; [self addChildViewController:self.discoverFeedWrapperViewController]; @@ -115,8 +115,7 @@ .discoverFeed]; [self.discoverFeedWrapperViewController.discoverFeed addChildViewController:self.contentSuggestionsViewController]; - [self.discoverFeedWrapperViewController.feedCollectionView - addSubview:self.contentSuggestionsViewController.view]; + [self.collectionView addSubview:self.contentSuggestionsViewController.view]; [self.contentSuggestionsViewController didMoveToParentViewController:self.discoverFeedWrapperViewController .discoverFeed]; @@ -125,7 +124,7 @@ // than the ContentSuggestions view. This causes elements to be hidden. As a // temporary workaround set clipsToBounds to NO to display these elements, and // add a gesture recognizer to interact with them. - self.discoverFeedWrapperViewController.feedCollectionView.clipsToBounds = NO; + self.collectionView.clipsToBounds = NO; UITapGestureRecognizer* singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapInView:)]; @@ -148,6 +147,8 @@ .collectionViewLayout); _contentSuggestionsLayout.isScrolledIntoFeed = self.isScrolledIntoFeed; _contentSuggestionsLayout.omniboxPositioner = self; + + [self registerNotifications]; } - (void)viewWillLayoutSubviews { @@ -180,7 +181,7 @@ .collectionView.contentSize.height]; [NSLayoutConstraint activateConstraints:@[ - [self.discoverFeedWrapperViewController.feedCollectionView.topAnchor + [self.collectionView.topAnchor constraintEqualToAnchor:contentSuggestionsView.bottomAnchor], [containerView.safeAreaLayoutGuide.leadingAnchor constraintEqualToAnchor:contentSuggestionsView.leadingAnchor], @@ -226,34 +227,39 @@ __weak NewTabPageViewController* weakSelf = self; - CGFloat yOffsetBeforeRotation = - self.discoverFeedWrapperViewController.feedCollectionView.contentOffset.y; + CGFloat yOffsetBeforeRotation = self.collectionView.contentOffset.y; BOOL isScrolledToTop = [self adjustedContentSuggestionsHeight] <= (-yOffsetBeforeRotation) + 1; - void (^alongsideBlock)(id<UIViewControllerTransitionCoordinatorContext>) = - ^(id<UIViewControllerTransitionCoordinatorContext> context) { - // Rotating the device to landscape removes the fake omnibox, reducing - // the height of the content suggestions. Since the NTP's top scroll - // position is dependent on the content suggestions height, rotating - // from landscape->portrait would mess up the top scroll position. This - // ensures that it is adjusted if necessary. - // TODO(crbug.com/1170995): Remove once the Feed supports a custom - // header. - if (isScrolledToTop && - -yOffsetBeforeRotation < - [weakSelf adjustedContentSuggestionsHeight]) { - weakSelf.discoverFeedWrapperViewController.feedCollectionView - .contentOffset = - CGPointMake(0, -[weakSelf adjustedContentSuggestionsHeight]); - [weakSelf updateFeedInsetsForContentSuggestions]; - } - [weakSelf.headerSynchronizer unfocusOmnibox]; - [weakSelf.contentSuggestionsViewController.collectionView - .collectionViewLayout invalidateLayout]; - [weakSelf.view setNeedsLayout]; - [weakSelf.view layoutIfNeeded]; - }; + void (^alongsideBlock)(id<UIViewControllerTransitionCoordinatorContext>) = ^( + id<UIViewControllerTransitionCoordinatorContext> context) { + [weakSelf handleFakeOmniboxForScrollPosition:weakSelf.collectionView + .contentOffset.y + force:YES]; + // Rotating the device can change the content suggestions height. This + // ensures that it is adjusted if necessary. + // TODO(crbug.com/1170995): Remove once the Feed supports a custom + // header. + if (isScrolledToTop && + -yOffsetBeforeRotation < [weakSelf adjustedContentSuggestionsHeight]) { + weakSelf.collectionView.contentOffset = + CGPointMake(0, -[weakSelf adjustedContentSuggestionsHeight]); + [weakSelf updateContentSuggestionForCurrentLayout]; + } else { + [weakSelf.contentSuggestionsViewController.collectionView + .collectionViewLayout invalidateLayout]; + } + [weakSelf.view setNeedsLayout]; + [weakSelf.view layoutIfNeeded]; + + // Pinned offset is different based on the orientation, so we reevaluate the + // minimum scroll position upon device rotation. + CGFloat pinnedOffsetY = [weakSelf.headerSynchronizer pinnedOffsetY]; + if ([weakSelf.headerSynchronizer isOmniboxFocused] && + weakSelf.collectionView.contentOffset.y < pinnedOffsetY) { + weakSelf.collectionView.contentOffset = CGPointMake(0, pinnedOffsetY); + } + }; [coordinator animateAlongsideTransition:alongsideBlock completion:nil]; } @@ -285,8 +291,7 @@ } - (void)stopScrolling { - UIScrollView* scrollView = - self.discoverFeedWrapperViewController.feedCollectionView; + UIScrollView* scrollView = self.collectionView; [scrollView setContentOffset:scrollView.contentOffset animated:NO]; } @@ -334,23 +339,18 @@ [self.overscrollActionsController scrollViewDidScroll:scrollView]; [self.panGestureHandler scrollViewDidScroll:scrollView]; [self.headerSynchronizer updateFakeOmniboxForScrollPosition]; + + CGFloat scrollPosition = scrollView.contentOffset.y; self.scrolledToTop = - scrollView.contentOffset.y >= [self.headerSynchronizer pinnedOffsetY]; + scrollPosition >= [self.headerSynchronizer pinnedOffsetY]; // Fixes the content suggestions collection view layout so that the header // scrolls at the same rate as the rest. - if (scrollView.contentOffset.y > -self.contentSuggestionsViewController - .collectionView.contentSize.height) { + if (scrollPosition > -self.contentSuggestionsViewController.collectionView + .contentSize.height) { [self.contentSuggestionsViewController.collectionView .collectionViewLayout invalidateLayout]; } - // Changes ownership of fake omnibox view based on scroll position. - if (!self.isScrolledIntoFeed && - scrollView.contentOffset.y > -kOffsetToPinOmnibox) { - [self stickFakeOmniboxToTop]; - } else if (self.isScrolledIntoFeed && - scrollView.contentOffset.y <= -kOffsetToPinOmnibox) { - [self resetFakeOmnibox]; - } + [self handleFakeOmniboxForScrollPosition:scrollPosition force:NO]; } - (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView { @@ -451,8 +451,7 @@ shouldReceiveTouch:(UITouch*)touch { // Ignore all touches inside the Feed CollectionView, which includes // ContentSuggestions. - UIView* viewToIgnoreTouches = - self.discoverFeedWrapperViewController.feedCollectionView; + UIView* viewToIgnoreTouches = self.collectionView; CGRect ignoreBoundsInView = [viewToIgnoreTouches convertRect:viewToIgnoreTouches.bounds toView:self.view]; @@ -466,17 +465,16 @@ - (void)configureOverscrollActionsController { // Ensure the feed's scroll view exists to prevent crashing the overscroll // controller. - if (!self.discoverFeedWrapperViewController.feedCollectionView) { + if (!self.collectionView) { return; } // Overscroll action does not work well with content offset, so set this // to never and internally offset the UI to account for safe area insets. - self.discoverFeedWrapperViewController.feedCollectionView - .contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + self.collectionView.contentInsetAdjustmentBehavior = + UIScrollViewContentInsetAdjustmentNever; self.overscrollActionsController = [[OverscrollActionsController alloc] - initWithScrollView:self.discoverFeedWrapperViewController - .feedCollectionView]; + initWithScrollView:self.collectionView]; [self.overscrollActionsController setStyle:OverscrollStyle::NTP_NON_INCOGNITO]; self.overscrollActionsController.delegate = self.overscrollDelegate; @@ -550,7 +548,7 @@ self.contentSuggestionsViewController.view.frame = CGRectMake( 0, -[self contentSuggestionsContentHeight], self.view.frame.size.width, [self contentSuggestionsContentHeight]); - self.discoverFeedWrapperViewController.feedCollectionView.contentInset = + self.collectionView.contentInset = UIEdgeInsetsMake([self adjustedContentSuggestionsHeight], 0, 0, 0); self.contentSuggestionsHeightConstraint.constant = [self contentSuggestionsContentHeight]; @@ -564,13 +562,6 @@ [self contentSuggestionsContentHeight] + self.view.safeAreaInsets.top; } -// Content suggestions height adjusted with the safe area top insets. -- (CGFloat)adjustedContentSuggestionsHeight { - return self.contentSuggestionsViewController.collectionView.contentSize - .height + - self.view.safeAreaInsets.top; -} - // TODO(crbug.com/1170995): Remove once the Feed header properly supports // ContentSuggestions. - (void)handleSingleTapInView:(UITapGestureRecognizer*)recognizer { @@ -586,12 +577,45 @@ } } -// Sets the feed collection contentOffset to |offset| to set the initial scroll -// position. -- (void)setContentOffset:(CGFloat)offset { - self.discoverFeedWrapperViewController.feedCollectionView.contentOffset = - CGPointMake(0, offset); - self.scrolledIntoFeed = offset > kOffsetToPinOmnibox; +// Handles ownership of the fake omnibox view based on scroll position. +// If |force| is YES, the fake omnibox will always be set based on the scroll +// position. If |force| is NO, the fake omnibox will only based on +// |isScrolledIntoFeed| to prevent setting it multiple times. +- (void)handleFakeOmniboxForScrollPosition:(CGFloat)scrollPosition + force:(BOOL)force { + if ((!self.isScrolledIntoFeed || force) && + scrollPosition > -kOffsetToPinOmnibox) { + [self stickFakeOmniboxToTop]; + } else if ((self.isScrolledIntoFeed || force) && + scrollPosition <= -kOffsetToPinOmnibox) { + [self resetFakeOmnibox]; + } +} + +// Registers notifications for certain actions on the NTP. +- (void)registerNotifications { + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(deviceOrientationDidChange) + name:UIDeviceOrientationDidChangeNotification + object:nil]; +} + +// Handles device rotation. +- (void)deviceOrientationDidChange { + if (self.viewDidAppear) { + [self.discoverFeedMetricsRecorder + recordDeviceOrientationChanged:[[UIDevice currentDevice] orientation]]; + } +} + +#pragma mark - Helpers + +// Content suggestions height adjusted with the safe area top insets. +- (CGFloat)adjustedContentSuggestionsHeight { + return self.contentSuggestionsViewController.collectionView.contentSize + .height + + self.view.safeAreaInsets.top; } #pragma mark - Setters @@ -604,4 +628,11 @@ self.contentSuggestionsLayout.isScrolledIntoFeed = scrolledIntoFeed; } +// Sets the feed collection contentOffset to |offset| to set the initial scroll +// position. +- (void)setContentOffset:(CGFloat)offset { + self.collectionView.contentOffset = CGPointMake(0, offset); + self.scrolledIntoFeed = offset > kOffsetToPinOmnibox; +} + @end
diff --git a/ios/chrome/browser/ui/settings/google_services/BUILD.gn b/ios/chrome/browser/ui/settings/google_services/BUILD.gn index f5c08b0..61de477 100644 --- a/ios/chrome/browser/ui/settings/google_services/BUILD.gn +++ b/ios/chrome/browser/ui/settings/google_services/BUILD.gn
@@ -172,7 +172,10 @@ source_set("unit_tests") { configs += [ "//build/config/compiler:enable_arc" ] testonly = true - sources = [ "manage_sync_settings_mediator_unittest.mm" ] + sources = [ + "accounts_table_view_controller_unittest.mm", + "manage_sync_settings_mediator_unittest.mm", + ] deps = [ ":google_services", "//base/test:test_support", @@ -191,6 +194,7 @@ "//ios/chrome/browser/ui/settings/cells", "//ios/chrome/browser/ui/settings/google_services:constants", "//ios/chrome/browser/ui/table_view", + "//ios/chrome/browser/ui/table_view:test_support", "//ios/chrome/browser/ui/table_view/cells", "//ios/public/provider/chrome/browser/signin:fake_chrome_identity", "//ios/public/provider/chrome/browser/signin:test_support",
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm index 56ef58b..514c5d89 100644 --- a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm
@@ -237,9 +237,16 @@ NSString* authenticatedEmail = [authenticatedIdentity userEmail]; for (const auto& account : identityManager->GetAccountsWithRefreshTokens()) { - ChromeIdentity* identity = ios::GetChromeBrowserProvider() - ->GetChromeIdentityService() - ->GetIdentityWithGaiaID(account.gaia); + ios::ChromeIdentityService* identityService = + ios::GetChromeBrowserProvider()->GetChromeIdentityService(); + ChromeIdentity* identity = + identityService->GetIdentityWithGaiaID(account.gaia); + if (!identity) { + // Ignore the case in which the identity is invalid at lookup time. This + // may be due to inconsistencies between the identity service and + // ProfileOAuth2TokenService. + continue; + } // TODO(crbug.com/1081274): This re-ordering will be redundant once we // apply ordering changes to the account reconciler. TableViewItem* item = [self accountItem:identity];
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller_unittest.mm new file mode 100644 index 0000000..97bba11 --- /dev/null +++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller_unittest.mm
@@ -0,0 +1,114 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.h" + +#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#import "ios/chrome/browser/main/test_browser.h" +#import "ios/chrome/browser/signin/authentication_service_delegate_fake.h" +#import "ios/chrome/browser/signin/authentication_service_factory.h" +#import "ios/chrome/browser/signin/authentication_service_fake.h" +#import "ios/chrome/browser/signin/identity_manager_factory.h" +#import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h" +#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h" +#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h" +#import "ios/web/public/test/web_task_environment.h" +#import "testing/gtest/include/gtest/gtest.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +class AccountsTableViewControllerTest : public ChromeTableViewControllerTest { + public: + AccountsTableViewControllerTest() { + TestChromeBrowserState::Builder builder; + builder.AddTestingFactory( + AuthenticationServiceFactory::GetInstance(), + AuthenticationServiceFactory::GetDefaultFactory()); + browser_state_ = builder.Build(); + browser_ = std::make_unique<TestBrowser>(browser_state_.get()); + + AuthenticationServiceFactory::CreateAndInitializeForBrowserState( + browser_state_.get(), + std::make_unique<AuthenticationServiceDelegateFake>()); + } + + ChromeTableViewController* InstantiateController() override { + return [[AccountsTableViewController alloc] initWithBrowser:browser_.get() + closeSettingsOnAddAccount:NO]; + } + + // Identity Services + signin::IdentityManager* identity_manager() { + return IdentityManagerFactory::GetForBrowserState(browser_state_.get()); + } + + ios::FakeChromeIdentityService* identity_service() { + return ios::FakeChromeIdentityService::GetInstanceFromChromeProvider(); + } + + AuthenticationService* authentication_service() { + return AuthenticationServiceFactory::GetForBrowserState( + browser_state_.get()); + } + + private: + web::WebTaskEnvironment task_environment_; + std::unique_ptr<TestChromeBrowserState> browser_state_; + std::unique_ptr<Browser> browser_; +}; + +// Tests that a valid identity is added to the model. +TEST_F(AccountsTableViewControllerTest, AddChromeIdentity) { + FakeChromeIdentity* identity = + [FakeChromeIdentity identityWithEmail:@"foo1@gmail.com" + gaiaID:@"foo1ID" + name:@"Fake Foo 1"]; + identity_service()->AddIdentity(identity); + + // Simulates a credential reload. + authentication_service()->SignIn(identity); + identity_service()->FireChromeIdentityReload(); + base::RunLoop().RunUntilIdle(); + + CreateController(); + CheckController(); + + EXPECT_EQ(2, NumberOfSections()); + EXPECT_EQ(2, NumberOfItemsInSection(0)); +} + +// Tests that an invalid identity is not added to the model. +TEST_F(AccountsTableViewControllerTest, IgnoreMismatchWithAccountInfo) { + FakeChromeIdentity* identity1 = + [FakeChromeIdentity identityWithEmail:@"foo1@gmail.com" + gaiaID:@"foo1ID" + name:@"Fake Foo 1"]; + FakeChromeIdentity* identity2 = + [FakeChromeIdentity identityWithEmail:@"foo2@gmail.com" + gaiaID:@"foo2ID" + name:@"Fake Foo 2"]; + identity_service()->AddIdentity(identity1); + identity_service()->AddIdentity(identity2); + + // Simulates a credential reload. + authentication_service()->SignIn(identity1); + identity_service()->FireChromeIdentityReload(); + base::RunLoop().RunUntilIdle(); + + CreateController(); + CheckController(); + + EXPECT_EQ(2, NumberOfSections()); + EXPECT_EQ(3, NumberOfItemsInSection(0)); + + // Removes identity2 from identity service but not account info storage. + identity_service()->ForgetIdentity(identity2, nil); + + [controller() loadModel]; + + EXPECT_EQ(2, NumberOfSections()); + EXPECT_EQ(2, NumberOfItemsInSection(0)); +}
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_commands.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_commands.h index 0429a1d..51c545e6 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_commands.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_commands.h
@@ -27,6 +27,9 @@ // Tells the receiver to close the item with identifier |itemID|. If there is // no item with that identifier, no item is closed. - (void)closeItemWithID:(NSString*)itemID; +// Tells the receiver to close the items with the identifiers in |itemIDs|. +// ItemIDs which are not associated with any item are ignored. +- (void)closeItemsWithIDs:(NSArray<NSString*>*)itemIDs; // Tells the receiver to close all items. - (void)closeAllItems; // Tells the receiver to save all items for an undo operation, then close all @@ -42,6 +45,12 @@ // confirmation when 'Close All' button is tapped. - (void)showCloseAllConfirmationActionSheetWithAnchor: (UIBarButtonItem*)buttonAnchor; +// Shows an action sheet, anchored to the UIBarButtonItem, that asks for +// confirmation when 'Close Items' button is tapped. +- (void) + showCloseItemsConfirmationActionSheetWithItems:(NSArray<NSString*>*)items + anchor: + (UIBarButtonItem*)buttonAnchor; @end #endif // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_GRID_GRID_GRID_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.h index c492e49..4c8a4ed 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.h
@@ -53,6 +53,11 @@ // use undo or closeAll text on the close all button based on |useUndo| value. - (void)useUndoCloseAll:(BOOL)useUndo; +// Sets target/action for tapping event on close tabs button. +- (void)setCloseTabsButtonTarget:(id)target action:(SEL)action; +// Set |enabled| on the close tabs button. +- (void)setCloseTabsButtonEnabled:(BOOL)enabled; + // Hides components and uses a black background color for tab grid transition // animation. - (void)hide;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.mm index 161fb0e..0822399 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.mm
@@ -168,6 +168,17 @@ _largeNewTabButton.alpha = 1.0; } +#pragma mark Close Tabs + +- (void)setCloseTabsButtonTarget:(id)target action:(SEL)action { + _closeTabsButton.target = target; + _closeTabsButton.action = action; +} + +- (void)setCloseTabsButtonEnabled:(BOOL)enabled { + _closeTabsButton.enabled = enabled; +} + #pragma mark - Private - (void)setupViews {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm index 2fe6fe9..9dd95973 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -801,6 +801,52 @@ [self.actionSheetCoordinator start]; } +- (void) + showCloseItemsConfirmationActionSheetWithTabGridMediator: + (TabGridMediator*)tabGridMediator + items: + (NSArray<NSString*>*) + items + anchor:(UIBarButtonItem*) + buttonAnchor { + if (tabGridMediator == self.regularTabsMediator) { + base::RecordAction(base::UserMetricsAction( + "MobileTabGridSelectionCloseRegularTabsConfirmationPresented")); + } else { + base::RecordAction(base::UserMetricsAction( + "MobileTabGridSelectionCloseIncognitoTabsConfirmationPresented")); + } + + self.actionSheetCoordinator = [[ActionSheetCoordinator alloc] + initWithBaseViewController:self.baseViewController + browser:self.browser + title:nil + message:nil + barButtonItem:buttonAnchor]; + + self.actionSheetCoordinator.alertStyle = UIAlertControllerStyleActionSheet; + + [self.actionSheetCoordinator + addItemWithTitle:base::SysUTF16ToNSString( + l10n_util::GetPluralStringFUTF16( + IDS_IOS_TAB_GRID_CLOSE_ALL_TABS_CONFIRMATION, + items.count)) + action:^{ + base::RecordAction(base::UserMetricsAction( + "MobileTabGridSelectionCloseTabsConfirmed")); + [tabGridMediator closeItemsWithIDs:items]; + } + style:UIAlertActionStyleDestructive]; + [self.actionSheetCoordinator + addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL) + action:^{ + base::RecordAction(base::UserMetricsAction( + "MobileTabGridSelectionCloseTabsCanceled")); + } + style:UIAlertActionStyleCancel]; + [self.actionSheetCoordinator start]; +} + #pragma mark - TabGridViewControllerDelegate - (TabGridPage)activePageForTabGridViewController:
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm index fc25789..af7ebaa 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
@@ -359,6 +359,18 @@ [self waitForSnackBarMessage:IDS_IOS_BOOKMARK_PAGE_SAVED triggeredByTappingItemWithMatcher:AddToBookmarksButton()]; + + [self longPressTabWithTitle:[NSString stringWithUTF8String:kTitle1]]; + + [[EarlGrey + selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId( + IDS_IOS_TOOLS_MENU_EDIT_BOOKMARK)] + performAction:grey_tap()]; + + [[EarlGrey selectElementWithMatcher: + chrome_test_util::NavigationBarTitleWithAccessibilityLabelId( + IDS_IOS_BOOKMARK_EDIT_SCREEN_TITLE)] + assertWithMatcher:grey_notNil()]; } // Tests the Share action on a tab grid item's context menu. @@ -959,7 +971,6 @@ [ChromeEarlGrey watchForButtonsWithLabels:@[ snackBarLabel ] timeout:kSnackbarAppearanceTimeout]; - // Add the page to the reading list. [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()]; // Wait for the snackbar to appear.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.h index 31732a26..36efe95 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.h
@@ -33,6 +33,15 @@ anchor:(UIBarButtonItem*) buttonAnchor; +- (void) + showCloseItemsConfirmationActionSheetWithTabGridMediator: + (TabGridMediator*)tabGridMediator + items: + (NSArray<NSString*>*) + items + anchor:(UIBarButtonItem*) + buttonAnchor; + @end // Mediates between model layer and tab grid UI layer.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm index 9f47b089..0d6d878 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm
@@ -347,6 +347,31 @@ self.webStateList->CloseWebStateAt(index, WebStateList::CLOSE_USER_ACTION); } +- (void)closeItemsWithIDs:(NSArray<NSString*>*)itemIDs { + __block bool allTabsClosed = true; + + self.webStateList->PerformBatchOperation( + base::BindOnce(^(WebStateList* list) { + for (NSString* itemID in itemIDs) { + int index = GetIndexOfTabWithId(list, itemID); + if (index != WebStateList::kInvalidIndex) + list->CloseWebStateAt(index, WebStateList::CLOSE_USER_ACTION); + } + + allTabsClosed = list->empty(); + })); + + if (allTabsClosed) { + if (!self.browserState->IsOffTheRecord()) { + base::RecordAction(base::UserMetricsAction( + "MobileTabGridSelectionCloseAllRegularTabsConfirmed")); + } else { + base::RecordAction(base::UserMetricsAction( + "MobileTabGridSelectionCloseAllIncognitoTabsConfirmed")); + } + } +} + - (void)closeAllItems { if (!self.browserState->IsOffTheRecord()) { base::RecordAction( @@ -406,6 +431,16 @@ anchor:buttonAnchor]; } +- (void) + showCloseItemsConfirmationActionSheetWithItems:(NSArray<NSString*>*)items + anchor: + (UIBarButtonItem*)buttonAnchor { + [self.delegate + showCloseItemsConfirmationActionSheetWithTabGridMediator:self + items:items + anchor:buttonAnchor]; +} + #pragma mark GridCommands helpers - (void)insertNewItemAtIndex:(NSUInteger)index withURL:(const GURL&)newTabURL {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm index 105c9b1..898ca0c 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
@@ -1233,6 +1233,8 @@ [bottomToolbar setNewTabButtonTarget:self action:@selector(newTabButtonTapped:)]; + [bottomToolbar setCloseTabsButtonTarget:self + action:@selector(closeSelectedTabs:)]; NamedGuide* guide = [[NamedGuide alloc] initWithName:kTabGridBottomToolbarGuide]; @@ -1673,6 +1675,8 @@ [gridViewController.selectedItemIDsForEditing count]; self.topToolbar.selectedTabsCount = selectedItemsCount; self.bottomToolbar.selectedTabsCount = selectedItemsCount; + + [self.bottomToolbar setCloseAllButtonEnabled:selectedItemsCount > 0]; return; } @@ -1918,6 +1922,29 @@ } } +- (void)closeSelectedTabs:(id)sender { + GridViewController* gridViewController = + [self gridViewControllerForPage:self.currentPage]; + NSArray<NSString*>* items = gridViewController.selectedItemIDsForEditing; + + switch (self.currentPage) { + case TabGridPageIncognitoTabs: + [self.incognitoTabsDelegate + showCloseItemsConfirmationActionSheetWithItems:items + anchor:sender]; + break; + case TabGridPageRegularTabs: + [self.regularTabsDelegate + showCloseItemsConfirmationActionSheetWithItems:items + anchor:sender]; + break; + case TabGridPageRemoteTabs: + NOTREACHED() + << "It is invalid to call close selected tabs on remote tabs."; + break; + } +} + - (void)pageControlChangedValue:(id)sender { // Map the page control slider position (in the range 0.0-1.0) to an // x-offset for the scroll view.
diff --git a/ios/chrome/browser/web/window_open_by_dom_egtest.mm b/ios/chrome/browser/web/window_open_by_dom_egtest.mm index ef69740..96f7eff 100644 --- a/ios/chrome/browser/web/window_open_by_dom_egtest.mm +++ b/ios/chrome/browser/web/window_open_by_dom_egtest.mm
@@ -73,21 +73,6 @@ [ChromeEarlGrey waitForMainTabCount:1]; } -// Tests that sessionStorage content is available for windows opened by DOM via -// target="_blank" links. -- (void)testLinkWithBlankTargetSessionStorage { - [ChromeEarlGrey executeJavaScript:@"sessionStorage.setItem('key', 'value');"]; - [ChromeEarlGrey - tapWebStateElementWithID:@"webScenarioWindowOpenSameURLWithBlankTarget"]; - - [ChromeEarlGrey waitForMainTabCount:2]; - [ChromeEarlGrey waitForWebStateContainingText:"Expected result"]; - - id value = - [ChromeEarlGrey executeJavaScript:@"sessionStorage.getItem('key');"]; - GREYAssert([value isEqual:@"value"], @"sessionStorage is not shared"); -} - // Tests tapping a link with target="_blank". - (void)testLinkWithBlankTarget { [ChromeEarlGrey tapWebStateElementWithID:@"webScenarioWindowOpenRegularLink"];
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 e3ff8d6..95163ff 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 @@ -041508f78b487f7a69244c22a519e2fcab7d4720 \ No newline at end of file +db27534a1f1982b264c30f025a13938f30775529 \ 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 805d553e..0001341 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 @@ -c5ff51d65a91b4575edebd49a43882298bb3ec0b \ No newline at end of file +8ec3b475f7ad6a2b1eee68a1e1d87458d8553c61 \ 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 d0ade49..4e36b3f 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 @@ -ff27837cf2ea405e5d3d8ac71414f3adad840b27 \ No newline at end of file +52aafa848db89e76ffb122435900e6dab06f0554 \ 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 6b98e44..b015ebd 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 @@ -516e93b2cfdb950fe8c5ee4bed359d3e1b3cb8d5 \ No newline at end of file +917bcad8f02480b935cc9f483f300dfd71cbfc68 \ 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 874fea36..16ac527 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 @@ -6ce9802b2d7f4b294690dd7dacf0b523df3fcb63 \ No newline at end of file +cd3de94a261c4beed1cb61f1c1528cb1d5534973 \ 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 5984ab97..ac7ded9 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 @@ -e8d1d7b0db4659e2165614de15a6d58ad9432164 \ No newline at end of file +546a60a461cecf76d0eba9d2a8bf5bbf071709b0 \ 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 f2cc3f6..538c3098 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 @@ -5b74a7623d1e4a5cf8a855c5a080bd77e7a6148b \ No newline at end of file +83a057386168496578379167f8341b6b361d18d1 \ 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 c9cd1c0..d54da4b 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 @@ -fa8b1ba488fc6967b38f7e36d9c044aa08d8b126 \ No newline at end of file +260126f06f6ce0309388ede6542e05f17a6c3cdf \ 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 3ac90e6c5..b2423db 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 @@ -1ccd98517d7c0589303cbacc934a34fb9ff1516b \ No newline at end of file +e60bc785bc787fe854167e02d28a6582c74692df \ 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 ca468ce..b3911355 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 @@ -e8dd4551fdee459d7f6cf68100225785b75cea8b \ No newline at end of file +638d9e2423fd67768fab41ce1c46109453596358 \ No newline at end of file
diff --git a/ios/web/plugin_placeholder_inttest.mm b/ios/web/plugin_placeholder_inttest.mm index 602ebde..22c22204 100644 --- a/ios/web/plugin_placeholder_inttest.mm +++ b/ios/web/plugin_placeholder_inttest.mm
@@ -76,7 +76,8 @@ } // Tests placeholder for a large <applet> with no fallback. -TEST_F(PluginPlaceholderTest, AppletOnly) { +// TODO(crbug.com/1217175): Test failing on iOS 14.5. +TEST_F(PluginPlaceholderTest, DISABLED_AppletOnly) { const char kPageDescription[] = "Applet, no fallback"; const std::string page = base::StringPrintf("<html><body width='800' height='600'>"
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn index f25ebfc..1292144 100644 --- a/ios/web_view/BUILD.gn +++ b/ios/web_view/BUILD.gn
@@ -297,6 +297,7 @@ "//components/translate/ios/browser", "//components/unified_consent", "//components/url_formatter", + "//components/variations", "//components/variations/net", "//components/version_info", "//components/version_info:version_string",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS index fe5f733f..f6bc7b84 100644 --- a/ios/web_view/internal/DEPS +++ b/ios/web_view/internal/DEPS
@@ -37,7 +37,7 @@ "+components/language/ios", "+components/unified_consent", "+components/url_formatter", - "+components/variations/net", + "+components/variations", "+components/version_info", "+components/webdata_services", "+components/web_resource",
diff --git a/ios/web_view/internal/web_view_web_main_parts.mm b/ios/web_view/internal/web_view_web_main_parts.mm index 229bdf5..1cc9c0f 100644 --- a/ios/web_view/internal/web_view_web_main_parts.mm +++ b/ios/web_view/internal/web_view_web_main_parts.mm
@@ -12,6 +12,7 @@ #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_payments_features.h" #include "components/password_manager/core/common/password_manager_features.h" +#include "components/variations/variations_ids_provider.h" #include "ios/web/public/webui/web_ui_ios_controller_factory.h" #include "ios/web_view/internal/app/application_context.h" #import "ios/web_view/internal/cwv_flags_internal.h" @@ -50,6 +51,9 @@ ApplicationContext::GetInstance()->PreCreateThreads(); + variations::VariationsIdsProvider::Create( + variations::VariationsIdsProvider::Mode::kUseSignedInState); + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); std::string enable_features = base::JoinString( {
diff --git a/ios/web_view/test/BUILD.gn b/ios/web_view/test/BUILD.gn index 7a84ea7..7e926f8 100644 --- a/ios/web_view/test/BUILD.gn +++ b/ios/web_view/test/BUILD.gn
@@ -29,6 +29,8 @@ "//base/test:run_all_unittests", "//base/test:test_support", "//components/url_formatter", + "//components/variations", + "//components/variations:test_support", "//ios/third_party/webkit", "//ios/web_view:web_view+link", "//net",
diff --git a/ios/web_view/test/DEPS b/ios/web_view/test/DEPS index 5d5d2fa..2af3fb6c 100644 --- a/ios/web_view/test/DEPS +++ b/ios/web_view/test/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+base", "+components/url_formatter", + "+components/variations", "+ios/testing", "+ios/web_view/public", "+mojo/core/embedder",
diff --git a/ios/web_view/test/web_view_autofill_inttest.mm b/ios/web_view/test/web_view_autofill_inttest.mm index b429491..92ed24f 100644 --- a/ios/web_view/test/web_view_autofill_inttest.mm +++ b/ios/web_view/test/web_view_autofill_inttest.mm
@@ -7,6 +7,7 @@ #include "base/strings/sys_string_conversions.h" #import "base/test/ios/wait_util.h" +#include "components/variations/variations_ids_provider.h" #import "ios/web_view/public/cwv_navigation_delegate.h" #import "ios/web_view/test/web_view_inttest_base.h" #import "ios/web_view/test/web_view_test_util.h" @@ -168,6 +169,7 @@ // Tests that CWVAutofillControllerDelegate receives callbacks. TEST_F(WebViewAutofillTest, TestDelegateCallbacks) { + ASSERT_TRUE(variations::VariationsIdsProvider::GetInstance()); ASSERT_TRUE(test_server_->Start()); ASSERT_TRUE(LoadTestPage()); ASSERT_TRUE(SetFormFieldValue(kTestAddressFieldID, kTestAddressFieldValue));
diff --git a/ios/web_view/test/web_view_inttest_base.h b/ios/web_view/test/web_view_inttest_base.h index 65b19c9c..3a6336f 100644 --- a/ios/web_view/test/web_view_inttest_base.h +++ b/ios/web_view/test/web_view_inttest_base.h
@@ -9,6 +9,7 @@ #include <memory> #include <string> +#include "components/variations/scoped_variations_ids_provider.h" #include "testing/platform_test.h" NS_ASSUME_NONNULL_BEGIN @@ -56,6 +57,9 @@ // Call ASSERT_TRUE(test_server_->Start()) before accessing the returned URL. GURL GetUrlForPageWithHtml(const std::string& html); + variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ + variations::VariationsIdsProvider::Mode::kUseSignedInState}; + // CWVWebView created with default configuration and frame equal to screen // bounds. CWVWebView* web_view_;
diff --git a/media/gpu/v4l2/v4l2_framerate_control.cc b/media/gpu/v4l2/v4l2_framerate_control.cc index 6ba06543..e565704 100644 --- a/media/gpu/v4l2/v4l2_framerate_control.cc +++ b/media/gpu/v4l2/v4l2_framerate_control.cc
@@ -6,6 +6,29 @@ #include "base/sequence_checker.h" +namespace { + +bool FrameRateControlPresent(scoped_refptr<media::V4L2Device> device) { + DCHECK(device); + + struct v4l2_streamparm parms; + memset(&parms, 0, sizeof(parms)); + parms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + // Try to set the framerate to 30fps to see if the control is available. + // VIDIOC_G_PARM can not be used as it does not return the current framerate. + parms.parm.output.timeperframe.numerator = 30; + parms.parm.output.timeperframe.denominator = 1000L; + + if (device->Ioctl(VIDIOC_S_PARM, &parms) != 0) { + VLOG(1) << "Failed to issue VIDIOC_S_PARM command"; + return false; + } + + return parms.parm.output.capability & V4L2_CAP_TIMEPERFRAME; +} + +} // namespace namespace media { static constexpr int kMovingAverageWindowSize = 32; @@ -18,12 +41,14 @@ scoped_refptr<V4L2Device> device, scoped_refptr<base::SequencedTaskRunner> task_runner) : device_(device), - framerate_control_present_(FrameRateControlPresent()), + framerate_control_present_(FrameRateControlPresent(device)), current_frame_duration_avg_ms_(0), last_frame_display_time_(base::TimeTicks::Now()), frame_duration_moving_average_(kMovingAverageWindowSize), task_runner_(task_runner), - weak_this_factory_(this) {} + weak_this_factory_(this) { + DETACH_FROM_SEQUENCE(sequence_checker_); +} V4L2FrameRateControl::~V4L2FrameRateControl() = default; @@ -105,25 +130,4 @@ weak_this_factory_.GetWeakPtr(), task_runner_)); } -bool V4L2FrameRateControl::FrameRateControlPresent() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(device_); - - struct v4l2_streamparm parms; - memset(&parms, 0, sizeof(parms)); - parms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - - // Try to set the framerate to 30fps to see if the control is available. - // VIDIOC_G_PARM can not be used as it does not return the current framerate. - parms.parm.output.timeperframe.numerator = 30; - parms.parm.output.timeperframe.denominator = 1000L; - - if (device_->Ioctl(VIDIOC_S_PARM, &parms) != 0) { - VLOG(1) << "Failed to issue VIDIOC_S_PARM command"; - return false; - } - - return parms.parm.output.capability & V4L2_CAP_TIMEPERFRAME; -} - } // namespace media
diff --git a/media/gpu/v4l2/v4l2_framerate_control.h b/media/gpu/v4l2/v4l2_framerate_control.h index c82d5c99..2438a53 100644 --- a/media/gpu/v4l2/v4l2_framerate_control.h +++ b/media/gpu/v4l2/v4l2_framerate_control.h
@@ -42,7 +42,6 @@ private: void UpdateFrameRate(); - bool FrameRateControlPresent(); scoped_refptr<V4L2Device> device_; const bool framerate_control_present_;
diff --git a/media/gpu/vaapi/h264_encoder.cc b/media/gpu/vaapi/h264_encoder.cc index cf283aa..d1867f1 100644 --- a/media/gpu/vaapi/h264_encoder.cc +++ b/media/gpu/vaapi/h264_encoder.cc
@@ -4,9 +4,15 @@ #include "media/gpu/vaapi/h264_encoder.h" +#include <va/va.h> +#include <va/va_enc_h264.h> + #include "base/bits.h" #include "base/cxx17_backports.h" +#include "base/memory/ref_counted_memory.h" #include "media/gpu/macros.h" +#include "media/gpu/vaapi/vaapi_common.h" +#include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/video/h264_level_limits.h" namespace media { @@ -39,6 +45,46 @@ // 4:2:0 constexpr int kChromaFormatIDC = 1; + +void FillVAEncRateControlParams( + uint32_t bps, + uint32_t window_size, + uint32_t initial_qp, + uint32_t min_qp, + uint32_t max_qp, + uint32_t framerate, + uint32_t buffer_size, + VAEncMiscParameterRateControl& rate_control_param, + VAEncMiscParameterFrameRate& framerate_param, + VAEncMiscParameterHRD& hrd_param) { + memset(&rate_control_param, 0, sizeof(rate_control_param)); + rate_control_param.bits_per_second = bps; + rate_control_param.window_size = window_size; + rate_control_param.initial_qp = initial_qp; + rate_control_param.min_qp = min_qp; + rate_control_param.max_qp = max_qp; + rate_control_param.rc_flags.bits.disable_frame_skip = true; + + memset(&framerate_param, 0, sizeof(framerate_param)); + framerate_param.framerate = framerate; + + memset(&hrd_param, 0, sizeof(hrd_param)); + hrd_param.buffer_size = buffer_size; + hrd_param.initial_buffer_fullness = buffer_size / 2; +} + +static scoped_refptr<base::RefCountedBytes> MakeRefCountedBytes(void* ptr, + size_t size) { + return base::MakeRefCounted<base::RefCountedBytes>( + reinterpret_cast<uint8_t*>(ptr), size); +} + +static void InitVAPictureH264(VAPictureH264* va_pic) { + *va_pic = {}; + va_pic->picture_id = VA_INVALID_ID; + va_pic->flags = VA_PICTURE_H264_INVALID; +} + } // namespace H264Encoder::EncodeParams::EncodeParams() @@ -56,15 +102,14 @@ max_ref_pic_list0_size(kMaxRefIdxL0Size), max_ref_pic_list1_size(kMaxRefIdxL1Size) {} -H264Encoder::Accelerator::~Accelerator() = default; - -H264Encoder::H264Encoder(std::unique_ptr<Accelerator> accelerator) - : packed_sps_(new H264BitstreamBuffer()), - packed_pps_(new H264BitstreamBuffer()), - accelerator_(std::move(accelerator)) {} +H264Encoder::H264Encoder(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + base::RepeatingClosure error_cb) + : VaapiVideoEncoderDelegate(vaapi_wrapper, error_cb), + packed_sps_(new H264BitstreamBuffer()), + packed_pps_(new H264BitstreamBuffer()) {} H264Encoder::~H264Encoder() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // H264Encoder can be destroyed on any thread. } bool H264Encoder::Initialize( @@ -159,7 +204,7 @@ bool H264Encoder::PrepareEncodeJob(EncodeJob* encode_job) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - scoped_refptr<H264Picture> pic = accelerator_->GetPicture(encode_job); + scoped_refptr<H264Picture> pic = GetPicture(encode_job); DCHECK(pic); if (encode_job->IsKeyframeRequested() || encoding_parameters_changed_) @@ -200,9 +245,9 @@ << " frame_num: " << pic->frame_num << " POC: " << pic->pic_order_cnt; - if (!accelerator_->SubmitFrameParameters( - encode_job, curr_params_, current_sps_, current_pps_, pic, - ref_pic_list0_, std::list<scoped_refptr<H264Picture>>())) { + if (!SubmitFrameParameters(encode_job, curr_params_, current_sps_, + current_pps_, pic, ref_pic_list0_, + std::list<scoped_refptr<H264Picture>>())) { DVLOGF(1) << "Failed submitting frame parameters"; return false; } @@ -210,8 +255,7 @@ if (pic->type == H264SliceHeader::kISlice) { // We always generate SPS and PPS with I(DR) frame. This will help for Seek // operation on the generated stream. - if (!accelerator_->SubmitPackedHeaders(encode_job, packed_sps_, - packed_pps_)) { + if (!SubmitPackedHeaders(encode_job, packed_sps_, packed_pps_)) { DVLOGF(1) << "Failed submitting keyframe headers"; return false; } @@ -270,6 +314,8 @@ } void H264Encoder::UpdateSPS() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + memset(¤t_sps_, 0, sizeof(H264SPS)); // Spec A.2 and A.3. @@ -371,6 +417,8 @@ } void H264Encoder::UpdatePPS() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + memset(¤t_pps_, 0, sizeof(H264PPS)); current_pps_.seq_parameter_set_id = current_sps_.seq_parameter_set_id; @@ -398,6 +446,8 @@ } void H264Encoder::GeneratePackedSPS() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + packed_sps_->Reset(); packed_sps_->BeginNALU(H264NALU::kSPS, 3); @@ -511,6 +561,8 @@ } void H264Encoder::GeneratePackedPPS() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + packed_pps_->Reset(); packed_pps_->BeginNALU(H264NALU::kPPS, 3); @@ -545,4 +597,229 @@ packed_pps_->FinishNALU(); } +void H264Encoder::SubmitH264BitstreamBuffer( + scoped_refptr<H264BitstreamBuffer> buffer) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderDataBufferType, + buffer->BytesInBuffer(), buffer->data())) { + error_cb_.Run(); + } +} + +bool H264Encoder::SubmitFrameParameters( + VaapiVideoEncoderDelegate::EncodeJob* job, + const H264Encoder::EncodeParams& encode_params, + const H264SPS& sps, + const H264PPS& pps, + scoped_refptr<H264Picture> pic, + const std::list<scoped_refptr<H264Picture>>& ref_pic_list0, + const std::list<scoped_refptr<H264Picture>>& ref_pic_list1) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + VAEncSequenceParameterBufferH264 seq_param = {}; + +#define SPS_TO_SP(a) seq_param.a = sps.a; + SPS_TO_SP(seq_parameter_set_id); + SPS_TO_SP(level_idc); + + seq_param.intra_period = encode_params.i_period_frames; + seq_param.intra_idr_period = encode_params.idr_period_frames; + seq_param.ip_period = encode_params.ip_period_frames; + seq_param.bits_per_second = encode_params.bitrate_bps; + + SPS_TO_SP(max_num_ref_frames); + absl::optional<gfx::Size> coded_size = sps.GetCodedSize(); + if (!coded_size) { + DVLOGF(1) << "Invalid coded size"; + return false; + } + constexpr int kH264MacroblockSizeInPixels = 16; + seq_param.picture_width_in_mbs = + coded_size->width() / kH264MacroblockSizeInPixels; + seq_param.picture_height_in_mbs = + coded_size->height() / kH264MacroblockSizeInPixels; + +#define SPS_TO_SP_FS(a) seq_param.seq_fields.bits.a = sps.a; + SPS_TO_SP_FS(chroma_format_idc); + SPS_TO_SP_FS(frame_mbs_only_flag); + SPS_TO_SP_FS(log2_max_frame_num_minus4); + SPS_TO_SP_FS(pic_order_cnt_type); + SPS_TO_SP_FS(log2_max_pic_order_cnt_lsb_minus4); +#undef SPS_TO_SP_FS + + SPS_TO_SP(bit_depth_luma_minus8); + SPS_TO_SP(bit_depth_chroma_minus8); + + SPS_TO_SP(frame_cropping_flag); + if (sps.frame_cropping_flag) { + SPS_TO_SP(frame_crop_left_offset); + SPS_TO_SP(frame_crop_right_offset); + SPS_TO_SP(frame_crop_top_offset); + SPS_TO_SP(frame_crop_bottom_offset); + } + + SPS_TO_SP(vui_parameters_present_flag); +#define SPS_TO_SP_VF(a) seq_param.vui_fields.bits.a = sps.a; + SPS_TO_SP_VF(timing_info_present_flag); +#undef SPS_TO_SP_VF + SPS_TO_SP(num_units_in_tick); + SPS_TO_SP(time_scale); +#undef SPS_TO_SP + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitBuffer, + base::Unretained(this), VAEncSequenceParameterBufferType, + MakeRefCountedBytes(&seq_param, sizeof(seq_param)))); + + VAEncPictureParameterBufferH264 pic_param = {}; + + auto va_surface_id = pic->AsVaapiH264Picture()->GetVASurfaceID(); + pic_param.CurrPic.picture_id = va_surface_id; + pic_param.CurrPic.TopFieldOrderCnt = pic->top_field_order_cnt; + pic_param.CurrPic.BottomFieldOrderCnt = pic->bottom_field_order_cnt; + pic_param.CurrPic.flags = 0; + + pic_param.coded_buf = job->coded_buffer_id(); + pic_param.pic_parameter_set_id = pps.pic_parameter_set_id; + pic_param.seq_parameter_set_id = pps.seq_parameter_set_id; + pic_param.frame_num = pic->frame_num; + pic_param.pic_init_qp = pps.pic_init_qp_minus26 + 26; + pic_param.num_ref_idx_l0_active_minus1 = + pps.num_ref_idx_l0_default_active_minus1; + + pic_param.pic_fields.bits.idr_pic_flag = pic->idr; + pic_param.pic_fields.bits.reference_pic_flag = pic->ref; +#define PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps.a; + PPS_TO_PP_PF(entropy_coding_mode_flag); + PPS_TO_PP_PF(transform_8x8_mode_flag); + PPS_TO_PP_PF(deblocking_filter_control_present_flag); +#undef PPS_TO_PP_PF + + VAEncSliceParameterBufferH264 slice_param = {}; + + slice_param.num_macroblocks = + seq_param.picture_width_in_mbs * seq_param.picture_height_in_mbs; + slice_param.macroblock_info = VA_INVALID_ID; + slice_param.slice_type = pic->type; + slice_param.pic_parameter_set_id = pps.pic_parameter_set_id; + slice_param.idr_pic_id = pic->idr_pic_id; + slice_param.pic_order_cnt_lsb = pic->pic_order_cnt_lsb; + slice_param.num_ref_idx_active_override_flag = true; + + for (size_t i = 0; i < base::size(pic_param.ReferenceFrames); ++i) + InitVAPictureH264(&pic_param.ReferenceFrames[i]); + + for (size_t i = 0; i < base::size(slice_param.RefPicList0); ++i) + InitVAPictureH264(&slice_param.RefPicList0[i]); + + for (size_t i = 0; i < base::size(slice_param.RefPicList1); ++i) + InitVAPictureH264(&slice_param.RefPicList1[i]); + + VAPictureH264* ref_frames_entry = pic_param.ReferenceFrames; + VAPictureH264* ref_list_entry = slice_param.RefPicList0; + // Initialize the current entry on slice and picture reference lists to + // |ref_pic| and advance list pointers. + auto fill_ref_frame = [&ref_frames_entry, + &ref_list_entry](scoped_refptr<H264Picture> ref_pic) { + VAPictureH264 va_pic_h264; + InitVAPictureH264(&va_pic_h264); + va_pic_h264.picture_id = ref_pic->AsVaapiH264Picture()->GetVASurfaceID(); + va_pic_h264.flags = 0; + + *ref_frames_entry = va_pic_h264; + *ref_list_entry = va_pic_h264; + ++ref_frames_entry; + ++ref_list_entry; + }; + + // Fill slice_param.RefPicList{0,1} with pictures from ref_pic_list{0,1}, + // respectively, and pic_param.ReferenceFrames with entries from both. + std::for_each(ref_pic_list0.begin(), ref_pic_list0.end(), fill_ref_frame); + ref_list_entry = slice_param.RefPicList1; + std::for_each(ref_pic_list1.begin(), ref_pic_list1.end(), fill_ref_frame); + + VAEncMiscParameterRateControl rate_control_param; + VAEncMiscParameterFrameRate framerate_param; + VAEncMiscParameterHRD hrd_param; + FillVAEncRateControlParams( + encode_params.bitrate_bps, + base::strict_cast<uint32_t>(encode_params.cpb_window_size_ms), + base::strict_cast<uint32_t>(pic_param.pic_init_qp), + base::strict_cast<uint32_t>(encode_params.min_qp), + base::strict_cast<uint32_t>(encode_params.max_qp), + encode_params.framerate, + base::strict_cast<uint32_t>(encode_params.cpb_size_bits), + rate_control_param, framerate_param, hrd_param); + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitBuffer, + base::Unretained(this), VAEncPictureParameterBufferType, + MakeRefCountedBytes(&pic_param, sizeof(pic_param)))); + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitBuffer, + base::Unretained(this), VAEncSliceParameterBufferType, + MakeRefCountedBytes(&slice_param, sizeof(slice_param)))); + + job->AddSetupCallback(base::BindOnce( + &VaapiVideoEncoderDelegate::SubmitVAEncMiscParamBuffer, + base::Unretained(this), VAEncMiscParameterTypeRateControl, + MakeRefCountedBytes(&rate_control_param, sizeof(rate_control_param)))); + + job->AddSetupCallback(base::BindOnce( + &VaapiVideoEncoderDelegate::SubmitVAEncMiscParamBuffer, + base::Unretained(this), VAEncMiscParameterTypeFrameRate, + MakeRefCountedBytes(&framerate_param, sizeof(framerate_param)))); + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitVAEncMiscParamBuffer, + base::Unretained(this), VAEncMiscParameterTypeHRD, + MakeRefCountedBytes(&hrd_param, sizeof(hrd_param)))); + + return true; +} + +scoped_refptr<H264Picture> H264Encoder::GetPicture(EncodeJob* job) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + return base::WrapRefCounted( + reinterpret_cast<H264Picture*>(job->picture().get())); +} + +bool H264Encoder::SubmitPackedHeaders( + EncodeJob* job, + scoped_refptr<H264BitstreamBuffer> packed_sps, + scoped_refptr<H264BitstreamBuffer> packed_pps) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Submit SPS. + VAEncPackedHeaderParameterBuffer par_buffer = {}; + par_buffer.type = VAEncPackedHeaderSequence; + par_buffer.bit_length = packed_sps->BytesInBuffer() * 8; + + job->AddSetupCallback(base::BindOnce( + &VaapiVideoEncoderDelegate::SubmitBuffer, base::Unretained(this), + VAEncPackedHeaderParameterBufferType, + MakeRefCountedBytes(&par_buffer, sizeof(par_buffer)))); + + job->AddSetupCallback(base::BindOnce(&H264Encoder::SubmitH264BitstreamBuffer, + base::Unretained(this), packed_sps)); + + // Submit PPS. + par_buffer = {}; + par_buffer.type = VAEncPackedHeaderPicture; + par_buffer.bit_length = packed_pps->BytesInBuffer() * 8; + + job->AddSetupCallback(base::BindOnce( + &VaapiVideoEncoderDelegate::SubmitBuffer, base::Unretained(this), + VAEncPackedHeaderParameterBufferType, + MakeRefCountedBytes(&par_buffer, sizeof(par_buffer)))); + + job->AddSetupCallback(base::BindOnce(&H264Encoder::SubmitH264BitstreamBuffer, + base::Unretained(this), packed_pps)); + + return true; +} + } // namespace media
diff --git a/media/gpu/vaapi/h264_encoder.h b/media/gpu/vaapi/h264_encoder.h index 19b1902..712b6037 100644 --- a/media/gpu/vaapi/h264_encoder.h +++ b/media/gpu/vaapi/h264_encoder.h
@@ -9,12 +9,12 @@ #include <list> #include "base/macros.h" -#include "base/sequence_checker.h" #include "media/filters/h264_bitstream_buffer.h" #include "media/gpu/h264_dpb.h" #include "media/gpu/vaapi/vaapi_video_encoder_delegate.h" namespace media { +class VaapiWrapper; // This class provides an H264 encoder functionality, generating stream headers, // managing encoder state, reference frames, and other codec parameters, while @@ -68,41 +68,8 @@ size_t max_ref_pic_list1_size; }; - // An accelerator interface. The client must provide an appropriate - // implementation on creation. - class Accelerator { - public: - Accelerator() = default; - virtual ~Accelerator(); - - // Returns the H264Picture to be used as output for |job|. - virtual scoped_refptr<H264Picture> GetPicture(EncodeJob* job) = 0; - - // Initializes |job| to insert the provided |packed_sps| and |packed_pps| - // before the frame produced by |job| into the output video stream. - virtual bool SubmitPackedHeaders( - EncodeJob* job, - scoped_refptr<H264BitstreamBuffer> packed_sps, - scoped_refptr<H264BitstreamBuffer> packed_pps) = 0; - - // Initializes |job| to use the provided |sps|, |pps|, |encode_params|, and - // encoded picture parameters in |pic|, as well as |ref_pic_list0| and - // |ref_pic_list1| as the corresponding H264 reference frame lists - // (RefPicList0 and RefPicList1 per spec) for the frame to be produced. - virtual bool SubmitFrameParameters( - EncodeJob* job, - const H264Encoder::EncodeParams& encode_params, - const H264SPS& sps, - const H264PPS& pps, - scoped_refptr<H264Picture> pic, - const std::list<scoped_refptr<H264Picture>>& ref_pic_list0, - const std::list<scoped_refptr<H264Picture>>& ref_pic_list1) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Accelerator); - }; - - explicit H264Encoder(std::unique_ptr<Accelerator> accelerator); + H264Encoder(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + base::RepeatingClosure error_cb); ~H264Encoder() override; // VaapiVideoEncoderDelegate implementation. @@ -130,6 +97,24 @@ // current profile and level. bool CheckConfigValidity(uint32_t bitrate, uint32_t framerate); + // Submits a H264BitstreamBuffer |buffer| to the driver. + void SubmitH264BitstreamBuffer(scoped_refptr<H264BitstreamBuffer> buffer); + + scoped_refptr<H264Picture> GetPicture(EncodeJob* job); + + bool SubmitPackedHeaders(EncodeJob* job, + scoped_refptr<H264BitstreamBuffer> packed_sps, + scoped_refptr<H264BitstreamBuffer> packed_pps); + + bool SubmitFrameParameters( + EncodeJob* job, + const H264Encoder::EncodeParams& encode_params, + const H264SPS& sps, + const H264PPS& pps, + scoped_refptr<H264Picture> pic, + const std::list<scoped_refptr<H264Picture>>& ref_pic_list0, + const std::list<scoped_refptr<H264Picture>>& ref_pic_list1); + // Current SPS, PPS and their packed versions. Packed versions are NALUs // in AnnexB format *without* emulation prevention three-byte sequences // (those are expected to be added by the client as needed). @@ -169,10 +154,6 @@ // RefPicList0 per spec (spec section 8.2.4.2). std::list<scoped_refptr<H264Picture>> ref_pic_list0_; - // Accelerator instance used to prepare encode jobs. - const std::unique_ptr<Accelerator> accelerator_; - - SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(H264Encoder); };
diff --git a/media/gpu/vaapi/h264_encoder_unittest.cc b/media/gpu/vaapi/h264_encoder_unittest.cc index c24b9cbc..b8ad924 100644 --- a/media/gpu/vaapi/h264_encoder_unittest.cc +++ b/media/gpu/vaapi/h264_encoder_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "media/gpu/vaapi/vaapi_wrapper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -30,25 +31,14 @@ VideoEncodeAccelerator::Config::StorageType::kShmem, VideoEncodeAccelerator::Config::ContentType::kCamera); -class MockH264Accelerator : public H264Encoder::Accelerator { +class MockVaapiWrapper : public VaapiWrapper { public: - MockH264Accelerator() = default; - MOCK_METHOD1( - GetPicture, - scoped_refptr<H264Picture>(VaapiVideoEncoderDelegate::EncodeJob* job)); - MOCK_METHOD3(SubmitPackedHeaders, - bool(VaapiVideoEncoderDelegate::EncodeJob*, - scoped_refptr<H264BitstreamBuffer>, - scoped_refptr<H264BitstreamBuffer>)); - MOCK_METHOD7(SubmitFrameParameters, - bool(VaapiVideoEncoderDelegate::EncodeJob*, - const H264Encoder::EncodeParams&, - const H264SPS&, - const H264PPS&, - scoped_refptr<H264Picture>, - const std::list<scoped_refptr<H264Picture>>&, - const std::list<scoped_refptr<H264Picture>>&)); + MockVaapiWrapper() : VaapiWrapper(kEncode) {} + + protected: + ~MockVaapiWrapper() override = default; }; + } // namespace class H264EncoderTest : public ::testing::Test { @@ -58,25 +48,21 @@ void ExpectLevel(uint8_t level) { EXPECT_EQ(encoder_->level_, level); } + MOCK_METHOD0(OnError, void()); + protected: std::unique_ptr<H264Encoder> encoder_; - MockH264Accelerator* accelerator_; + scoped_refptr<MockVaapiWrapper> mock_vaapi_wrapper_; }; void H264EncoderTest::SetUp() { - auto mock_accelerator = std::make_unique<MockH264Accelerator>(); - accelerator_ = mock_accelerator.get(); - encoder_ = std::make_unique<H264Encoder>(std::move(mock_accelerator)); + mock_vaapi_wrapper_ = base::MakeRefCounted<MockVaapiWrapper>(); + ASSERT_TRUE(mock_vaapi_wrapper_); - // Set default behaviors for mock methods for convenience. - ON_CALL(*accelerator_, GetPicture(_)) - .WillByDefault(Invoke([](VaapiVideoEncoderDelegate::EncodeJob*) { - return new H264Picture(); - })); - ON_CALL(*accelerator_, SubmitPackedHeaders(_, _, _)) - .WillByDefault(Return(true)); - ON_CALL(*accelerator_, SubmitFrameParameters(_, _, _, _, _, _, _)) - .WillByDefault(Return(true)); + encoder_ = std::make_unique<H264Encoder>( + mock_vaapi_wrapper_, + base::BindRepeating(&H264EncoderTest::OnError, base::Unretained(this))); + EXPECT_CALL(*this, OnError()).Times(0); } TEST_F(H264EncoderTest, Initialize) {
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc index c62978da..9c3658e 100644 --- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc +++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -140,79 +140,6 @@ return VaapiWrapper::GetSupportedEncodeProfiles(); } -class VaapiVideoEncodeAccelerator::H264Accelerator - : public H264Encoder::Accelerator { - public: - explicit H264Accelerator(VaapiVideoEncodeAccelerator* vea) : vea_(vea) {} - - ~H264Accelerator() override = default; - - // H264Encoder::Accelerator implementation. - scoped_refptr<H264Picture> GetPicture( - VaapiVideoEncoderDelegate::EncodeJob* job) override; - - bool SubmitPackedHeaders( - VaapiVideoEncoderDelegate::EncodeJob* job, - scoped_refptr<H264BitstreamBuffer> packed_sps, - scoped_refptr<H264BitstreamBuffer> packed_pps) override; - - bool SubmitFrameParameters( - VaapiVideoEncoderDelegate::EncodeJob* job, - const H264Encoder::EncodeParams& encode_params, - const H264SPS& sps, - const H264PPS& pps, - scoped_refptr<H264Picture> pic, - const std::list<scoped_refptr<H264Picture>>& ref_pic_list0, - const std::list<scoped_refptr<H264Picture>>& ref_pic_list1) override; - - private: - VaapiVideoEncodeAccelerator* const vea_; -}; - -class VaapiVideoEncodeAccelerator::VP8Accelerator - : public VP8Encoder::Accelerator { - public: - explicit VP8Accelerator(VaapiVideoEncodeAccelerator* vea) : vea_(vea) {} - - ~VP8Accelerator() override = default; - - // VP8Encoder::Accelerator implementation. - scoped_refptr<VP8Picture> GetPicture( - VaapiVideoEncoderDelegate::EncodeJob* job) override; - - bool SubmitFrameParameters(VaapiVideoEncoderDelegate::EncodeJob* job, - const VP8Encoder::EncodeParams& encode_params, - scoped_refptr<VP8Picture> pic, - const Vp8ReferenceFrameVector& ref_frames, - const std::array<bool, kNumVp8ReferenceBuffers>& - ref_frames_used) override; - - private: - VaapiVideoEncodeAccelerator* const vea_; -}; - -class VaapiVideoEncodeAccelerator::VP9Accelerator - : public VP9Encoder::Accelerator { - public: - explicit VP9Accelerator(VaapiVideoEncodeAccelerator* vea) : vea_(vea) {} - - ~VP9Accelerator() override = default; - - // VP9Encoder::Accelerator implementation. - scoped_refptr<VP9Picture> GetPicture( - VaapiVideoEncoderDelegate::EncodeJob* job) override; - - bool SubmitFrameParameters( - VaapiVideoEncoderDelegate::EncodeJob* job, - const VP9Encoder::EncodeParams& encode_params, - scoped_refptr<VP9Picture> pic, - const Vp9ReferenceFrameVector& ref_frames, - const std::array<bool, kVp9NumRefsPerFrame>& ref_frames_used) override; - - private: - VaapiVideoEncodeAccelerator* const vea_; -}; - VaapiVideoEncodeAccelerator::VaapiVideoEncodeAccelerator() : output_buffer_byte_size_(0), state_(kUninitialized), @@ -344,28 +271,33 @@ output_codec_ = VideoCodecProfileToVideoCodec(config.output_profile); VaapiVideoEncoderDelegate::Config ave_config{}; DCHECK_EQ(IsConfiguredForTesting(), !!encoder_); + // Base::Unretained(this) is safe because |error_cb| is called by + // |encoder_| and |this| outlives |encoder_|. + auto error_cb = base::BindRepeating( + [](VaapiVideoEncodeAccelerator* const vea) { + vea->SetState(kError); + vea->NotifyError(kPlatformFailureError); + }, + base::Unretained(this)); switch (output_codec_) { case kCodecH264: - if (!IsConfiguredForTesting()) { - encoder_ = std::make_unique<H264Encoder>( - std::make_unique<H264Accelerator>(this)); - } + if (!IsConfiguredForTesting()) + encoder_ = std::make_unique<H264Encoder>(vaapi_wrapper_, error_cb); + DCHECK_EQ(ave_config.bitrate_control, VaapiVideoEncoderDelegate::BitrateControl::kConstantBitrate); break; case kCodecVP8: - if (!IsConfiguredForTesting()) { - encoder_ = std::make_unique<VP8Encoder>( - std::make_unique<VP8Accelerator>(this)); - } + if (!IsConfiguredForTesting()) + encoder_ = std::make_unique<VP8Encoder>(vaapi_wrapper_, error_cb); + DCHECK_EQ(ave_config.bitrate_control, VaapiVideoEncoderDelegate::BitrateControl::kConstantBitrate); break; case kCodecVP9: - if (!IsConfiguredForTesting()) { - encoder_ = std::make_unique<VP9Encoder>( - std::make_unique<VP9Accelerator>(this)); - } + if (!IsConfiguredForTesting()) + encoder_ = std::make_unique<VP9Encoder>(vaapi_wrapper_, error_cb); + ave_config.bitrate_control = VaapiVideoEncoderDelegate::BitrateControl:: kConstantQuantizationParameter; break; @@ -500,57 +432,6 @@ NOTIFY_ERROR(kPlatformFailureError, "Failed to upload frame"); } -void VaapiVideoEncodeAccelerator::SubmitBuffer( - VABufferType type, - scoped_refptr<base::RefCountedBytes> buffer) { - DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); - - if (!vaapi_wrapper_->SubmitBuffer(type, buffer->size(), buffer->front())) - NOTIFY_ERROR(kPlatformFailureError, "Failed submitting a buffer"); -} - -void VaapiVideoEncodeAccelerator::SubmitVAEncMiscParamBuffer( - VAEncMiscParameterType type, - scoped_refptr<base::RefCountedBytes> buffer) { - DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); - - const size_t temp_size = sizeof(VAEncMiscParameterBuffer) + buffer->size(); - std::vector<uint8_t> temp(temp_size); - - auto* const va_buffer = - reinterpret_cast<VAEncMiscParameterBuffer*>(temp.data()); - va_buffer->type = type; - memcpy(va_buffer->data, buffer->front(), buffer->size()); - - if (!vaapi_wrapper_->SubmitBuffer(VAEncMiscParameterBufferType, temp_size, - temp.data())) { - NOTIFY_ERROR(kPlatformFailureError, "Failed submitting a buffer"); - } -} - -void VaapiVideoEncodeAccelerator::SubmitH264BitstreamBuffer( - scoped_refptr<H264BitstreamBuffer> buffer) { - DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); - - if (!vaapi_wrapper_->SubmitBuffer(VAEncPackedHeaderDataBufferType, - buffer->BytesInBuffer(), buffer->data())) { - NOTIFY_ERROR(kPlatformFailureError, "Failed submitting a bitstream buffer"); - } -} - -void VaapiVideoEncodeAccelerator::NotifyEncodedChunkSize( - VABufferID buffer_id, - VASurfaceID sync_surface_id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); - const uint64_t encoded_chunk_size = - vaapi_wrapper_->GetEncodedChunkSize(buffer_id, sync_surface_id); - if (encoded_chunk_size == 0) - NOTIFY_ERROR(kPlatformFailureError, "Failed getting an encoded chunksize"); - - DCHECK(encoder_); - encoder_->BitrateControlUpdate(encoded_chunk_size); -} - void VaapiVideoEncodeAccelerator::TryToReturnBitstreamBuffer() { DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); @@ -1005,514 +886,4 @@ } } -static void InitVAPictureH264(VAPictureH264* va_pic) { - *va_pic = {}; - va_pic->picture_id = VA_INVALID_ID; - va_pic->flags = VA_PICTURE_H264_INVALID; -} - -static scoped_refptr<base::RefCountedBytes> MakeRefCountedBytes(void* ptr, - size_t size) { - return base::MakeRefCounted<base::RefCountedBytes>( - reinterpret_cast<uint8_t*>(ptr), size); -} - -bool VaapiVideoEncodeAccelerator::H264Accelerator::SubmitFrameParameters( - VaapiVideoEncoderDelegate::EncodeJob* job, - const H264Encoder::EncodeParams& encode_params, - const H264SPS& sps, - const H264PPS& pps, - scoped_refptr<H264Picture> pic, - const std::list<scoped_refptr<H264Picture>>& ref_pic_list0, - const std::list<scoped_refptr<H264Picture>>& ref_pic_list1) { - VAEncSequenceParameterBufferH264 seq_param = {}; - -#define SPS_TO_SP(a) seq_param.a = sps.a; - SPS_TO_SP(seq_parameter_set_id); - SPS_TO_SP(level_idc); - - seq_param.intra_period = encode_params.i_period_frames; - seq_param.intra_idr_period = encode_params.idr_period_frames; - seq_param.ip_period = encode_params.ip_period_frames; - seq_param.bits_per_second = encode_params.bitrate_bps; - - SPS_TO_SP(max_num_ref_frames); - absl::optional<gfx::Size> coded_size = sps.GetCodedSize(); - if (!coded_size) { - DVLOGF(1) << "Invalid coded size"; - return false; - } - constexpr int kH264MacroblockSizeInPixels = 16; - seq_param.picture_width_in_mbs = - coded_size->width() / kH264MacroblockSizeInPixels; - seq_param.picture_height_in_mbs = - coded_size->height() / kH264MacroblockSizeInPixels; - -#define SPS_TO_SP_FS(a) seq_param.seq_fields.bits.a = sps.a; - SPS_TO_SP_FS(chroma_format_idc); - SPS_TO_SP_FS(frame_mbs_only_flag); - SPS_TO_SP_FS(log2_max_frame_num_minus4); - SPS_TO_SP_FS(pic_order_cnt_type); - SPS_TO_SP_FS(log2_max_pic_order_cnt_lsb_minus4); -#undef SPS_TO_SP_FS - - SPS_TO_SP(bit_depth_luma_minus8); - SPS_TO_SP(bit_depth_chroma_minus8); - - SPS_TO_SP(frame_cropping_flag); - if (sps.frame_cropping_flag) { - SPS_TO_SP(frame_crop_left_offset); - SPS_TO_SP(frame_crop_right_offset); - SPS_TO_SP(frame_crop_top_offset); - SPS_TO_SP(frame_crop_bottom_offset); - } - - SPS_TO_SP(vui_parameters_present_flag); -#define SPS_TO_SP_VF(a) seq_param.vui_fields.bits.a = sps.a; - SPS_TO_SP_VF(timing_info_present_flag); -#undef SPS_TO_SP_VF - SPS_TO_SP(num_units_in_tick); - SPS_TO_SP(time_scale); -#undef SPS_TO_SP - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitBuffer, - base::Unretained(vea_), VAEncSequenceParameterBufferType, - MakeRefCountedBytes(&seq_param, sizeof(seq_param)))); - - VAEncPictureParameterBufferH264 pic_param = {}; - - auto va_surface_id = pic->AsVaapiH264Picture()->GetVASurfaceID(); - pic_param.CurrPic.picture_id = va_surface_id; - pic_param.CurrPic.TopFieldOrderCnt = pic->top_field_order_cnt; - pic_param.CurrPic.BottomFieldOrderCnt = pic->bottom_field_order_cnt; - pic_param.CurrPic.flags = 0; - - pic_param.coded_buf = job->coded_buffer_id(); - pic_param.pic_parameter_set_id = pps.pic_parameter_set_id; - pic_param.seq_parameter_set_id = pps.seq_parameter_set_id; - pic_param.frame_num = pic->frame_num; - pic_param.pic_init_qp = pps.pic_init_qp_minus26 + 26; - pic_param.num_ref_idx_l0_active_minus1 = - pps.num_ref_idx_l0_default_active_minus1; - - pic_param.pic_fields.bits.idr_pic_flag = pic->idr; - pic_param.pic_fields.bits.reference_pic_flag = pic->ref; -#define PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps.a; - PPS_TO_PP_PF(entropy_coding_mode_flag); - PPS_TO_PP_PF(transform_8x8_mode_flag); - PPS_TO_PP_PF(deblocking_filter_control_present_flag); -#undef PPS_TO_PP_PF - - VAEncSliceParameterBufferH264 slice_param = {}; - - slice_param.num_macroblocks = - seq_param.picture_width_in_mbs * seq_param.picture_height_in_mbs; - slice_param.macroblock_info = VA_INVALID_ID; - slice_param.slice_type = pic->type; - slice_param.pic_parameter_set_id = pps.pic_parameter_set_id; - slice_param.idr_pic_id = pic->idr_pic_id; - slice_param.pic_order_cnt_lsb = pic->pic_order_cnt_lsb; - slice_param.num_ref_idx_active_override_flag = true; - - for (size_t i = 0; i < base::size(pic_param.ReferenceFrames); ++i) - InitVAPictureH264(&pic_param.ReferenceFrames[i]); - - for (size_t i = 0; i < base::size(slice_param.RefPicList0); ++i) - InitVAPictureH264(&slice_param.RefPicList0[i]); - - for (size_t i = 0; i < base::size(slice_param.RefPicList1); ++i) - InitVAPictureH264(&slice_param.RefPicList1[i]); - - VAPictureH264* ref_frames_entry = pic_param.ReferenceFrames; - VAPictureH264* ref_list_entry = slice_param.RefPicList0; - // Initialize the current entry on slice and picture reference lists to - // |ref_pic| and advance list pointers. - auto fill_ref_frame = [&ref_frames_entry, - &ref_list_entry](scoped_refptr<H264Picture> ref_pic) { - VAPictureH264 va_pic_h264; - InitVAPictureH264(&va_pic_h264); - va_pic_h264.picture_id = ref_pic->AsVaapiH264Picture()->GetVASurfaceID(); - va_pic_h264.flags = 0; - - *ref_frames_entry = va_pic_h264; - *ref_list_entry = va_pic_h264; - ++ref_frames_entry; - ++ref_list_entry; - }; - - // Fill slice_param.RefPicList{0,1} with pictures from ref_pic_list{0,1}, - // respectively, and pic_param.ReferenceFrames with entries from both. - std::for_each(ref_pic_list0.begin(), ref_pic_list0.end(), fill_ref_frame); - ref_list_entry = slice_param.RefPicList1; - std::for_each(ref_pic_list1.begin(), ref_pic_list1.end(), fill_ref_frame); - - VAEncMiscParameterRateControl rate_control_param; - VAEncMiscParameterFrameRate framerate_param; - VAEncMiscParameterHRD hrd_param; - FillVAEncRateControlParams( - encode_params.bitrate_bps, - base::strict_cast<uint32_t>(encode_params.cpb_window_size_ms), - base::strict_cast<uint32_t>(pic_param.pic_init_qp), - base::strict_cast<uint32_t>(encode_params.min_qp), - base::strict_cast<uint32_t>(encode_params.max_qp), - encode_params.framerate, - base::strict_cast<uint32_t>(encode_params.cpb_size_bits), - rate_control_param, framerate_param, hrd_param); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitBuffer, - base::Unretained(vea_), VAEncPictureParameterBufferType, - MakeRefCountedBytes(&pic_param, sizeof(pic_param)))); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitBuffer, - base::Unretained(vea_), VAEncSliceParameterBufferType, - MakeRefCountedBytes(&slice_param, sizeof(slice_param)))); - - job->AddSetupCallback(base::BindOnce( - &VaapiVideoEncodeAccelerator::SubmitVAEncMiscParamBuffer, - base::Unretained(vea_), VAEncMiscParameterTypeRateControl, - MakeRefCountedBytes(&rate_control_param, sizeof(rate_control_param)))); - - job->AddSetupCallback(base::BindOnce( - &VaapiVideoEncodeAccelerator::SubmitVAEncMiscParamBuffer, - base::Unretained(vea_), VAEncMiscParameterTypeFrameRate, - MakeRefCountedBytes(&framerate_param, sizeof(framerate_param)))); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitVAEncMiscParamBuffer, - base::Unretained(vea_), VAEncMiscParameterTypeHRD, - MakeRefCountedBytes(&hrd_param, sizeof(hrd_param)))); - - return true; -} - -scoped_refptr<H264Picture> -VaapiVideoEncodeAccelerator::H264Accelerator::GetPicture( - VaapiVideoEncoderDelegate::EncodeJob* job) { - return base::WrapRefCounted( - reinterpret_cast<H264Picture*>(job->picture().get())); -} - -bool VaapiVideoEncodeAccelerator::H264Accelerator::SubmitPackedHeaders( - VaapiVideoEncoderDelegate::EncodeJob* job, - scoped_refptr<H264BitstreamBuffer> packed_sps, - scoped_refptr<H264BitstreamBuffer> packed_pps) { - // Submit SPS. - VAEncPackedHeaderParameterBuffer par_buffer = {}; - par_buffer.type = VAEncPackedHeaderSequence; - par_buffer.bit_length = packed_sps->BytesInBuffer() * 8; - - job->AddSetupCallback(base::BindOnce( - &VaapiVideoEncodeAccelerator::SubmitBuffer, base::Unretained(vea_), - VAEncPackedHeaderParameterBufferType, - MakeRefCountedBytes(&par_buffer, sizeof(par_buffer)))); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitH264BitstreamBuffer, - base::Unretained(vea_), packed_sps)); - - // Submit PPS. - par_buffer = {}; - par_buffer.type = VAEncPackedHeaderPicture; - par_buffer.bit_length = packed_pps->BytesInBuffer() * 8; - - job->AddSetupCallback(base::BindOnce( - &VaapiVideoEncodeAccelerator::SubmitBuffer, base::Unretained(vea_), - VAEncPackedHeaderParameterBufferType, - MakeRefCountedBytes(&par_buffer, sizeof(par_buffer)))); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitH264BitstreamBuffer, - base::Unretained(vea_), packed_pps)); - - return true; -} - -scoped_refptr<VP8Picture> -VaapiVideoEncodeAccelerator::VP8Accelerator::GetPicture( - VaapiVideoEncoderDelegate::EncodeJob* job) { - return base::WrapRefCounted( - reinterpret_cast<VP8Picture*>(job->picture().get())); -} - -bool VaapiVideoEncodeAccelerator::VP8Accelerator::SubmitFrameParameters( - VaapiVideoEncoderDelegate::EncodeJob* job, - const VP8Encoder::EncodeParams& encode_params, - scoped_refptr<VP8Picture> pic, - const Vp8ReferenceFrameVector& ref_frames, - const std::array<bool, kNumVp8ReferenceBuffers>& ref_frames_used) { - VAEncSequenceParameterBufferVP8 seq_param = {}; - - const auto& frame_header = pic->frame_hdr; - seq_param.frame_width = frame_header->width; - seq_param.frame_height = frame_header->height; - seq_param.frame_width_scale = frame_header->horizontal_scale; - seq_param.frame_height_scale = frame_header->vertical_scale; - seq_param.error_resilient = 1; - seq_param.bits_per_second = encode_params.bitrate_allocation.GetSumBps(); - seq_param.intra_period = encode_params.kf_period_frames; - - VAEncPictureParameterBufferVP8 pic_param = {}; - - pic_param.reconstructed_frame = pic->AsVaapiVP8Picture()->GetVASurfaceID(); - DCHECK_NE(pic_param.reconstructed_frame, VA_INVALID_ID); - - auto last_frame = ref_frames.GetFrame(Vp8RefType::VP8_FRAME_LAST); - pic_param.ref_last_frame = - last_frame ? last_frame->AsVaapiVP8Picture()->GetVASurfaceID() - : VA_INVALID_ID; - auto golden_frame = ref_frames.GetFrame(Vp8RefType::VP8_FRAME_GOLDEN); - pic_param.ref_gf_frame = - golden_frame ? golden_frame->AsVaapiVP8Picture()->GetVASurfaceID() - : VA_INVALID_ID; - auto alt_frame = ref_frames.GetFrame(Vp8RefType::VP8_FRAME_ALTREF); - pic_param.ref_arf_frame = - alt_frame ? alt_frame->AsVaapiVP8Picture()->GetVASurfaceID() - : VA_INVALID_ID; - pic_param.coded_buf = job->coded_buffer_id(); - DCHECK_NE(pic_param.coded_buf, VA_INVALID_ID); - pic_param.ref_flags.bits.no_ref_last = - !ref_frames_used[Vp8RefType::VP8_FRAME_LAST]; - pic_param.ref_flags.bits.no_ref_gf = - !ref_frames_used[Vp8RefType::VP8_FRAME_GOLDEN]; - pic_param.ref_flags.bits.no_ref_arf = - !ref_frames_used[Vp8RefType::VP8_FRAME_ALTREF]; - - if (frame_header->IsKeyframe()) { - pic_param.ref_flags.bits.force_kf = true; - } - - pic_param.pic_flags.bits.frame_type = frame_header->frame_type; - pic_param.pic_flags.bits.version = frame_header->version; - pic_param.pic_flags.bits.show_frame = frame_header->show_frame; - pic_param.pic_flags.bits.loop_filter_type = frame_header->loopfilter_hdr.type; - pic_param.pic_flags.bits.num_token_partitions = - frame_header->num_of_dct_partitions; - pic_param.pic_flags.bits.segmentation_enabled = - frame_header->segmentation_hdr.segmentation_enabled; - pic_param.pic_flags.bits.update_mb_segmentation_map = - frame_header->segmentation_hdr.update_mb_segmentation_map; - pic_param.pic_flags.bits.update_segment_feature_data = - frame_header->segmentation_hdr.update_segment_feature_data; - - pic_param.pic_flags.bits.loop_filter_adj_enable = - frame_header->loopfilter_hdr.loop_filter_adj_enable; - - pic_param.pic_flags.bits.refresh_entropy_probs = - frame_header->refresh_entropy_probs; - pic_param.pic_flags.bits.refresh_golden_frame = - frame_header->refresh_golden_frame; - pic_param.pic_flags.bits.refresh_alternate_frame = - frame_header->refresh_alternate_frame; - pic_param.pic_flags.bits.refresh_last = frame_header->refresh_last; - pic_param.pic_flags.bits.copy_buffer_to_golden = - frame_header->copy_buffer_to_golden; - pic_param.pic_flags.bits.copy_buffer_to_alternate = - frame_header->copy_buffer_to_alternate; - pic_param.pic_flags.bits.sign_bias_golden = frame_header->sign_bias_golden; - pic_param.pic_flags.bits.sign_bias_alternate = - frame_header->sign_bias_alternate; - pic_param.pic_flags.bits.mb_no_coeff_skip = frame_header->mb_no_skip_coeff; - if (frame_header->IsKeyframe()) - pic_param.pic_flags.bits.forced_lf_adjustment = true; - - static_assert(std::extent<decltype(pic_param.loop_filter_level)>() == - std::extent<decltype(pic_param.ref_lf_delta)>() && - std::extent<decltype(pic_param.ref_lf_delta)>() == - std::extent<decltype(pic_param.mode_lf_delta)>() && - std::extent<decltype(pic_param.ref_lf_delta)>() == - std::extent<decltype( - frame_header->loopfilter_hdr.ref_frame_delta)>() && - std::extent<decltype(pic_param.mode_lf_delta)>() == - std::extent<decltype( - frame_header->loopfilter_hdr.mb_mode_delta)>(), - "Invalid loop filter array sizes"); - - for (size_t i = 0; i < base::size(pic_param.loop_filter_level); ++i) { - pic_param.loop_filter_level[i] = frame_header->loopfilter_hdr.level; - pic_param.ref_lf_delta[i] = frame_header->loopfilter_hdr.ref_frame_delta[i]; - pic_param.mode_lf_delta[i] = frame_header->loopfilter_hdr.mb_mode_delta[i]; - } - - pic_param.sharpness_level = frame_header->loopfilter_hdr.sharpness_level; - pic_param.clamp_qindex_high = encode_params.max_qp; - pic_param.clamp_qindex_low = encode_params.min_qp; - - VAQMatrixBufferVP8 qmatrix_buf = {}; - for (size_t i = 0; i < base::size(qmatrix_buf.quantization_index); ++i) - qmatrix_buf.quantization_index[i] = frame_header->quantization_hdr.y_ac_qi; - - qmatrix_buf.quantization_index_delta[0] = - frame_header->quantization_hdr.y_dc_delta; - qmatrix_buf.quantization_index_delta[1] = - frame_header->quantization_hdr.y2_dc_delta; - qmatrix_buf.quantization_index_delta[2] = - frame_header->quantization_hdr.y2_ac_delta; - qmatrix_buf.quantization_index_delta[3] = - frame_header->quantization_hdr.uv_dc_delta; - qmatrix_buf.quantization_index_delta[4] = - frame_header->quantization_hdr.uv_ac_delta; - - VAEncMiscParameterRateControl rate_control_param; - VAEncMiscParameterFrameRate framerate_param; - VAEncMiscParameterHRD hrd_param; - FillVAEncRateControlParams( - base::checked_cast<uint32_t>( - encode_params.bitrate_allocation.GetSumBps()), - base::strict_cast<uint32_t>(encode_params.cpb_window_size_ms), - base::strict_cast<uint32_t>(encode_params.initial_qp), - base::strict_cast<uint32_t>(encode_params.min_qp), - base::strict_cast<uint32_t>(encode_params.max_qp), - encode_params.framerate, - base::strict_cast<uint32_t>(encode_params.cpb_size_bits), - rate_control_param, framerate_param, hrd_param); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitBuffer, - base::Unretained(vea_), VAEncSequenceParameterBufferType, - MakeRefCountedBytes(&seq_param, sizeof(seq_param)))); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitBuffer, - base::Unretained(vea_), VAEncPictureParameterBufferType, - MakeRefCountedBytes(&pic_param, sizeof(pic_param)))); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitBuffer, - base::Unretained(vea_), VAQMatrixBufferType, - MakeRefCountedBytes(&qmatrix_buf, sizeof(qmatrix_buf)))); - - job->AddSetupCallback(base::BindOnce( - &VaapiVideoEncodeAccelerator::SubmitVAEncMiscParamBuffer, - base::Unretained(vea_), VAEncMiscParameterTypeRateControl, - MakeRefCountedBytes(&rate_control_param, sizeof(rate_control_param)))); - - job->AddSetupCallback(base::BindOnce( - &VaapiVideoEncodeAccelerator::SubmitVAEncMiscParamBuffer, - base::Unretained(vea_), VAEncMiscParameterTypeFrameRate, - MakeRefCountedBytes(&framerate_param, sizeof(framerate_param)))); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitVAEncMiscParamBuffer, - base::Unretained(vea_), VAEncMiscParameterTypeHRD, - MakeRefCountedBytes(&hrd_param, sizeof(hrd_param)))); - - return true; -} - -scoped_refptr<VP9Picture> -VaapiVideoEncodeAccelerator::VP9Accelerator::GetPicture( - VaapiVideoEncoderDelegate::EncodeJob* job) { - return base::WrapRefCounted( - reinterpret_cast<VP9Picture*>(job->picture().get())); -} - -bool VaapiVideoEncodeAccelerator::VP9Accelerator::SubmitFrameParameters( - VaapiVideoEncoderDelegate::EncodeJob* job, - const VP9Encoder::EncodeParams& encode_params, - scoped_refptr<VP9Picture> pic, - const Vp9ReferenceFrameVector& ref_frames, - const std::array<bool, kVp9NumRefsPerFrame>& ref_frames_used) { - VAEncSequenceParameterBufferVP9 seq_param = {}; - - const auto& frame_header = pic->frame_hdr; - // TODO(crbug.com/811912): Double check whether the - // max_frame_width or max_frame_height affects any of the memory - // allocation and tighten these values based on that. - constexpr gfx::Size kMaxFrameSize(4096, 4096); - seq_param.max_frame_width = kMaxFrameSize.height(); - seq_param.max_frame_height = kMaxFrameSize.width(); - seq_param.bits_per_second = encode_params.bitrate_allocation.GetSumBps(); - seq_param.intra_period = encode_params.kf_period_frames; - - VAEncPictureParameterBufferVP9 pic_param = {}; - - pic_param.frame_width_src = frame_header->frame_width; - pic_param.frame_height_src = frame_header->frame_height; - pic_param.frame_width_dst = frame_header->render_width; - pic_param.frame_height_dst = frame_header->render_height; - - pic_param.reconstructed_frame = pic->AsVaapiVP9Picture()->GetVASurfaceID(); - DCHECK_NE(pic_param.reconstructed_frame, VA_INVALID_ID); - - for (size_t i = 0; i < kVp9NumRefFrames; i++) { - auto ref_pic = ref_frames.GetFrame(i); - pic_param.reference_frames[i] = - ref_pic ? ref_pic->AsVaapiVP9Picture()->GetVASurfaceID() - : VA_INVALID_ID; - } - - pic_param.coded_buf = job->coded_buffer_id(); - DCHECK_NE(pic_param.coded_buf, VA_INVALID_ID); - - if (frame_header->IsKeyframe()) { - pic_param.ref_flags.bits.force_kf = true; - } else { - // Non-key frame mode, the frame has at least 1 reference frames. - size_t first_used_ref_frame = 3; - for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { - if (ref_frames_used[i]) { - first_used_ref_frame = std::min(first_used_ref_frame, i); - pic_param.ref_flags.bits.ref_frame_ctrl_l0 |= (1 << i); - } - } - CHECK_LT(first_used_ref_frame, 3u); - - pic_param.ref_flags.bits.ref_last_idx = - ref_frames_used[0] ? frame_header->ref_frame_idx[0] - : frame_header->ref_frame_idx[first_used_ref_frame]; - pic_param.ref_flags.bits.ref_gf_idx = - ref_frames_used[1] ? frame_header->ref_frame_idx[1] - : frame_header->ref_frame_idx[first_used_ref_frame]; - pic_param.ref_flags.bits.ref_arf_idx = - ref_frames_used[2] ? frame_header->ref_frame_idx[2] - : frame_header->ref_frame_idx[first_used_ref_frame]; - } - - pic_param.pic_flags.bits.frame_type = frame_header->frame_type; - pic_param.pic_flags.bits.show_frame = frame_header->show_frame; - pic_param.pic_flags.bits.error_resilient_mode = - frame_header->error_resilient_mode; - pic_param.pic_flags.bits.intra_only = frame_header->intra_only; - pic_param.pic_flags.bits.allow_high_precision_mv = - frame_header->allow_high_precision_mv; - pic_param.pic_flags.bits.mcomp_filter_type = - frame_header->interpolation_filter; - pic_param.pic_flags.bits.frame_parallel_decoding_mode = - frame_header->frame_parallel_decoding_mode; - pic_param.pic_flags.bits.reset_frame_context = - frame_header->reset_frame_context; - pic_param.pic_flags.bits.refresh_frame_context = - frame_header->refresh_frame_context; - pic_param.pic_flags.bits.frame_context_idx = frame_header->frame_context_idx; - - pic_param.refresh_frame_flags = frame_header->refresh_frame_flags; - - pic_param.luma_ac_qindex = frame_header->quant_params.base_q_idx; - pic_param.luma_dc_qindex_delta = frame_header->quant_params.delta_q_y_dc; - pic_param.chroma_ac_qindex_delta = frame_header->quant_params.delta_q_uv_ac; - pic_param.chroma_dc_qindex_delta = frame_header->quant_params.delta_q_uv_dc; - pic_param.filter_level = frame_header->loop_filter.level; - pic_param.log2_tile_rows = frame_header->tile_rows_log2; - pic_param.log2_tile_columns = frame_header->tile_cols_log2; - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitBuffer, - base::Unretained(vea_), VAEncSequenceParameterBufferType, - MakeRefCountedBytes(&seq_param, sizeof(seq_param)))); - - job->AddSetupCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::SubmitBuffer, - base::Unretained(vea_), VAEncPictureParameterBufferType, - MakeRefCountedBytes(&pic_param, sizeof(pic_param)))); - - job->AddPostExecuteCallback( - base::BindOnce(&VaapiVideoEncodeAccelerator::NotifyEncodedChunkSize, - base::Unretained(vea_), job->coded_buffer_id(), - job->input_surface()->id())); - return true; -} - } // namespace media
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.h b/media/gpu/vaapi/vaapi_video_encode_accelerator.h index d25dc07f65..6fe18d8 100644 --- a/media/gpu/vaapi/vaapi_video_encode_accelerator.h +++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.h
@@ -49,7 +49,6 @@ private: friend class VaapiVideoEncodeAcceleratorTest; class H264Accelerator; - class VP8Accelerator; class VP9Accelerator; using EncodeJob = VaapiVideoEncoderDelegate::EncodeJob; @@ -137,22 +136,6 @@ // Sets the encoder state to |state| on the correct thread. void SetState(State state); - // Submits |buffer| of |type| to the driver. - void SubmitBuffer(VABufferType type, - scoped_refptr<base::RefCountedBytes> buffer); - - // Submits a VAEncMiscParameterBuffer |buffer| of type |type| to the driver. - void SubmitVAEncMiscParamBuffer(VAEncMiscParameterType type, - scoped_refptr<base::RefCountedBytes> buffer); - - // Submits a H264BitstreamBuffer |buffer| to the driver. - void SubmitH264BitstreamBuffer(scoped_refptr<H264BitstreamBuffer> buffer); - - // Gets the encoded chunk size whose id is |buffer_id| and notifies |encoder_| - // the size. - void NotifyEncodedChunkSize(VABufferID buffer_id, - VASurfaceID sync_surface_id); - bool IsConfiguredForTesting() const { return !supported_profiles_for_testing_.empty(); } @@ -204,6 +187,7 @@ State state_; // Encoder instance managing video codec state and preparing encode jobs. + // Should only be used on |encoder_task_runner_|. std::unique_ptr<VaapiVideoEncoderDelegate> encoder_; // VA surfaces available for encoding.
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc index 15ae0fb..7e9c6e7 100644 --- a/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc +++ b/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc
@@ -13,6 +13,7 @@ #include "base/test/task_environment.h" #include "media/gpu/vaapi/vaapi_utils.h" #include "media/gpu/vaapi/vaapi_wrapper.h" +#include "media/gpu/vaapi/vp9_encoder.h" #include "media/gpu/vaapi/vp9_temporal_layers.h" #include "media/gpu/vp9_picture.h" #include "media/video/video_encode_accelerator.h" @@ -88,6 +89,7 @@ class MockVaapiWrapper : public VaapiWrapper { public: MockVaapiWrapper(CodecMode mode) : VaapiWrapper(mode) {} + MOCK_METHOD2(GetVAEncMaxNumOfRefFrames, bool(VideoCodecProfile, size_t*)); MOCK_METHOD5(CreateContextAndSurfaces, bool(unsigned int, @@ -110,8 +112,11 @@ ~MockVaapiWrapper() override = default; }; -class MockVaapiVideoEncoderDelegate : public VaapiVideoEncoderDelegate { +class MockVP9Encoder : public VP9Encoder { public: + MockVP9Encoder(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + base::RepeatingClosure error_cb) + : VP9Encoder(vaapi_wrapper, error_cb) {} MOCK_METHOD2(Initialize, bool(const VideoEncodeAccelerator::Config&, const VaapiVideoEncoderDelegate::Config&)); @@ -135,16 +140,23 @@ VaapiVideoEncodeAcceleratorTest() = default; ~VaapiVideoEncodeAcceleratorTest() override = default; + MOCK_METHOD0(OnError, void()); + void SetUp() override { mock_vaapi_wrapper_ = base::MakeRefCounted<MockVaapiWrapper>(VaapiWrapper::kEncode); + encoder_.reset(new VaapiVideoEncodeAccelerator); auto* vaapi_encoder = reinterpret_cast<VaapiVideoEncodeAccelerator*>(encoder_.get()); vaapi_encoder->vaapi_wrapper_ = mock_vaapi_wrapper_; - vaapi_encoder->encoder_ = std::make_unique<MockVaapiVideoEncoderDelegate>(); - mock_encoder_ = reinterpret_cast<MockVaapiVideoEncoderDelegate*>( - vaapi_encoder->encoder_.get()); + vaapi_encoder->encoder_ = std::make_unique<MockVP9Encoder>( + mock_vaapi_wrapper_, + base::BindRepeating(&VaapiVideoEncodeAcceleratorTest::OnError, + base::Unretained(this))); + EXPECT_CALL(*this, OnError()).Times(0); + mock_encoder_ = + reinterpret_cast<MockVP9Encoder*>(vaapi_encoder->encoder_.get()); } void SetDefaultMocksBehavior(const VideoEncodeAccelerator::Config& config) { @@ -233,11 +245,13 @@ reinterpret_cast<VP9Picture*>(picture)->metadata_for_encoding = Vp9Metadata(); } - job->AddPostExecuteCallback(base::BindOnce( - &VaapiVideoEncodeAccelerator::NotifyEncodedChunkSize, - base::Unretained( - reinterpret_cast<VaapiVideoEncodeAccelerator*>(encoder)), - kCodedBufferId, kInputSurfaceId)); + auto* vaapi_encoder = + reinterpret_cast<VaapiVideoEncodeAccelerator*>(encoder); + job->AddPostExecuteCallback( + base::BindOnce(&VP9Encoder::NotifyEncodedChunkSize, + base::Unretained(reinterpret_cast<VP9Encoder*>( + vaapi_encoder->encoder_.get())), + kCodedBufferId, kInputSurfaceId)); return true; })); EXPECT_CALL( @@ -302,7 +316,7 @@ MockVideoEncodeAcceleratorClient client_; std::unique_ptr<VideoEncodeAccelerator> encoder_; scoped_refptr<MockVaapiWrapper> mock_vaapi_wrapper_; - MockVaapiVideoEncoderDelegate* mock_encoder_ = nullptr; + MockVP9Encoder* mock_encoder_ = nullptr; }; struct VaapiVideoEncodeAcceleratorTestParam {
diff --git a/media/gpu/vaapi/vaapi_video_encoder_delegate.cc b/media/gpu/vaapi/vaapi_video_encoder_delegate.cc index 653ee70..f09a5d8 100644 --- a/media/gpu/vaapi/vaapi_video_encoder_delegate.cc +++ b/media/gpu/vaapi/vaapi_video_encoder_delegate.cc
@@ -6,11 +6,13 @@ #include <va/va.h> +#include "base/memory/ref_counted_memory.h" #include "media/base/video_frame.h" #include "media/gpu/codec_picture.h" #include "media/gpu/gpu_video_encode_accelerator_helpers.h" #include "media/gpu/vaapi/va_surface.h" #include "media/gpu/vaapi/vaapi_utils.h" +#include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/video/video_encode_accelerator.h" namespace media { @@ -93,12 +95,25 @@ return picture_; } +VaapiVideoEncoderDelegate::VaapiVideoEncoderDelegate( + scoped_refptr<VaapiWrapper> vaapi_wrapper, + base::RepeatingClosure error_cb) + : vaapi_wrapper_(vaapi_wrapper), error_cb_(error_cb) { + DETACH_FROM_SEQUENCE(sequence_checker_); +} + +VaapiVideoEncoderDelegate::~VaapiVideoEncoderDelegate() = default; + size_t VaapiVideoEncoderDelegate::GetBitstreamBufferSize() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return GetEncodeBitstreamBufferSize(GetCodedSize()); } void VaapiVideoEncoderDelegate::BitrateControlUpdate( uint64_t encoded_chunk_size_bytes) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + NOTREACHED() << __func__ << "() is called to on an" << "VaapiVideoEncoderDelegate that doesn't support BitrateControl" @@ -108,7 +123,38 @@ BitstreamBufferMetadata VaapiVideoEncoderDelegate::GetMetadata( EncodeJob* encode_job, size_t payload_size) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return BitstreamBufferMetadata( payload_size, encode_job->IsKeyframeRequested(), encode_job->timestamp()); } + +void VaapiVideoEncoderDelegate::SubmitBuffer( + VABufferType type, + scoped_refptr<base::RefCountedBytes> buffer) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!vaapi_wrapper_->SubmitBuffer(type, buffer->size(), buffer->front())) + error_cb_.Run(); +} + +void VaapiVideoEncoderDelegate::SubmitVAEncMiscParamBuffer( + VAEncMiscParameterType type, + scoped_refptr<base::RefCountedBytes> buffer) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + const size_t temp_size = sizeof(VAEncMiscParameterBuffer) + buffer->size(); + std::vector<uint8_t> temp(temp_size); + + auto* const va_buffer = + reinterpret_cast<VAEncMiscParameterBuffer*>(temp.data()); + va_buffer->type = type; + memcpy(va_buffer->data, buffer->front(), buffer->size()); + + if (!vaapi_wrapper_->SubmitBuffer(VAEncMiscParameterBufferType, temp_size, + temp.data())) { + error_cb_.Run(); + } +} + } // namespace media
diff --git a/media/gpu/vaapi/vaapi_video_encoder_delegate.h b/media/gpu/vaapi/vaapi_video_encoder_delegate.h index c44a5a9..adc28e6 100644 --- a/media/gpu/vaapi/vaapi_video_encoder_delegate.h +++ b/media/gpu/vaapi/vaapi_video_encoder_delegate.h
@@ -5,12 +5,14 @@ #ifndef MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODER_DELEGATE_H_ #define MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODER_DELEGATE_H_ +#include <va/va.h> #include <vector> #include "base/callback.h" #include "base/containers/queue.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h" +#include "base/sequence_checker.h" #include "base/time/time.h" #include "media/base/video_bitrate_allocation.h" #include "media/base/video_codecs.h" @@ -18,16 +20,17 @@ #include "media/video/video_encoder_info.h" #include "ui/gfx/geometry/size.h" -namespace media { +namespace base { +class RefCountedBytes; +} +namespace media { struct BitstreamBufferMetadata; class CodecPicture; class ScopedVABuffer; class VideoFrame; class VASurface; - -// Verbatim from va/va.h. -typedef unsigned int VABufferID; +class VaapiWrapper; // An VaapiVideoEncoderDelegate performs high-level, platform-independent // encoding process tasks, such as managing codec state, reference frames, etc., @@ -41,8 +44,9 @@ // clients, and associated with the EncodeJob object. class VaapiVideoEncoderDelegate { public: - VaapiVideoEncoderDelegate() = default; - virtual ~VaapiVideoEncoderDelegate() = default; + VaapiVideoEncoderDelegate(scoped_refptr<VaapiWrapper> vaapi_wrapper, + base::RepeatingClosure error_cb); + virtual ~VaapiVideoEncoderDelegate(); enum class BitrateControl { kConstantBitrate, // Constant Bitrate mode. This class relies on other @@ -200,6 +204,21 @@ virtual BitstreamBufferMetadata GetMetadata(EncodeJob* encode_job, size_t payload_size); + + // Submits |buffer| of |type| to the driver. + void SubmitBuffer(VABufferType type, + scoped_refptr<base::RefCountedBytes> buffer); + + // Submits a VAEncMiscParameterBuffer |buffer| of type |type| to the driver. + void SubmitVAEncMiscParamBuffer(VAEncMiscParameterType type, + scoped_refptr<base::RefCountedBytes> buffer); + + protected: + const scoped_refptr<VaapiWrapper> vaapi_wrapper_; + + base::RepeatingClosure error_cb_; + + SEQUENCE_CHECKER(sequence_checker_); }; } // namespace media
diff --git a/media/gpu/vaapi/vp8_encoder.cc b/media/gpu/vaapi/vp8_encoder.cc index 5ded395..b69c40c 100644 --- a/media/gpu/vaapi/vp8_encoder.cc +++ b/media/gpu/vaapi/vp8_encoder.cc
@@ -4,8 +4,14 @@ #include "media/gpu/vaapi/vp8_encoder.h" +#include <va/va.h> +#include <va/va_enc_vp8.h> + #include "base/bits.h" +#include "base/memory/ref_counted_memory.h" #include "media/gpu/macros.h" +#include "media/gpu/vaapi/vaapi_common.h" +#include "media/gpu/vaapi/vaapi_wrapper.h" namespace media { @@ -24,6 +30,40 @@ constexpr uint8_t kMaxQP = 117; // This stands for 32 as a real ac value (see rfc 14.1. table ac_qlookup). constexpr uint8_t kDefaultQP = 28; + +void FillVAEncRateControlParams( + uint32_t bps, + uint32_t window_size, + uint32_t initial_qp, + uint32_t min_qp, + uint32_t max_qp, + uint32_t framerate, + uint32_t buffer_size, + VAEncMiscParameterRateControl& rate_control_param, + VAEncMiscParameterFrameRate& framerate_param, + VAEncMiscParameterHRD& hrd_param) { + memset(&rate_control_param, 0, sizeof(rate_control_param)); + rate_control_param.bits_per_second = bps; + rate_control_param.window_size = window_size; + rate_control_param.initial_qp = initial_qp; + rate_control_param.min_qp = min_qp; + rate_control_param.max_qp = max_qp; + rate_control_param.rc_flags.bits.disable_frame_skip = true; + + memset(&framerate_param, 0, sizeof(framerate_param)); + framerate_param.framerate = framerate; + + memset(&hrd_param, 0, sizeof(hrd_param)); + hrd_param.buffer_size = buffer_size; + hrd_param.initial_buffer_fullness = buffer_size / 2; +} + +static scoped_refptr<base::RefCountedBytes> MakeRefCountedBytes(void* ptr, + size_t size) { + return base::MakeRefCounted<base::RefCountedBytes>( + reinterpret_cast<uint8_t*>(ptr), size); +} + } // namespace VP8Encoder::EncodeParams::EncodeParams() @@ -44,17 +84,19 @@ InitializeFrameHeader(); } -VP8Encoder::VP8Encoder(std::unique_ptr<Accelerator> accelerator) - : accelerator_(std::move(accelerator)) {} +VP8Encoder::VP8Encoder(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + base::RepeatingClosure error_cb) + : VaapiVideoEncoderDelegate(vaapi_wrapper, error_cb) {} VP8Encoder::~VP8Encoder() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // VP8Encoder can be destroyed on any thread. } bool VP8Encoder::Initialize( const VideoEncodeAccelerator::Config& config, const VaapiVideoEncoderDelegate::Config& ave_config) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (VideoCodecProfileToVideoCodec(config.output_profile) != kCodecVP8) { DVLOGF(1) << "Invalid profile: " << GetProfileName(config.output_profile); return false; @@ -103,7 +145,7 @@ frame_num_++; frame_num_ %= current_params_.kf_period_frames; - scoped_refptr<VP8Picture> picture = accelerator_->GetPicture(encode_job); + scoped_refptr<VP8Picture> picture = GetPicture(encode_job); DCHECK(picture); UpdateFrameHeader(encode_job->IsKeyframeRequested()); @@ -119,9 +161,8 @@ std::fill(std::begin(ref_frames_used), std::end(ref_frames_used), false); } - if (!accelerator_->SubmitFrameParameters(encode_job, current_params_, picture, - reference_frames_, - ref_frames_used)) { + if (!SubmitFrameParameters(encode_job, current_params_, picture, + reference_frames_, ref_frames_used)) { LOG(ERROR) << "Failed submitting frame parameters"; return false; } @@ -155,6 +196,8 @@ } void VP8Encoder::InitializeFrameHeader() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + current_frame_hdr_ = {}; DCHECK(!visible_size_.IsEmpty()); current_frame_hdr_.width = visible_size_.width(); @@ -176,6 +219,8 @@ } void VP8Encoder::UpdateFrameHeader(bool keyframe) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (keyframe) { current_frame_hdr_.frame_type = Vp8FrameHeader::KEYFRAME; current_frame_hdr_.refresh_last = true; @@ -199,7 +244,183 @@ } void VP8Encoder::UpdateReferenceFrames(scoped_refptr<VP8Picture> picture) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + reference_frames_.Refresh(picture); } +scoped_refptr<VP8Picture> VP8Encoder::GetPicture( + VaapiVideoEncoderDelegate::EncodeJob* job) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + return base::WrapRefCounted( + reinterpret_cast<VP8Picture*>(job->picture().get())); +} + +bool VP8Encoder::SubmitFrameParameters( + VaapiVideoEncoderDelegate::EncodeJob* job, + const EncodeParams& encode_params, + scoped_refptr<VP8Picture> pic, + const Vp8ReferenceFrameVector& ref_frames, + const std::array<bool, kNumVp8ReferenceBuffers>& ref_frames_used) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + VAEncSequenceParameterBufferVP8 seq_param = {}; + + const auto& frame_header = pic->frame_hdr; + seq_param.frame_width = frame_header->width; + seq_param.frame_height = frame_header->height; + seq_param.frame_width_scale = frame_header->horizontal_scale; + seq_param.frame_height_scale = frame_header->vertical_scale; + seq_param.error_resilient = 1; + seq_param.bits_per_second = encode_params.bitrate_allocation.GetSumBps(); + seq_param.intra_period = encode_params.kf_period_frames; + + VAEncPictureParameterBufferVP8 pic_param = {}; + + pic_param.reconstructed_frame = pic->AsVaapiVP8Picture()->GetVASurfaceID(); + DCHECK_NE(pic_param.reconstructed_frame, VA_INVALID_ID); + + auto last_frame = ref_frames.GetFrame(Vp8RefType::VP8_FRAME_LAST); + pic_param.ref_last_frame = + last_frame ? last_frame->AsVaapiVP8Picture()->GetVASurfaceID() + : VA_INVALID_ID; + auto golden_frame = ref_frames.GetFrame(Vp8RefType::VP8_FRAME_GOLDEN); + pic_param.ref_gf_frame = + golden_frame ? golden_frame->AsVaapiVP8Picture()->GetVASurfaceID() + : VA_INVALID_ID; + auto alt_frame = ref_frames.GetFrame(Vp8RefType::VP8_FRAME_ALTREF); + pic_param.ref_arf_frame = + alt_frame ? alt_frame->AsVaapiVP8Picture()->GetVASurfaceID() + : VA_INVALID_ID; + pic_param.coded_buf = job->coded_buffer_id(); + DCHECK_NE(pic_param.coded_buf, VA_INVALID_ID); + pic_param.ref_flags.bits.no_ref_last = + !ref_frames_used[Vp8RefType::VP8_FRAME_LAST]; + pic_param.ref_flags.bits.no_ref_gf = + !ref_frames_used[Vp8RefType::VP8_FRAME_GOLDEN]; + pic_param.ref_flags.bits.no_ref_arf = + !ref_frames_used[Vp8RefType::VP8_FRAME_ALTREF]; + + if (frame_header->IsKeyframe()) { + pic_param.ref_flags.bits.force_kf = true; + } + + pic_param.pic_flags.bits.frame_type = frame_header->frame_type; + pic_param.pic_flags.bits.version = frame_header->version; + pic_param.pic_flags.bits.show_frame = frame_header->show_frame; + pic_param.pic_flags.bits.loop_filter_type = frame_header->loopfilter_hdr.type; + pic_param.pic_flags.bits.num_token_partitions = + frame_header->num_of_dct_partitions; + pic_param.pic_flags.bits.segmentation_enabled = + frame_header->segmentation_hdr.segmentation_enabled; + pic_param.pic_flags.bits.update_mb_segmentation_map = + frame_header->segmentation_hdr.update_mb_segmentation_map; + pic_param.pic_flags.bits.update_segment_feature_data = + frame_header->segmentation_hdr.update_segment_feature_data; + + pic_param.pic_flags.bits.loop_filter_adj_enable = + frame_header->loopfilter_hdr.loop_filter_adj_enable; + + pic_param.pic_flags.bits.refresh_entropy_probs = + frame_header->refresh_entropy_probs; + pic_param.pic_flags.bits.refresh_golden_frame = + frame_header->refresh_golden_frame; + pic_param.pic_flags.bits.refresh_alternate_frame = + frame_header->refresh_alternate_frame; + pic_param.pic_flags.bits.refresh_last = frame_header->refresh_last; + pic_param.pic_flags.bits.copy_buffer_to_golden = + frame_header->copy_buffer_to_golden; + pic_param.pic_flags.bits.copy_buffer_to_alternate = + frame_header->copy_buffer_to_alternate; + pic_param.pic_flags.bits.sign_bias_golden = frame_header->sign_bias_golden; + pic_param.pic_flags.bits.sign_bias_alternate = + frame_header->sign_bias_alternate; + pic_param.pic_flags.bits.mb_no_coeff_skip = frame_header->mb_no_skip_coeff; + if (frame_header->IsKeyframe()) + pic_param.pic_flags.bits.forced_lf_adjustment = true; + + static_assert(std::extent<decltype(pic_param.loop_filter_level)>() == + std::extent<decltype(pic_param.ref_lf_delta)>() && + std::extent<decltype(pic_param.ref_lf_delta)>() == + std::extent<decltype(pic_param.mode_lf_delta)>() && + std::extent<decltype(pic_param.ref_lf_delta)>() == + std::extent<decltype( + frame_header->loopfilter_hdr.ref_frame_delta)>() && + std::extent<decltype(pic_param.mode_lf_delta)>() == + std::extent<decltype( + frame_header->loopfilter_hdr.mb_mode_delta)>(), + "Invalid loop filter array sizes"); + + for (size_t i = 0; i < base::size(pic_param.loop_filter_level); ++i) { + pic_param.loop_filter_level[i] = frame_header->loopfilter_hdr.level; + pic_param.ref_lf_delta[i] = frame_header->loopfilter_hdr.ref_frame_delta[i]; + pic_param.mode_lf_delta[i] = frame_header->loopfilter_hdr.mb_mode_delta[i]; + } + + pic_param.sharpness_level = frame_header->loopfilter_hdr.sharpness_level; + pic_param.clamp_qindex_high = encode_params.max_qp; + pic_param.clamp_qindex_low = encode_params.min_qp; + + VAQMatrixBufferVP8 qmatrix_buf = {}; + for (size_t i = 0; i < base::size(qmatrix_buf.quantization_index); ++i) + qmatrix_buf.quantization_index[i] = frame_header->quantization_hdr.y_ac_qi; + + qmatrix_buf.quantization_index_delta[0] = + frame_header->quantization_hdr.y_dc_delta; + qmatrix_buf.quantization_index_delta[1] = + frame_header->quantization_hdr.y2_dc_delta; + qmatrix_buf.quantization_index_delta[2] = + frame_header->quantization_hdr.y2_ac_delta; + qmatrix_buf.quantization_index_delta[3] = + frame_header->quantization_hdr.uv_dc_delta; + qmatrix_buf.quantization_index_delta[4] = + frame_header->quantization_hdr.uv_ac_delta; + + VAEncMiscParameterRateControl rate_control_param; + VAEncMiscParameterFrameRate framerate_param; + VAEncMiscParameterHRD hrd_param; + FillVAEncRateControlParams( + base::checked_cast<uint32_t>( + encode_params.bitrate_allocation.GetSumBps()), + base::strict_cast<uint32_t>(encode_params.cpb_window_size_ms), + base::strict_cast<uint32_t>(encode_params.initial_qp), + base::strict_cast<uint32_t>(encode_params.min_qp), + base::strict_cast<uint32_t>(encode_params.max_qp), + encode_params.framerate, + base::strict_cast<uint32_t>(encode_params.cpb_size_bits), + rate_control_param, framerate_param, hrd_param); + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitBuffer, + base::Unretained(this), VAEncSequenceParameterBufferType, + MakeRefCountedBytes(&seq_param, sizeof(seq_param)))); + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitBuffer, + base::Unretained(this), VAEncPictureParameterBufferType, + MakeRefCountedBytes(&pic_param, sizeof(pic_param)))); + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitBuffer, + base::Unretained(this), VAQMatrixBufferType, + MakeRefCountedBytes(&qmatrix_buf, sizeof(qmatrix_buf)))); + + job->AddSetupCallback(base::BindOnce( + &VaapiVideoEncoderDelegate::SubmitVAEncMiscParamBuffer, + base::Unretained(this), VAEncMiscParameterTypeRateControl, + MakeRefCountedBytes(&rate_control_param, sizeof(rate_control_param)))); + + job->AddSetupCallback(base::BindOnce( + &VaapiVideoEncoderDelegate::SubmitVAEncMiscParamBuffer, + base::Unretained(this), VAEncMiscParameterTypeFrameRate, + MakeRefCountedBytes(&framerate_param, sizeof(framerate_param)))); + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitVAEncMiscParamBuffer, + base::Unretained(this), VAEncMiscParameterTypeHRD, + MakeRefCountedBytes(&hrd_param, sizeof(hrd_param)))); + + return true; +} } // namespace media
diff --git a/media/gpu/vaapi/vp8_encoder.h b/media/gpu/vaapi/vp8_encoder.h index 50c94ebc..fec53d6a 100644 --- a/media/gpu/vaapi/vp8_encoder.h +++ b/media/gpu/vaapi/vp8_encoder.h
@@ -9,7 +9,6 @@ #include <vector> #include "base/macros.h" -#include "base/sequence_checker.h" #include "media/base/video_bitrate_allocation.h" #include "media/gpu/vaapi/vaapi_video_encoder_delegate.h" #include "media/gpu/vp8_picture.h" @@ -17,6 +16,7 @@ #include "media/parsers/vp8_parser.h" namespace media { +class VaapiWrapper; class VP8Encoder : public VaapiVideoEncoderDelegate { public: @@ -47,32 +47,8 @@ bool error_resilient_mode; }; - // An accelerator interface. The client must provide an appropriate - // implementation on creation. - class Accelerator { - public: - Accelerator() = default; - virtual ~Accelerator() = default; - - // Returns the VP8Picture to be used as output for |job|. - virtual scoped_refptr<VP8Picture> GetPicture(EncodeJob* job) = 0; - - // Initializes |job| to use the provided |encode_params| as its parameters, - // and |pic| as the target, as well as |ref_frames| as reference frames for - // it. |ref_frames_used| specifies which frames in |ref_frames| will be - // actually used as reference frames on encoding. Returns true on success. - virtual bool SubmitFrameParameters( - EncodeJob* job, - const VP8Encoder::EncodeParams& encode_params, - scoped_refptr<VP8Picture> pic, - const Vp8ReferenceFrameVector& ref_frames, - const std::array<bool, kNumVp8ReferenceBuffers>& ref_frames_used) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Accelerator); - }; - - explicit VP8Encoder(std::unique_ptr<Accelerator> accelerator); + VP8Encoder(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + base::RepeatingClosure error_cb); ~VP8Encoder() override; // VaapiVideoEncoderDelegate implementation. @@ -90,6 +66,15 @@ void UpdateReferenceFrames(scoped_refptr<VP8Picture> picture); void Reset(); + scoped_refptr<VP8Picture> GetPicture(EncodeJob* job); + + bool SubmitFrameParameters( + EncodeJob* job, + const EncodeParams& encode_params, + scoped_refptr<VP8Picture> pic, + const Vp8ReferenceFrameVector& ref_frames, + const std::array<bool, kNumVp8ReferenceBuffers>& ref_frames_used); + gfx::Size visible_size_; gfx::Size coded_size_; // Macroblock-aligned. @@ -101,9 +86,6 @@ Vp8FrameHeader current_frame_hdr_; Vp8ReferenceFrameVector reference_frames_; - const std::unique_ptr<Accelerator> accelerator_; - - SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(VP8Encoder); };
diff --git a/media/gpu/vaapi/vp9_encoder.cc b/media/gpu/vaapi/vp9_encoder.cc index dcbbf8a..8af57cd90 100644 --- a/media/gpu/vaapi/vp9_encoder.cc +++ b/media/gpu/vaapi/vp9_encoder.cc
@@ -7,9 +7,14 @@ #include <algorithm> #include <numeric> +#include <va/va.h> + #include "base/bits.h" +#include "base/memory/ref_counted_memory.h" #include "base/numerics/safe_conversions.h" #include "media/gpu/macros.h" +#include "media/gpu/vaapi/vaapi_common.h" +#include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/gpu/vaapi/vp9_rate_control.h" #include "media/gpu/vaapi/vp9_temporal_layers.h" #include "third_party/libvpx/source/libvpx/vp9/ratectrl_rtc.h" @@ -153,6 +158,13 @@ } return rc_cfg; } + +static scoped_refptr<base::RefCountedBytes> MakeRefCountedBytes(void* ptr, + size_t size) { + return base::MakeRefCounted<base::RefCountedBytes>( + reinterpret_cast<uint8_t*>(ptr), size); +} + } // namespace VP9Encoder::EncodeParams::EncodeParams() @@ -170,11 +182,12 @@ rate_ctrl_ = std::move(rate_ctrl); } -VP9Encoder::VP9Encoder(std::unique_ptr<Accelerator> accelerator) - : accelerator_(std::move(accelerator)) {} +VP9Encoder::VP9Encoder(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + base::RepeatingClosure error_cb) + : VaapiVideoEncoderDelegate(vaapi_wrapper, error_cb) {} VP9Encoder::~VP9Encoder() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // VP9Encoder can be destroyed on any thread. } bool VP9Encoder::Initialize( @@ -264,15 +277,14 @@ frame_num_++; frame_num_ %= current_params_.kf_period_frames; - scoped_refptr<VP9Picture> picture = accelerator_->GetPicture(encode_job); + scoped_refptr<VP9Picture> picture = GetPicture(encode_job); DCHECK(picture); std::array<bool, kVp9NumRefsPerFrame> ref_frames_used = {false, false, false}; SetFrameHeader(encode_job->IsKeyframeRequested(), picture.get(), &ref_frames_used); - if (!accelerator_->SubmitFrameParameters(encode_job, current_params_, picture, - reference_frames_, - ref_frames_used)) { + if (!SubmitFrameParameters(encode_job, current_params_, picture, + reference_frames_, ref_frames_used)) { LOG(ERROR) << "Failed submitting frame parameters"; return false; } @@ -283,15 +295,19 @@ BitstreamBufferMetadata VP9Encoder::GetMetadata(EncodeJob* encode_job, size_t payload_size) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto metadata = VaapiVideoEncoderDelegate::GetMetadata(encode_job, payload_size); - auto picture = accelerator_->GetPicture(encode_job); + auto picture = GetPicture(encode_job); DCHECK(picture); metadata.vp9 = picture->metadata_for_encoding; return metadata; } void VP9Encoder::BitrateControlUpdate(uint64_t encoded_chunk_size_bytes) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!rate_ctrl_) { DLOG(ERROR) << __func__ << "() is called when no bitrate controller exists"; return; @@ -333,6 +349,8 @@ } Vp9FrameHeader VP9Encoder::GetDefaultFrameHeader(const bool keyframe) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + Vp9FrameHeader hdr{}; DCHECK(!visible_size_.IsEmpty()); hdr.frame_width = visible_size_.width(); @@ -351,6 +369,7 @@ bool keyframe, VP9Picture* picture, std::array<bool, kVp9NumRefsPerFrame>* ref_frames_used) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(picture); DCHECK(ref_frames_used); @@ -400,4 +419,129 @@ reference_frames_.Refresh(picture); } +void VP9Encoder::NotifyEncodedChunkSize(VABufferID buffer_id, + VASurfaceID sync_surface_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + const uint64_t encoded_chunk_size = + vaapi_wrapper_->GetEncodedChunkSize(buffer_id, sync_surface_id); + if (encoded_chunk_size == 0) + error_cb_.Run(); + + BitrateControlUpdate(encoded_chunk_size); +} + +scoped_refptr<VP9Picture> VP9Encoder::GetPicture(EncodeJob* job) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + return base::WrapRefCounted( + reinterpret_cast<VP9Picture*>(job->picture().get())); +} + +bool VP9Encoder::SubmitFrameParameters( + EncodeJob* job, + const EncodeParams& encode_params, + scoped_refptr<VP9Picture> pic, + const Vp9ReferenceFrameVector& ref_frames, + const std::array<bool, kVp9NumRefsPerFrame>& ref_frames_used) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + VAEncSequenceParameterBufferVP9 seq_param = {}; + + const auto& frame_header = pic->frame_hdr; + // TODO(crbug.com/811912): Double check whether the + // max_frame_width or max_frame_height affects any of the memory + // allocation and tighten these values based on that. + constexpr gfx::Size kMaxFrameSize(4096, 4096); + seq_param.max_frame_width = kMaxFrameSize.height(); + seq_param.max_frame_height = kMaxFrameSize.width(); + seq_param.bits_per_second = encode_params.bitrate_allocation.GetSumBps(); + seq_param.intra_period = encode_params.kf_period_frames; + + VAEncPictureParameterBufferVP9 pic_param = {}; + + pic_param.frame_width_src = frame_header->frame_width; + pic_param.frame_height_src = frame_header->frame_height; + pic_param.frame_width_dst = frame_header->render_width; + pic_param.frame_height_dst = frame_header->render_height; + + pic_param.reconstructed_frame = pic->AsVaapiVP9Picture()->GetVASurfaceID(); + DCHECK_NE(pic_param.reconstructed_frame, VA_INVALID_ID); + + for (size_t i = 0; i < kVp9NumRefFrames; i++) { + auto ref_pic = ref_frames.GetFrame(i); + pic_param.reference_frames[i] = + ref_pic ? ref_pic->AsVaapiVP9Picture()->GetVASurfaceID() + : VA_INVALID_ID; + } + + pic_param.coded_buf = job->coded_buffer_id(); + DCHECK_NE(pic_param.coded_buf, VA_INVALID_ID); + + if (frame_header->IsKeyframe()) { + pic_param.ref_flags.bits.force_kf = true; + } else { + // Non-key frame mode, the frame has at least 1 reference frames. + size_t first_used_ref_frame = 3; + for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { + if (ref_frames_used[i]) { + first_used_ref_frame = std::min(first_used_ref_frame, i); + pic_param.ref_flags.bits.ref_frame_ctrl_l0 |= (1 << i); + } + } + CHECK_LT(first_used_ref_frame, 3u); + + pic_param.ref_flags.bits.ref_last_idx = + ref_frames_used[0] ? frame_header->ref_frame_idx[0] + : frame_header->ref_frame_idx[first_used_ref_frame]; + pic_param.ref_flags.bits.ref_gf_idx = + ref_frames_used[1] ? frame_header->ref_frame_idx[1] + : frame_header->ref_frame_idx[first_used_ref_frame]; + pic_param.ref_flags.bits.ref_arf_idx = + ref_frames_used[2] ? frame_header->ref_frame_idx[2] + : frame_header->ref_frame_idx[first_used_ref_frame]; + } + + pic_param.pic_flags.bits.frame_type = frame_header->frame_type; + pic_param.pic_flags.bits.show_frame = frame_header->show_frame; + pic_param.pic_flags.bits.error_resilient_mode = + frame_header->error_resilient_mode; + pic_param.pic_flags.bits.intra_only = frame_header->intra_only; + pic_param.pic_flags.bits.allow_high_precision_mv = + frame_header->allow_high_precision_mv; + pic_param.pic_flags.bits.mcomp_filter_type = + frame_header->interpolation_filter; + pic_param.pic_flags.bits.frame_parallel_decoding_mode = + frame_header->frame_parallel_decoding_mode; + pic_param.pic_flags.bits.reset_frame_context = + frame_header->reset_frame_context; + pic_param.pic_flags.bits.refresh_frame_context = + frame_header->refresh_frame_context; + pic_param.pic_flags.bits.frame_context_idx = frame_header->frame_context_idx; + + pic_param.refresh_frame_flags = frame_header->refresh_frame_flags; + + pic_param.luma_ac_qindex = frame_header->quant_params.base_q_idx; + pic_param.luma_dc_qindex_delta = frame_header->quant_params.delta_q_y_dc; + pic_param.chroma_ac_qindex_delta = frame_header->quant_params.delta_q_uv_ac; + pic_param.chroma_dc_qindex_delta = frame_header->quant_params.delta_q_uv_dc; + pic_param.filter_level = frame_header->loop_filter.level; + pic_param.log2_tile_rows = frame_header->tile_rows_log2; + pic_param.log2_tile_columns = frame_header->tile_cols_log2; + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitBuffer, + base::Unretained(this), VAEncSequenceParameterBufferType, + MakeRefCountedBytes(&seq_param, sizeof(seq_param)))); + + job->AddSetupCallback( + base::BindOnce(&VaapiVideoEncoderDelegate::SubmitBuffer, + base::Unretained(this), VAEncPictureParameterBufferType, + MakeRefCountedBytes(&pic_param, sizeof(pic_param)))); + + job->AddPostExecuteCallback(base::BindOnce( + &VP9Encoder::NotifyEncodedChunkSize, base::Unretained(this), + job->coded_buffer_id(), job->input_surface()->id())); + return true; +} + } // namespace media
diff --git a/media/gpu/vaapi/vp9_encoder.h b/media/gpu/vaapi/vp9_encoder.h index 2ce293b..aac6224 100644 --- a/media/gpu/vaapi/vp9_encoder.h +++ b/media/gpu/vaapi/vp9_encoder.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/macros.h" -#include "base/sequence_checker.h" #include "media/base/video_bitrate_allocation.h" #include "media/filters/vp9_parser.h" #include "media/gpu/vaapi/vaapi_video_encoder_delegate.h" @@ -19,6 +18,7 @@ #include "media/gpu/vp9_reference_frame_vector.h" namespace media { +class VaapiWrapper; class VP9TemporalLayers; class VP9RateControl; @@ -51,34 +51,8 @@ bool error_resilient_mode; }; - // An accelerator interface. The client must provide an appropriate - // implementation on creation. - class Accelerator { - public: - Accelerator() = default; - virtual ~Accelerator() = default; - - // Returns the VP9Picture to be used as output for |job|. - virtual scoped_refptr<VP9Picture> GetPicture(EncodeJob* job) = 0; - - // Initializes |job| to use the provided |encode_params| as its parameters, - // and |pic| as the target, as well as |ref_frames| as reference frames for - // it. |ref_frames_used| is to specify whether each of |ref_frame_idx| of - // VP9FrameHeader in |pic| is used. If |ref_frames_used[i]| is true, - // ref_frame_idx[i] will be used as a reference frame. Returns true on - // success. - virtual bool SubmitFrameParameters( - EncodeJob* job, - const VP9Encoder::EncodeParams& encode_params, - scoped_refptr<VP9Picture> pic, - const Vp9ReferenceFrameVector& ref_frames, - const std::array<bool, kVp9NumRefsPerFrame>& ref_frames_used) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Accelerator); - }; - - explicit VP9Encoder(std::unique_ptr<Accelerator> accelerator); + VP9Encoder(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + base::RepeatingClosure error_cb); ~VP9Encoder() override; // VaapiVideoEncoderDelegate implementation. @@ -95,6 +69,7 @@ private: friend class VP9EncoderTest; + friend class VaapiVideoEncodeAcceleratorTest; void set_rate_ctrl_for_testing(std::unique_ptr<VP9RateControl> rate_ctrl); @@ -104,6 +79,20 @@ std::array<bool, kVp9NumRefsPerFrame>* ref_frames_used); void UpdateReferenceFrames(scoped_refptr<VP9Picture> picture); + // Gets the encoded chunk size whose id is |buffer_id| and updates the bitrate + // control. + void NotifyEncodedChunkSize(VABufferID buffer_id, + VASurfaceID sync_surface_id); + + scoped_refptr<VP9Picture> GetPicture(EncodeJob* job); + + bool SubmitFrameParameters( + EncodeJob* job, + const EncodeParams& encode_params, + scoped_refptr<VP9Picture> pic, + const Vp9ReferenceFrameVector& ref_frames, + const std::array<bool, kVp9NumRefsPerFrame>& ref_frames_used); + gfx::Size visible_size_; gfx::Size coded_size_; // Macroblock-aligned. @@ -117,9 +106,7 @@ std::unique_ptr<VP9TemporalLayers> temporal_layers_; std::unique_ptr<VP9RateControl> rate_ctrl_; - const std::unique_ptr<Accelerator> accelerator_; - SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(VP9Encoder); }; } // namespace media
diff --git a/media/gpu/vaapi/vp9_encoder_unittest.cc b/media/gpu/vaapi/vp9_encoder_unittest.cc index 5c78ae8..e6dd408 100644 --- a/media/gpu/vaapi/vp9_encoder_unittest.cc +++ b/media/gpu/vaapi/vp9_encoder_unittest.cc
@@ -14,6 +14,8 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "media/filters/vp9_parser.h" +#include "media/gpu/vaapi/vaapi_common.h" +#include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/gpu/vaapi/vp9_rate_control.h" #include "media/gpu/vaapi/vp9_temporal_layers.h" #include "testing/gmock/include/gmock/gmock.h" @@ -166,20 +168,12 @@ (!temporal_layer_id || arg.temporal_layer_id == *temporal_layer_id); } -class MockVP9Accelerator : public VP9Encoder::Accelerator { +class MockVaapiWrapper : public VaapiWrapper { public: - MockVP9Accelerator() = default; - ~MockVP9Accelerator() override = default; - MOCK_METHOD1( - GetPicture, - scoped_refptr<VP9Picture>(VaapiVideoEncoderDelegate::EncodeJob*)); + MockVaapiWrapper() : VaapiWrapper(kEncodeConstantQuantizationParameter) {} - MOCK_METHOD5(SubmitFrameParameters, - bool(VaapiVideoEncoderDelegate::EncodeJob*, - const VP9Encoder::EncodeParams&, - scoped_refptr<VP9Picture>, - const Vp9ReferenceFrameVector&, - const std::array<bool, kVp9NumRefsPerFrame>&)); + protected: + ~MockVaapiWrapper() override = default; }; class MockVP9RateControl : public VP9RateControl { @@ -206,6 +200,8 @@ void SetUp() override; + MOCK_METHOD0(OnError, void()); + protected: void InitializeVP9Encoder(BitrateControl bitrate_control, size_t num_temporal_layers); @@ -219,25 +215,33 @@ private: std::unique_ptr<VaapiVideoEncoderDelegate::EncodeJob> CreateEncodeJob( - bool keyframe); + bool keyframe, + const scoped_refptr<VASurface>& va_surface, + const scoped_refptr<VP9Picture>& picture); void UpdateRatesSequence(const VideoBitrateAllocation& bitrate_allocation, uint32_t framerate, BitrateControl bitrate_control, size_t num_temporal_layers); std::unique_ptr<VP9Encoder> encoder_; - MockVP9Accelerator* mock_accelerator_ = nullptr; + scoped_refptr<MockVaapiWrapper> mock_vaapi_wrapper_; MockVP9RateControl* mock_rate_ctrl_ = nullptr; }; void VP9EncoderTest::SetUp() { - auto mock_accelerator = std::make_unique<MockVP9Accelerator>(); - mock_accelerator_ = mock_accelerator.get(); - encoder_ = std::make_unique<VP9Encoder>(std::move(mock_accelerator)); + mock_vaapi_wrapper_ = base::MakeRefCounted<MockVaapiWrapper>(); + ASSERT_TRUE(mock_vaapi_wrapper_); + + encoder_ = std::make_unique<VP9Encoder>( + mock_vaapi_wrapper_, + base::BindRepeating(&VP9EncoderTest::OnError, base::Unretained(this))); + EXPECT_CALL(*this, OnError()).Times(0); } std::unique_ptr<VaapiVideoEncoderDelegate::EncodeJob> -VP9EncoderTest::CreateEncodeJob(bool keyframe) { +VP9EncoderTest::CreateEncodeJob(bool keyframe, + const scoped_refptr<VASurface>& va_surface, + const scoped_refptr<VP9Picture>& picture) { auto input_frame = VideoFrame::CreateFrame( kDefaultVideoEncodeAcceleratorConfig.input_format, kDefaultVideoEncodeAcceleratorConfig.input_visible_size, @@ -245,8 +249,15 @@ kDefaultVideoEncodeAcceleratorConfig.input_visible_size, base::TimeDelta()); LOG_ASSERT(input_frame) << " Failed to create VideoFrame"; + + constexpr VABufferID kDummyVABufferID = 12; + auto scoped_va_buffer = ScopedVABuffer::CreateForTesting( + kDummyVABufferID, VAEncCodedBufferType, + kDefaultVideoEncodeAcceleratorConfig.input_visible_size.GetArea()); + return std::make_unique<VaapiVideoEncoderDelegate::EncodeJob>( - input_frame, keyframe, base::DoNothing()); + input_frame, keyframe, base::DoNothing(), va_surface, picture, + std::move(scoped_va_buffer)); } void VP9EncoderTest::InitializeVP9Encoder(BitrateControl bitrate_control, @@ -294,12 +305,15 @@ expected_ref_frames_used, absl::optional<uint8_t> expected_temporal_layer_id) { InSequence seq; - auto encode_job = CreateEncodeJob(is_keyframe); - scoped_refptr<VP9Picture> picture(new VP9Picture); - EXPECT_CALL(*mock_accelerator_, GetPicture(encode_job.get())) - .WillOnce(Invoke([picture](VaapiVideoEncoderDelegate::EncodeJob*) { - return picture; - })); + + constexpr VASurfaceID kDummyVASurfaceID = 123; + auto va_surface = base::MakeRefCounted<VASurface>( + kDummyVASurfaceID, + kDefaultVideoEncodeAcceleratorConfig.input_visible_size, + VA_RT_FORMAT_YUV420, base::DoNothing()); + scoped_refptr<VP9Picture> picture = new VaapiVP9Picture(va_surface); + + auto encode_job = CreateEncodeJob(is_keyframe, va_surface, picture); FRAME_TYPE libvpx_frame_type = is_keyframe ? FRAME_TYPE::KEY_FRAME : FRAME_TYPE::INTER_FRAME; @@ -312,17 +326,9 @@ EXPECT_CALL(*mock_rate_ctrl_, GetQP()).WillOnce(Return(kDefaultQP)); EXPECT_CALL(*mock_rate_ctrl_, GetLoopfilterLevel()) .WillOnce(Return(kDefaultLoopFilterLevel)); - if (expected_ref_frames_used) { - EXPECT_CALL(*mock_accelerator_, - SubmitFrameParameters( - encode_job.get(), _, _, _, - ::testing::ElementsAreArray(*expected_ref_frames_used))) - .WillOnce(Return(true)); - } else { - EXPECT_CALL(*mock_accelerator_, - SubmitFrameParameters(encode_job.get(), _, _, _, _)) - .WillOnce(Return(true)); - } + + // TODO(mcasas): Consider setting expectations on MockVaapiWrapper calls. + EXPECT_TRUE(encoder_->PrepareEncodeJob(encode_job.get())); // TODO(hiroh): Test for encoder_->reference_frames_.
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc index 28cf481..3153413 100644 --- a/net/disk_cache/entry_unittest.cc +++ b/net/disk_cache/entry_unittest.cc
@@ -5743,10 +5743,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_NONE, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); } TEST_F(DiskCacheSimplePrefetchTest, NoFullSmallSpeculative) { @@ -5759,10 +5755,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 1); } TEST_F(DiskCacheSimplePrefetchTest, NoFullLargeSpeculative) { @@ -5777,10 +5769,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); } TEST_F(DiskCacheSimplePrefetchTest, SmallFullNoSpeculative) { @@ -5793,10 +5781,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_NONE, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); } TEST_F(DiskCacheSimplePrefetchTest, LargeFullNoSpeculative) { @@ -5809,10 +5793,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); } TEST_F(DiskCacheSimplePrefetchTest, SmallFullSmallSpeculative) { @@ -5825,10 +5805,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 1); } TEST_F(DiskCacheSimplePrefetchTest, LargeFullSmallSpeculative) { @@ -5842,10 +5818,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); } class DiskCacheSimpleAppCachePrefetchTest : public DiskCacheSimplePrefetchTest { @@ -5864,10 +5836,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.EntryTrailerPrefetchDelta", 0, 1); } TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullSmallSpeculative) { @@ -5880,10 +5848,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.EntryTrailerPrefetchDelta", 0, 1); } TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullLargeSpeculative) { @@ -5899,10 +5863,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.EntryTrailerPrefetchDelta", 0, 1); } TEST_F(DiskCacheSimpleAppCachePrefetchTest, SmallFullNoSpeculative) { @@ -5915,10 +5875,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.EntryTrailerPrefetchDelta", 0, 1); } TEST_F(DiskCacheSimpleAppCachePrefetchTest, LargeFullNoSpeculative) { @@ -5932,10 +5888,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", - 0); } TEST_F(DiskCacheSimpleAppCachePrefetchTest, SmallFullSmallSpeculative) { @@ -5948,10 +5900,6 @@ histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", - 1); } TEST_F(DiskCacheSimpleAppCachePrefetchTest, LargeFullSmallSpeculative) { @@ -5965,8 +5913,4 @@ histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", - 0); }
diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc index 7b82043f..e901b327 100644 --- a/net/disk_cache/simple/simple_synchronous_entry.cc +++ b/net/disk_cache/simple/simple_synchronous_entry.cc
@@ -1496,8 +1496,6 @@ size_t offset = file_size - length; if (!prefetch_data.PrefetchFromFile(&file, offset, length)) return net::ERR_FAILED; - SIMPLE_CACHE_UMA(COUNTS_100000, "EntryTrailerPrefetchSize", cache_type_, - trailer_prefetch_size); } else { // Do no prefetching. RecordOpenPrefetchMode(cache_type_, prefetch_mode); @@ -1547,13 +1545,6 @@ computed_trailer_prefetch_size_ = prefetch_data.GetDesiredTrailerPrefetchSize(); - // If we performed a trailer prefetch, record how accurate the prefetch was - // compared to the ideal value. - if (prefetch_mode == OPEN_PREFETCH_TRAILER) { - SIMPLE_CACHE_UMA(COUNTS_100000, "EntryTrailerPrefetchDelta", cache_type_, - (trailer_prefetch_size - computed_trailer_prefetch_size_)); - } - // If prefetch buffer is available, and we have sha256(key) (so we don't need // to look at the header), extract out stream 1 info as well. int stream_1_offset = out_entry_stat->GetOffsetInFile(
diff --git a/remoting/host/chromoting_host.h b/remoting/host/chromoting_host.h index 3c9c0ae..b6532f6e 100644 --- a/remoting/host/chromoting_host.h +++ b/remoting/host/chromoting_host.h
@@ -12,7 +12,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/sequence_checker.h" #include "base/threading/thread.h" #include "net/base/backoff_entry.h"
diff --git a/remoting/protocol/webrtc_audio_source_adapter.cc b/remoting/protocol/webrtc_audio_source_adapter.cc index e56eed1..b519419 100644 --- a/remoting/protocol/webrtc_audio_source_adapter.cc +++ b/remoting/protocol/webrtc_audio_source_adapter.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/check_op.h" +#include "base/observer_list.h" #include "base/synchronization/lock.h" #include "base/threading/thread_checker.h" #include "remoting/proto/audio.pb.h"
diff --git a/remoting/protocol/webrtc_audio_source_adapter.h b/remoting/protocol/webrtc_audio_source_adapter.h index e867cd1..248d4ca3 100644 --- a/remoting/protocol/webrtc_audio_source_adapter.h +++ b/remoting/protocol/webrtc_audio_source_adapter.h
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/observer_list.h" #include "base/single_thread_task_runner.h" #include "third_party/webrtc/api/media_stream_interface.h"
diff --git a/services/cert_verifier/trial_comparison_cert_verifier_mojo.h b/services/cert_verifier/trial_comparison_cert_verifier_mojo.h index ee59b74..c177e393f 100644 --- a/services/cert_verifier/trial_comparison_cert_verifier_mojo.h +++ b/services/cert_verifier/trial_comparison_cert_verifier_mojo.h
@@ -9,7 +9,6 @@ #include "base/component_export.h" #include "base/macros.h" -#include "base/observer_list.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/services/network/public/cpp/data_element.h b/services/network/public/cpp/data_element.h index 84e1859a..89a93e0 100644 --- a/services/network/public/cpp/data_element.h +++ b/services/network/public/cpp/data_element.h
@@ -13,7 +13,6 @@ #include <utility> #include <vector> -#include "base/check_op.h" #include "base/component_export.h" #include "base/files/file_path.h" #include "base/strings/string_piece.h"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 0313113..391be97f 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -21403,7 +21403,7 @@ { "cpu": "arm64", "inside_docker": "1", - "os": "Ubuntu-16.04" + "os": "Ubuntu-20.04" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -21425,7 +21425,7 @@ { "cpu": "arm64", "inside_docker": "1", - "os": "Ubuntu-16.04" + "os": "Ubuntu-20.04" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -21447,7 +21447,7 @@ { "cpu": "arm64", "inside_docker": "1", - "os": "Ubuntu-16.04" + "os": "Ubuntu-20.04" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -21469,7 +21469,7 @@ { "cpu": "arm64", "inside_docker": "1", - "os": "Ubuntu-16.04" + "os": "Ubuntu-20.04" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -21491,7 +21491,7 @@ { "cpu": "arm64", "inside_docker": "1", - "os": "Ubuntu-16.04" + "os": "Ubuntu-20.04" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -21513,7 +21513,7 @@ { "cpu": "arm64", "inside_docker": "1", - "os": "Ubuntu-16.04" + "os": "Ubuntu-20.04" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -21535,7 +21535,7 @@ { "cpu": "arm64", "inside_docker": "1", - "os": "Ubuntu-16.04" + "os": "Ubuntu-20.04" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -21554,7 +21554,7 @@ { "cpu": "arm64", "inside_docker": "1", - "os": "Ubuntu-16.04" + "os": "Ubuntu-20.04" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 26f698ba..415f8b6 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -2784,7 +2784,7 @@ 'mixins': [ 'arm64', 'docker', - 'linux-xenial', + 'linux-focal', ], }, 'fuchsia-fyi-x64-dbg': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index e33a736..c980959 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -113,6 +113,24 @@ ] } ], + "AgsaGoogleAppBrowserFinchDrivenStudy": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "params": { + "key": "value" + }, + "enable_features": [ + "ExperimentsForAgsa" + ] + } + ] + } + ], "AmpBackgroundTab": [ { "platforms": [ @@ -2052,29 +2070,6 @@ ] } ], - "CodeCacheDeduplicationStudy": [ - { - "platforms": [ - "android", - "chromeos", - "chromeos_lacros", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled_16K", - "params": { - "size": "16384" - }, - "enable_features": [ - "CodeCacheDeduplicationStudy" - ] - } - ] - } - ], "ColorProviderRedirection": [ { "platforms": [ @@ -3269,21 +3264,6 @@ ] } ], - "EnableCsrssLockdown": [ - { - "platforms": [ - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "EnableCsrssLockdown" - ] - } - ] - } - ], "EnableDynamicUpdate": [ { "platforms": [ @@ -5826,7 +5806,7 @@ { "name": "Enabled", "params": { - "availability": ">=14", + "availability": ">=0", "event_1": "name:permission_request_shown;comparator:>=3;window:90;storage:90", "event_trigger": "name:page_info_iph_triggered;comparator:==0;window:90;storage:90", "event_used": "name:page_info_opened;comparator:==0;window:90;storage:90", @@ -7276,31 +7256,6 @@ ] } ], - "SimplifiedUrlDisplay": [ - { - "platforms": [ - "chromeos", - "chromeos_lacros", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "AllDisplayExperimentsEnabled", - "params": { - "enable_keyword_elision": "false" - }, - "enable_features": [ - "OmniboxUIExperimentElideToRegistrableDomain", - "OmniboxUIExperimentHideSteadyStateUrlPathQueryAndRefOnInteraction", - "OmniboxUIExperimentRevealSteadyStateUrlPathQueryAndRefOnHover", - "SafeBrowsingDelayedWarnings" - ] - } - ] - } - ], "SimplifySignOutIOS": [ { "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore index dfedc29..ac7eeb0 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore
@@ -72,6 +72,7 @@ /depot_tools /devtools-frontend/src /directxsdk +/distributed_point_functions/src /dom_distiller_js/dist /eigen3/src /elfutils/src
diff --git a/third_party/android_deps/build.gradle b/third_party/android_deps/build.gradle index 3c9f8cd..da4950e 100644 --- a/third_party/android_deps/build.gradle +++ b/third_party/android_deps/build.gradle
@@ -5,17 +5,17 @@ apply plugin: ChromiumPlugin buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" + repositories { + maven { + url 'https://plugins.gradle.org/m2/' + } } - } - dependencies { - classpath "org.owasp:dependency-check-gradle:6+" - } + dependencies { + classpath 'org.owasp:dependency-check-gradle:6+' + } } -apply plugin: "org.owasp.dependencycheck" +apply plugin: 'org.owasp.dependencycheck' repositories { mavenCentral() @@ -27,14 +27,14 @@ dependencyCheck { // Any known vulnerability of any severity will cause the build to fail. failBuildOnCVSS = 0 - suppressionFile = file("vulnerability_supressions.xml") + suppressionFile = file('vulnerability_supressions.xml') // Libraries used in these configurations aren't shipped in Chrome. // They are only used to aid in compiling or testing. skipConfigurations = [ - "buildCompile", - "buildCompileNoDeps", - "androidTestCompile", - "testCompile" + 'buildCompile', + 'buildCompileNoDeps', + 'androidTestCompile', + 'testCompile' ] } @@ -42,10 +42,10 @@ // Note about the configuration names: they are defined in buildSrc/ChromiumPlugin // Replacement for com.android.support:design - compile "com.google.android.material:material:1.2.0-alpha06" + compile 'com.google.android.material:material:1.2.0-alpha06' // Architecture components - def archComponentsVersion = '1.1.1' + String archComponentsVersion = '1.1.1' compile "android.arch.lifecycle:runtime:${archComponentsVersion}" compile "android.arch.lifecycle:common:${archComponentsVersion}" compile "android.arch.lifecycle:common-java8:${archComponentsVersion}" @@ -54,12 +54,12 @@ // Play services libraries // See https://developers.google.com/android/guides/releases for updates // Starting from 15.0.0 these libraries are allowed to update independently - def gmsVersion = '17.0.0' + String gmsVersion = '17.0.0' compile "com.google.android.gms:play-services-basement:${gmsVersion}" compile "com.google.android.gms:play-services-tasks:${gmsVersion}" compile "com.google.android.gms:play-services-base:${gmsVersion}" compile "com.google.android.gms:play-services-auth-base:${gmsVersion}" - compile "com.google.android.gms:play-services-auth-api-phone:17.5.0" + compile 'com.google.android.gms:play-services-auth-api-phone:17.5.0' compile "com.google.android.gms:play-services-auth:${gmsVersion}" compile "com.google.android.gms:play-services-cast:${gmsVersion}" compile "com.google.android.gms:play-services-cast-framework:${gmsVersion}" @@ -67,13 +67,13 @@ compile "com.google.android.gms:play-services-instantapps:${gmsVersion}" compile "com.google.android.gms:play-services-gcm:${gmsVersion}" compile "com.google.android.gms:play-services-location:${gmsVersion}" - compile "com.google.android.gms:play-services-vision-common:18.0.0" - compile "com.google.android.gms:play-services-vision:18.0.0" - compile "com.google.android.gms:play-services-fido:19.0.0-beta" + compile 'com.google.android.gms:play-services-vision-common:18.0.0' + compile 'com.google.android.gms:play-services-vision:18.0.0' + compile 'com.google.android.gms:play-services-fido:19.0.0-beta' // TODO (bjoyce): Remove after androidx migration crbug.com/896775 // Support v4 libraries - def supportLibVersion = '28.0.0' + String supportLibVersion = '28.0.0' compile "com.android.support:support-v4:${supportLibVersion}" compile "com.android.support:support-compat:${supportLibVersion}" compile "com.android.support:support-core-ui:${supportLibVersion}" @@ -89,85 +89,84 @@ compile "com.android.support:customview:${supportLibVersion}" compile "com.android.support:drawerlayout:${supportLibVersion}" compile "com.android.support:interpolator:${supportLibVersion}" - compile "com.android.support:localbroadcastmanager:1.1.0-SNAPSHOT" + compile 'com.android.support:localbroadcastmanager:1.1.0-SNAPSHOT' compile "com.android.support:swiperefreshlayout:${supportLibVersion}" compile "com.android.support:viewpager:${supportLibVersion}" - compile "com.android.support:multidex:1.0.0" + compile 'com.android.support:multidex:1.0.0' - compile "com.google.code.findbugs:jsr305:3.0.2" - compile "com.google.firebase:firebase-iid:21.0.1" - compile "com.google.firebase:firebase-messaging:21.0.1" - compile "com.google.guava:failureaccess:1.0.1" - compile "com.google.j2objc:j2objc-annotations:1.1" - compile "com.google.protobuf:protobuf-javalite:3.13.0" - compile "javax.annotation:javax.annotation-api:1.3.2" - compile "javax.annotation:jsr250-api:1.0" - compile "javax.inject:javax.inject:1" + compile 'com.google.code.findbugs:jsr305:3.0.2' + compile 'com.google.firebase:firebase-iid:21.0.1' + compile 'com.google.firebase:firebase-messaging:21.0.1' + compile 'com.google.guava:failureaccess:1.0.1' + compile 'com.google.j2objc:j2objc-annotations:1.1' + compile 'com.google.protobuf:protobuf-javalite:3.13.0' + compile 'javax.annotation:javax.annotation-api:1.3.2' + compile 'javax.annotation:jsr250-api:1.0' + compile 'javax.inject:javax.inject:1' // Used by R8 to desugar library functions. // See instructions in //third_party/r8/README.chromium for how to // update desugar_jdk_libs.json (needed when changing this version). - compile "com.android.tools:desugar_jdk_libs:1.1.1" - compile "com.android.tools:desugar_jdk_libs_configuration:1.1.1" + compile 'com.android.tools:desugar_jdk_libs:1.1.1' + compile 'com.android.tools:desugar_jdk_libs_configuration:1.1.1' // Upstream guava introduced versions with -android suffix starting with version // 22 to remove incompatible code with android. Thus we keep two jars, one for // the full guava and one that supports android. - compile "com.google.guava:guava:30.1-android" + compile 'com.google.guava:guava:30.1-android' // Needed by androidx. - compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3" + compile 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3' // buildCompile targets have supports_android = false. - buildCompile "com.google.guava:guava:30.1-jre" + buildCompile 'com.google.guava:guava:30.1-jre' - def daggerVersion = '2.30' + String daggerVersion = '2.30' compile "com.google.dagger:dagger:${daggerVersion}" buildCompile "com.google.dagger:dagger-compiler:${daggerVersion}" // Matches version depended on by Dagger. - buildCompile "com.squareup:javapoet:1.13.0" + buildCompile 'com.squareup:javapoet:1.13.0' - def errorproneVersion = '2.4.0' + String errorproneVersion = '2.4.0' // Used by downstream targets. compile "com.google.errorprone:error_prone_annotations:${errorproneVersion}" - compile "org.checkerframework:checker-compat-qual:2.5.3" - compile "org.codehaus.mojo:animal-sniffer-annotations:1.17" + compile 'org.checkerframework:checker-compat-qual:2.5.3' + compile 'org.codehaus.mojo:animal-sniffer-annotations:1.17' // Dedicated configuration to avoid using higher version number. The 9999 version is empty. - compileListenableFuture "com.google.guava:listenablefuture:1.0" + compileListenableFuture 'com.google.guava:listenablefuture:1.0' buildCompile "com.google.errorprone:error_prone_core:${errorproneVersion}" buildCompile "com.google.errorprone:error_prone_check_api:${errorproneVersion}" buildCompile "com.google.errorprone:error_prone_annotation:${errorproneVersion}" - buildCompile "com.google.errorprone:javac:9+181-r4173-1" + buildCompile 'com.google.errorprone:javac:9+181-r4173-1' - buildCompile "com.google.auto.service:auto-service:1.0-rc6" - buildCompile "com.google.auto.service:auto-service-annotations:1.0-rc6" - buildCompile "com.google.code.gson:gson:2.8.0" - buildCompile "org.ow2.asm:asm:7.0" - buildCompile "org.ow2.asm:asm-commons:7.0" - buildCompile "org.ow2.asm:asm-tree:7.0" - buildCompile "org.ow2.asm:asm-util:7.0" + buildCompile 'com.google.auto.service:auto-service:1.0-rc6' + buildCompile 'com.google.auto.service:auto-service-annotations:1.0-rc6' + buildCompile 'com.google.code.gson:gson:2.8.0' + buildCompile 'org.ow2.asm:asm:7.0' + buildCompile 'org.ow2.asm:asm-commons:7.0' + buildCompile 'org.ow2.asm:asm-tree:7.0' + buildCompile 'org.ow2.asm:asm-util:7.0' // Used by resource shrinking. // buildCompileNoDeps targets do not bring in any of their dependencies, // this list of targets is carefully curated for the use of the resources // shrinker. If these are needed for something other than the resources // shrinker, use buildCompile instead. - def androidToolsVersion = '30.0.0-alpha10' + String androidToolsVersion = '30.0.0-alpha10' buildCompileNoDeps "com.android.tools:sdk-common:${androidToolsVersion}" buildCompileNoDeps "com.android.tools:common:${androidToolsVersion}" buildCompileNoDeps "com.android.tools.layoutlib:layoutlib-api:${androidToolsVersion}" - buildCompile "org.jetbrains.kotlin:kotlin-stdlib:1.4.32" + buildCompile 'org.jetbrains.kotlin:kotlin-stdlib:1.4.32' - androidTestCompile "com.googlecode.java-diff-utils:diffutils:1.3.0" + androidTestCompile 'com.googlecode.java-diff-utils:diffutils:1.3.0' // Version 1.2 is needed by espresso-web, but we'll newer 1.2.1. - androidTestCompile "org.ccil.cowan.tagsoup:tagsoup:1.2.1" + androidTestCompile 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' - - def robolectricVersion = '4.3.1' + String robolectricVersion = '4.3.1' // Use testCompile to avoid having support_android = true set on // robolectric dependencies. testCompile "org.robolectric:robolectric:${robolectricVersion}"
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib/3pp/fetch.py index ce1d2a9..ce3559e55 100755 --- a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib/3pp/fetch.py +++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib/3pp/fetch.py
@@ -12,9 +12,9 @@ import json import os -_FILE_URL = 'https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.4.32/kotlin-stdlib-1.4.32.jar' -_FILE_NAME = 'kotlin-stdlib-1.4.32.jar' -_FILE_VERSION = '1.4.32' +_FILE_URL = 'https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.5.10/kotlin-stdlib-1.5.10.jar' +_FILE_NAME = 'kotlin-stdlib-1.5.10.jar' +_FILE_VERSION = '1.5.10' def do_latest():
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_common/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_common/3pp/fetch.py index c59dc7e..1f768a0 100755 --- a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_common/3pp/fetch.py +++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_common/3pp/fetch.py
@@ -12,9 +12,9 @@ import json import os -_FILE_URL = 'https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.32/kotlin-stdlib-common-1.4.32.jar' -_FILE_NAME = 'kotlin-stdlib-common-1.4.32.jar' -_FILE_VERSION = '1.4.32' +_FILE_URL = 'https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.5.10/kotlin-stdlib-common-1.5.10.jar' +_FILE_NAME = 'kotlin-stdlib-common-1.5.10.jar' +_FILE_VERSION = '1.5.10' def do_latest():
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index f19febd1..c6fd7e1 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -528,6 +528,8 @@ // See crbug.com/1008483. const base::Feature kTransformInterop{"TransformInterop", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kBackfaceVisibilityInterop{ + "BackfaceVisibilityInterop", base::FEATURE_DISABLED_BY_DEFAULT}; // When enabled, beacons (and friends) have ResourceLoadPriority::kLow, // not ResourceLoadPriority::kVeryLow.
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 307bbdc0..07a8ec1 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -159,6 +159,7 @@ kIgnoreCrossOriginWindowWhenNamedAccessOnWindow; BLINK_COMMON_EXPORT extern const base::Feature kTransformInterop; +BLINK_COMMON_EXPORT extern const base::Feature kBackfaceVisibilityInterop; BLINK_COMMON_EXPORT extern const base::Feature kSubresourceRedirect;
diff --git a/third_party/blink/public/common/manifest/manifest.h b/third_party/blink/public/common/manifest/manifest.h index cb432b6..8318cfff 100644 --- a/third_party/blink/public/common/manifest/manifest.h +++ b/third_party/blink/public/common/manifest/manifest.h
@@ -251,7 +251,8 @@ // False if parsing failed or the field was not present. // TODO(crbug.com/1212263): This field is non-standard and part of a Chrome - // experiment. + // experiment. See: + // https://github.com/robbiemc/pwa-isolated-storage/blob/main/explainer.md bool isolated_storage = false; };
diff --git a/third_party/blink/public/mojom/manifest/manifest.mojom b/third_party/blink/public/mojom/manifest/manifest.mojom index 1cf9b32..57e8c0d2 100644 --- a/third_party/blink/public/mojom/manifest/manifest.mojom +++ b/third_party/blink/public/mojom/manifest/manifest.mojom
@@ -85,7 +85,8 @@ CaptureLinks capture_links; // TODO(crbug.com/1212263): This field is non-standard and part of a Chrome - // experiment. + // experiment. See: + // https://github.com/robbiemc/pwa-isolated-storage/blob/main/explainer.md bool isolated_storage; };
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h index accd722..17365cf8 100644 --- a/third_party/blink/public/platform/web_runtime_features.h +++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -152,6 +152,7 @@ EnableRestrictAutomaticLazyFrameLoadingToDataSaver(bool); BLINK_PLATFORM_EXPORT static void EnableRestrictAutomaticLazyImageLoadingToDataSaver(bool); + BLINK_PLATFORM_EXPORT static void EnableSecurePaymentConfirmationAPIV2(bool); BLINK_PLATFORM_EXPORT static void EnableSecurePaymentConfirmationDebug(bool); BLINK_PLATFORM_EXPORT static void EnableScriptedSpeechRecognition(bool); BLINK_PLATFORM_EXPORT static void EnableScriptedSpeechSynthesis(bool); @@ -232,6 +233,7 @@ BLINK_PLATFORM_EXPORT static void EnableInstalledApp(bool); BLINK_PLATFORM_EXPORT static void EnableTransformInterop(bool); + BLINK_PLATFORM_EXPORT static void EnableBackfaceVisibilityInterop(bool); BLINK_PLATFORM_EXPORT static void EnableVideoWakeLockOptimisationHiddenMuted( bool); BLINK_PLATFORM_EXPORT static void EnableContentIndex(bool);
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h index 7acd3f2..97e150f 100644 --- a/third_party/blink/public/web/web_view.h +++ b/third_party/blink/public/web/web_view.h
@@ -462,7 +462,10 @@ virtual int32_t HistoryBackListCount() const = 0; virtual int32_t HistoryForwardListCount() const = 0; - // Portals -------------------------------------------------------------- + // Misc ------------------------------------------------------------- + + // Returns the number of live WebView instances in this process. + BLINK_EXPORT static size_t GetWebViewCount(); protected: ~WebView() = default;
diff --git a/third_party/blink/renderer/core/OWNERS b/third_party/blink/renderer/core/OWNERS index 5436e37c..ab038c7 100644 --- a/third_party/blink/renderer/core/OWNERS +++ b/third_party/blink/renderer/core/OWNERS
@@ -19,8 +19,6 @@ dlibby@microsoft.com # drott reviews font specific changes. drott@chromium.org -dsinclair@chromium.org -dstockwell@chromium.org # dtapuska reviews input-related changes dtapuska@chromium.org enne@chromium.org @@ -37,17 +35,14 @@ hayato@chromium.org hiroshige@chromium.org ikilpatrick@chromium.org -inferno@chromium.org japhet@chromium.org jarhar@chromium.org jbroman@chromium.org jfernandez@igalia.com -jianli@chromium.org jochen@chromium.org junov@chromium.org kbr@chromium.org keishi@chromium.org -kenneth.r.christiansen@intel.com kinuko@chromium.org kojii@chromium.org kouhei@chromium.org @@ -61,7 +56,6 @@ pfeldman@chromium.org pkasting@chromium.org rego@igalia.com -rbyers@chromium.org rbuis@igalia.com robhogan@gmail.com schenney@chromium.org @@ -70,7 +64,6 @@ svillar@igalia.com szager@chromium.org thakis@chromium.org -timloh@chromium.org tkent@chromium.org vmpstr@chromium.org vollick@chromium.org
diff --git a/third_party/blink/renderer/core/css/css_default_style_sheets.cc b/third_party/blink/renderer/core/css/css_default_style_sheets.cc index 8b62da40..255388e 100644 --- a/third_party/blink/renderer/core/css/css_default_style_sheets.cc +++ b/third_party/blink/renderer/core/css/css_default_style_sheets.cc
@@ -105,15 +105,15 @@ InitializeDefaultStyles(); #if DCHECK_IS_ON() - default_style_->CompactRulesIfNeeded(); + default_html_style_->CompactRulesIfNeeded(); default_mathml_style_->CompactRulesIfNeeded(); default_svg_style_->CompactRulesIfNeeded(); - default_quirks_style_->CompactRulesIfNeeded(); + default_html_quirks_style_->CompactRulesIfNeeded(); default_print_style_->CompactRulesIfNeeded(); - DCHECK(default_style_->UniversalRules()->IsEmpty()); + DCHECK(default_html_style_->UniversalRules()->IsEmpty()); DCHECK(default_mathml_style_->UniversalRules()->IsEmpty()); DCHECK(default_svg_style_->UniversalRules()->IsEmpty()); - DCHECK(default_quirks_style_->UniversalRules()->IsEmpty()); + DCHECK(default_html_quirks_style_->UniversalRules()->IsEmpty()); DCHECK(default_print_style_->UniversalRules()->IsEmpty()); #endif } @@ -144,17 +144,18 @@ void CSSDefaultStyleSheets::InitializeDefaultStyles() { // This must be called only from constructor / PrepareForLeakDetection. - default_style_ = MakeGarbageCollected<RuleSet>(); + default_html_style_ = MakeGarbageCollected<RuleSet>(); default_mathml_style_ = MakeGarbageCollected<RuleSet>(); default_svg_style_ = MakeGarbageCollected<RuleSet>(); - default_quirks_style_ = MakeGarbageCollected<RuleSet>(); + default_html_quirks_style_ = MakeGarbageCollected<RuleSet>(); default_print_style_ = MakeGarbageCollected<RuleSet>(); default_media_controls_style_ = MakeGarbageCollected<RuleSet>(); default_forced_color_style_.Clear(); default_pseudo_element_style_.Clear(); - default_style_->AddRulesFromSheet(DefaultStyleSheet(), ScreenEval()); - default_quirks_style_->AddRulesFromSheet(QuirksStyleSheet(), ScreenEval()); + default_html_style_->AddRulesFromSheet(DefaultStyleSheet(), ScreenEval()); + default_html_quirks_style_->AddRulesFromSheet(QuirksStyleSheet(), + ScreenEval()); default_print_style_->AddRulesFromSheet(DefaultStyleSheet(), PrintEval()); } @@ -204,6 +205,30 @@ builder->Append("; "); } +void CSSDefaultStyleSheets::AddRulesToDefaultStyleSheets( + StyleSheetContents* rules, + NamespaceType type) { + switch (type) { + case NamespaceType::kHTML: + default_html_style_->AddRulesFromSheet(rules, ScreenEval()); + default_html_quirks_style_->AddRulesFromSheet(rules, ScreenEval()); + break; + case NamespaceType::kSVG: + default_svg_style_->AddRulesFromSheet(rules, ScreenEval()); + break; + case NamespaceType::kMathML: + default_mathml_style_->AddRulesFromSheet(rules, ScreenEval()); + break; + case NamespaceType::kMediaControls: + default_media_controls_style_->AddRulesFromSheet(rules, ScreenEval()); + break; + } + // Add to print and forced color for all namespaces. + default_print_style_->AddRulesFromSheet(rules, PrintEval()); + if (default_forced_color_style_) + default_forced_color_style_->AddRulesFromSheet(rules, ForcedColorsEval()); +} + bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetsForElement( const Element& element) { bool changed_default_style = false; @@ -211,12 +236,7 @@ if (element.IsSVGElement() && !svg_style_sheet_) { svg_style_sheet_ = ParseUASheet(UncompressResourceAsASCIIString(IDR_UASTYLE_SVG_CSS)); - default_svg_style_->AddRulesFromSheet(SvgStyleSheet(), ScreenEval()); - default_print_style_->AddRulesFromSheet(SvgStyleSheet(), PrintEval()); - if (default_forced_color_style_) { - default_forced_color_style_->AddRulesFromSheet(SvgStyleSheet(), - ForcedColorsEval()); - } + AddRulesToDefaultStyleSheets(svg_style_sheet_, NamespaceType::kSVG); changed_default_style = true; } @@ -227,8 +247,7 @@ RuntimeEnabledFeatures::MathMLCoreEnabled() ? UncompressResourceAsASCIIString(IDR_UASTYLE_MATHML_CSS) : UncompressResourceAsASCIIString(IDR_UASTYLE_MATHML_FALLBACK_CSS)); - default_mathml_style_->AddRulesFromSheet(MathmlStyleSheet(), ScreenEval()); - default_print_style_->AddRulesFromSheet(MathmlStyleSheet(), PrintEval()); + AddRulesToDefaultStyleSheets(mathml_style_sheet_, NamespaceType::kMathML); changed_default_style = true; } @@ -238,14 +257,8 @@ // and <audio>. media_controls_style_sheet_ = ParseUASheet(media_controls_style_sheet_loader_->GetUAStyleSheet()); - default_media_controls_style_->AddRulesFromSheet(MediaControlsStyleSheet(), - ScreenEval()); - default_print_style_->AddRulesFromSheet(MediaControlsStyleSheet(), - PrintEval()); - if (default_forced_color_style_) { - default_forced_color_style_->AddRulesFromSheet(MediaControlsStyleSheet(), - ForcedColorsEval()); - } + AddRulesToDefaultStyleSheets(media_controls_style_sheet_, + NamespaceType::kMediaControls); changed_default_style = true; } @@ -277,10 +290,8 @@ settings->GetTextTrackTextSize()); builder.Append(" } "); text_track_style_sheet_ = ParseUASheet(builder.ToString()); - default_media_controls_style_->AddRulesFromSheet(text_track_style_sheet_, - ScreenEval()); - default_print_style_->AddRulesFromSheet(text_track_style_sheet_, - PrintEval()); + AddRulesToDefaultStyleSheets(text_track_style_sheet_, + NamespaceType::kMediaControls); changed_default_style = true; } } @@ -292,18 +303,11 @@ ? UncompressResourceAsASCIIString(IDR_UASTYLE_POPUP_CSS) : String(); popup_style_sheet_ = ParseUASheet(popup_rules); - // TODO(crbug.com/1201360): refactor this into a separate function. - default_style_->AddRulesFromSheet(PopupStyleSheet(), ScreenEval()); - default_print_style_->AddRulesFromSheet(PopupStyleSheet(), PrintEval()); - default_quirks_style_->AddRulesFromSheet(PopupStyleSheet(), ScreenEval()); - if (default_forced_color_style_) { - default_forced_color_style_->AddRulesFromSheet(PopupStyleSheet(), - ForcedColorsEval()); - } + AddRulesToDefaultStyleSheets(popup_style_sheet_, NamespaceType::kHTML); changed_default_style = true; } - DCHECK(!default_style_->Features().HasIdsInSelectors()); + DCHECK(!default_html_style_->Features().HasIdsInSelectors()); return changed_default_style; } @@ -337,13 +341,8 @@ webxr_overlay_style_sheet_ = ParseUASheet( UncompressResourceAsASCIIString(IDR_UASTYLE_WEBXR_OVERLAY_CSS)); - default_style_->AddRulesFromSheet(webxr_overlay_style_sheet_, ScreenEval()); - default_print_style_->AddRulesFromSheet(webxr_overlay_style_sheet_, - PrintEval()); - if (default_forced_color_style_) { - default_forced_color_style_->AddRulesFromSheet(webxr_overlay_style_sheet_, - ForcedColorsEval()); - } + AddRulesToDefaultStyleSheets(webxr_overlay_style_sheet_, + NamespaceType::kHTML); return true; } @@ -355,9 +354,7 @@ UncompressResourceAsASCIIString(IDR_UASTYLE_FULLSCREEN_CSS) + LayoutTheme::GetTheme().ExtraFullscreenStyleSheet(); fullscreen_style_sheet_ = ParseUASheet(fullscreen_rules); - default_style_->AddRulesFromSheet(FullscreenStyleSheet(), ScreenEval()); - default_quirks_style_->AddRulesFromSheet(FullscreenStyleSheet(), - ScreenEval()); + AddRulesToDefaultStyleSheets(fullscreen_style_sheet_, NamespaceType::kHTML); } bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetForForcedColors() { @@ -394,8 +391,8 @@ void CSSDefaultStyleSheets::CollectFeaturesTo(const Document& document, RuleFeatureSet& features) { - if (DefaultStyle()) - features.Add(DefaultStyle()->Features()); + if (DefaultHtmlStyle()) + features.Add(DefaultHtmlStyle()->Features()); if (DefaultMediaControlsStyle()) features.Add(DefaultMediaControlsStyle()->Features()); if (DefaultMathMLStyle()) @@ -405,10 +402,10 @@ } void CSSDefaultStyleSheets::Trace(Visitor* visitor) const { - visitor->Trace(default_style_); + visitor->Trace(default_html_style_); visitor->Trace(default_mathml_style_); visitor->Trace(default_svg_style_); - visitor->Trace(default_quirks_style_); + visitor->Trace(default_html_quirks_style_); visitor->Trace(default_print_style_); visitor->Trace(default_view_source_style_); visitor->Trace(default_forced_color_style_);
diff --git a/third_party/blink/renderer/core/css/css_default_style_sheets.h b/third_party/blink/renderer/core/css/css_default_style_sheets.h index bab7c6b2..44fed53 100644 --- a/third_party/blink/renderer/core/css/css_default_style_sheets.h +++ b/third_party/blink/renderer/core/css/css_default_style_sheets.h
@@ -55,10 +55,10 @@ void EnsureDefaultStyleSheetForFullscreen(); bool EnsureDefaultStyleSheetForForcedColors(); - RuleSet* DefaultStyle() { return default_style_.Get(); } + RuleSet* DefaultHtmlStyle() { return default_html_style_.Get(); } RuleSet* DefaultMathMLStyle() { return default_mathml_style_.Get(); } RuleSet* DefaultSVGStyle() { return default_svg_style_.Get(); } - RuleSet* DefaultQuirksStyle() { return default_quirks_style_.Get(); } + RuleSet* DefaultHtmlQuirksStyle() { return default_html_quirks_style_.Get(); } RuleSet* DefaultPrintStyle() { return default_print_style_.Get(); } RuleSet* DefaultViewSourceStyle(); RuleSet* DefaultForcedColorStyle() { @@ -116,10 +116,19 @@ private: void InitializeDefaultStyles(); - Member<RuleSet> default_style_; + enum class NamespaceType { + kHTML, + kMathML, + kSVG, + kMediaControls, // Not exactly a namespace + }; + void AddRulesToDefaultStyleSheets(StyleSheetContents* rules, + NamespaceType type); + + Member<RuleSet> default_html_style_; Member<RuleSet> default_mathml_style_; Member<RuleSet> default_svg_style_; - Member<RuleSet> default_quirks_style_; + Member<RuleSet> default_html_quirks_style_; Member<RuleSet> default_print_style_; Member<RuleSet> default_view_source_style_; Member<RuleSet> default_forced_color_style_;
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc index f6eaf41..69181e4a 100644 --- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc +++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -570,7 +570,7 @@ CSSDefaultStyleSheets::Instance(); if (!print_media_type_) { if (LIKELY(element.IsHTMLElement() || element.IsVTTElement())) { - MatchRuleSet(collector, default_style_sheets.DefaultStyle()); + MatchRuleSet(collector, default_style_sheets.DefaultHtmlStyle()); if (UNLIKELY(IsInMediaUAShadow(element))) { MatchRuleSet(collector, default_style_sheets.DefaultMediaControlsStyle()); @@ -586,7 +586,7 @@ // In quirks mode, we match rules from the quirks user agent sheet. if (GetDocument().InQuirksMode()) - MatchRuleSet(collector, default_style_sheets.DefaultQuirksStyle()); + MatchRuleSet(collector, default_style_sheets.DefaultHtmlQuirksStyle()); // If document uses view source styles (in view source mode or in xml viewer // mode), then we match rules from the view source style sheet.
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index b411a54..69621be3 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2033,8 +2033,10 @@ return; } - if (InStyleRecalc()) + if (InStyleRecalc()) { + NOTREACHED() << "We should not re-enter style recalc for the same document"; return; + } #if DCHECK_IS_ON() int assigned_nodes_in_slot_count = 0;
diff --git a/third_party/blink/renderer/core/dom/events/event_path.cc b/third_party/blink/renderer/core/dom/events/event_path.cc index 7222d294..8c34562 100644 --- a/third_party/blink/renderer/core/dom/events/event_path.cc +++ b/third_party/blink/renderer/core/dom/events/event_path.cc
@@ -68,7 +68,11 @@ } static inline bool EventPathShouldBeEmptyFor(Node& node) { - return node.IsPseudoElement() && !node.parentElement(); + // Event path should be empty for orphaned pseudo elements, and nodes + // whose document is stopped. In corner cases (crbug.com/1210480), the node + // document can get detached before we can remove event listeners. + return (node.IsPseudoElement() && !node.parentElement()) || + node.GetDocument().IsStopped(); } void EventPath::Initialize() {
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc index bd6d49a..79fa48f 100644 --- a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc +++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -706,9 +706,8 @@ PageWidgetDelegate::Animate(*page_, base::TimeTicks::Now()); } -bool WebPagePopupImpl::WillHandleGestureEvent(const WebGestureEvent& event) { - return false; -} +void WebPagePopupImpl::WillHandleGestureEvent(const WebGestureEvent& event, + bool* suppress) {} void WebPagePopupImpl::WillHandleMouseEvent(const WebMouseEvent& event) {}
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.h b/third_party/blink/renderer/core/exported/web_page_popup_impl.h index 4e25100f..5e8b332b 100644 --- a/third_party/blink/renderer/core/exported/web_page_popup_impl.h +++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.h
@@ -124,7 +124,8 @@ void BeginMainFrame(base::TimeTicks last_frame_time) override; void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) final; WebInputEventResult DispatchBufferedTouchEvents() override; - bool WillHandleGestureEvent(const WebGestureEvent& event) override; + void WillHandleGestureEvent(const WebGestureEvent& event, + bool* suppress) override; void WillHandleMouseEvent(const WebMouseEvent& event) override; void ObserveGestureEventAndResult( const WebGestureEvent& gesture_event,
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index f2fbcc76..81c8878 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -494,6 +494,10 @@ return web_view.get(); } +size_t WebView::GetWebViewCount() { + return WebViewImpl::AllInstances().size(); +} + void WebView::UpdateVisitedLinkState(uint64_t link_hash) { Page::VisitedStateChanged(link_hash); }
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index 6814fdb..facd36a1 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -2208,28 +2208,30 @@ trackers); } -bool WebFrameWidgetImpl::WillHandleGestureEvent(const WebGestureEvent& event) { +void WebFrameWidgetImpl::WillHandleGestureEvent(const WebGestureEvent& event, + bool* suppress) { possible_drag_event_info_.source = ui::mojom::blink::DragEventSource::kTouch; possible_drag_event_info_.location = gfx::ToFlooredPoint(event.PositionInScreen()); - bool move_cursor = false; + bool handle_as_cursor_control = false; switch (event.GetType()) { case WebInputEvent::Type::kGestureScrollBegin: { if (event.data.scroll_begin.cursor_control) { swipe_to_move_cursor_activated_ = true; - move_cursor = true; + handle_as_cursor_control = true; } break; } case WebInputEvent::Type::kGestureScrollUpdate: { if (swipe_to_move_cursor_activated_) - move_cursor = true; + handle_as_cursor_control = true; break; } case WebInputEvent::Type::kGestureScrollEnd: { if (swipe_to_move_cursor_activated_) { swipe_to_move_cursor_activated_ = false; + handle_as_cursor_control = true; } break; } @@ -2238,16 +2240,15 @@ } // TODO(crbug.com/1140106): Place cursor for scroll begin other than just move // cursor. - if (move_cursor) { + if (handle_as_cursor_control) { WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget(); if (focused_frame) { gfx::Point base(event.PositionInWidget().x(), event.PositionInWidget().y()); focused_frame->MoveCaretSelection(base); } - return true; + *suppress = true; } - return false; } void WebFrameWidgetImpl::WillHandleMouseEvent(const WebMouseEvent& event) {
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h index 8062134..2e53ad9a 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -634,7 +634,8 @@ base::TimeTicks first_scroll_timestamp) override; void DidCompletePageScaleAnimation() override; void FocusChangeComplete() override; - bool WillHandleGestureEvent(const WebGestureEvent& event) override; + void WillHandleGestureEvent(const WebGestureEvent& event, + bool* suppress) override; void WillHandleMouseEvent(const WebMouseEvent& event) override; void ObserveGestureEventAndResult( const WebGestureEvent& gesture_event,
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_test.cc b/third_party/blink/renderer/core/frame/web_frame_widget_test.cc index 9a47b75..ab3aa0d1 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_test.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_test.cc
@@ -242,7 +242,8 @@ const cc::OverscrollBehavior& overscroll_behavior, bool event_processed)); - MOCK_METHOD1(WillHandleGestureEvent, bool(const WebGestureEvent& event)); + MOCK_METHOD2(WillHandleGestureEvent, + void(const WebGestureEvent& event, bool* suppress)); // mojom::blink::WidgetHost overrides: using SimWebFrameWidget::SetCursor; @@ -284,7 +285,8 @@ WebCoalescedInputEvent(event.Clone(), {}, {}, ui::LatencyInfo()), std::move(callback)); } - bool OverscrollGestureEvent(const blink::WebGestureEvent& event) { + void WillHandleGestureEvent(const blink::WebGestureEvent& event, + bool* suppress) { if (event.GetType() == WebInputEvent::Type::kGestureScrollUpdate) { MockMainFrameWidget()->DidOverscroll( gfx::Vector2dF(event.data.scroll_update.delta_x, @@ -294,9 +296,8 @@ event.PositionInWidget(), gfx::Vector2dF(event.data.scroll_update.velocity_x, event.data.scroll_update.velocity_y)); - return true; + *suppress = true; } - return false; } const base::HistogramTester& histogram_tester() const { @@ -335,9 +336,9 @@ } TEST_F(WebFrameWidgetImplSimTest, EventOverscroll) { - ON_CALL(*MockMainFrameWidget(), WillHandleGestureEvent(_)) + ON_CALL(*MockMainFrameWidget(), WillHandleGestureEvent(_, _)) .WillByDefault(testing::Invoke( - this, &WebFrameWidgetImplSimTest::OverscrollGestureEvent)); + this, &WebFrameWidgetImplSimTest::WillHandleGestureEvent)); EXPECT_CALL(*MockMainFrameWidget(), HandleInputEvent(_)) .WillRepeatedly(::testing::Return(WebInputEventResult::kNotHandled));
diff --git a/third_party/blink/renderer/core/html/build.gni b/third_party/blink/renderer/core/html/build.gni index 5a9e4059..6b8e4c0f 100644 --- a/third_party/blink/renderer/core/html/build.gni +++ b/third_party/blink/renderer/core/html/build.gni
@@ -25,6 +25,8 @@ "canvas/canvas_rendering_context_factory.h", "canvas/canvas_rendering_context_host.cc", "canvas/canvas_rendering_context_host.h", + "canvas/canvas_resource_tracker.cc", + "canvas/canvas_resource_tracker.h", "canvas/html_canvas_element.cc", "canvas/html_canvas_element.h", "canvas/image_data.cc", @@ -635,6 +637,7 @@ "canvas/canvas_async_blob_creator_test.cc", "canvas/canvas_font_cache_test.cc", "canvas/canvas_rendering_api_ukm_metrics_test.cc", + "canvas/canvas_resource_tracker_test.cc", "canvas/html_canvas_element_test.cc", "canvas/image_data_test.cc", "custom/custom_element_definition_test.cc",
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.cc b/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.cc index 47a8bcc..2fe67b1 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_performance_monitor.cc
@@ -19,27 +19,19 @@ const char* const kHostTypeName_Canvas = ".Canvas"; const char* const kHostTypeName_OffscreenCanvas = ".OffscreenCanvas"; -const char* const kThreadTypeName_Main = ".MainThread"; -const char* const kThreadTypeName_Worker = ".Worker"; - -const char* const kContextTypeName_2D = ".2D"; +const char* const kContextTypeName_2D_Accelerated = ".2D.Accelerated"; +const char* const kContextTypeName_2D_Unaccelerated = ".2D.Unaccelerated"; const char* const kContextTypeName_WebGL = ".WebGL"; const char* const kContextTypeName_WebGL2 = ".WebGL2"; const char* const kContextTypeName_WebGPU = ".WebGPU"; const char* const kContextTypeName_ImageBitmap = ".ImageBitmap"; -const char* const kResourceTypeName_Bitmap = ".Bitmap"; -const char* const kResourceTypeName_SharedBitmap = ".SharedBitmap"; -const char* const kResourceTypeName_SharedImage = ".SharedImage"; -const char* const kResourceTypeName_PassThrough = ".PassThrough"; -const char* const kResourceTypeName_SwapChain = ".SwapChain"; -const char* const kResourceTypeName_SkiaDawnSharedImage = - ".SkiaDawnSharedImage"; - const char* const kFilterName_All = ".All"; const char* const kFilterName_Animation = ".Animation"; const char* const kMeasurementName_RenderTaskDuration = ".RenderTaskDuration"; +const char* const kMeasurementName_PartitionAlloc = ".PartitionAlloc"; +const char* const kMeasurementName_BlinkGC = ".BlinkGC"; // The inverse of the probability that a given task will be measured. // I.e. a value of X means that each task has a probability 1/X of being @@ -54,22 +46,20 @@ explicit RenderingContextDescriptionCodec(const uint32_t& key); bool IsOffscreen() const { return key_.get<IsOffscreenField>(); } + bool IsAccelerated() const { return key_.get<IsAcceleratedField>(); } CanvasRenderingContext::ContextType ContextType() const; - CanvasResourceProvider::ResourceProviderType ResourceType() const; uint32_t GetKey() const { return key_.bits(); } bool IsValid() const { return is_valid_; } const char* GetHostTypeName() const; - const char* GetThreadTypeName() const; const char* GetContextTypeName() const; - const char* GetResourceTypeName() const; private: using Key = WTF::SingleThreadedBitField<uint32_t>; using IsOffscreenField = Key::DefineFirstValue<bool, 1>; - using ContextTypeField = IsOffscreenField::DefineNextValue<uint32_t, 8>; - using ResourceTypeField = ContextTypeField::DefineNextValue<uint32_t, 8>; - using PaddingField = ResourceTypeField::DefineNextValue<bool, 1>; + using IsAcceleratedField = IsOffscreenField::DefineNextValue<bool, 1>; + using ContextTypeField = IsAcceleratedField::DefineNextValue<uint32_t, 8>; + using PaddingField = ContextTypeField::DefineNextValue<bool, 1>; Key key_; bool is_valid_; @@ -82,8 +72,8 @@ return; key_.set<IsOffscreenField>(context->Host()->IsOffscreenCanvas()); + key_.set<IsOffscreenField>(context->IsAccelerated()); key_.set<ContextTypeField>(context->GetContextType()); - key_.set<ResourceTypeField>(context->Host()->ResourceProvider()->GetType()); // The padding field ensures at least one bit is set in the key in order // to avoid a key == 0, which is not supported by WTF::HashSet key_.set<PaddingField>(true); @@ -99,24 +89,15 @@ key_.get<ContextTypeField>()); } -CanvasResourceProvider::ResourceProviderType -RenderingContextDescriptionCodec::ResourceType() const { - return static_cast<CanvasResourceProvider::ResourceProviderType>( - key_.get<ResourceTypeField>()); -} - const char* RenderingContextDescriptionCodec::GetHostTypeName() const { return IsOffscreen() ? kHostTypeName_OffscreenCanvas : kHostTypeName_Canvas; } -const char* RenderingContextDescriptionCodec::GetThreadTypeName() const { - return WTF::IsMainThread() ? kThreadTypeName_Main : kThreadTypeName_Worker; -} - const char* RenderingContextDescriptionCodec::GetContextTypeName() const { switch (ContextType()) { case CanvasRenderingContext::kContext2D: - return kContextTypeName_2D; + return IsAccelerated() ? kContextTypeName_2D_Accelerated + : kContextTypeName_2D_Unaccelerated; case CanvasRenderingContext::kContextExperimentalWebgl: case CanvasRenderingContext::kContextWebgl: return kContextTypeName_WebGL; @@ -132,26 +113,6 @@ } } -const char* RenderingContextDescriptionCodec::GetResourceTypeName() const { - switch (ResourceType()) { - case CanvasResourceProvider::kBitmap: - return kResourceTypeName_Bitmap; - case CanvasResourceProvider::kSharedBitmap: - return kResourceTypeName_SharedBitmap; - case CanvasResourceProvider::kSharedImage: - return kResourceTypeName_SharedImage; - case CanvasResourceProvider::kPassThrough: - return kResourceTypeName_PassThrough; - case CanvasResourceProvider::kSwapChain: - return kResourceTypeName_SwapChain; - case CanvasResourceProvider::kSkiaDawnSharedImage: - return kResourceTypeName_SkiaDawnSharedImage; - default: - NOTREACHED(); - return ""; - } -} - } // unnamed namespace namespace blink { @@ -211,16 +172,6 @@ int partition_alloc_kb = WTF::Partitions::TotalActiveBytes() / kKiloByte; int blink_gc_alloc_kb = ProcessHeap::TotalAllocatedObjectSize() / kKiloByte; - bool canvas_context_type_was_used[CanvasRenderingContext::kMaxValue]; - for (bool& b : canvas_context_type_was_used) { - b = false; - } - - bool offscreen_context_type_was_used[CanvasRenderingContext::kMaxValue]; - for (bool& b : offscreen_context_type_was_used) { - b = false; - } - while (!rendering_context_descriptions_.IsEmpty()) { RenderingContextDescriptionCodec desc( rendering_context_descriptions_.TakeAny()); @@ -230,10 +181,9 @@ // info. WTF::String histogram_name_prefix = WTF::String("Blink") + desc.GetHostTypeName(); - WTF::String histogram_name_radical = WTF::String(desc.GetThreadTypeName()) + - desc.GetContextTypeName() + - desc.GetResourceTypeName(); + WTF::String histogram_name_radical = WTF::String(desc.GetContextTypeName()); + // Render task duration metric for all render tasks. { WTF::String histogram_name = histogram_name_prefix + kMeasurementName_RenderTaskDuration + @@ -242,6 +192,7 @@ elapsed_time); } + // Render task duration metric for rAF callbacks only. if (call_type_ == CallType::kAnimation) { WTF::String histogram_name = histogram_name_prefix + kMeasurementName_RenderTaskDuration + @@ -249,85 +200,24 @@ base::UmaHistogramMicrosecondsTimes(histogram_name.Latin1(), elapsed_time); } - if (desc.IsOffscreen()) { - offscreen_context_type_was_used[desc.ContextType()] = true; - } else { - canvas_context_type_was_used[desc.ContextType()] = true; + + // PartitionAlloc heap size metric + { + WTF::String histogram_name = histogram_name_prefix + + kMeasurementName_PartitionAlloc + + histogram_name_radical; + base::UmaHistogramMemoryKB(histogram_name.Latin1(), partition_alloc_kb); + } + + // Blink garbage collected heap size metric + { + WTF::String histogram_name = histogram_name_prefix + + kMeasurementName_BlinkGC + + histogram_name_radical; + base::UmaHistogramMemoryKB(histogram_name.Latin1(), blink_gc_alloc_kb); } } - if (canvas_context_type_was_used[CanvasRenderingContext::kContext2D]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.PartionAlloc.2D", partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.BlinkGC.2D", blink_gc_alloc_kb); - } - - if (canvas_context_type_was_used[CanvasRenderingContext::kContextWebgl] || - canvas_context_type_was_used - [CanvasRenderingContext::kContextExperimentalWebgl]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.PartionAlloc.WebGL", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.BlinkGC.WebGL", blink_gc_alloc_kb); - } - - if (canvas_context_type_was_used[CanvasRenderingContext::kContextWebgl2]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.PartionAlloc.WebGL2", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.BlinkGC.WebGL2", blink_gc_alloc_kb); - } - - if (canvas_context_type_was_used - [CanvasRenderingContext::kContextGPUPresent]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.PartionAlloc.WebGPU", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.BlinkGC.WebGPU", blink_gc_alloc_kb); - } - - if (canvas_context_type_was_used - [CanvasRenderingContext::kContextImageBitmap]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.PartionAlloc.ImageBitmap", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.Canvas.BlinkGC.ImageBitmap", - blink_gc_alloc_kb); - } - - if (offscreen_context_type_was_used[CanvasRenderingContext::kContext2D]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.PartionAlloc.2D", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.BlinkGC.2D", - blink_gc_alloc_kb); - } - - if (offscreen_context_type_was_used[CanvasRenderingContext::kContextWebgl] || - offscreen_context_type_was_used - [CanvasRenderingContext::kContextExperimentalWebgl]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.PartionAlloc.WebGL", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.BlinkGC.WebGL", - blink_gc_alloc_kb); - } - - if (offscreen_context_type_was_used[CanvasRenderingContext::kContextWebgl2]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.PartionAlloc.WebGL2", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.BlinkGC.WebGL2", - blink_gc_alloc_kb); - } - - if (offscreen_context_type_was_used - [CanvasRenderingContext::kContextGPUPresent]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.PartionAlloc.WebGPU", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.BlinkGC.WebGPU", - blink_gc_alloc_kb); - } - - if (offscreen_context_type_was_used - [CanvasRenderingContext::kContextImageBitmap]) { - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.PartionAlloc.ImageBitmap", - partition_alloc_kb); - UMA_HISTOGRAM_MEMORY_KB("Blink.OffscreenCanvas.BlinkGC.ImageBitmap", - blink_gc_alloc_kb); - } } void CanvasPerformanceMonitor::DidProcessTask(TimeTicks start_time,
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.cc b/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.cc new file mode 100644 index 0000000..470a131 --- /dev/null +++ b/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.cc
@@ -0,0 +1,40 @@ +// Copyright 2021 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 "third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h" + +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h" +#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h" +#include "v8/include/v8.h" + +namespace blink { + +CanvasResourceTracker* CanvasResourceTracker::For(v8::Isolate* isolate) { + auto* isolate_data = V8PerIsolateData::From(isolate); + auto* canvas_resource_tracker = static_cast<CanvasResourceTracker*>( + isolate_data->CanvasResourceTracker()); + if (!canvas_resource_tracker) { + canvas_resource_tracker = MakeGarbageCollected<CanvasResourceTracker>(); + isolate_data->SetCanvasResourceTracker(canvas_resource_tracker); + } + return canvas_resource_tracker; +} + +void CanvasResourceTracker::Add(CanvasRenderingContextHost* resource, + ExecutionContext* execution_context) { + resource_map_.insert(resource, execution_context); +} + +const CanvasResourceTracker::ResourceMap& +CanvasResourceTracker::GetResourceMap() const { + return resource_map_; +} + +void CanvasResourceTracker::Trace(Visitor* visitor) const { + V8PerIsolateData::GarbageCollectedData::Trace(visitor); + visitor->Trace(resource_map_); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h b/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h new file mode 100644 index 0000000..5c92a150 --- /dev/null +++ b/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h
@@ -0,0 +1,42 @@ +// Copyright 2021 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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RESOURCE_TRACKER_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RESOURCE_TRACKER_H_ + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/heap/member.h" + +namespace v8 { +class Isolate; +} + +namespace blink { + +class CanvasRenderingContextHost; +class ExecutionContext; + +class CORE_EXPORT CanvasResourceTracker final + : public V8PerIsolateData::GarbageCollectedData { + public: + using ResourceMap = HeapHashMap<WeakMember<CanvasRenderingContextHost>, + WeakMember<ExecutionContext>>; + + static CanvasResourceTracker* For(v8::Isolate*); + + void Add(CanvasRenderingContextHost*, ExecutionContext*); + const ResourceMap& GetResourceMap() const; + + void Trace(Visitor*) const override; + + private: + ResourceMap resource_map_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RESOURCE_TRACKER_H_
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker_test.cc b/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker_test.cc new file mode 100644 index 0000000..155d24e --- /dev/null +++ b/third_party/blink/renderer/core/html/canvas/canvas_resource_tracker_test.cc
@@ -0,0 +1,30 @@ +// Copyright 2021 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 "third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h" + +#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" +#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" + +namespace blink { + +class HTMLCanvasResourceTrackerTest : public RenderingTest { + public: + HTMLCanvasResourceTrackerTest() + : RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()) {} +}; + +TEST_F(HTMLCanvasResourceTrackerTest, AddCanvasElement) { + GetDocument().GetSettings()->SetScriptEnabled(true); + SetBodyInnerHTML("<canvas id='canvas'></canvas>"); + auto* canvas = To<HTMLCanvasElement>(GetDocument().getElementById("canvas")); + auto* context = GetDocument().GetExecutionContext(); + for (auto entry : + CanvasResourceTracker::For(context->GetIsolate())->GetResourceMap()) { + EXPECT_EQ(canvas, entry.key); + EXPECT_EQ(context, entry.value); + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index b522be2f..bbe02ed9 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -72,6 +72,7 @@ #include "third_party/blink/renderer/core/html/canvas/canvas_font_cache.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h" +#include "third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h" #include "third_party/blink/renderer/core/html/canvas/image_data.h" #include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/forms/html_select_element.h" @@ -134,6 +135,9 @@ externally_allocated_memory_(0) { UseCounter::Count(document, WebFeature::kHTMLCanvasElement); GetDocument().IncrementNumberOfCanvases(); + auto* execution_context = GetExecutionContext(); + CanvasResourceTracker::For(execution_context->GetIsolate()) + ->Add(this, execution_context); } HTMLCanvasElement::~HTMLCanvasElement() {
diff --git a/third_party/blink/renderer/core/inspector/inspector_highlight.cc b/third_party/blink/renderer/core/inspector/inspector_highlight.cc index 01bd300..30998dc7 100644 --- a/third_party/blink/renderer/core/inspector/inspector_highlight.cc +++ b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
@@ -644,18 +644,20 @@ GridTrackSizingDirection direction, float scale, LayoutUnit gap, + LayoutUnit rtl_offset, const Vector<LayoutUnit>& positions, const Vector<LayoutUnit>& alt_axis_positions, const Vector<String>* authored_values) { LayoutObject* layout_object = node->GetLayoutObject(); - bool is_rtl = direction == kForColumns && - !layout_object->StyleRef().IsLeftToRightDirection(); + bool is_rtl = !layout_object->StyleRef().IsLeftToRightDirection(); std::unique_ptr<protocol::ListValue> sizes = protocol::ListValue::create(); size_t track_count = positions.size(); LayoutUnit alt_axis_pos = GetPositionForFirstTrack( layout_object, direction == kForRows ? kForColumns : kForRows, alt_axis_positions); + if (is_rtl && direction == kForRows) + alt_axis_pos += rtl_offset; for (size_t i = 1; i < track_count; i++) { LayoutUnit current_position = @@ -665,11 +667,11 @@ LayoutUnit gap_offset = i < track_count - 1 ? gap : LayoutUnit(); LayoutUnit width = current_position - prev_position - gap_offset; - if (is_rtl) + if (is_rtl && direction == kForColumns) width = prev_position - current_position - gap_offset; LayoutUnit main_axis_pos = prev_position + width / 2; - if (is_rtl) - main_axis_pos = prev_position - width / 2; + if (is_rtl && direction == kForColumns) + main_axis_pos = rtl_offset + prev_position - width / 2; auto adjusted_size = AdjustForAbsoluteZoom::AdjustFloat( width * scale, layout_object->StyleRef()); PhysicalOffset track_size_pos(main_axis_pos, alt_axis_pos); @@ -692,12 +694,12 @@ const LayoutUnit& grid_gap, GridTrackSizingDirection direction, float scale, + LayoutUnit rtl_offset, const Vector<LayoutUnit>& positions, const Vector<LayoutUnit>& alt_axis_positions) { LayoutObject* layout_object = node->GetLayoutObject(); auto* grid_interface = ToInterface<LayoutNGGridInterface>(layout_object); - bool is_rtl = direction == kForColumns && - !layout_object->StyleRef().IsLeftToRightDirection(); + bool is_rtl = !layout_object->StyleRef().IsLeftToRightDirection(); std::unique_ptr<protocol::ListValue> number_positions = protocol::ListValue::create(); @@ -707,6 +709,9 @@ layout_object, direction == kForRows ? kForColumns : kForRows, alt_axis_positions); + if (is_rtl && direction == kForRows) + alt_axis_pos += rtl_offset; + // Find index of the first explicit Grid Line. size_t first_explicit_index = grid_interface->ExplicitGridStartForDirection(direction); @@ -715,7 +720,7 @@ // if needed. for (size_t i = first_explicit_index; i < track_count; ++i) { LayoutUnit gapOffset = grid_gap / 2; - if (is_rtl) + if (is_rtl && direction == kForColumns) gapOffset *= -1; // No need for a gap offset if there is no gap, or the first line is // explicit, or this is the last line. @@ -724,6 +729,8 @@ } LayoutUnit offset = GetPositionForTrackAt(layout_object, i, direction, positions); + if (is_rtl && direction == kForColumns) + offset += rtl_offset; PhysicalOffset number_position(offset - gapOffset, alt_axis_pos); if (direction == kForRows) number_position = Transpose(number_position); @@ -739,12 +746,12 @@ const LayoutUnit& grid_gap, GridTrackSizingDirection direction, float scale, + LayoutUnit rtl_offset, const Vector<LayoutUnit>& positions, const Vector<LayoutUnit>& alt_axis_positions) { LayoutObject* layout_object = node->GetLayoutObject(); auto* grid_interface = ToInterface<LayoutNGGridInterface>(layout_object); - bool is_rtl = direction == kForColumns && - !layout_object->StyleRef().IsLeftToRightDirection(); + bool is_rtl = !layout_object->StyleRef().IsLeftToRightDirection(); std::unique_ptr<protocol::ListValue> number_positions = protocol::ListValue::create(); @@ -753,6 +760,8 @@ LayoutUnit alt_axis_pos = GetPositionForLastTrack( layout_object, direction == kForRows ? kForColumns : kForRows, alt_axis_positions); + if (is_rtl && direction == kForRows) + alt_axis_pos += rtl_offset; // This is the number of tracks from the start of the grid, to the end of the // explicit grid (including any leading implicit tracks). @@ -762,6 +771,8 @@ { LayoutUnit first_offset = GetPositionForFirstTrack(layout_object, direction, positions); + if (is_rtl && direction == kForColumns) + first_offset += rtl_offset; // Always start negative numbers at the first line. std::unique_ptr<protocol::DictionaryValue> pos = @@ -777,7 +788,7 @@ // if needed. for (size_t i = 1; i <= explicit_grid_end_track_count; i++) { LayoutUnit gapOffset = grid_gap / 2; - if (is_rtl) + if (is_rtl && direction == kForColumns) gapOffset *= -1; if (grid_gap == 0 || (i == explicit_grid_end_track_count && i == track_count - 1)) { @@ -785,6 +796,8 @@ } LayoutUnit offset = GetPositionForTrackAt(layout_object, i, direction, positions); + if (is_rtl && direction == kForColumns) + offset += rtl_offset; PhysicalOffset number_position(offset - gapOffset, alt_axis_pos); if (direction == kForRows) number_position = Transpose(number_position); @@ -1210,6 +1223,13 @@ auto column_gap = grid_interface->GridGap(kForColumns) + grid_interface->GridItemOffset(kForColumns); + // In legacy grid the last column in rtl will go to the extent of the grid, + // all the way to the left. In NG, this is not the case, and will stop sooner + // if the tracks don't take up the full size of the grid. + LayoutUnit rtl_offset; + if (layout_object->IsLayoutNGGrid()) + rtl_offset = To<LayoutBox>(layout_object)->LogicalWidth() - columns.back(); + if (grid_highlight_config.show_track_sizes) { Element* element = DynamicTo<Element>(node); DCHECK(element); @@ -1226,17 +1246,22 @@ grid_info->setValue( "columnTrackSizes", - BuildGridTrackSizes(node, kForColumns, scale, column_gap, columns, rows, - &column_authored_values)); + BuildGridTrackSizes(node, kForColumns, scale, column_gap, rtl_offset, + columns, rows, &column_authored_values)); grid_info->setValue( "rowTrackSizes", - BuildGridTrackSizes(node, kForRows, scale, row_gap, rows, columns, - &row_authored_values)); + BuildGridTrackSizes(node, kForRows, scale, row_gap, rtl_offset, rows, + columns, &row_authored_values)); } + bool is_ltr = layout_object->StyleRef().IsLeftToRightDirection(); + PathBuilder row_builder; PathBuilder row_gap_builder; LayoutUnit row_left = columns.front(); + if (!is_ltr) { + row_left += rtl_offset; + } LayoutUnit row_width = columns.back() - columns.front(); for (size_t i = 1; i < rows.size(); ++i) { // Rows @@ -1266,15 +1291,15 @@ PathBuilder column_gap_builder; LayoutUnit column_top = rows.front(); LayoutUnit column_height = rows.back() - rows.front(); - bool is_ltr = layout_object->StyleRef().IsLeftToRightDirection(); for (size_t i = 1; i < columns.size(); ++i) { PhysicalSize size(columns.at(i) - columns.at(i - 1), column_height); if (i != columns.size() - 1) size.width -= column_gap; LayoutUnit line_left = GetPositionForTrackAt(layout_object, i - 1, kForColumns, columns); - if (!is_ltr) - line_left -= size.width; + if (!is_ltr) { + line_left += rtl_offset - size.width; + } PhysicalOffset position(line_left, column_top); PhysicalRect column(position, size); FloatQuad column_quad = layout_object->LocalRectToAbsoluteQuad(column); @@ -1288,6 +1313,8 @@ GetPositionForTrackAt(layout_object, i, kForColumns, columns); if (is_ltr) gap_left -= column_gap; + else + gap_left += rtl_offset; PhysicalOffset gap_position(gap_left, column_top); PhysicalSize gap_size(column_gap, column_height); PhysicalRect gap(gap_position, gap_size); @@ -1301,24 +1328,26 @@ // Positive Row and column Line positions if (grid_highlight_config.show_positive_line_numbers) { - grid_info->setValue("positiveRowLineNumberPositions", - BuildGridPositiveLineNumberPositions( - node, row_gap, kForRows, scale, rows, columns)); + grid_info->setValue( + "positiveRowLineNumberPositions", + BuildGridPositiveLineNumberPositions(node, row_gap, kForRows, scale, + rtl_offset, rows, columns)); grid_info->setValue( "positiveColumnLineNumberPositions", BuildGridPositiveLineNumberPositions(node, column_gap, kForColumns, - scale, columns, rows)); + scale, rtl_offset, columns, rows)); } // Negative Row and column Line positions if (grid_highlight_config.show_negative_line_numbers) { - grid_info->setValue("negativeRowLineNumberPositions", - BuildGridNegativeLineNumberPositions( - node, row_gap, kForRows, scale, rows, columns)); + grid_info->setValue( + "negativeRowLineNumberPositions", + BuildGridNegativeLineNumberPositions(node, row_gap, kForRows, scale, + rtl_offset, rows, columns)); grid_info->setValue( "negativeColumnLineNumberPositions", BuildGridNegativeLineNumberPositions(node, column_gap, kForColumns, - scale, columns, rows)); + scale, rtl_offset, columns, rows)); } // Area names
diff --git a/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc b/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc index c280dc1f..6078c35e 100644 --- a/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc +++ b/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
@@ -781,22 +781,15 @@ void InspectorStyle::PopulateAllProperties( Vector<CSSPropertySourceData>& result) { - HashSet<String> source_property_names; - if (source_data_ && source_data_->HasProperties()) { Vector<CSSPropertySourceData>& source_property_data = source_data_->property_data; - for (const auto& data : source_property_data) { + for (const auto& data : source_property_data) result.push_back(data); - source_property_names.insert(data.name.DeprecatedLower()); - } } for (int i = 0, size = style_->length(); i < size; ++i) { String name = style_->item(i); - if (!source_property_names.insert(name.DeprecatedLower()).is_new_entry) - continue; - if (!IsValidCSSPropertyID( CssPropertyID(style_->GetExecutionContext(), name))) continue;
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni index a3902f07..47148db 100644 --- a/third_party/blink/renderer/core/layout/build.gni +++ b/third_party/blink/renderer/core/layout/build.gni
@@ -488,6 +488,8 @@ "ng/ng_constraint_space_builder.h", "ng/ng_container_fragment_builder.cc", "ng/ng_container_fragment_builder.h", + "ng/ng_disable_side_effects_scope.cc", + "ng/ng_disable_side_effects_scope.h", "ng/ng_early_break.h", "ng/ng_fieldset_layout_algorithm.cc", "ng/ng_fieldset_layout_algorithm.h",
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 3fb5588..f7dd39b7 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -84,6 +84,7 @@ #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h" +#include "third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.h" #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_utils.h" @@ -3282,8 +3283,8 @@ void LayoutBox::AddLayoutResult(scoped_refptr<const NGLayoutResult> result) { const auto& fragment = To<NGPhysicalBoxFragment>(result->PhysicalFragment()); - // |layout_results_| is particulary critical when |SideEffectsDisabled|. - DCHECK(!result->GetConstraintSpaceForCaching().SideEffectsDisabled()); + // |layout_results_| is particularly critical when side effects are disabled. + DCHECK(!NGDisableSideEffectsScope::IsDisabled()); layout_results_.push_back(std::move(result)); CheckDidAddFragment(*this, fragment); @@ -3319,8 +3320,8 @@ NGFragmentItems::ClearAssociatedFragments(this); } } - // |layout_results_| is particulary critical when |SideEffectsDisabled|. - DCHECK(!result->GetConstraintSpaceForCaching().SideEffectsDisabled()); + // |layout_results_| is particularly critical when side effects are disabled. + DCHECK(!NGDisableSideEffectsScope::IsDisabled()); layout_results_[index] = std::move(result); CheckDidAddFragment(*this, fragment);
diff --git a/third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid.cc b/third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid.cc index 9272bf7..2c1c320 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid.cc
@@ -69,11 +69,8 @@ LayoutUnit LayoutNGGrid::GridItemOffset( GridTrackSizingDirection direction) const { NOT_DESTROYED(); - const auto* grid_data = GetGridData(); - const auto& geometry = (direction == kForRows) ? grid_data->row_geometry - : grid_data->column_geometry; - DCHECK(geometry.sets.size()); - return geometry.sets[0].offset; + // Distribution offset is baked into the gutter_size in GridNG. + return LayoutUnit(); } Vector<LayoutUnit> LayoutNGGrid::TrackSizesForComputedStyle( @@ -127,7 +124,7 @@ LayoutUnit current_offset = geometry.sets[0].offset; expanded_positions.ReserveInitialCapacity( - std::min<wtf_size_t>(geometry.total_track_count + 1, kGridMaxTracks)); + std::min<wtf_size_t>(geometry.total_track_count + 1, kGridMaxTracks + 1)); expanded_positions.emplace_back(current_offset); bool is_last_range_collapsed = true; @@ -143,9 +140,11 @@ (range.IsCollapsed() ? LayoutUnit() : geometry.gutter_size); expanded_positions.emplace_back(current_offset); - // Respect total track count limit. - DCHECK(expanded_positions.size() <= kGridMaxTracks); - if (expanded_positions.size() == kGridMaxTracks) + // Respect total track count limit, don't forget to account for the + // initial offset. + DCHECK_LE(expanded_positions.size(), + static_cast<unsigned int>(kGridMaxTracks + 1)); + if (expanded_positions.size() == kGridMaxTracks + 1) return; } }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc index 7ff7ca6..f22adef 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -48,6 +48,7 @@ #include "third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h" +#include "third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.h" #include "third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h" #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h" @@ -686,7 +687,7 @@ scoped_refptr<const NGLayoutResult> layout_result) const { // Computing MinMax after layout. Do not modify the |LayoutObject| tree, paint // properties, and other global states. - if (constraint_space.SideEffectsDisabled()) + if (NGDisableSideEffectsScope::IsDisabled()) return; // If we abort layout and don't clear the cached layout-result, we can end @@ -802,18 +803,15 @@ /* depends_on_block_constraints */ false); } - scoped_refptr<const NGLayoutResult> layout_result; - if (GetLayoutBox()->NeedsLayout() || - constraint_space.SideEffectsDisabled()) { - layout_result = Layout(constraint_space); - } else { - // If we're computing MinMax after layout, we need to set - // |SideEffectsDisabled| so that |Layout| does not update the - // |LayoutObject| tree and other global states. - NGConstraintSpace side_effects_disabled = - constraint_space.CloneWithSideEffectsDisabled(); - layout_result = Layout(side_effects_disabled); - } + // If we're computing MinMax after layout, we need to disable side effects + // so that |Layout| does not update the |LayoutObject| tree and other global + // states. + absl::optional<NGDisableSideEffectsScope> disable_side_effects; + if (!GetLayoutBox()->NeedsLayout()) + disable_side_effects.emplace(); + + scoped_refptr<const NGLayoutResult> layout_result = + Layout(constraint_space); DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess); sizes = NGFragment({container_writing_mode, TextDirection::kLtr}, layout_result->PhysicalFragment()) @@ -1712,9 +1710,9 @@ CopyBaselinesFromLegacyLayout(constraint_space, &builder); layout_result = builder.ToBoxFragment(); - // When |SideEffectsDisabled|, it's not possible to disable side effects + // When side effects are disabled, it's not possible to disable side effects // completely for legacy, but at least keep the fragment tree unaffected. - if (!constraint_space.SideEffectsDisabled()) { + if (!NGDisableSideEffectsScope::IsDisabled()) { box_->SetCachedLayoutResult(layout_result); // If |SetCachedLayoutResult| did not update cached |LayoutResult|, @@ -1728,7 +1726,7 @@ } } } - } else if (layout_result && !constraint_space.SideEffectsDisabled()) { + } else if (layout_result && !NGDisableSideEffectsScope::IsDisabled()) { // OOF-positioned nodes have a two-tier cache, and their layout results // must always contain the correct percentage resolution size. // See |NGBlockNode::CachedLayoutResultForOutOfFlowPositioned|.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h index 8594faf..f19c7d3d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -159,12 +159,6 @@ return copy; } - NGConstraintSpace CloneWithSideEffectsDisabled() const { - NGConstraintSpace copy = *this; - copy.DisableSideEffects(); - return copy; - } - ~NGConstraintSpace() { if (HasRareData()) delete rare_data_; @@ -452,14 +446,6 @@ return static_cast<NGCacheSlot>(bitfields_.cache_slot); } - // Returns true if this layout is for computing purposes, and that it should - // just return fragments without updating the |LayoutObject| tree, paint - // properties, and other global objects. This is used e.g., when computing - // MinMax after layout. - bool SideEffectsDisabled() const { - return HasRareData() && rare_data_->side_effects_disabled; - } - // Some layout modes “stretch” their children to a fixed size (e.g. flex, // grid). These flags represented whether a layout needs to produce a // fragment that satisfies a fixed constraint in the inline and block @@ -784,7 +770,6 @@ explicit RareData(const NGBfcOffset bfc_offset) : bfc_offset(bfc_offset), data_union_type(static_cast<unsigned>(kNone)), - side_effects_disabled(false), is_line_clamp_context(false), is_legacy_table_cell(false), is_restricted_block_size_table_cell(false), @@ -802,7 +787,6 @@ fragmentainer_block_size(other.fragmentainer_block_size), fragmentainer_offset_at_bfc(other.fragmentainer_offset_at_bfc), data_union_type(other.data_union_type), - side_effects_disabled(other.side_effects_disabled), is_line_clamp_context(other.is_line_clamp_context), is_legacy_table_cell(other.is_legacy_table_cell), is_restricted_block_size_table_cell( @@ -1149,8 +1133,6 @@ unsigned data_union_type : 3; - unsigned side_effects_disabled : 1; - unsigned is_line_clamp_context : 1; unsigned is_legacy_table_cell : 1; @@ -1448,8 +1430,6 @@ return rare_data_; } - void DisableSideEffects() { EnsureRareData()->side_effects_disabled = true; } - LogicalSize available_size_; // To save a little space, we union these two fields. rare_data_ is valid if
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h index f8595270..0779995 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -36,8 +36,6 @@ adjust_inline_size_if_needed) { if (parent_space.IsInsideBalancedColumns()) space_.EnsureRareData()->is_inside_balanced_columns = true; - if (parent_space.SideEffectsDisabled()) - DisableSideEffects(); } // The setters on this builder are in the writing mode of parent_writing_mode. @@ -241,8 +239,6 @@ space_.bitfields_.cache_slot = static_cast<unsigned>(slot); } - void DisableSideEffects() { space_.DisableSideEffects(); } - void SetBlockStartAnnotationSpace(LayoutUnit space) { if (space) space_.EnsureRareData()->SetBlockStartAnnotationSpace(space);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.cc b/third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.cc new file mode 100644 index 0000000..f14b25a --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.cc
@@ -0,0 +1,11 @@ +// Copyright 2021 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 "third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.h" + +namespace blink { + +unsigned CORE_EXPORT NGDisableSideEffectsScope::count_ = 0; + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.h b/third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.h new file mode 100644 index 0000000..c16f1b3f --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/ng_disable_side_effects_scope.h
@@ -0,0 +1,35 @@ +// Copyright 2021 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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_DISABLE_SIDE_EFFECTS_SCOPE_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_DISABLE_SIDE_EFFECTS_SCOPE_H_ + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" + +namespace blink { + +// Setup a scope where this layout is for computing purposes, and that it should +// just return fragments without updating the |LayoutObject| tree, paint +// properties, and other global objects. This is used e.g., when computing +// MinMax after layout. +class CORE_EXPORT NGDisableSideEffectsScope { + STACK_ALLOCATED(); + + public: + NGDisableSideEffectsScope() { ++count_; } + ~NGDisableSideEffectsScope() { + DCHECK(count_); + --count_; + } + + static bool IsDisabled() { return count_; } + + private: + static unsigned count_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_DISABLE_SIDE_EFFECTS_SCOPE_H_
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 d3bcc28..ef98d896 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
@@ -905,7 +905,7 @@ /* intrinsic_size */ kIndefiniteSize, /* available_block_size_adjustment */ LayoutUnit(), &main_percentage_resolution_size); - DCHECK_NE(*replaced_block, kIndefiniteSize); + DCHECK_GE(*replaced_block, LayoutUnit()); replaced_block = block_min_max_sizes.ClampSizeToMinAndMax(*replaced_block); } @@ -1004,7 +1004,7 @@ replaced_inline = ResolveMainInlineLength( space, style, border_padding, MinMaxSizesFunc, inline_length_to_resolve, available_inline_size_adjustment); - DCHECK_NE(*replaced_inline, kIndefiniteSize); + DCHECK_GE(*replaced_inline, LayoutUnit()); replaced_inline = inline_min_max_sizes.ClampSizeToMinAndMax(*replaced_inline); }
diff --git a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc index 1f8a3f2..f334eeeb 100644 --- a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc +++ b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
@@ -148,21 +148,14 @@ static bool CheckShapeImageOrigin(Document& document, const StyleImage& style_image) { - if (style_image.IsGeneratedImage()) + String failing_url; + if (style_image.IsAccessAllowed(failing_url)) return true; - - DCHECK(style_image.CachedImage()); - ImageResourceContent& image_content = *(style_image.CachedImage()); - if (image_content.IsAccessAllowed()) - return true; - - const KURL& url = image_content.Url(); - String url_string = url.IsNull() ? "''" : url.ElidedString(); + String url_string = failing_url.IsNull() ? "''" : failing_url; document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( mojom::ConsoleMessageSource::kSecurity, mojom::ConsoleMessageLevel::kError, "Unsafe attempt to load URL " + url_string + ".")); - return false; }
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc index 5c6ba509a..35e61e22 100644 --- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc +++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -24,6 +24,7 @@ #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h" +#include "third_party/blink/renderer/core/html/canvas/canvas_resource_tracker.h" #include "third_party/blink/renderer/core/html/canvas/image_data.h" #include "third_party/blink/renderer/core/html/canvas/ukm_parameters.h" #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" @@ -72,6 +73,7 @@ } } + CanvasResourceTracker::For(context->GetIsolate())->Add(this, context); UpdateMemoryUsage(); }
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc index 1d7a14a..ab800f8 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
@@ -332,9 +332,18 @@ corrected_end != end_container || corrected_end_offset != ephemeral_range.EndPosition().ComputeOffsetInContainerNode()) { - range_ = MakeGarbageCollected<RangeInFlatTree>( - PositionInFlatTree(corrected_start, corrected_start_offset), - PositionInFlatTree(corrected_end, corrected_end_offset)); + PositionInFlatTree start(corrected_start, corrected_start_offset); + PositionInFlatTree end(corrected_end, corrected_end_offset); + + // TODO(bokan): This can sometimes occur from a selection. Avoid crashing + // from this case but this can come from a seemingly correct range so we + // should investigate the source of the bug. https://crbug.com/1216357 + if (start >= end) { + range_ = nullptr; + return; + } + + range_ = MakeGarbageCollected<RangeInFlatTree>(start, end); } } @@ -344,8 +353,19 @@ range_->StartPosition().GetDocument()->UpdateStyleAndLayout( DocumentUpdateReason::kFindInPage); - // Shouldn't continue if selection is empty. + // TODO(bokan): This can sometimes occur from a selection. Avoid crashing from + // this case but this can come from a seemingly correct range so we should + // investigate the source of the bug. + // https://crbug.com/1216357 EphemeralRangeInFlatTree ephemeral_range = range_->ToEphemeralRange(); + if (ephemeral_range.StartPosition() >= ephemeral_range.EndPosition()) { + state_ = kFailure; + error_ = LinkGenerationError::kEmptySelection; + ResolveSelectorState(); + return; + } + + // Shouldn't continue if selection is empty. String selected_text = PlainText(ephemeral_range).StripWhiteSpace(); if (selected_text.IsEmpty()) { state_ = kFailure; @@ -355,6 +375,18 @@ } AdjustSelection(); + + // TODO(bokan): This can sometimes occur from a selection. Avoid crashing from + // this case but this can come from a seemingly correct range so we should + // investigate the source of the bug. + // https://crbug.com/1216357 + if (!range_) { + state_ = kFailure; + error_ = LinkGenerationError::kEmptySelection; + ResolveSelectorState(); + return; + } + UMA_HISTOGRAM_COUNTS_1000("SharedHighlights.LinkGenerated.SelectionLength", PlainText(range_->ToEphemeralRange()).length()); state_ = kNeedsNewCandidate;
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc index 7faa6a4..9a5980d 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
@@ -1736,4 +1736,20 @@ GetTextFragmentSelectorGenerator()->GetNextTextBlockForTesting(end)); } +TEST_F(TextFragmentSelectorGeneratorTest, BeforeAndAfterAnchor) { + SimRequest request("https://example.com/test.html", "text/html"); + LoadURL("https://example.com/test.html"); + request.Complete(R"HTML( + <!DOCTYPE html> + Foo + <div id="first">Hello World</div> + Bar + )HTML"); + + Node* node = GetDocument().getElementById("first"); + const auto& start = Position(node, PositionAnchorType::kBeforeAnchor); + const auto& end = Position(node, PositionAnchorType::kAfterAnchor); + VerifySelectorFails(start, end, LinkGenerationError::kEmptySelection); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc index bd173d1..e937cf5 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -111,7 +111,7 @@ static CompositingReasons BackfaceInvisibility3DAncestorReason( const PaintLayer& layer) { - if (RuntimeEnabledFeatures::TransformInteropEnabled()) { + if (RuntimeEnabledFeatures::BackfaceVisibilityInteropEnabled()) { if (auto* compositing_container = layer.CompositingContainer()) { if (compositing_container->GetLayoutObject() .StyleRef()
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc index 15ad33b..76c6184 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
@@ -290,7 +290,8 @@ TEST_F(CompositingReasonFinderTest, CompositeWithBackfaceVisibilityAncestorAndPreserve3D) { - ScopedTransformInteropForTest enabled(true); + ScopedTransformInteropForTest ti_enabled(true); + ScopedBackfaceVisibilityInteropForTest bfi_enabled(true); SetBodyInnerHTML(R"HTML( <!DOCTYPE html> @@ -311,7 +312,8 @@ TEST_F(CompositingReasonFinderTest, CompositeWithBackfaceVisibilityAncestorAndPreserve3DWithInterveningDiv) { - ScopedTransformInteropForTest enabled(true); + ScopedTransformInteropForTest ti_enabled(true); + ScopedBackfaceVisibilityInteropForTest bfi_enabled(true); SetBodyInnerHTML(R"HTML( <!DOCTYPE html> @@ -334,7 +336,8 @@ TEST_F(CompositingReasonFinderTest, CompositeWithBackfaceVisibilityAncestorWithInterveningStackingDiv) { - ScopedTransformInteropForTest enabled(true); + ScopedTransformInteropForTest ti_enabled(true); + ScopedBackfaceVisibilityInteropForTest bfi_enabled(true); SetBodyInnerHTML(R"HTML( <!DOCTYPE html> @@ -362,7 +365,8 @@ TEST_F(CompositingReasonFinderTest, CompositeWithBackfaceVisibilityAncestorAndFlattening) { - ScopedTransformInteropForTest enabled(true); + ScopedTransformInteropForTest ti_enabled(true); + ScopedBackfaceVisibilityInteropForTest bfi_enabled(true); SetBodyInnerHTML(R"HTML( <!DOCTYPE html> @@ -382,7 +386,8 @@ } TEST_F(CompositingReasonFinderTest, CompositeWithBackfaceVisibility) { - ScopedTransformInteropForTest enabled(true); + ScopedTransformInteropForTest ti_enabled(true); + ScopedBackfaceVisibilityInteropForTest bfi_enabled(true); SetBodyInnerHTML(R"HTML( <!DOCTYPE html>
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index 8ede5c6..c1d9761 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -503,7 +503,7 @@ const PaintPhase paint_phase = paint_info.phase; const NGPhysicalBoxFragment& fragment = PhysicalFragment(); const ComputedStyle& style = fragment.Style(); - bool is_visible = IsVisibleToPaint(fragment, style); + const bool is_visible = IsVisibleToPaint(fragment, style); if (ShouldPaintSelfBlockBackground(paint_phase)) { if (is_visible) { PaintBoxDecorationBackground(paint_info, paint_offset, @@ -561,13 +561,6 @@ } } else if (!fragment.IsInlineFormattingContext()) { PaintBlockChildren(paint_info, paint_offset); - - if (is_visible && paint_info.phase == PaintPhase::kForeground && - box_fragment_.IsTableNG()) { - NGTablePainter(box_fragment_) - .PaintCollapsedBorders(paint_info, paint_offset, - VisualRect(paint_offset)); - } } } @@ -581,6 +574,15 @@ if (!is_visible) return; + + // Collapsed borders paint *after* children have painted their backgrounds. + if (box_fragment_.IsTableNG() && + paint_phase == PaintPhase::kDescendantBlockBackgroundsOnly) { + NGTablePainter(box_fragment_) + .PaintCollapsedBorders(paint_info, paint_offset, + VisualRect(paint_offset)); + } + if (ShouldPaintSelfOutline(paint_phase)) { if (NGOutlineUtils::HasPaintedOutline(style, fragment.GetNode())) { NGFragmentPainter(fragment, GetDisplayItemClient())
diff --git a/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc b/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc index e44355f..356e9af 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_table_painters.cc
@@ -420,7 +420,6 @@ void NGTablePainter::PaintCollapsedBorders(const PaintInfo& paint_info, const PhysicalOffset& paint_offset, const IntRect& visual_rect) { - DCHECK_EQ(paint_info.phase, PaintPhase::kForeground); const NGTableBorders* collapsed_borders = fragment_.TableCollapsedBorders(); if (!collapsed_borders) return;
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc index 61917469..dfb03078 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -769,7 +769,7 @@ reasons |= CompositingReason::kWillChangeFilter; reasons |= CompositingReason::kWillChangeBackdropFilter; - if (RuntimeEnabledFeatures::TransformInteropEnabled()) + if (RuntimeEnabledFeatures::BackfaceVisibilityInteropEnabled()) reasons |= CompositingReason::kBackfaceInvisibility3DAncestor; return reasons;
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc index f8028de1..510a103 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -833,8 +833,9 @@ TEST_P(PaintPropertyTreeBuilderTest, BackfaceVisibilityWithPseudoStacking3DChildren) { - ScopedTransformInteropForTest enabled(true); - // TODO(chrishtr): implement for CAP. This entails computing + ScopedTransformInteropForTest ti_enabled(true); + ScopedBackfaceVisibilityInteropForTest bfi_enabled(true); + // TODO(chrishtr, dbaron): implement for CAP. This entails computing // has_backface_invisible_ancestor_in_same_3d_context in the pre-paint tree // walk. if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
diff --git a/third_party/blink/renderer/core/style/style_fetched_image.cc b/third_party/blink/renderer/core/style/style_fetched_image.cc index cc194f21..b216e713 100644 --- a/third_party/blink/renderer/core/style/style_fetched_image.cc +++ b/third_party/blink/renderer/core/style/style_fetched_image.cc
@@ -107,6 +107,14 @@ return image_->ErrorOccurred(); } +bool StyleFetchedImage::IsAccessAllowed(String& failing_url) const { + DCHECK(image_->IsLoaded()); + if (image_->IsAccessAllowed()) + return true; + failing_url = image_->Url().ElidedString(); + return false; +} + FloatSize StyleFetchedImage::ImageSize( const Document&, float multiplier,
diff --git a/third_party/blink/renderer/core/style/style_fetched_image.h b/third_party/blink/renderer/core/style/style_fetched_image.h index 843c35c..a81a3efc 100644 --- a/third_party/blink/renderer/core/style/style_fetched_image.h +++ b/third_party/blink/renderer/core/style/style_fetched_image.h
@@ -57,6 +57,8 @@ bool CanRender() const override; bool IsLoaded() const override; bool ErrorOccurred() const override; + bool IsAccessAllowed(String&) const override; + FloatSize ImageSize(const Document&, float multiplier, const FloatSize& default_object_size,
diff --git a/third_party/blink/renderer/core/style/style_fetched_image_set.cc b/third_party/blink/renderer/core/style/style_fetched_image_set.cc index 0fe22a0..20e010c 100644 --- a/third_party/blink/renderer/core/style/style_fetched_image_set.cc +++ b/third_party/blink/renderer/core/style/style_fetched_image_set.cc
@@ -93,6 +93,14 @@ return best_fit_image_->ErrorOccurred(); } +bool StyleFetchedImageSet::IsAccessAllowed(String& failing_url) const { + DCHECK(best_fit_image_->IsLoaded()); + if (best_fit_image_->IsAccessAllowed()) + return true; + failing_url = best_fit_image_->Url().ElidedString(); + return false; +} + FloatSize StyleFetchedImageSet::ImageSize( const Document&, float multiplier,
diff --git a/third_party/blink/renderer/core/style/style_fetched_image_set.h b/third_party/blink/renderer/core/style/style_fetched_image_set.h index 5eb6f5f..6244d5e 100644 --- a/third_party/blink/renderer/core/style/style_fetched_image_set.h +++ b/third_party/blink/renderer/core/style/style_fetched_image_set.h
@@ -65,6 +65,8 @@ bool CanRender() const override; bool IsLoaded() const override; bool ErrorOccurred() const override; + bool IsAccessAllowed(String&) const override; + FloatSize ImageSize(const Document&, float multiplier, const FloatSize& default_object_size,
diff --git a/third_party/blink/renderer/core/style/style_generated_image.h b/third_party/blink/renderer/core/style/style_generated_image.h index a1ec410e..dd52aee 100644 --- a/third_party/blink/renderer/core/style/style_generated_image.h +++ b/third_party/blink/renderer/core/style/style_generated_image.h
@@ -47,6 +47,8 @@ CSSValue* ComputedCSSValue(const ComputedStyle&, bool allow_visited_style) const override; + bool IsAccessAllowed(String&) const override { return true; } + FloatSize ImageSize(const Document&, float multiplier, const FloatSize& default_object_size,
diff --git a/third_party/blink/renderer/core/style/style_image.h b/third_party/blink/renderer/core/style/style_image.h index 353307a6..5cdae67 100644 --- a/third_party/blink/renderer/core/style/style_image.h +++ b/third_party/blink/renderer/core/style/style_image.h
@@ -72,6 +72,11 @@ // Any underlying resources this <image> references failed to load. virtual bool ErrorOccurred() const { return false; } + // Is the <image> considered same-origin? Can only be called if IsLoaded() + // returns true. |failing_url| is set to the (potentially formatted) URL of + // the first non-same-origin <image>. + virtual bool IsAccessAllowed(String& failing_url) const = 0; + // Determine the concrete object size of this <image>, scaled by multiplier, // using the specified default object size. Return value as a FloatSize // because we want integer sizes to remain integers when zoomed and then
diff --git a/third_party/blink/renderer/core/style/style_pending_image.h b/third_party/blink/renderer/core/style/style_pending_image.h index 6acdd06..a2aa9c0 100644 --- a/third_party/blink/renderer/core/style/style_pending_image.h +++ b/third_party/blink/renderer/core/style/style_pending_image.h
@@ -54,6 +54,7 @@ CSSValue* ComputedCSSValue(const ComputedStyle& style, bool allow_visited_style) const override; + bool IsAccessAllowed(String&) const override { return true; } FloatSize ImageSize(const Document&, float, const FloatSize&,
diff --git a/third_party/blink/renderer/core/svg/svg_animated_length.h b/third_party/blink/renderer/core/svg/svg_animated_length.h index e52ad81..e3450e1 100644 --- a/third_party/blink/renderer/core/svg/svg_animated_length.h +++ b/third_party/blink/renderer/core/svg/svg_animated_length.h
@@ -57,6 +57,16 @@ SVGParsingError AttributeChanged(const String&) override; + // TODO(fs): This doesn't handle calc expressions. For that, we'd probably + // need to rewrap the CSSMathExpressionNode with a kValueRangeNonNegative + // range specification. + const CSSValue* NonNegativeCssValue() const { + if (CurrentValue()->IsNegativeNumericLiteral()) { + return nullptr; + } + return &CurrentValue()->AsCSSPrimitiveValue(); + } + const CSSValue& CssValue() const { return CurrentValue()->AsCSSPrimitiveValue(); }
diff --git a/third_party/blink/renderer/core/svg/svg_svg_element.cc b/third_party/blink/renderer/core/svg/svg_svg_element.cc index a2ea0cd..9a205aa 100644 --- a/third_party/blink/renderer/core/svg/svg_svg_element.cc +++ b/third_party/blink/renderer/core/svg/svg_svg_element.cc
@@ -220,12 +220,19 @@ y_->CssValue()); } else if (IsOutermostSVGSVGElement() && (property == width_ || property == height_)) { + // SVG allows negative numbers for these attributes but CSS doesn't allow + // negative <length> values for the corresponding CSS properties. So remove + // negative values here. if (property == width_) { - AddPropertyToPresentationAttributeStyle(style, property->CssPropertyId(), - width_->CssValue()); + if (const CSSValue* width = width_->NonNegativeCssValue()) { + AddPropertyToPresentationAttributeStyle( + style, property->CssPropertyId(), *width); + } } else if (property == height_) { - AddPropertyToPresentationAttributeStyle(style, property->CssPropertyId(), - height_->CssValue()); + if (const CSSValue* height = height_->NonNegativeCssValue()) { + AddPropertyToPresentationAttributeStyle( + style, property->CssPropertyId(), *height); + } } } else { SVGGraphicsElement::CollectStyleForPresentationAttribute(name, value,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index 117bde81..82c5ee7 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -3918,18 +3918,16 @@ wtf_size_t length = children.size(); int new_index = index; for (wtf_size_t i = 0; i < length; ++i) { + if (children[i]->IsDetached()) { + CHECK(false) << "Cannot add a detached child: " + << "\n* Child: " << children[i]->ToString(true, true) + << "\n* Parent: " << child->ToString(true, true) + << "\n* Grandparent: " << ToString(true, true); + } // If the child was owned, it will be added elsewhere as a direct // child of the object owning it. - if (!AXObjectCache().IsAriaOwned(children[i])) { - SANITIZER_CHECK(!children[i]->IsDetached()) - << "Cannot add a detached child: " - << "\n* Child: " << children[i]->ToString(true, true) - << "\n* Parent: " << child->ToString(true, true) - << "\n* Grandparent: " << ToString(true, true) - << "\n* Included ancestor: " - << child->ParentObjectIncludedInTree()->ToString(true, true); + if (!AXObjectCache().IsAriaOwned(children[i])) children_.insert(new_index++, children[i]); - } } } else { children_.insert(index, child);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 616a4b67..a19d62b 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -517,6 +517,32 @@ return true; } +void DetachAndRemoveFromChildrenOfAncestors(AXObject* obj) { + DCHECK(obj); + + bool is_included = obj->LastKnownIsIncludedInTreeValue(); + + AXObject* parent = obj->CachedParentObject(); + + obj->Detach(); + + // If |obj| is not included, it cannot be in any ancestor's cached children. + // This rule improves performance when removing an entire of unincluded nodes. + if (!is_included) + return; + + // Clear children of ancestors in order to ensure this detached object is not + // cached an ancestor's list of children: + // Any ancestor up to the first included ancestor can contain the now-detached + // child in it's cached children, and therefore must update children. + while (parent && !parent->LastKnownIsIncludedInTreeValue()) { + if (parent->NeedsToUpdateChildren() || parent->IsDetached()) + break; // Processing has already occurred for this ancestor. + parent->SetNeedsToUpdateChildren(); + parent = parent->CachedParentObject(); + } +} + } // namespace // static @@ -1338,7 +1364,8 @@ AXObject* parent = obj->CachedParentObject(); - obj->Detach(); + DetachAndRemoveFromChildrenOfAncestors(obj); + RemoveAXID(obj); // Finally, remove the object. @@ -1347,12 +1374,13 @@ if (!objects_.Take(ax_id)) return; + DCHECK_GE(objects_.size(), ids_in_use_.size()); + // This will clear the children of |parent| immediately, and therefore must // come after obj->Detach(), which accesses the children in order // to detach all of them from |parent|. + // It will also fire a children changed event. ChildrenChanged(parent); - - DCHECK_GE(objects_.size(), ids_in_use_.size()); } // This is safe to call even if there isn't a current mapping. @@ -1885,8 +1913,6 @@ if (!obj || obj->IsDetached()) return; - obj->SetNeedsToUpdateChildren(); - Node* node = obj->GetNode(); if (node && !nodes_with_pending_children_changed_.insert(node).is_new_entry) return; @@ -2081,7 +2107,9 @@ DCHECK(!layout_object_mapping_.at(node->GetLayoutObject())) << node << " " << node->GetLayoutObject(); } - current->Detach(); + + DetachAndRemoveFromChildrenOfAncestors(current); + // TODO(accessibility) We don't use the return value, can we use .erase() // and it will still make sure that the object is cleaned up? objects_.Take(retained_axid);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc index fbd4ace7..70fec6e 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -57,8 +57,11 @@ } bool AXRelationCache::IsAriaOwned(const AXObject* child) const { - return child && - aria_owned_child_to_owner_mapping_.Contains(child->AXObjectID()); + if (!child) + return false; + DCHECK(!child->IsDetached()) + << "Child was detached: " << child->ToString(true, true); + return aria_owned_child_to_owner_mapping_.Contains(child->AXObjectID()); } AXObject* AXRelationCache::GetAriaOwnedParent(const AXObject* child) const {
diff --git a/third_party/blink/renderer/modules/breakout_box/BUILD.gn b/third_party/blink/renderer/modules/breakout_box/BUILD.gn index a53ecd6..497fde0 100644 --- a/third_party/blink/renderer/modules/breakout_box/BUILD.gn +++ b/third_party/blink/renderer/modules/breakout_box/BUILD.gn
@@ -6,6 +6,7 @@ blink_modules_sources("breakout_box") { sources = [ + "frame_queue.h", "frame_queue_transferring_optimizer.cc", "frame_queue_transferring_optimizer.h", "frame_queue_underlying_source.cc", @@ -44,6 +45,7 @@ source_set("unit_tests") { testonly = true sources = [ + "frame_queue_test.cc", "media_stream_audio_track_underlying_sink_test.cc", "media_stream_audio_track_underlying_source_test.cc", "media_stream_track_generator_test.cc",
diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue.h b/third_party/blink/renderer/modules/breakout_box/frame_queue.h new file mode 100644 index 0000000..f5c2b23 --- /dev/null +++ b/third_party/blink/renderer/modules/breakout_box/frame_queue.h
@@ -0,0 +1,92 @@ +// Copyright 2021 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 THIRD_PARTY_BLINK_RENDERER_MODULES_BREAKOUT_BOX_FRAME_QUEUE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_BREAKOUT_BOX_FRAME_QUEUE_H_ + +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/renderer/platform/wtf/deque.h" +#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" +#include "third_party/blink/renderer/platform/wtf/threading_primitives.h" + +namespace blink { + +// Implements a thread-safe circular queue. +template <typename NativeFrameType> +class FrameQueue + : public WTF::ThreadSafeRefCounted<FrameQueue<NativeFrameType>> { + public: + explicit FrameQueue(wtf_size_t max_size) + : max_size_(std::max(1u, max_size)) {} + + void Push(NativeFrameType frame) { + MutexLocker locker_(lock_); + if (queue_.size() == max_size_) + queue_.pop_front(); + queue_.push_back(std::move(frame)); + } + + absl::optional<NativeFrameType> Pop() { + MutexLocker locker_(lock_); + if (queue_.empty()) + return absl::nullopt; + return queue_.TakeFirst(); + } + + bool IsEmpty() { + MutexLocker locker_(lock_); + return queue_.empty(); + } + + wtf_size_t MaxSize() const { return max_size_; } + + void Clear() { + MutexLocker locker_(lock_); + queue_.clear(); + } + + private: + Mutex lock_; + Deque<NativeFrameType> queue_ GUARDED_BY(lock_); + const wtf_size_t max_size_; +}; + +// Wrapper that allows sharing a single FrameQueue reference across multiple +// threads. +template <typename NativeFrameType> +class FrameQueueHandle { + public: + explicit FrameQueueHandle( + scoped_refptr<FrameQueue<NativeFrameType>> frame_queue) + : queue_(std::move(frame_queue)) { + DCHECK(queue_); + } + FrameQueueHandle(const FrameQueueHandle&) = delete; + FrameQueueHandle& operator=(const FrameQueueHandle&) = delete; + + ~FrameQueueHandle() { Invalidate(); } + + // Returns a copy of |queue_|, which should be checked for nullity and + // re-used throughout the scope of a function call, instead of calling + // Queue() multiple times. Otherwise the queue could be destroyed + // between calls. + scoped_refptr<FrameQueue<NativeFrameType>> Queue() const { + MutexLocker locker(mutex_); + return queue_; + } + + // Releases the internal FrameQueue reference. + void Invalidate() { + MutexLocker locker(mutex_); + queue_.reset(); + } + + private: + mutable Mutex mutex_; + scoped_refptr<FrameQueue<NativeFrameType>> queue_ GUARDED_BY(mutex_); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_BREAKOUT_BOX_STREAM_TEST_UTILS_H_
diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_test.cc b/third_party/blink/renderer/modules/breakout_box/frame_queue_test.cc new file mode 100644 index 0000000..6a44cd89 --- /dev/null +++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_test.cc
@@ -0,0 +1,144 @@ +// Copyright 2021 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 "third_party/blink/renderer/modules/breakout_box/frame_queue.h" + +#include "base/synchronization/waitable_event.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" +#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" + +namespace blink { + +class FrameQueueTest : public testing::Test { + public: + FrameQueueTest() : io_task_runner_(Platform::Current()->GetIOTaskRunner()) {} + + protected: + ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_; + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; +}; + +TEST_F(FrameQueueTest, PushPopMatches) { + const int kMaxSize = 5; + scoped_refptr<FrameQueue<int>> queue = + base::MakeRefCounted<FrameQueue<int>>(kMaxSize); + for (int i = 0; i < kMaxSize; ++i) + queue->Push(i); + for (int i = 0; i < kMaxSize; ++i) { + absl::optional<int> element = queue->Pop(); + EXPECT_TRUE(element.has_value()); + EXPECT_EQ(*element, i); + } +} + +TEST_F(FrameQueueTest, EmptyQueueReturnsNullopt) { + scoped_refptr<FrameQueue<int>> queue = + base::MakeRefCounted<FrameQueue<int>>(5); + absl::optional<int> element = queue->Pop(); + EXPECT_FALSE(element.has_value()); +} + +TEST_F(FrameQueueTest, QueueDropsOldElements) { + const int kMaxSize = 5; + const int kNumInsertions = 10; + scoped_refptr<FrameQueue<int>> queue = + base::MakeRefCounted<FrameQueue<int>>(kMaxSize); + for (int i = 0; i < kNumInsertions; ++i) + queue->Push(i); + for (int i = 0; i < kMaxSize; ++i) { + absl::optional<int> element = queue->Pop(); + EXPECT_TRUE(element.has_value()); + EXPECT_EQ(*element, kNumInsertions - kMaxSize + i); + } + EXPECT_TRUE(queue->IsEmpty()); + EXPECT_FALSE(queue->Pop().has_value()); +} + +TEST_F(FrameQueueTest, FrameQueueHandle) { + const int kMaxSize = 5; + scoped_refptr<FrameQueue<int>> original_queue = + base::MakeRefCounted<FrameQueue<int>>(kMaxSize); + FrameQueueHandle<int> handle1(original_queue); + FrameQueueHandle<int> handle2(std::move(original_queue)); + + for (int i = 0; i < kMaxSize; ++i) { + auto queue = handle1.Queue(); + EXPECT_TRUE(queue); + queue->Push(i); + } + for (int i = 0; i < kMaxSize; ++i) { + auto queue = handle2.Queue(); + EXPECT_TRUE(queue); + absl::optional<int> element = queue->Pop(); + EXPECT_TRUE(element.has_value()); + EXPECT_EQ(*element, i); + } + + EXPECT_TRUE(handle1.Queue()); + handle1.Invalidate(); + EXPECT_FALSE(handle1.Queue()); + + EXPECT_TRUE(handle2.Queue()); + handle2.Invalidate(); + EXPECT_FALSE(handle2.Queue()); +} + +TEST_F(FrameQueueTest, PushValuesInOrderOnSeparateThread) { + const int kMaxSize = 3; + const int kNumElements = 100; + scoped_refptr<FrameQueue<int>> original_queue = + base::MakeRefCounted<FrameQueue<int>>(kMaxSize); + FrameQueueHandle<int> handle1(std::move(original_queue)); + FrameQueueHandle<int> handle2(handle1.Queue()); + + base::WaitableEvent start_event; + base::WaitableEvent end_event; + PostCrossThreadTask( + *io_task_runner_, FROM_HERE, + CrossThreadBindOnce( + [](FrameQueueHandle<int>* handle, base::WaitableEvent* start_event, + base::WaitableEvent* end_event) { + auto queue = handle->Queue(); + EXPECT_TRUE(queue); + start_event->Signal(); + for (int i = 0; i < kNumElements; ++i) + queue->Push(i); + handle->Invalidate(); + end_event->Signal(); + }, + CrossThreadUnretained(&handle1), CrossThreadUnretained(&start_event), + CrossThreadUnretained(&end_event))); + + auto queue = handle2.Queue(); + int last_value_read = -1; + start_event.Wait(); + for (int i = 0; i < kNumElements; ++i) { + absl::optional<int> element = queue->Pop(); + if (element) { + EXPECT_GE(*element, 0); + EXPECT_LT(*element, kNumElements); + EXPECT_GT(*element, last_value_read); + last_value_read = *element; + } + } + end_event.Wait(); + EXPECT_FALSE(handle1.Queue()); + EXPECT_TRUE(handle2.Queue()); + + int num_read = 0; + while (!queue->IsEmpty()) { + absl::optional<int> element = queue->Pop(); + EXPECT_TRUE(element.has_value()); + EXPECT_GE(*element, 0); + EXPECT_LT(*element, kNumElements); + EXPECT_GT(*element, last_value_read); + last_value_read = *element; + num_read++; + } + EXPECT_LE(num_read, kMaxSize); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.cc b/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.cc index aecca0f0..fbd2d13b 100644 --- a/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.cc +++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.cc
@@ -39,7 +39,7 @@ auto* source = MakeGarbageCollected< TransferredFrameQueueUnderlyingSource<NativeFrameType>>( - script_state, host, host_runner_, max_queue_size_); + script_state, host, host_runner_); PostCrossThreadTask( *host_runner_, FROM_HERE,
diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc index b484bca..09bb4315 100644 --- a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc +++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc
@@ -26,19 +26,39 @@ : UnderlyingSourceBase(script_state), realm_task_runner_(ExecutionContext::From(script_state) ->GetTaskRunner(TaskType::kInternalMediaRealTime)), - max_queue_size_(std::max(1u, max_queue_size)) {} + frame_queue_handle_( + base::MakeRefCounted<FrameQueue<NativeFrameType>>(max_queue_size)) {} + +template <typename NativeFrameType> +FrameQueueUnderlyingSource<NativeFrameType>::FrameQueueUnderlyingSource( + ScriptState* script_state, + FrameQueueUnderlyingSource<NativeFrameType>* other_source) + : UnderlyingSourceBase(script_state), + realm_task_runner_(ExecutionContext::From(script_state) + ->GetTaskRunner(TaskType::kInternalMediaRealTime)), + frame_queue_handle_(other_source->frame_queue_handle_.Queue()) {} template <typename NativeFrameType> ScriptPromise FrameQueueUnderlyingSource<NativeFrameType>::pull( ScriptState* script_state) { DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); - if (!queue_.empty()) { - ProcessPullRequest(); - } else { + auto frame_queue = frame_queue_handle_.Queue(); + if (!frame_queue) + return ScriptPromise::CastUndefined(script_state); + if (frame_queue->IsEmpty()) { + MutexLocker locker(mutex_); is_pending_pull_ = true; + return ScriptPromise::CastUndefined(script_state); } - - DCHECK_LT(queue_.size(), max_queue_size_); + // Enqueuing the frame in the stream controller synchronously can lead to a + // state where the JS code issuing and handling the read requests keeps + // executing and prevents other tasks from executing. To avoid this, enqueue + // the frame on another task. See https://crbug.com/1216445#c1 + realm_task_runner_->PostTask( + FROM_HERE, + WTF::Bind(&FrameQueueUnderlyingSource< + NativeFrameType>::MaybeSendFrameFromQueueToStream, + WrapPersistent(this))); return ScriptPromise::CastUndefined(script_state); } @@ -55,6 +75,12 @@ "Invalid track", DOMException::GetErrorName(DOMExceptionCode::kInvalidStateError))); } + if (is_pending_close_) { + realm_task_runner_->PostTask( + FROM_HERE, + WTF::Bind(&FrameQueueUnderlyingSource<NativeFrameType>::Close, + WrapWeakPersistent(this))); + } return ScriptPromise::CastUndefined(script_state); } @@ -69,9 +95,22 @@ } template <typename NativeFrameType> -void FrameQueueUnderlyingSource<NativeFrameType>::CloseController() { - if (Controller()) - Controller()->Close(); +bool FrameQueueUnderlyingSource<NativeFrameType>::HasPendingActivity() const { + MutexLocker locker(mutex_); + return is_pending_pull_ && Controller(); +} + +template <typename NativeFrameType> +void FrameQueueUnderlyingSource<NativeFrameType>::ContextDestroyed() { + DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); + UnderlyingSourceBase::ContextDestroyed(); + frame_queue_handle_.Invalidate(); +} + +template <typename NativeFrameType> +wtf_size_t FrameQueueUnderlyingSource<NativeFrameType>::MaxQueueSize() const { + auto queue = frame_queue_handle_.Queue(); + return queue ? queue->MaxSize() : 0; } template <typename NativeFrameType> @@ -80,20 +119,56 @@ if (is_closed_) return; + // The source has not started. Postpone close until it starts. + if (!Controller()) { + is_pending_close_ = true; + return; + } + StopFrameDelivery(); CloseController(); - queue_.clear(); - pending_transfer_queue_.clear(); - transfer_frames_cb_.Reset(); - transfer_done_cb_.Reset(); - is_pending_pull_ = false; - + frame_queue_handle_.Invalidate(); is_closed_ = true; + { + MutexLocker locker(mutex_); + is_pending_pull_ = false; + if (transferred_source_) { + PostCrossThreadTask( + *transferred_source_->GetRealmRunner(), FROM_HERE, + CrossThreadBindOnce( + &FrameQueueUnderlyingSource<NativeFrameType>::Close, + WrapCrossThreadWeakPersistent(transferred_source_.Get()))); + } + transferred_source_.Clear(); + } } template <typename NativeFrameType> -bool FrameQueueUnderlyingSource<NativeFrameType>::HasPendingActivity() const { - return is_pending_pull_ && Controller(); +void FrameQueueUnderlyingSource<NativeFrameType>::QueueFrame( + NativeFrameType media_frame) { + bool should_send_frame_to_stream; + { + MutexLocker locker(mutex_); + if (transferred_source_) { + transferred_source_->QueueFrame(std::move(media_frame)); + return; + } + should_send_frame_to_stream = is_pending_pull_; + } + + auto frame_queue = frame_queue_handle_.Queue(); + if (!frame_queue) + return; + + frame_queue->Push(std::move(media_frame)); + if (should_send_frame_to_stream) { + PostCrossThreadTask( + *realm_task_runner_, FROM_HERE, + CrossThreadBindOnce( + &FrameQueueUnderlyingSource< + NativeFrameType>::MaybeSendFrameFromQueueToStream, + WrapCrossThreadPersistent(this))); + } } template <typename NativeFrameType> @@ -103,184 +178,54 @@ } template <typename NativeFrameType> +bool FrameQueueUnderlyingSource<NativeFrameType>::IsPendingPullForTesting() + const { + MutexLocker locker(mutex_); + return is_pending_pull_; +} + +template <typename NativeFrameType> double FrameQueueUnderlyingSource<NativeFrameType>::DesiredSizeForTesting() const { + DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); return Controller()->DesiredSize(); } template <typename NativeFrameType> -void FrameQueueUnderlyingSource<NativeFrameType>::ContextDestroyed() { +void FrameQueueUnderlyingSource<NativeFrameType>::TransferSource( + FrameQueueUnderlyingSource<NativeFrameType>* transferred_source) { DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); - UnderlyingSourceBase::ContextDestroyed(); - queue_.clear(); -} - -template <typename NativeFrameType> -void FrameQueueUnderlyingSource<NativeFrameType>::QueueFrame( - NativeFrameType media_frame) { - DCHECK(!queue_transferred_); - - // We don't bother to acquire a lock to check |transfer_frames_cb_|. - // It should be set on |realm_task_runner_| (at which point it's - // still fine to call QueueFrameOnRealmTaskRunnder()), and unset on - // |transfer_task_runner_| - if (transfer_frames_cb_) { - DCHECK(transfer_task_runner_->RunsTasksInCurrentSequence()); - pending_transfer_queue_.push_back(std::move(media_frame)); - return; - } - - if (realm_task_runner_->RunsTasksInCurrentSequence()) { - QueueFrameOnRealmTaskRunner(std::move(media_frame)); - return; - } - - PostCrossThreadTask( - *realm_task_runner_, FROM_HERE, - CrossThreadBindOnce(&FrameQueueUnderlyingSource< - NativeFrameType>::QueueFrameOnRealmTaskRunner, - WrapCrossThreadPersistent(this), - std::move(media_frame))); -} - -template <typename NativeFrameType> -void FrameQueueUnderlyingSource<NativeFrameType>::QueueFrameOnRealmTaskRunner( - NativeFrameType media_frame) { - DCHECK(!queue_transferred_); - DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); - DCHECK_LE(queue_.size(), max_queue_size_); - - if (transfer_frames_cb_) { - // We are currently transferring this frame queue. This frame should be - // immediately sent, because older frames (the ones in |queue_|) are - // already transferred, and new frames are saved in - // |pending_transfer_queue_|. - DCHECK(queue_.empty()); - transfer_frames_cb_.Run(std::move(media_frame)); - return; - } - - // The queue was stopped, and we shouldn't save frames. - if (!Controller()) - return; - - // If the |queue_| is empty and the consumer has signaled a pull, bypass - // |queue_| and send the frame directly to the stream controller. - if (queue_.empty() && is_pending_pull_) { - SendFrameToStream(std::move(media_frame)); - return; - } - - if (queue_.size() == max_queue_size_) - queue_.pop_front(); - - queue_.push_back(std::move(media_frame)); - if (is_pending_pull_) { - ProcessPullRequest(); - } -} - -template <typename NativeFrameType> -void FrameQueueUnderlyingSource<NativeFrameType>::TransferQueueFromRealmRunner( - TransferFramesCB transfer_frames_cb, - scoped_refptr<base::SequencedTaskRunner> transfer_task_runner, - CrossThreadOnceClosure transfer_done_cb) { - DCHECK(!queue_transferred_); - DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); - - // QueueFrame() will stop posting frames to QueueFrameOnRealmTaskRunner(). - // New frames will be saved in |pending_transfer_queue_| instead. - transfer_frames_cb_ = std::move(transfer_frames_cb); - transfer_done_cb_ = std::move(transfer_done_cb); - transfer_task_runner_ = std::move(transfer_task_runner); - - // All current frames should be send immediately, as they are the oldest. - while (!queue_.empty()) { - transfer_frames_cb_.Run(std::move(queue_.front())); - queue_.pop_front(); - } - - // Make sure that all in-flight calls to QueueFrameOnRealmTaskRunner() - // settle. - EnsureAllRealmRunnerFramesProcessed(); -} - -template <typename NativeFrameType> -void FrameQueueUnderlyingSource< - NativeFrameType>::EnsureAllRealmRunnerFramesProcessed() { - DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); - DCHECK(!queue_transferred_); - DCHECK(queue_.empty()); - - auto frame_barrier_done_cb = ConvertToBaseOnceCallback( - CrossThreadBindOnce(&FrameQueueUnderlyingSource< - NativeFrameType>::OnAllRealmRunnerFrameProcessed, - WrapCrossThreadPersistent(this))); - - // Send |frame_barrier_done_cb| to |transfer_task_runner_| and back, - // acting as a "barrier" for pending QueueFrameOnRealmTaskRunner() calls. - transfer_task_runner_->PostTask( - FROM_HERE, - BindPostTask(realm_task_runner_, std::move(frame_barrier_done_cb))); -} - -template <typename NativeFrameType> -void FrameQueueUnderlyingSource< - NativeFrameType>::OnAllRealmRunnerFrameProcessed() { - DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); - DCHECK(!queue_transferred_); - DCHECK(queue_.empty()); - - // We can now start queueing frames directly on the transferred source. + MutexLocker locker(mutex_); + DCHECK(!transferred_source_); + transferred_source_ = transferred_source; CloseController(); + frame_queue_handle_.Invalidate(); +} - // Unset this flag, as to not keep |this| alive through HasPendingActivity(). - is_pending_pull_ = false; - - PostCrossThreadTask( - *transfer_task_runner_.get(), FROM_HERE, - CrossThreadBindOnce( - &FrameQueueUnderlyingSource< - NativeFrameType>::FinalizeQueueTransferOnTransferRunner, - WrapCrossThreadPersistent(this))); +template <typename NativeFrameType> +void FrameQueueUnderlyingSource<NativeFrameType>::CloseController() { + DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); + if (Controller()) + Controller()->Close(); } template <typename NativeFrameType> void FrameQueueUnderlyingSource< - NativeFrameType>::FinalizeQueueTransferOnTransferRunner() { - DCHECK(transfer_task_runner_->RunsTasksInCurrentSequence()); - DCHECK(!queue_transferred_); - DCHECK(queue_.empty()); + NativeFrameType>::MaybeSendFrameFromQueueToStream() { + DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); + auto frame_queue = frame_queue_handle_.Queue(); + if (!frame_queue) + return; - // All frames that were bound to the |realm_task_runner_| have been - // transferred. We can transfer our temporary frames without fear of changing - // the ordering of frames. - while (!pending_transfer_queue_.empty()) { - transfer_frames_cb_.Run(std::move(pending_transfer_queue_.front())); - pending_transfer_queue_.pop_front(); + absl::optional<NativeFrameType> media_frame = frame_queue->Pop(); + if (!media_frame.has_value()) + return; + + Controller()->Enqueue(MakeBlinkFrame(std::move(media_frame.value()))); + { + MutexLocker locker(mutex_); + is_pending_pull_ = false; } - - queue_transferred_ = true; - transfer_task_runner_.reset(); - transfer_frames_cb_.Reset(); - std::move(transfer_done_cb_).Run(); -} - -template <typename NativeFrameType> -void FrameQueueUnderlyingSource<NativeFrameType>::ProcessPullRequest() { - DCHECK(!queue_.empty()); - SendFrameToStream(std::move(queue_.front())); - queue_.pop_front(); -} - -template <typename NativeFrameType> -void FrameQueueUnderlyingSource<NativeFrameType>::SendFrameToStream( - NativeFrameType media_frame) { - DCHECK(Controller()); - DCHECK(media_frame); - - Controller()->Enqueue(MakeBlinkFrame(std::move(media_frame))); - is_pending_pull_ = false; } template <>
diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h index a50a0a82..55fe478 100644 --- a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h +++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h
@@ -9,6 +9,7 @@ #include "media/base/audio_buffer.h" #include "media/base/video_frame.h" #include "third_party/blink/renderer/core/streams/underlying_source_base.h" +#include "third_party/blink/renderer/modules/breakout_box/frame_queue.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/wtf/deque.h" @@ -22,6 +23,8 @@ public: using TransferFramesCB = CrossThreadFunction<void(NativeFrameType)>; + // Initializes a new FrameQueueUnderlyingSource with a new internal circular + // queue that can hold up to |queue_size| elements. FrameQueueUnderlyingSource(ScriptState*, wtf_size_t queue_size); ~FrameQueueUnderlyingSource() override = default; @@ -40,89 +43,79 @@ // ExecutionLifecycleObserver void ContextDestroyed() override; - wtf_size_t MaxQueueSize() const { return max_queue_size_; } + wtf_size_t MaxQueueSize() const; // Clears all internal state and closes the UnderlyingSource's Controller. // Must be called on |realm_task_runner_|. void Close(); - bool IsClosed() { return is_closed_; } - - // Adds a frame to |queue_|, dropping the oldest frame if it is full. - // Can be called from any task runner, and will jump to |realm_task_runner_|. - void QueueFrame(NativeFrameType media_frame); + bool IsClosed() { + DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); + return is_closed_; + } // Start or stop the delivery of frames via QueueFrame(). // Must be called on |realm_task_runner_|. virtual bool StartFrameDelivery() = 0; virtual void StopFrameDelivery() = 0; - bool IsPendingPullForTesting() const { return is_pending_pull_; } - const Deque<NativeFrameType>& QueueForTesting() const { return queue_; } + // Delivers a new frame to this source. + void QueueFrame(NativeFrameType); + + bool IsPendingPullForTesting() const; double DesiredSizeForTesting() const; void Trace(Visitor*) const override; protected: + // Initializes a new FrameQueueUnderlyingSource containing a + // |frame_queue_handle_| that references the same internal circular queue as + // |other_source|. + FrameQueueUnderlyingSource( + ScriptState*, + FrameQueueUnderlyingSource<NativeFrameType>* other_source); scoped_refptr<base::SequencedTaskRunner> GetRealmRunner() { return realm_task_runner_; } - // Starts transferring frames via |transfer_frames_cb|, guaranteeing frame - // ordering between frames received on |realm_task_runner_| and - // |transfer_task_runner|. QueueFrames() can still called until - // |transfer_done_cb| runs, at which point QueueFrames() should never be - // called again. - // - // Note: - // - This must be called on |realm_task_runner_|. - // - |transfer_done_cb| will be run on |transfer_task_runner|. - // - |transfer_task_runner| must be the task runner on which QueueFrame() is - // normally called. - void TransferQueueFromRealmRunner( - TransferFramesCB transfer_frames_cb, - scoped_refptr<base::SequencedTaskRunner> transfer_task_runner, - CrossThreadOnceClosure transfer_done_cb); + // Sets |transferred_source| as the new target for frames arriving via + // QueueFrame(). |transferred_source| will pull frames from the same circular + // queue. Must be called on |realm_task_runner_|. + void TransferSource( + FrameQueueUnderlyingSource<NativeFrameType>* transferred_source); private: + // Must be called on |realm_task_runner_|. void CloseController(); - void QueueFrameOnRealmTaskRunner(NativeFrameType media_frame); - void ProcessPullRequest(); - void SendFrameToStream(NativeFrameType media_frame); + + // If the internal queue is not empty, pops a frame from it and enqueues it + // into the the stream's controller. Must be called on |realm_task_runner|. + void MaybeSendFrameFromQueueToStream(); + + // Creates a JS frame (VideoFrame or AudioData) backed by |media_frame|. + // Must be called on |realm_task_runner_|. ScriptWrappable* MakeBlinkFrame(NativeFrameType media_frame); - // Used to make sure no new frames arrive via QueueFrameOnRealmTaskRunner(). - void EnsureAllRealmRunnerFramesProcessed(); - void OnAllRealmRunnerFrameProcessed(); - - // Must be called on the same task runner that calls QueueFrame() (most likely - // the IO thread). Transfers all frames in |pending_transfer_queue_| via - // |transfer_frames_cb|, and clears |transfer_frames_cb|. - // QueueFrame() should never be called after this. - void FinalizeQueueTransferOnTransferRunner(); - bool is_closed_ = false; + bool is_pending_close_ = false; - // Main task runner for the window or worker context. + // Main task runner for the window or worker context this source runs on. const scoped_refptr<base::SequencedTaskRunner> realm_task_runner_; - // Used when the queue is being transferred, to redirect frames that are in - // flight between QueueFrames() and QueueFrameOnRealmTaskRunner(). - TransferFramesCB transfer_frames_cb_; - scoped_refptr<base::SequencedTaskRunner> transfer_task_runner_; - CrossThreadOnceClosure transfer_done_cb_; + // |frame_queue_handle_| is a handle containing a reference to an internal + // circular queue prior to the stream controller's queue. It allows dropping + // older frames in case frames accumulate due to slow consumption. + // Frames are normally pushed on a background task runner (for example, the + // IO thread) and popped on |realm_task_runner_|. + FrameQueueHandle<NativeFrameType> frame_queue_handle_; - // Accumulates frames received while we are transferring the queue. - Deque<NativeFrameType> pending_transfer_queue_; - - bool queue_transferred_ = false; - - // An internal deque prior to the stream controller's queue. It acts as a ring - // buffer and allows dropping old frames instead of new ones in case frames - // accumulate due to slow consumption. - Deque<NativeFrameType> queue_; - const wtf_size_t max_queue_size_; - bool is_pending_pull_ = false; + mutable Mutex mutex_; + // If the stream backed by this source is transferred to another in-process + // realm (e.g., a Worker), |transferred_source_| is the source of the + // transferred stream. + CrossThreadPersistent<FrameQueueUnderlyingSource<NativeFrameType>> + transferred_source_ GUARDED_BY(mutex_); + bool is_pending_pull_ GUARDED_BY(mutex_) = false; }; template <>
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source_test.cc index 5b91219..470cd05 100644 --- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source_test.cc +++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source_test.cc
@@ -17,8 +17,10 @@ #include "third_party/blink/renderer/core/streams/readable_stream.h" #include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h" #include "third_party/blink/renderer/modules/breakout_box/pushable_media_stream_audio_source.h" +#include "third_party/blink/renderer/modules/breakout_box/stream_test_utils.h" #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h" #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h" +#include "third_party/blink/renderer/modules/webcodecs/audio_data.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h" #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h" @@ -142,8 +144,8 @@ auto* track = CreateTrack(v8_scope.GetExecutionContext()); auto* source = CreateSource(script_state, track, buffer_size); EXPECT_EQ(source->MaxQueueSize(), buffer_size); - // Create a stream to ensure there is a controller associated to the source. - ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0); + auto* stream = + ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0); // Add a sink to the track to make it possible to wait until a pushed frame // is delivered to sinks, including |source|, which is a sink of the track. @@ -160,83 +162,30 @@ sink_loop.Run(); }; - const auto& queue = source->QueueForTesting(); for (wtf_size_t i = 0; i < buffer_size; ++i) { - EXPECT_EQ(queue.size(), i); base::TimeDelta timestamp = base::TimeDelta::FromSeconds(i); push_frame_sync(timestamp); - EXPECT_EQ(queue.back()->timestamp(), timestamp); - EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta()); } // Push another frame while the queue is full. - EXPECT_EQ(queue.size(), buffer_size); push_frame_sync(base::TimeDelta::FromSeconds(buffer_size)); - // Since the queue was full, the oldest frame from the queue should have been - // dropped. - EXPECT_EQ(queue.size(), buffer_size); - EXPECT_EQ(queue.back()->timestamp(), - base::TimeDelta::FromSeconds(buffer_size)); - EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(1)); + // Since the queue was full, the oldest frame from the queue (timestamp 0) + // should have been dropped. + NonThrowableExceptionState exception_state; + auto* reader = + stream->GetDefaultReaderForTesting(script_state, exception_state); + for (wtf_size_t i = 1; i <= buffer_size; ++i) { + AudioData* audio_data = ReadObjectFromStream<AudioData>(v8_scope, reader); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(audio_data->timestamp()), + base::TimeDelta::FromSeconds(i)); + } - // Pulling with frames in the queue should move the oldest frame in the queue - // to the stream's controller. - EXPECT_EQ(source->DesiredSizeForTesting(), 0); + // Pulling causes a pending pull since there are no frames available for + // reading. EXPECT_FALSE(source->IsPendingPullForTesting()); source->pull(script_state); - EXPECT_EQ(source->DesiredSizeForTesting(), -1); - EXPECT_FALSE(source->IsPendingPullForTesting()); - EXPECT_EQ(queue.size(), buffer_size - 1); - EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(2)); - - source->Close(); - EXPECT_EQ(queue.size(), 0u); - - WebMediaStreamAudioSink::RemoveFromAudioTrack( - &mock_sink, WebMediaStreamTrack(track->Component())); - track->stopTrack(v8_scope.GetExecutionContext()); -} - -TEST_F(MediaStreamAudioTrackUnderlyingSourceTest, - BypassQueueAfterPullWithEmptyBuffer) { - V8TestingScope v8_scope; - ScriptState* script_state = v8_scope.GetScriptState(); - auto* track = CreateTrack(v8_scope.GetExecutionContext()); - auto* source = CreateSource(script_state, track); - // Create a stream to ensure there is a controller associated to the source. - ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0); - - MockMediaStreamAudioSink mock_sink; - WebMediaStreamAudioSink::AddToAudioTrack( - &mock_sink, WebMediaStreamTrack(track->Component())); - - auto push_frame_sync = [&mock_sink, track, this]() { - base::RunLoop sink_loop; - EXPECT_CALL(mock_sink, OnData(_, _)) - .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure())); - PushData(track); - sink_loop.Run(); - }; - - // At first, the queue is empty and the desired size is empty as well. - EXPECT_TRUE(source->QueueForTesting().empty()); - EXPECT_EQ(source->DesiredSizeForTesting(), 0); - EXPECT_FALSE(source->IsPendingPullForTesting()); - - source->pull(script_state); - EXPECT_TRUE(source->QueueForTesting().empty()); - EXPECT_EQ(source->DesiredSizeForTesting(), 0); EXPECT_TRUE(source->IsPendingPullForTesting()); - EXPECT_TRUE(source->HasPendingActivity()); - - push_frame_sync(); - // Since a pull was pending, the frame is put directly in the stream - // controller, bypassing the source queue. - EXPECT_TRUE(source->QueueForTesting().empty()); - EXPECT_EQ(source->DesiredSizeForTesting(), -1); - EXPECT_FALSE(source->IsPendingPullForTesting()); - EXPECT_FALSE(source->HasPendingActivity()); source->Close(); WebMediaStreamAudioSink::RemoveFromAudioTrack(
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc index 73906a5..b6d7678 100644 --- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc +++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc
@@ -17,22 +17,6 @@ namespace blink { -namespace { - -void PostFrameToTransferredSource( - scoped_refptr<base::SequencedTaskRunner> transferred_runner, - TransferredVideoFrameQueueUnderlyingSource* transferred_source, - scoped_refptr<media::VideoFrame> media_frame) { - PostCrossThreadTask( - *transferred_runner.get(), FROM_HERE, - CrossThreadBindOnce( - &TransferredVideoFrameQueueUnderlyingSource::QueueFrame, - WrapCrossThreadPersistent(transferred_source), - std::move(media_frame))); -} - -} // namespace - MediaStreamVideoTrackUnderlyingSource::MediaStreamVideoTrackUnderlyingSource( ScriptState* script_state, MediaStreamComponent* track, @@ -70,28 +54,7 @@ scoped_refptr<base::SequencedTaskRunner> transferred_runner, TransferredVideoFrameQueueUnderlyingSource* source) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!transferred_source_); - - transferred_runner_ = std::move(transferred_runner); - transferred_source_ = source; - - auto finalize_transfer = [](MediaStreamVideoTrackUnderlyingSource* self) { - DCHECK(self->GetIOTaskRunner()->RunsTasksInCurrentSequence()); - self->was_transferred_ = true; - }; - - // All queued frames will be immediately transferred. All frames in flight for - // the main thread will be immediately transferred as they arrive. - // - // New frames queued via QueueFrame() in OnFrameFromTrack() will be saved in - // a temporary queue, only accessed on the IO thread, until - // FinalizeQueueTransfer() is called. - TransferQueueFromRealmRunner( - CrossThreadBindRepeating(&PostFrameToTransferredSource, - transferred_runner_, - WrapCrossThreadPersistent(source)), - GetIOTaskRunner(), - CrossThreadBindOnce(finalize_transfer, WrapCrossThreadPersistent(this))); + TransferSource(source); RecordBreakoutBoxUsage(BreakoutBoxUsage::kReadableVideoWorker); } @@ -100,13 +63,6 @@ std::vector<scoped_refptr<media::VideoFrame>> /*scaled_media_frames*/, base::TimeTicks estimated_capture_time) { DCHECK(GetIOTaskRunner()->RunsTasksInCurrentSequence()); - - if (was_transferred_) { - PostFrameToTransferredSource(transferred_runner_, transferred_source_.Get(), - std::move(media_frame)); - return; - } - // The scaled video frames are currently ignored. QueueFrame(std::move(media_frame)); }
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h index 583a0d4..ddb1f8d 100644 --- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h +++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h
@@ -56,12 +56,6 @@ std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames, base::TimeTicks estimated_capture_time); - scoped_refptr<base::SequencedTaskRunner> transferred_runner_; - CrossThreadFrameQueueSource transferred_source_; - - // Only accessed on the IO runner. - bool was_transferred_ = false; - // Only used to prevent the gargabe collector from reclaiming the media // stream track processor that created |this|. const Member<ScriptWrappable> media_stream_track_processor_;
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source_test.cc index f6652da..a809f87a 100644 --- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source_test.cc +++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source_test.cc
@@ -15,9 +15,11 @@ #include "third_party/blink/renderer/core/streams/readable_stream.h" #include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h" #include "third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.h" +#include "third_party/blink/renderer/modules/breakout_box/stream_test_utils.h" #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h" #include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h" #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h" +#include "third_party/blink/renderer/modules/webcodecs/video_frame.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" @@ -137,8 +139,9 @@ const wtf_size_t buffer_size = 5; auto* source = CreateSource(script_state, track, buffer_size); EXPECT_EQ(source->MaxQueueSize(), buffer_size); - // Create a stream to ensure there is a controller associated to the source. - ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0); + auto* stream = + ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0); + // Add a sink to the track to make it possible to wait until a pushed frame // is delivered to sinks, including |source|, which is a sink of the track. MockMediaStreamVideoSink mock_sink; @@ -151,79 +154,32 @@ sink_loop.Run(); }; - const auto& queue = source->QueueForTesting(); for (wtf_size_t i = 0; i < buffer_size; ++i) { - EXPECT_EQ(queue.size(), i); base::TimeDelta timestamp = base::TimeDelta::FromSeconds(i); push_frame_sync(timestamp); - EXPECT_EQ(queue.back()->timestamp(), timestamp); - EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(0)); } // Push another frame while the queue is full. - EXPECT_EQ(queue.size(), buffer_size); + // EXPECT_EQ(queue.size(), buffer_size); push_frame_sync(base::TimeDelta::FromSeconds(buffer_size)); - // Since the queue was full, the oldest frame from the queue should have been - // dropped. - EXPECT_EQ(queue.size(), buffer_size); - EXPECT_EQ(queue.back()->timestamp(), - base::TimeDelta::FromSeconds(buffer_size)); - EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(1)); + // Since the queue was full, the oldest frame from the queue (timestamp 0) + // should have been dropped. + NonThrowableExceptionState exception_state; + auto* reader = + stream->GetDefaultReaderForTesting(script_state, exception_state); + for (wtf_size_t i = 1; i <= buffer_size; ++i) { + VideoFrame* video_frame = + ReadObjectFromStream<VideoFrame>(v8_scope, reader); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(*video_frame->timestamp()), + base::TimeDelta::FromSeconds(i)); + } - // Pulling with frames in the queue should move the oldest frame in the queue - // to the stream's controller. - EXPECT_EQ(source->DesiredSizeForTesting(), 0); + // Pulling causes a pending pull since there are no frames available for + // reading. EXPECT_FALSE(source->IsPendingPullForTesting()); source->pull(script_state); - EXPECT_EQ(source->DesiredSizeForTesting(), -1); - EXPECT_FALSE(source->IsPendingPullForTesting()); - EXPECT_EQ(queue.size(), buffer_size - 1); - EXPECT_EQ(queue.front()->timestamp(), base::TimeDelta::FromSeconds(2)); - - source->Close(); - EXPECT_EQ(queue.size(), 0u); - track->stopTrack(v8_scope.GetExecutionContext()); -} - -TEST_F(MediaStreamVideoTrackUnderlyingSourceTest, - BypassQueueAfterPullWithEmptyBuffer) { - V8TestingScope v8_scope; - ScriptState* script_state = v8_scope.GetScriptState(); - auto* track = CreateTrack(v8_scope.GetExecutionContext()); - auto* source = CreateSource(script_state, track); - - // Create a stream to ensure there is a controller associated to the source. - ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0); - - MockMediaStreamVideoSink mock_sink; - mock_sink.ConnectToTrack(WebMediaStreamTrack(source->Track())); - auto push_frame_sync = [&mock_sink, this]() { - base::RunLoop sink_loop; - EXPECT_CALL(mock_sink, OnVideoFrame(_)) - .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure())); - PushFrame(); - sink_loop.Run(); - }; - - // At first, the queue is empty and the desired size is empty as well. - EXPECT_TRUE(source->QueueForTesting().empty()); - EXPECT_EQ(source->DesiredSizeForTesting(), 0); - EXPECT_FALSE(source->IsPendingPullForTesting()); - - source->pull(script_state); - EXPECT_TRUE(source->QueueForTesting().empty()); - EXPECT_EQ(source->DesiredSizeForTesting(), 0); EXPECT_TRUE(source->IsPendingPullForTesting()); - EXPECT_TRUE(source->HasPendingActivity()); - - push_frame_sync(); - // Since a pull was pending, the frame is put directly in the stream - // controller, bypassing the source queue. - EXPECT_TRUE(source->QueueForTesting().empty()); - EXPECT_EQ(source->DesiredSizeForTesting(), -1); - EXPECT_FALSE(source->IsPendingPullForTesting()); - EXPECT_FALSE(source->HasPendingActivity()); source->Close(); track->stopTrack(v8_scope.GetExecutionContext());
diff --git a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.cc index 4a7291c..5c62b8f1 100644 --- a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.cc +++ b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.cc
@@ -16,9 +16,8 @@ TransferredFrameQueueUnderlyingSource( ScriptState* script_state, FrameQueueHost* host, - scoped_refptr<base::SequencedTaskRunner> host_runner, - wtf_size_t max_queue_size) - : FrameQueueUnderlyingSource<NativeFrameType>(script_state, max_queue_size), + scoped_refptr<base::SequencedTaskRunner> host_runner) + : FrameQueueUnderlyingSource<NativeFrameType>(script_state, host), host_runner_(host_runner), host_(host) {}
diff --git a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h index 26e785fd..5f8a3671 100644 --- a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h +++ b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h
@@ -20,8 +20,7 @@ TransferredFrameQueueUnderlyingSource( ScriptState*, FrameQueueHost*, - scoped_refptr<base::SequencedTaskRunner> host_runner, - wtf_size_t queue_size); + scoped_refptr<base::SequencedTaskRunner> host_runner); ~TransferredFrameQueueUnderlyingSource() override = default; TransferredFrameQueueUnderlyingSource( @@ -29,10 +28,6 @@ TransferredFrameQueueUnderlyingSource& operator=( const TransferredFrameQueueUnderlyingSource&) = delete; - // Clears all internal state and closes the UnderlyingSource's Controller. - // Must be called on |realm_task_runner_|. - void Close(); - // FrameQueueUnderlyingSource<NativeFrameType> implementation. bool StartFrameDelivery() override; void StopFrameDelivery() override;
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc index 1b59156..5cbd266 100644 --- a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc +++ b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
@@ -360,4 +360,14 @@ return profiler_group_; } +void V8PerIsolateData::SetCanvasResourceTracker( + V8PerIsolateData::GarbageCollectedData* canvas_resource_tracker) { + canvas_resource_tracker_ = canvas_resource_tracker; +} + +V8PerIsolateData::GarbageCollectedData* +V8PerIsolateData::CanvasResourceTracker() { + return canvas_resource_tracker_; +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h index c042302..521f0b6 100644 --- a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h +++ b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
@@ -193,6 +193,9 @@ void SetProfilerGroup(V8PerIsolateData::GarbageCollectedData*); V8PerIsolateData::GarbageCollectedData* ProfilerGroup(); + void SetCanvasResourceTracker(V8PerIsolateData::GarbageCollectedData*); + V8PerIsolateData::GarbageCollectedData* CanvasResourceTracker(); + ActiveScriptWrappableManager* GetActiveScriptWrappableManager() const { return active_script_wrappable_manager_; } @@ -264,6 +267,7 @@ Vector<base::OnceClosure> end_of_scope_tasks_; std::unique_ptr<Data> thread_debugger_; Persistent<GarbageCollectedData> profiler_group_; + Persistent<GarbageCollectedData> canvas_resource_tracker_; Persistent<ActiveScriptWrappableManager> active_script_wrappable_manager_;
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc index 1870532e..f2cf2e7 100644 --- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc +++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -476,6 +476,10 @@ SetRestrictAutomaticLazyImageLoadingToDataSaverEnabled(enable); } +void WebRuntimeFeatures::EnableSecurePaymentConfirmationAPIV2(bool enable) { + RuntimeEnabledFeatures::SetSecurePaymentConfirmationAPIV2Enabled(enable); +} + void WebRuntimeFeatures::EnableSecurePaymentConfirmationDebug(bool enable) { RuntimeEnabledFeatures::SetSecurePaymentConfirmationDebugEnabled(enable); } @@ -648,6 +652,10 @@ RuntimeEnabledFeatures::SetTransformInteropEnabled(enable); } +void WebRuntimeFeatures::EnableBackfaceVisibilityInterop(bool enable) { + RuntimeEnabledFeatures::SetBackfaceVisibilityInteropEnabled(enable); +} + void WebRuntimeFeatures::EnableVideoWakeLockOptimisationHiddenMuted( bool enable) { RuntimeEnabledFeatures::SetVideoWakeLockOptimisationHiddenMutedEnabled(
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc index 8216053..a5f0651 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
@@ -126,11 +126,6 @@ } ++num_cached_new_items_; - if (!RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) { - ProcessNewItem(new_paint_artifact_->GetDisplayItemList().AppendByMoving( - current_paint_artifact_->GetDisplayItemList()[cached_item])); - } - next_item_to_match_ = cached_item + 1; // Items before |next_item_to_match_| have been copied so we don't need to // index them. @@ -148,6 +143,9 @@ return false; } + ProcessNewItem(new_paint_artifact_->GetDisplayItemList().AppendByMoving( + current_paint_artifact_->GetDisplayItemList()[cached_item])); + return true; } @@ -168,6 +166,7 @@ // this one. The ancestor subsequence is supposed to have already "copied", // so we should let the client continue to actually paint the descendant // subsequences without "copying". + ++num_cached_new_subsequences_; return false; } @@ -564,6 +563,7 @@ markers.client, markers.start_chunk_index + new_start_chunk_index - start_chunk_index, markers.end_chunk_index + new_start_chunk_index - start_chunk_index}); + ++num_cached_new_subsequences_; } EndSubsequence(client, new_subsequence_index, new_start_chunk_index);
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc b/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc index 9f04bc5..014d63b 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc
@@ -1291,6 +1291,9 @@ DrawRect(context, content2b, kForegroundType, IntRect(100, 200, 50, 200)); } } + + EXPECT_EQ(0u, NumCachedNewItems()); + EXPECT_EQ(0u, NumCachedNewSubsequences()); CommitAndFinishCycle(); EXPECT_THAT(GetPaintController().GetDisplayItemList(), @@ -1324,6 +1327,8 @@ EXPECT_TRUE( SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container2)); + EXPECT_EQ(7u, NumCachedNewItems()); + EXPECT_EQ(6u, NumCachedNewSubsequences()); CommitAndFinishCycle(); EXPECT_THAT(GetPaintController().GetDisplayItemList(), @@ -1358,6 +1363,8 @@ EXPECT_TRUE( SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, container1)); + EXPECT_EQ(7u, NumCachedNewItems()); + EXPECT_EQ(6u, NumCachedNewSubsequences()); CommitAndFinishCycle(); EXPECT_THAT(GetPaintController().GetDisplayItemList(),
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 76c1f98..05c5e92 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -237,6 +237,11 @@ name: "AutoplayIgnoresWebAudio", settable_from_internals: true, }, + // When enabled, enforces new interoperable semantics for 3D transforms. + // See crbug.com/1008483. + { + name: "BackfaceVisibilityInterop", + }, { name: "BackForwardCache", }, @@ -1857,6 +1862,9 @@ status: "experimental", }, { + name: "SecurePaymentConfirmationAPIV2", + }, + { name: "SecurePaymentConfirmationDebug", }, {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h index 24b41b7..fa79d7d1 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/task/sequence_manager/task_queue.h" #include "base/time/time.h" #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc index f5751be..82757ec0 100644 --- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc +++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
@@ -539,8 +539,8 @@ // Disable occlusion if de-jelly effect is enabled. settings.enable_occlusion &= !settings.allow_de_jelly_effect; - settings.enable_transform_interop = - base::FeatureList::IsEnabled(features::kTransformInterop); + settings.enable_backface_visibility_interop = + base::FeatureList::IsEnabled(features::kBackfaceVisibilityInterop); return settings; }
diff --git a/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc b/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc index 86b891d..39faa22 100644 --- a/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc +++ b/third_party/blink/renderer/platform/widget/compositing/widget_compositor_unittest.cc
@@ -29,7 +29,8 @@ return WebInputEventResult::kNotHandled; } bool SupportsBufferedTouchEvents() override { return false; } - bool WillHandleGestureEvent(const WebGestureEvent&) override { return false; } + void WillHandleGestureEvent(const WebGestureEvent&, bool* suppress) override { + } void WillHandleMouseEvent(const WebMouseEvent&) override {} void ObserveGestureEventAndResult(const WebGestureEvent&, const gfx::Vector2dF&,
diff --git a/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc b/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc index c21b28c1..be9a8ad 100644 --- a/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc +++ b/third_party/blink/renderer/platform/widget/input/widget_base_input_handler.cc
@@ -415,8 +415,9 @@ if (WebInputEvent::IsGestureEventType(input_event.GetType())) { const WebGestureEvent& gesture_event = static_cast<const WebGestureEvent&>(input_event); - prevent_default = prevent_default || - widget_->client()->WillHandleGestureEvent(gesture_event); + bool suppress = false; + widget_->client()->WillHandleGestureEvent(gesture_event, &suppress); + prevent_default = prevent_default || suppress; } WebInputEventResult processed = prevent_default
diff --git a/third_party/blink/renderer/platform/widget/widget_base_client.h b/third_party/blink/renderer/platform/widget/widget_base_client.h index 32208ec..9ff3ce6 100644 --- a/third_party/blink/renderer/platform/widget/widget_base_client.h +++ b/third_party/blink/renderer/platform/widget/widget_base_client.h
@@ -127,7 +127,8 @@ virtual bool SupportsBufferedTouchEvents() = 0; virtual void DidHandleKeyEvent() {} - virtual bool WillHandleGestureEvent(const WebGestureEvent& event) = 0; + virtual void WillHandleGestureEvent(const WebGestureEvent& event, + bool* suppress) = 0; virtual void WillHandleMouseEvent(const WebMouseEvent& event) = 0; virtual void ObserveGestureEventAndResult( const WebGestureEvent& gesture_event,
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-percent-based-scrolling b/third_party/blink/web_tests/FlagExpectations/enable-percent-based-scrolling index 4a49b83..5ebf714 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-percent-based-scrolling +++ b/third_party/blink/web_tests/FlagExpectations/enable-percent-based-scrolling
@@ -23,9 +23,10 @@ crbug.com/1204176 fast/scrolling/wheel-scroll-latching-on-scrollbar.html [ Failure ] # fast/scrolling/events -crbug.com/1204176 fast/scrolling/events/overscroll-event-fired-to-document.html [ Failure ] -crbug.com/1204176 fast/scrolling/events/overscroll-event-fired-to-scrolled-element.html [ Failure ] -crbug.com/1204176 fast/scrolling/events/overscroll-event-fired-to-window.html [ Failure ] +crbug.com/1204176 fast/scrolling/events/overscroll-event-fired-to-document.html [ Timeout Failure ] +crbug.com/1204176 fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html [ Timeout Failure ] +crbug.com/1204176 fast/scrolling/events/overscroll-event-fired-to-scrolled-element.html [ Timeout Failure ] +crbug.com/1204176 fast/scrolling/events/overscroll-event-fired-to-window.html [ Timeout Failure ] # fast/scroll-snap/ crbug.com/1204176 fast/scroll-snap/snaps-after-touchpad-scrolling.html [ Failure ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests index 00b593a806..5d120df 100644 --- a/third_party/blink/web_tests/SlowTests +++ b/third_party/blink/web_tests/SlowTests
@@ -61,10 +61,6 @@ crbug.com/24182 html/marquee/marquee-destroyed-without-removed-from-crash.html [ Slow ] crbug.com/24182 fast/js/regress/string-cons-tower.html [ Slow ] crbug.com/24182 fast/events/tabindex-focus-blur-all.html [ Slow ] -crbug.com/24182 svg/hixie/perf/003.xml [ Slow ] -crbug.com/24182 svg/hixie/perf/004.xml [ Slow ] -crbug.com/24182 svg/hixie/perf/005.xml [ Slow ] -crbug.com/24182 svg/hixie/perf/006.xml [ Slow ] crbug.com/451577 [ Debug ] fast/dom/gc-treescope.html [ Slow ] crbug.com/451577 [ Debug ] fast/frames/calculate-round.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index cca90a6..e1862f6a 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1298,9 +1298,6 @@ crbug.com/995106 external/wpt/css/css-pseudo/first-letter-exclude-inline-child-marker.html [ Failure ] crbug.com/1172333 external/wpt/css/css-pseudo/first-letter-digraph.html [ Failure ] -crbug.com/929098 external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox.html [ Failure ] -crbug.com/929098 virtual/dark-color-scheme/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-change-checkbox.html [ Pass ] - crbug.com/1205953 external/wpt/css/css-will-change/will-change-fixpos-cb-position-1.html [ Failure ] crbug.com/1207788 external/wpt/css/css-will-change/will-change-stacking-context-mask-1.html [ Failure ] @@ -2523,6 +2520,25 @@ crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-206.xht [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 [ Win10 ] external/wpt/websockets/remove-own-iframe-during-onerror.window.html?wss [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/stream/tentative/constructor.any.serviceworker.html?wss [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/stream/tentative/constructor.any.worker.html?wss [ Timeout ] +crbug.com/626703 [ Win10 ] virtual/synchronous_html_parser/external/wpt/content-security-policy/reporting/report-only-in-meta.sub.html [ Timeout ] +crbug.com/626703 [ Win10 ] virtual/plz-dedicated-worker/external/wpt/service-workers/cache-storage/worker/cache-abort.https.html [ Timeout ] +crbug.com/626703 [ Win10 ] virtual/plz-dedicated-worker/external/wpt/service-workers/cache-storage/window/cache-abort.https.html [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/basic-auth.any.sharedworker.html?wss [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/stream/tentative/constructor.any.html?wss [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/service-workers/cache-storage/serviceworker/cache-abort.https.html [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/remove-own-iframe-during-onerror.window.html [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/stream/tentative/constructor.any.sharedworker.html?wss [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/basic-auth.any.worker.html?wss [ Timeout ] +crbug.com/626703 [ Win10 ] virtual/plz-service-worker/external/wpt/service-workers/cache-storage/window/cache-abort.https.html [ Timeout ] +crbug.com/626703 [ Win10 ] virtual/plz-service-worker/external/wpt/service-workers/cache-storage/worker/cache-abort.https.html [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/constructor/010.html [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/basic-auth.any.html?wss [ Timeout ] +crbug.com/626703 [ Win10 ] external/wpt/websockets/basic-auth.any.serviceworker.html?wss [ Timeout ] +crbug.com/626703 [ Win ] external/wpt/websockets/opening-handshake/005.html [ Failure ] +crbug.com/626703 [ Win ] external/wpt/websockets/opening-handshake/005.html?wss [ Failure ] crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCSctpTransport-maxChannels.html [ Timeout ] crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/RTCSctpTransport-maxChannels.html [ Timeout ] crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/getstats.html [ Timeout ] @@ -4066,7 +4082,6 @@ crbug.com/1179585 virtual/layout_ng_svg_text/svg/hittest/text-small-font-size-and-viewbox.html [ Failure ] crbug.com/1179585 virtual/layout_ng_svg_text/svg/hittest/text-with-multiple-tspans.svg [ Failure ] crbug.com/1179585 virtual/layout_ng_svg_text/svg/hittest/text-with-text-path.svg [ Failure ] -crbug.com/1179585 virtual/layout_ng_svg_text/svg/hixie/perf/004.xml [ Pass Timeout Failure ] crbug.com/1179585 virtual/layout_ng_svg_text/svg/masking/mask-of-root.html [ Failure ] crbug.com/1179585 virtual/layout_ng_svg_text/svg/stroke/non-scaling-stroke-text-decoration.html [ Failure ] crbug.com/1179585 virtual/layout_ng_svg_text/svg/stroke/non-scaling-stroke-text-decoration-dashed.html [ Failure ] @@ -5417,26 +5432,39 @@ crbug.com/1008483 external/wpt/css/css-transforms/transform3d-sorting-004.html [ Failure ] crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/3d-rendering-context-behavior.tentative.html [ Pass ] -crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/backface-visibility-hidden-004.tentative.html [ Pass ] -crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/backface-visibility-hidden-005.tentative.html [ Pass ] -crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/backface-visibility-hidden-animated-002.html [ Pass ] crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/preserve-3d-flat-grouping-properties-containing-block.tentative.html [ Pass ] crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/3d-rendering-context-and-abspos.html [ Pass ] crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/3d-rendering-context-and-fixpos.html [ Pass ] crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/transform3d-sorting-004.html [ Pass ] crbug.com/1008483 virtual/transform-interop/compositing/geometry/require-own-backing-recalc-order.html [ Failure ] -crbug.com/1008483 virtual/transform-interop/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor.html [ Failure ] -crbug.com/1008483 virtual/transform-interop/paint/invalidation/stacking-context-lost.html [ Failure ] -crbug.com/1008483 virtual/transform-interop/paint/invalidation/multicol/multicol-as-paint-container.html [ Failure ] crbug.com/1008483 virtual/transform-interop/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html [ Failure ] crbug.com/1008483 virtual/transform-interop/transforms/3d/point-mapping/3d-point-mapping-2.html [ Failure ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/3d-rendering-context-behavior.tentative.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/backface-visibility-hidden-004.tentative.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/backface-visibility-hidden-005.tentative.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/backface-visibility-hidden-animated-002.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/preserve-3d-flat-grouping-properties-containing-block.tentative.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/3d-rendering-context-and-abspos.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/3d-rendering-context-and-fixpos.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/transform3d-sorting-004.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/compositing/geometry/require-own-backing-recalc-order.html [ Failure ] +crbug.com/1008483 virtual/backface-visibility-interop/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor.html [ Failure ] +crbug.com/1008483 virtual/backface-visibility-interop/paint/invalidation/stacking-context-lost.html [ Failure ] +crbug.com/1008483 virtual/backface-visibility-interop/paint/invalidation/multicol/multicol-as-paint-container.html [ Failure ] +crbug.com/1008483 virtual/backface-visibility-interop/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html [ Failure ] +crbug.com/1008483 virtual/backface-visibility-interop/transforms/3d/point-mapping/3d-point-mapping-2.html [ Failure ] + crbug.com/943503 external/wpt/css/css-transforms/transform3d-perspective-003.html [ Failure ] crbug.com/943503 external/wpt/css/css-transforms/transform3d-perspective-004.html [ Failure ] crbug.com/943503 virtual/transform-interop/external/wpt/css/css-transforms/transform3d-perspective-003.html [ Pass ] crbug.com/943503 virtual/transform-interop/external/wpt/css/css-transforms/transform3d-perspective-004.html [ Pass ] +crbug.com/943503 virtual/backface-visibility-interop/external/wpt/css/css-transforms/transform3d-perspective-003.html [ Pass ] +crbug.com/943503 virtual/backface-visibility-interop/external/wpt/css/css-transforms/transform3d-perspective-004.html [ Pass ] +crbug.com/943503 virtual/backface-visibility-interop/external/wpt/css/css-transforms/transform3d-perspective-005.html [ Pass ] + # Swiftshader issue. crbug.com/1048149 external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerwidth.html [ Crash Timeout ] crbug.com/1048149 external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screeny.html [ Crash Timeout ] @@ -5579,23 +5607,14 @@ # fast/scrolling/events crbug.com/1204176 virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-document.html [ Failure Timeout ] +crbug.com/1204176 virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html [ Failure Timeout ] crbug.com/1204176 virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-scrolled-element.html [ Failure Timeout ] crbug.com/1204176 virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-window.html [ Failure Timeout ] crbug.com/1204176 virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-document.html [ Failure Timeout ] +crbug.com/1204176 virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html [ Failure Timeout ] crbug.com/1204176 virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-scrolled-element.html [ Failure Timeout ] crbug.com/1204176 virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-window.html [ Failure Timeout ] -crbug.com/1209724 [ Win ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/scrollend-event-fired-to-document.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/scrollend-event-fired-to-element-with-overscroll-behavior.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/scrollend-event-fired-to-scrolled-element.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/events/scrollend-event-fired-to-window.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/scrollend-event-fired-to-document.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/scrollend-event-fired-to-element-with-overscroll-behavior.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/scrollend-event-fired-to-scrolled-element.html [ Timeout ] -crbug.com/1209724 [ Win ] virtual/main-threaded-percent-based-scrolling/fast/scrolling/events/scrollend-event-fired-to-window.html [ Timeout ] - ### END PERCENT BASED SCROLLING TEST FAILURES # Sheriff 2020-02-28 @@ -5972,10 +5991,10 @@ # Rename document.featurePolicy to document.permissionsPolicy crbug.com/1123116 external/wpt/permissions-policy/payment-supported-by-permissions-policy.tentative.html [ Failure ] crbug.com/1123116 external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-all.https.sub.html [ Failure ] -crbug.com/1123116 external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-self.https.sub.html [ Failure ] +crbug.com/1123116 external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-self.https.sub.html [ Failure Timeout ] crbug.com/1123116 external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some-override.https.sub.html [ Failure ] -crbug.com/1123116 external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some.https.sub.html [ Failure ] -crbug.com/1123116 external/wpt/permissions-policy/permissions-policy-frame-policy-disallowed-for-all.https.sub.html [ Failure ] +crbug.com/1123116 external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some.https.sub.html [ Failure Timeout ] +crbug.com/1123116 external/wpt/permissions-policy/permissions-policy-frame-policy-disallowed-for-all.https.sub.html [ Failure Timeout ] # Rename "feature-policy-violation" report type to "permissions-policy-violation" report type. crbug.com/1123116 external/wpt/feature-policy/reporting/camera-reporting.https.html [ Timeout ] @@ -6161,9 +6180,6 @@ crbug.com/1168785 [ Mac ] virtual/threaded-prefer-compositing/fast/scrolling/autoscroll-latch-clicked-node-if-parent-unscrollable.html [ Timeout ] crbug.com/1168785 virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/autoscroll-latch-clicked-node-if-parent-unscrollable.html [ Pass Timeout ] -# Sheriff 2021-01-29 -crbug.com/1172437 svg/hixie/perf/004.xml [ Timeout Pass ] - # flaky test crbug.com/1173956 http/tests/xsl/xslt-transform-with-javascript-disabled.html [ Failure Pass ] @@ -6717,6 +6733,8 @@ crbug.com/1008483 external/wpt/css/css-transforms/transform-table-007.html [ Failure ] crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/transform-table-006.html [ Pass ] crbug.com/1008483 virtual/transform-interop/external/wpt/css/css-transforms/transform-table-007.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/transform-table-006.html [ Pass ] +crbug.com/1008483 virtual/backface-visibility-interop/external/wpt/css/css-transforms/transform-table-007.html [ Pass ] external/wpt/css/css-transforms/transform-table-008.html [ Failure ] external/wpt/css/css-transforms/transform-translatex-006.html [ Failure ] external/wpt/css/css-transforms/transforms-rotate-degree-45.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index eb54cf9..a4cb878 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -863,6 +863,15 @@ "args": [ "--enable-features=TransformInterop" ] }, { + "prefix": "backface-visibility-interop", + "bases": [ "external/wpt/css/css-transforms", + "transforms/", + "compositing/geometry/", + "compositing/overflow/", + "paint/invalidation/" ], + "args": [ "--enable-features=TransformInterop,BackfaceVisibilityInterop" ] + }, + { "prefix": "portals", "bases": [ "external/wpt/fetch/metadata/portal.https.sub.html", "external/wpt/portals",
diff --git a/third_party/blink/web_tests/external/wpt/accessibility/crashtests/table-ignored-child.html b/third_party/blink/web_tests/external/wpt/accessibility/crashtests/table-ignored-child.html new file mode 100644 index 0000000..99f385f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/accessibility/crashtests/table-ignored-child.html
@@ -0,0 +1,18 @@ +<html> +<head> +<script> +window.onload = function() { + document.querySelector('object').appendChild(document.querySelector('#move-me')); +}; +</script> +</head> +<body dir="rtl"> +<object></object> +<table> + <caption style="display:none"> + <span> + <div id="move-me"></div> + </span> + </caption> +</table> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/collapsed-border-paint-phase-001.html b/third_party/blink/web_tests/external/wpt/css/css-tables/collapsed-border-paint-phase-001.html new file mode 100644 index 0000000..9c45eb71 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/collapsed-border-paint-phase-001.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/CSS2/zindex.html"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" content="A tables collapsed borders paint in the background paint phase."> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<table style="border-collapse: collapse; border-spacing: 0;"> + <td style="border-right: 50px solid red; padding: 0;"> + <div style="width: 50px; line-height: 0;"> + <!-- Paints in the foreground phase above the collapsed borders. --> + <div style="display: inline-block; width: 100px; height: 100px; background: green;"></div> + </div> + </td> +</table>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/collapsed-border-paint-phase-002.html b/third_party/blink/web_tests/external/wpt/css/css-tables/collapsed-border-paint-phase-002.html new file mode 100644 index 0000000..865069da --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/collapsed-border-paint-phase-002.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/CSS2/zindex.html"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" content="A tables collapsed borders paint in the background paint phase, after children."> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<!DOCTYPE html> +<table style="border-collapse: collapse; border-spacing: 0;"> + <td style="border-right: solid 100px green; height: 100px; padding: 0;"> + <div style="width: 0;"> + <div style="width: 100px; height: 100px; background: red;"></div> + </div> + </td> +</table>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/node-appendchild-crash.html b/third_party/blink/web_tests/external/wpt/dom/nodes/node-appendchild-crash.html new file mode 100644 index 0000000..245de87 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/nodes/node-appendchild-crash.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" href="mailto:masonf@chromium.org"> +<link rel="help" href="https://crbug.com/1210480"> +<meta name="assert" content="The renderer should not crash."> + +<iframe id=iframe></iframe> +<select>Text Node + <option id=option></option> +</select> + +<script> + window.onload=function() { + iframe.addEventListener('DOMNodeInsertedIntoDocument',function() {}); + option.remove(); + iframe.contentDocument.body.appendChild(document.body); + } +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html index 1f9c084..67c97ba 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html
@@ -14,6 +14,7 @@ function frameLoaded() { var testframe = document.getElementById('testframe'); assert_equals(testframe.contentDocument.contentType, "image/png"); + assert_equals(testframe.contentDocument.compatMode, "CSS1Compat", "Media documents should be in standards mode"); var testframeChildren = testframe.contentDocument.body.childNodes; assert_equals(testframeChildren.length, 1, "Body of image document has 1 child"); assert_equals(testframeChildren[0].nodeName, "IMG", "Only child of body must be an <img> element");
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html index 1ae414ce..9bce1f0 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html
@@ -15,6 +15,7 @@ var contentType = getMediaContentType(url); testframe.onload = this.step_func_done(function() { assert_equals(testframe.contentDocument.contentType, contentType); + assert_equals(testframe.contentDocument.compatMode, "CSS1Compat", "Media documents should be in standards mode"); var testframeChildren = testframe.contentDocument.body.childNodes; assert_equals(testframeChildren.length, 1, "Body of image document has 1 child"); assert_equals(testframeChildren[0].nodeName, "VIDEO", "Only child of body must be an <video> element");
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-text/load-text-plain-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-text/load-text-plain-expected.txt deleted file mode 100644 index aecbfdd..0000000 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-text/load-text-plain-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -This is a testharness.js-based test. -FAIL Checking document metadata for text file assert_equals: expected "BackCompat" but got "CSS1Compat" -PASS Checking DOM for text file -PASS Checking contents for text file -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-text/load-text-plain.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-text/load-text-plain.html index bd4fd78..ad75631 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-text/load-text-plain.html +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/read-text/load-text-plain.html
@@ -13,7 +13,7 @@ iframe.onload = function(e) { var doc = iframe.contentDocument; t.step(function() { - assert_equals(doc.compatMode, "BackCompat"); + assert_equals(doc.compatMode, "CSS1Compat"); assert_equals(doc.contentType, "text/plain"); assert_equals(doc.doctype, null); t.done();
diff --git a/third_party/blink/web_tests/external/wpt/svg/crashtests/chrome-bug-1207590.html b/third_party/blink/web_tests/external/wpt/svg/crashtests/chrome-bug-1207590.html new file mode 100644 index 0000000..3cbf61f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/crashtests/chrome-bug-1207590.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<style> +body, svg { + position: absolute; +} +</style> +<svg width="-1"></svg> +<svg width="-5"></svg> +<svg height="-1"></svg> +<svg height="-5"></svg>
diff --git a/third_party/blink/web_tests/fast/events/wheel/wheelevent-ctrl.html b/third_party/blink/web_tests/fast/events/wheel/wheelevent-ctrl.html index c621a5a..a0c777d 100644 --- a/third_party/blink/web_tests/fast/events/wheel/wheelevent-ctrl.html +++ b/third_party/blink/web_tests/fast/events/wheel/wheelevent-ctrl.html
@@ -18,84 +18,102 @@ <script> var scrollAmount = 1; var last_event = null; +// TODO(crbug.com/1204176): expectedDeltaY will not match expectations if +// percent-based scrolling is enabled. var expectedDeltaY = scrollAmount * pixelsPerTick(); -var testDiv; - -function wheelHandler(e) { - assert_equals(last_event, null); - last_event = e; -} +var testDiv = document.getElementById('target'); +var scroller_target = elementCenter(testDiv); // Reset the page state and last wheel event. function reset() { - last_event = null; - window.scrollTo(0,0); + last_event = null; + testDiv.scrollTop = 0; + window.scrollTo(0, 0); } -testDiv = document.getElementById('target'); +function wheelHandler(e) { + assert_equals(last_event, null); + last_event = e; +} + document.addEventListener('wheel', wheelHandler); -var scroller_target = elementCenter(testDiv); promise_test(async () => { - reset(); - await wheelTick(0, scrollAmount, scroller_target, SPEED_INSTANT, Modifiers.CONTROL); - await conditionHolds( () => { - return testDiv.scrollTop == 0; - }); - assert_equals(last_event.deltaY, expectedDeltaY); - assert_true(last_event.ctrlKey); + reset(); + await waitForCompositorCommit(); + const wheelPromise = waitForEvent(document, 'wheel'); + await wheelTick(0, scrollAmount, scroller_target, SPEED_INSTANT, + Modifiers.CONTROL); + await wheelPromise; + await conditionHolds(() => { + return testDiv.scrollTop == 0; + }); + assert_equals(last_event.deltaY, expectedDeltaY); + assert_true(last_event.ctrlKey); }, "Div: Ctrl+wheel doesn't scroll."); promise_test(async () => { - reset(); - await wheelTick(0, scrollAmount, scroller_target, SPEED_INSTANT); - await waitFor( () => { - return testDiv.scrollTop == last_event.deltaY; - }); - assert_equals(last_event.deltaY, expectedDeltaY); - assert_false(last_event.ctrlKey); + reset(); + await waitForCompositorCommit(); + const wheelPromise = waitForEvent(document, 'wheel'); + await wheelTick(0, scrollAmount, scroller_target, SPEED_INSTANT); + await wheelPromise; + await waitForAnimationEndTimeBased(() => { return testDiv.scrollTop; }); + assert_equals(testDiv.scrollTop, expectedDeltaY); + assert_equals(last_event.deltaY, expectedDeltaY); + assert_false(last_event.ctrlKey); }, "Div: No-Ctrl wheel scrolls."); // Test mousewheel events over the document var document_element = document.getElementById('target2'); var document_target = elementCenter(document_element); promise_test(async () => { - reset(); - await wheelTick(0, scrollAmount, document_target, SPEED_INSTANT, Modifiers.CONTROL); - await conditionHolds( () => { - return document_element.scrollTop == 0; - }); - assert_equals(last_event.deltaY, expectedDeltaY); - assert_true(last_event.ctrlKey); - assert_equals(window.scrollY, 0); + reset(); + await waitForCompositorCommit(); + const wheelPromise = waitForEvent(document, 'wheel'); + await wheelTick(0, scrollAmount, document_target, SPEED_INSTANT, + Modifiers.CONTROL); + await wheelPromise; + await conditionHolds(() => { + return document_element.scrollTop == 0; + }); + assert_equals(last_event.deltaY, expectedDeltaY); + assert_true(last_event.ctrlKey); + assert_equals(window.scrollY, 0); }, "Doc: Ctrl+wheel doesn't scroll."); // The smoothScrollWithXY here indicates that we set |precise_scrolling_deltas| to // true to simulate a high precision touch pad which should scroll even if // control is down, rather than zooming. promise_test(async () => { - reset(); - var source = GestureSourceType.MOUSE_INPUT; - await smoothScrollWithXY(0, scrollAmount* pixelsPerTick(), document_target.x, - document_target.y, source, SPEED_INSTANT, - true /* precise_scrolling_deltas */, - false /* scroll_by_page */, true /* cursor_visible */, - false /* scroll_by_percentage */, Modifiers.CONTROL); - await waitFor( () => { - return window.scrollY == last_event.deltaY; - }); - assert_equals(last_event.deltaY, expectedDeltaY); - assert_true(last_event.ctrlKey); + reset(); + await waitForCompositorCommit(); + const wheelPromise = waitForEvent(document, 'wheel'); + var source = GestureSourceType.MOUSE_INPUT; + await smoothScrollWithXY(0, scrollAmount* pixelsPerTick(), document_target.x, + document_target.y, source, SPEED_INSTANT, + true /* precise_scrolling_deltas */, + false /* scroll_by_page */, + true /* cursor_visible */, + false /* scroll_by_percentage */, + Modifiers.CONTROL); + await wheelPromise; + await waitForAnimationEndTimeBased(() => { return window.scrollY; }); + assert_equals(window.scrollY, expectedDeltaY); + assert_equals(last_event.deltaY, expectedDeltaY); + assert_true(last_event.ctrlKey); }, "Doc: Ctrl+high precision touchpad scroll scrolls."); promise_test(async () => { - reset(); - await wheelTick(0, scrollAmount, document_target, SPEED_INSTANT); - await waitFor( () => { - return window.scrollY == expectedDeltaY; - }); - assert_equals(last_event.deltaY, expectedDeltaY); - assert_false(last_event.ctrlKey); + reset(); + await waitForCompositorCommit(); + const wheelPromise = waitForEvent(document, 'wheel'); + await wheelTick(0, scrollAmount, document_target, SPEED_INSTANT); + await wheelPromise; + await waitForAnimationEndTimeBased(() => { return window.scrollY; }); + assert_equals(window.scrollY, expectedDeltaY); + assert_equals(last_event.deltaY, expectedDeltaY); + assert_false(last_event.ctrlKey); }, "Doc: No-Ctrl wheel scrolls."); </script>
diff --git a/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-document.html b/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-document.html index 174fa2d7..75af1fa 100644 --- a/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-document.html +++ b/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-document.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../../resources/gesture-util.js"></script> -<script src="resources/scroll-util.js"></script> <script src="../../../virtual/percent-based-scrolling/resources/percent-based-util.js"></script> <style> #targetDiv { @@ -33,7 +32,15 @@ var x = rect.left + rect.width / 2; var y = rect.top + rect.height / 2; -const pixelsToScroll = 800; +// SPEED_INSTANT doesn't work here because tests are timing out. +// This could actually be a bug in how the overscroll event is computed. +// Possible explanation on what happens is that "leftover" delta from a single +// event doesn't cause an overscroll event, only when the next event arrives +// and the full delta is overscroll do we dispatch the event. +// When the speed is INSTANT we'll put the entire scrolling delta into a single +// event so we don't generate an overscroll event in that case. +const pixelsPerSec = 2000; +const pixelsToScroll = 600; const { x: pixelsToScrollX, y: pixelsToScrollY } = calculatePixelsToScroll( target_div, pixelsToScroll, pixelsToScroll ); @@ -56,13 +63,19 @@ overscrolled_y_delta = 0; // Scroll up on target div and wait for the doc to get overscroll event. - await scrollUp(pixelsToScrollY, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollY, x, y, source_device, "up", pixelsPerSec, + precise_scrolling_delta + ); await waitFor(() => { return overscrolled_y_delta < 0; }, 'Document did not receive overscroll event after scroll up on target.'); assert_equals(target_div.scrollTop, 0); // Scroll left on target div and wait for the doc to get overscroll event. - await scrollLeft(pixelsToScrollX, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollX, x, y, source_device, "left", pixelsPerSec, + precise_scrolling_delta + ); await waitFor(() => { return overscrolled_x_delta < 0; }, 'Document did not receive overscroll event after scroll left on target.'); assert_equals(target_div.scrollLeft, 0);
diff --git a/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html b/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html index a4f650c3..6094796 100644 --- a/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html +++ b/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../../resources/gesture-util.js"></script> -<script src="resources/scroll-util.js"></script> <script src="../../../virtual/percent-based-scrolling/resources/percent-based-util.js"></script> <style> #overscrollXDiv { @@ -52,7 +51,15 @@ var x = rect.left + rect.width / 2; var y = rect.top + rect.height / 2; -const pixelsToScroll = 800; +// SPEED_INSTANT doesn't work here because tests are timing out. +// This could actually be a bug in how the overscroll event is computed. +// Possible explanation on what happens is that "leftover" delta from a single +// event doesn't cause an overscroll event, only when the next event arrives +// and the full delta is overscroll do we dispatch the event. +// When the speed is INSTANT we'll put the entire scrolling delta into a single +// event so we don't generate an overscroll event in that case. +const pixelsPerSec = 2000; +const pixelsToScroll = 600; const { x: pixelsToScrollX, y: pixelsToScrollY } = calculatePixelsToScroll( target_div, pixelsToScroll, pixelsToScroll ); @@ -75,14 +82,17 @@ addEventListener("overscroll", onOverscrollY); async function test_overscroll_event_fire(source_device, - precise_scrolling_delta ) { + precise_scrolling_delta) { overscrolled_x_delta = 0; overscrolled_y_delta = 0; await waitForCompositorCommit(); // Scroll up on target div and wait for the element with overscroll-y to get // overscroll event. - await scrollUp(pixelsToScrollY, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollY, x, y, source_device, "up", pixelsPerSec, + precise_scrolling_delta + ); await waitFor(() => { return overscrolled_y_delta < 0; }, 'Expected element did not receive overscroll event after scroll up on ' + 'target.'); @@ -90,7 +100,10 @@ // Scroll left on target div and wait for the element with overscroll-x to // get overscroll event. - await scrollLeft(pixelsToScrollX, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollX, x, y, source_device, "left", pixelsPerSec, + precise_scrolling_delta + ); await waitFor(() => { return overscrolled_x_delta < 0; }, 'Expected element did not receive overscroll event after scroll left ' + 'on target.');
diff --git a/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-scrolled-element.html b/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-scrolled-element.html index 63718c8a..9e163e3 100644 --- a/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-scrolled-element.html +++ b/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-scrolled-element.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../../resources/gesture-util.js"></script> -<script src="resources/scroll-util.js"></script> <script src="../../../virtual/percent-based-scrolling/resources/percent-based-util.js"></script> <style> #scrollableDiv { @@ -33,7 +32,15 @@ var x = rect.left + rect.width / 2; var y = rect.top + rect.height / 2; -const pixelsToScroll = 2400; +// SPEED_INSTANT doesn't work here because tests are timing out. +// This could actually be a bug in how the overscroll event is computed. +// Possible explanation on what happens is that "leftover" delta from a single +// event doesn't cause an overscroll event, only when the next event arrives +// and the full delta is overscroll do we dispatch the event. +// When the speed is INSTANT we'll put the entire scrolling delta into a single +// event so we don't generate an overscroll event in that case. +const pixelsPerSec = 2000; +const pixelsToScroll = 800; const { x: pixelsToScrollX, y: pixelsToScrollY } = calculatePixelsToScroll( scrolling_div, pixelsToScroll, pixelsToScroll ); @@ -56,7 +63,10 @@ await waitForCompositorCommit(); // Do a horizontal scroll and wait for overscroll event. - await scrollRight(pixelsToScrollX, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollX, x, y, source_device, "right", pixelsPerSec, + precise_scrolling_delta + ); await waitFor(() => { return overscrolled_x_delta > 0; }, 'Scroller did not receive overscroll event after horizontal scroll.'); await waitForAnimationEndTimeBased(() => { return scrolling_div.scrollLeft }); @@ -67,7 +77,10 @@ overscrolled_y_delta = 0; // Do a vertical scroll and wait for overscroll event. - await scrollDown(pixelsToScrollY, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollY, x, y, source_device, "down", pixelsPerSec, + precise_scrolling_delta + ); await waitFor(() => { return overscrolled_y_delta > 0; }, 'Scroller did not receive overscroll event after vertical scroll.'); await waitForAnimationEndTimeBased(() => { return scrolling_div.scrollTop });
diff --git a/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-window.html b/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-window.html index 952684ea..a152734 100644 --- a/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-window.html +++ b/third_party/blink/web_tests/fast/scrolling/events/overscroll-event-fired-to-window.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../../resources/gesture-util.js"></script> -<script src="resources/scroll-util.js"></script> <script src="../../../virtual/percent-based-scrolling/resources/percent-based-util.js"></script> <style> #targetDiv { @@ -33,7 +32,15 @@ var x = rect.left + rect.width / 2; var y = rect.top + rect.height / 2; -const pixelsToScroll = 800; +// SPEED_INSTANT doesn't work here because tests are timing out. +// This could actually be a bug in how the overscroll event is computed. +// Possible explanation on what happens is that "leftover" delta from a single +// event doesn't cause an overscroll event, only when the next event arrives +// and the full delta is overscroll do we dispatch the event. +// When the speed is INSTANT we'll put the entire scrolling delta into a single +// event so we don't generate an overscroll event in that case. +const pixelsPerSec = 2000; +const pixelsToScroll = 600; const { y: pixelsToScrollY } = calculatePixelsToScroll( target_div, pixelsToScroll, pixelsToScroll ); @@ -49,12 +56,15 @@ window.addEventListener("overscroll", onOverscroll); async function test_overscroll_event_fire(source_device, - precise_scroll_deltas) { + precise_scrolling_delta) { window_received_overscroll = false; await waitForCompositorCommit(); // Scroll up on target div and wait for the window to get overscroll event. - await scrollUp(pixelsToScrollY, source_device, precise_scroll_deltas); + await smoothScroll( + pixelsToScrollY, x, y, source_device, "up", pixelsPerSec, + precise_scrolling_delta + ); await waitFor(() => { return window_received_overscroll; }, 'Window did not receive overscroll event after scroll up on target.'); }
diff --git a/third_party/blink/web_tests/fast/scrolling/events/resources/scroll-util.js b/third_party/blink/web_tests/fast/scrolling/events/resources/scroll-util.js deleted file mode 100644 index 6c89100..0000000 --- a/third_party/blink/web_tests/fast/scrolling/events/resources/scroll-util.js +++ /dev/null
@@ -1,42 +0,0 @@ -// The functions in this file require gesture-util.js - -function scroll( - pixelsToScroll, direction, source_device, precise_scrolling_delta -) { - return smoothScroll(pixelsToScroll, x, y, source_device, direction, - 6000 /*pixels per sec*/, precise_scrolling_delta); -} - -function scrollLeft(pixelsToScroll, source_device, precise_scrolling_delta) { - if (source_device == GestureSourceType.MOUSE_INPUT) - return scroll( - pixelsToScroll, "left", source_device, precise_scrolling_delta - ); - return scroll(pixelsToScroll, "left", source_device); -} - -function scrollUp(pixelsToScroll, source_device, precise_scrolling_delta) { - if (source_device == GestureSourceType.MOUSE_INPUT) - return scroll(pixelsToScroll, "up", source_device, precise_scrolling_delta); - return scroll(pixelsToScroll, "up", source_device); -} -function scrollUp(pixelsToScroll, source_device, precise_scrolling_delta) { - if (source_device == GestureSourceType.MOUSE_INPUT) - return scroll(pixelsToScroll, "up", source_device, precise_scrolling_delta); - return scroll(pixelsToScroll, "up", source_device); -} -function scrollRight(pixelsToScroll, source_device, precise_scrolling_delta) { - if (source_device == GestureSourceType.MOUSE_INPUT) - return scroll( - pixelsToScroll, "right", source_device, precise_scrolling_delta - ); - return scroll(pixelsToScroll, "right", source_device); -} - -function scrollDown(pixelsToScroll, source_device, precise_scrolling_delta) { - if (source_device == GestureSourceType.MOUSE_INPUT) - return scroll( - pixelsToScroll, "down", source_device, precise_scrolling_delta - ); - return scroll(pixelsToScroll, "down", source_device); -}
diff --git a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-document.html b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-document.html index 86f37f95..4afc370 100644 --- a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-document.html +++ b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-document.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../../resources/gesture-util.js"></script> -<script src="resources/scroll-util.js"></script> <script src="../../../virtual/percent-based-scrolling/resources/percent-based-util.js"></script> <style> #targetDiv { @@ -49,7 +48,10 @@ // Scroll left on target div and wait for the doc to get scrollend event. let scrollendPromise = waitForScrollendEvent(document); - await scrollLeft(pixelsToScrollX, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollX, x, y, source_device, "left", SPEED_INSTANT, + precise_scrolling_delta + ); await scrollendPromise.then((event) => { assert_false(event.cancelable); // scrollend events are bubbled when the target node is document. @@ -59,7 +61,10 @@ // Scroll up on target div and wait for the doc to get scrollend event. scrollendPromise = waitForScrollendEvent(document); - await scrollUp(pixelsToScrollY, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollY, x, y, source_device, "up", SPEED_INSTANT, + precise_scrolling_delta + ); await scrollendPromise.then((event) => { assert_false(event.cancelable); // scrollend events are bubbled when the target node is document.
diff --git a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-element-with-overscroll-behavior.html b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-element-with-overscroll-behavior.html index 62c1a5b..4779427d 100644 --- a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-element-with-overscroll-behavior.html +++ b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-element-with-overscroll-behavior.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../../resources/gesture-util.js"></script> -<script src="resources/scroll-util.js"></script> <script src="../../../virtual/percent-based-scrolling/resources/percent-based-util.js"></script> <style> #overscrollXDiv { @@ -82,7 +81,10 @@ // Scroll left on target div and wait for the element with overscroll-x to // get scrollend event. - await scrollLeft(pixelsToScrollX, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollX, x, y, source_device, "left", SPEED_INSTANT, + precise_scrolling_delta + ); await waitFor(() => { return horizontal_scrollend_arrived; }, 'Expected element did not receive scrollend event after scroll left ' + 'on target.'); @@ -90,7 +92,10 @@ // Scroll up on target div and wait for the element with overscroll-y to get // scrollend event. - await scrollUp(pixelsToScrollY, source_device, precise_scrolling_delta); + await smoothScroll( + pixelsToScrollY, x, y, source_device, "up", SPEED_INSTANT, + precise_scrolling_delta + ); await waitFor(() => { return vertical_scrollend_arrived; }, 'Expected element did not receive scrollend event after scroll up on ' + 'target.');
diff --git a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-scrolled-element.html b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-scrolled-element.html index ffb8963e8c..699db8d 100644 --- a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-scrolled-element.html +++ b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-scrolled-element.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../../resources/gesture-util.js"></script> -<script src="resources/scroll-util.js"></script> <script src="../../../virtual/percent-based-scrolling/resources/percent-based-util.js"></script> <style> #scrollableDiv { @@ -54,14 +53,17 @@ scrolling_div.addEventListener("scrollend", onVerticalScrollEnd); async function test_scrollend_event_fire(source_device, - precise_scroll_deltas) { + precise_scrolling_delta) { horizontal_scrollend_arrived = false; vertical_scrollend_arrived = false; scrolling_div.scrollTo(0, 0); await waitForCompositorCommit(); // Do a horizontal scroll and wait for scrollend event. - await scrollRight(pixelsToScrollX, source_device, precise_scroll_deltas); + await smoothScroll( + pixelsToScrollX, x, y, source_device, "right", SPEED_INSTANT, + precise_scrolling_delta + ); await waitFor(() => { return horizontal_scrollend_arrived; }, 'Scroller did not receive scrollend event after horizontal scroll.'); await waitForAnimationEndTimeBased(() => { return scrolling_div.scrollLeft }); @@ -69,7 +71,10 @@ scrolling_div.clientWidth); // Do a vertical scroll and wait for scrollend event. - await scrollDown(pixelsToScrollY, source_device, precise_scroll_deltas); + await smoothScroll( + pixelsToScrollY, x, y, source_device, "down", SPEED_INSTANT, + precise_scrolling_delta + ); await waitFor(() => { return vertical_scrollend_arrived; }, 'Scroller did not receive scrollend event after vertical scroll.'); await waitForAnimationEndTimeBased(() => { return scrolling_div.scrollTop });
diff --git a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-window.html b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-window.html index e5e28af0..2a803ac 100644 --- a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-window.html +++ b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-to-window.html
@@ -2,7 +2,6 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../../resources/gesture-util.js"></script> -<script src="resources/scroll-util.js"></script> <script src="../../../virtual/percent-based-scrolling/resources/percent-based-util.js"></script> <style> #targetDiv { @@ -39,7 +38,7 @@ ); async function test_scrollend_event_fire(t, source_device, - precise_scroll_deltas) { + precise_scrolling_delta) { scrollend_arrived = false; await waitForCompositorCommit(); @@ -50,7 +49,10 @@ // Scroll up on target div and wait for the window to get the scrollend event. const scrollendPromise = waitForScrollendEvent(window); - await scrollUp(pixelsToScrollY, source_device, precise_scroll_deltas); + await smoothScroll( + pixelsToScrollY, x, y, source_device, "up", SPEED_INSTANT, + precise_scrolling_delta + ); await scrollendPromise.then((event) => { assert_false(event.cancelable); // scrollend events targeting the document are bubbled to the window.
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/elements-panel-styles-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/elements-panel-styles-expected.txt index b693760..2a1c7af3 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/elements-panel-styles-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/elements/elements-panel-styles-expected.txt
@@ -33,6 +33,7 @@ margin-bottom: 2px; 2px - .foo elements-panel-styles.css:21 -> elements-panel-styles.css:21:7 margin-left: 0px; + 0px - .foo elements-panel-styles.css:21 -> elements-panel-styles.css:21:7 margin-right: 0px; 0px - .foo elements-panel-styles.css:21 -> elements-panel-styles.css:21:7 margin-top: 10px; @@ -84,6 +85,7 @@ margin-top: 10px; margin-right: 0px; margin-bottom: 2px; + margin-left: 0px; border-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px;
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp-expected.txt index 88b2abe..e3061ed 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp-expected.txt
@@ -11,6 +11,7 @@ Running: testAddProperty === Added rule modified === width: 100%; +width: 100%; === Selector changed === body { width: 100%; @@ -20,4 +21,5 @@ Running: testModifyInlineStyle === Inline style modified === font-size: 14px; +font-size: 14px;
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp.js b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp.js index 8a4449d..b0c9270 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp.js +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp.js
@@ -109,6 +109,6 @@ return; var allProperties = style.allProperties(); for (var i = 0; i < allProperties.length; ++i) - TestRunner.addResult(allProperties[i].text); + TestRunner.addResult(allProperties[i].propertyText); } })();
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/get-set-stylesheet-text-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/get-set-stylesheet-text-expected.txt index 6be198bf..ebc19a4 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/get-set-stylesheet-text-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/get-set-stylesheet-text-expected.txt
@@ -39,4 +39,5 @@ rule h1: [regular] ['COLOR':'Red'] @[0:5-0:16] +['color':'red'] @[undefined-undefined]
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-with-shorthands-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-with-shorthands-expected.txt new file mode 100644 index 0000000..e0a6d5f --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-with-shorthands-expected.txt
@@ -0,0 +1,128 @@ +Tests that properties overridden by a shorthand are displayed as inactive in the sidebar. + +display: block; + block - div user agent stylesheet +margin-bottom: 0px; + 0px - #inspected1 <style> +margin-left: 0px; + 0px - #inspected1 <style> +margin-right: 0px; + 0px - #inspected1 <style> +margin-top: 0px; + 0px - #inspected1 <style> +[expanded] +element.style { () + +[expanded] +#inspected1 { (<style>) +/-- overloaded --/ margin-top: 100px; + margin: 0; + margin-top: 0px; + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + +[expanded] +div { (user agent stylesheet) + display: block; + +display: block; + block - div user agent stylesheet +padding-bottom: 0px; + 0px - #inspected2 <style> +padding-left: 0px; + 0px - #inspected2 <style> +padding-right: 0px; + 0px - #inspected2 <style> +padding-top: 0px; + 0px - #inspected2 <style> +[expanded] +element.style { () + +[expanded] +#inspected2 { (<style>) +/-- overloaded --/ padding: 100px; + padding-top: 0px; + padding-right: 0px; + padding-bottom: 0px; + padding-left: 0px; + padding: 0; + padding-top: 0px; + padding-right: 0px; + padding-bottom: 0px; + padding-left: 0px; + +[expanded] +div { (user agent stylesheet) + display: block; + +border-bottom-color: rgb(0, 0, 0); + initial - #inspected3 <style> +border-bottom-style: solid; + solid - #inspected3 <style> +border-bottom-width: 0px; + 0px - #inspected3 <style> +border-image-outset: 0; + initial - #inspected3 <style> +border-image-repeat: stretch; + initial - #inspected3 <style> +border-image-slice: 100%; + initial - #inspected3 <style> +border-image-source: none; + initial - #inspected3 <style> +border-image-width: 1; + initial - #inspected3 <style> +border-left-color: rgb(0, 0, 0); + initial - #inspected3 <style> +border-left-style: solid; + solid - #inspected3 <style> +border-left-width: 0px; + 0px - #inspected3 <style> +border-right-color: rgb(0, 0, 0); + initial - #inspected3 <style> +border-right-style: solid; + solid - #inspected3 <style> +border-right-width: 0px; + 0px - #inspected3 <style> +border-top-color: rgb(0, 0, 0); + initial - #inspected3 <style> +border-top-style: solid; + solid - #inspected3 <style> +border-top-width: 0px; + 0px - #inspected3 <style> +display: block; + block - div user agent stylesheet +[expanded] +element.style { () + +[expanded] +#inspected3 { (<style>) + border-width: 100px; + border-top-width: 0px; + border-right-width: 0px; + border-bottom-width: 0px; + border-left-width: 0px; + border: 0 solid; + border-top-color: initial; + border-top-style: solid; + border-top-width: 0px; + border-right-color: initial; + border-right-style: solid; + border-right-width: 0px; + border-bottom-color: initial; + border-bottom-style: solid; + border-bottom-width: 0px; + border-left-color: initial; + border-left-style: solid; + border-left-width: 0px; + border-image-source: initial; + border-image-slice: initial; + border-image-width: initial; + border-image-outset: initial; + border-image-repeat: initial; + +[expanded] +div { (user agent stylesheet) + display: block; + +
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-with-shorthands.js b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-with-shorthands.js new file mode 100644 index 0000000..319c0a2 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-2/inactive-properties-with-shorthands.js
@@ -0,0 +1,39 @@ +// Copyright 2021 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. + +(async function() { + TestRunner.addResult(`Tests that properties overridden by a shorthand are displayed as inactive in the sidebar.\n`); + await TestRunner.loadModule('elements'); await TestRunner.loadTestModule('elements_test_runner'); + await TestRunner.showPanel('elements'); + await TestRunner.loadHTML(` + <style> + #inspected1 { + /* Longhand overridden by shorthand */ + margin-top: 100px; + margin: 0; + } + #inspected2 { + /* Shorthand overridden by itself */ + padding: 100px; + padding: 0; + } + #inspected3 { + /* TODO: Shorthand overridden by a super-shorthand */ + border-width: 100px; + border: 0 solid; + } + </style> + <div id="inspected1">Test 1</div> + <div id="inspected2">Test 2</div> + <div id="inspected3">Test 3</div> + `); + + for (let i = 1; i <= 3; ++i) { + await new Promise((resolve) => { + ElementsTestRunner.selectNodeAndWaitForStylesWithComputed('inspected' + i, resolve); + }); + await ElementsTestRunner.dumpSelectedElementStyles(false, false); + } + TestRunner.completeTest(); +})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-new-API-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-new-API-expected.txt index edee979..0d8bc2d5 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-new-API-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-4/styles-new-API-expected.txt
@@ -30,10 +30,14 @@ ['important':'!important' is-important non-parsed] @[16:4-16:25] ['color':'yellow'] @[17:4-17:18] ['color':'"badcolor" ! important /* good property with strange value */' is-important non-parsed] @[18:4-18:73] + ['font-size':'12px'] @[undefined-undefined] + ['color':'yellow'] @[undefined-undefined] + ['height':'100% !important' is-important] @[undefined-undefined] } body.main1: [regular, 21:29-21:67] { ['color':'#F00BAA'] @[21:81-21:96] ['zoo':'moo /* not an !important unrecognized property */' non-parsed] @[21:96-21:149] + ['color':'rgb(240, 11, 170)'] @[undefined-undefined] } body.main2: [regular, 23:0-23:10] { ['background':'green /* value !important comment */ !important /* no semicolon, very !important */' is-important] @[23:11-23:106] @@ -65,6 +69,7 @@ PseudoType=after body::after: [regular, 26:0-26:11] { ['content':'"After body"'] @[27:4-27:26] + ['content':'"After body"'] @[undefined-undefined] } === Inherited styles for body === @@ -75,12 +80,16 @@ } html: [regular, 4:0-4:4] { ['font-weight':'400'] @[5:4-5:21] + ['font-weight':'400'] @[undefined-undefined] } === Inline style for body === ['font-weight':'normal'] @[0:0-0:20] ['width':'85%'] @[0:21-0:32] ['background-image':'url(bar.png)'] @[0:33-0:63] +['font-weight':'normal'] @[undefined-undefined] +['width':'85%'] @[undefined-undefined] +['background-image':'url("bar.png")'] @[undefined-undefined] Running: test_forcedStateHover === BODY with forced :hover === @@ -107,10 +116,14 @@ ['important':'!important' is-important non-parsed] @[16:4-16:25] ['color':'yellow'] @[17:4-17:18] ['color':'"badcolor" ! important /* good property with strange value */' is-important non-parsed] @[18:4-18:73] + ['font-size':'12px'] @[undefined-undefined] + ['color':'yellow'] @[undefined-undefined] + ['height':'100% !important' is-important] @[undefined-undefined] } body.main1: [regular, 21:29-21:67] { ['color':'#F00BAA'] @[21:81-21:96] ['zoo':'moo /* not an !important unrecognized property */' non-parsed] @[21:96-21:149] + ['color':'rgb(240, 11, 170)'] @[undefined-undefined] } body.main2: [regular, 23:0-23:10] { ['background':'green /* value !important comment */ !important /* no semicolon, very !important */' is-important] @[23:11-23:106] @@ -139,6 +152,7 @@ } body:hover: [regular, 13:0-13:10] { ['color':'#CDE'] @[14:2-14:14] + ['color':'rgb(204, 221, 238)'] @[undefined-undefined] } Running: test_forcedStateTarget @@ -210,13 +224,18 @@ ['important':'!important' is-important non-parsed] @[16:4-16:25] ['color':'yellow'] @[17:4-17:18] ['color':'"badcolor" ! important /* good property with strange value */' is-important non-parsed] @[18:4-18:73] + ['font-size':'12px'] @[undefined-undefined] + ['color':'yellow'] @[undefined-undefined] + ['height':'100% !important' is-important] @[undefined-undefined] } body: [inspector, 0:0-0:4] { ['font-family':'serif'] @[0:6-0:25] + ['font-family':'serif'] @[undefined-undefined] } body.main1: [regular, 21:29-21:67] { ['color':'#F00BAA'] @[21:81-21:96] ['zoo':'moo /* not an !important unrecognized property */' non-parsed] @[21:96-21:149] + ['color':'rgb(240, 11, 170)'] @[undefined-undefined] } body.main2: [regular, 23:0-23:10] { ['background':'green /* value !important comment */ !important /* no semicolon, very !important */' is-important] @[23:11-23:106]
diff --git a/third_party/blink/web_tests/http/tests/devtools/modify-cross-domain-rule-expected.txt b/third_party/blink/web_tests/http/tests/devtools/modify-cross-domain-rule-expected.txt index f24483d..88cf6d5 100644 --- a/third_party/blink/web_tests/http/tests/devtools/modify-cross-domain-rule-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/modify-cross-domain-rule-expected.txt
@@ -7,6 +7,8 @@ === Rule modified === color: green; width: 100%; +color: green; +width: 100%; === Selector changed === body { color: green;
diff --git a/third_party/blink/web_tests/http/tests/devtools/modify-cross-domain-rule.js b/third_party/blink/web_tests/http/tests/devtools/modify-cross-domain-rule.js index 55fafd5..d9ecd86 100644 --- a/third_party/blink/web_tests/http/tests/devtools/modify-cross-domain-rule.js +++ b/third_party/blink/web_tests/http/tests/devtools/modify-cross-domain-rule.js
@@ -110,6 +110,6 @@ return; var allProperties = style.allProperties(); for (var i = 0; i < allProperties.length; ++i) - TestRunner.addResult(allProperties[i].text); + TestRunner.addResult(allProperties[i].propertyText); } })();
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-add-rule-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-add-rule-expected.txt index 367e93a..54f98908 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-add-rule-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-add-rule-expected.txt
@@ -50,19 +50,26 @@ Dumping matched rules: *#test* { regular content: 'EDITED'; + content: "EDITED"; } *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -96,22 +103,29 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular } *#test* { regular content: 'EDITED'; + content: "EDITED"; } Dumping inherited rules: @@ -142,19 +156,26 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } *#test* { regular content: 'EDITED'; + content: "EDITED"; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -190,19 +211,26 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular content: 'EDITED'; + content: "EDITED"; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -240,19 +268,26 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular content: 'EDITED'; + content: "EDITED"; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -286,20 +321,27 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular content: 'EDITED'; + content: "EDITED"; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -333,20 +375,27 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular content: 'EDITED'; + content: "EDITED"; } @media (min-width: 1px) *#test* { regular @@ -380,16 +429,22 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -397,6 +452,7 @@ @media (min-width: 1px) *#test* { regular content: 'EDITED'; + content: "EDITED"; } Dumping inherited rules:
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-create-stylesheet-and-add-rule-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-create-stylesheet-and-add-rule-expected.txt index 57da1c1..8f5a546 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-create-stylesheet-and-add-rule-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-create-stylesheet-and-add-rule-expected.txt
@@ -3,6 +3,7 @@ Dumping matched rules: *#inspected* { regular color: red; + color: red; } Dumping inherited rules: Adding a rule to the existing stylesheet. @@ -15,6 +16,7 @@ } *#inspected* { regular color: red; + color: red; } Dumping inherited rules: Creating inspector stylesheet. @@ -27,6 +29,7 @@ } *#inspected* { regular color: red; + color: red; } *#inspected* { inspector }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-get-keyframes-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-get-keyframes-expected.txt index 34e9fd5a..f32b5a9a9 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-get-keyframes-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-get-keyframes-expected.txt
@@ -3,28 +3,35 @@ @keyframes animName { 0% { width: 100px; + width: 100px; } 10% { width: 150px; + width: 150px; } 100% { width: 200px; + width: 200px; } } @keyframes mediaAnim { 0% { opacity: 0; + opacity: 0; } 100% { opacity: 1; + opacity: 1; } } @keyframes styleSheetAnim { 0% { color: red; + color: red; } 100% { color: blue; + color: blue; } }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-get-styles-for-node-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-get-styles-for-node-expected.txt index c47efcc2..34cd8f1 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-get-styles-for-node-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-get-styles-for-node-expected.txt
@@ -19,10 +19,13 @@ { padding-top: 55px; margin-top: 33px !important; + padding-top: 55px; + margin-top: 33px !important; } Dumping matched rules: *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -30,6 +33,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -37,11 +41,17 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; } Dumping inherited rules: padding-top: 20px; + padding-top: 20px; *#parent-div* { regular width: 100px; contain: size layout style; + width: 100px; + contain: size layout style; }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-inline-style-ranges-after-attr-modification-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-inline-style-ranges-after-attr-modification-expected.txt index 4f919e4ed..6f2c080 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-inline-style-ranges-after-attr-modification-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-inline-style-ranges-after-attr-modification-expected.txt
@@ -30,6 +30,10 @@ text : color: blue; value : blue } + [1] : { + name : color + value : blue + } ] cssText : color: blue; range : {
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-set-effective-property-value-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-set-effective-property-value-expected.txt index 28bee53e..225839053 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-set-effective-property-value-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-set-effective-property-value-expected.txt
@@ -4,10 +4,14 @@ padding-top: 55px; margin-top: 33px !important; --x: foo; + padding-top: 55px; + --x: foo; + margin-top: 33px !important; } Dumping matched rules: *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -15,6 +19,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -22,6 +27,9 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; } Dumping inherited rules: @@ -30,9 +38,13 @@ padding-top: 55px; margin-top: 33px !important; --x: foo; + padding-top: 55px; + --x: foo; + margin-top: 33px !important; } *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -40,6 +52,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -47,6 +60,9 @@ margin-left: 20px; padding-left: 101px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 101px; + margin-top: 15px !important; } Running test: testChangePropertyInShortHand @@ -54,9 +70,13 @@ padding-top: 55px; margin-top: 33px !important; --x: foo; + padding-top: 55px; + --x: foo; + margin-top: 33px !important; } *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 101px 40px; @@ -64,6 +84,7 @@ padding-right: 20px; padding-bottom: 101px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -71,6 +92,9 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; } Running test: testChangeImportantProperty @@ -78,9 +102,13 @@ padding-top: 55px; margin-top: 33px !important; --x: foo; + padding-top: 55px; + --x: foo; + margin-top: 33px !important; } *#inspected* { regular margin-left: 101px !important; + margin-left: 101px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -88,6 +116,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -95,6 +124,9 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; } Running test: testChangeInlineProperty @@ -102,9 +134,13 @@ padding-top: 101px; margin-top: 33px !important; --x: foo; + padding-top: 101px; + --x: foo; + margin-top: 33px !important; } *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -112,6 +148,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -119,6 +156,9 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; } Running test: testChangeInlineImportantProperty @@ -126,9 +166,13 @@ padding-top: 55px; margin-top: 101px !important; --x: foo; + padding-top: 55px; + --x: foo; + margin-top: 101px !important; } *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -136,6 +180,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -143,6 +188,9 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; } Running test: testChangeMissingProperty @@ -151,9 +199,14 @@ margin-top: 33px !important; --x: foo; margin-bottom: 101px; + padding-top: 55px; + --x: foo; + margin-bottom: 101px; + margin-top: 33px !important; } *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -161,6 +214,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -168,12 +222,16 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; } Running test: testAppendWithSeparator Dumping inline style: { padding-left: 10px; + padding-left: 10px; } Dumping matched rules: Dumping inherited rules: @@ -181,6 +239,8 @@ { padding-left: 10px; padding-right: 101px; + padding-left: 10px; + padding-right: 101px; } Running test: testChangeCustomProperty @@ -188,9 +248,13 @@ padding-top: 55px; margin-top: 33px !important; --x: bar; + padding-top: 55px; + --x: bar; + margin-top: 33px !important; } *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -198,6 +262,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -205,5 +270,8 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-set-inline-style-tag-text-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-set-inline-style-tag-text-expected.txt index 90cf70b..65bc7c59 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-set-inline-style-tag-text-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-set-inline-style-tag-text-expected.txt
@@ -10,6 +10,7 @@ Dumping matched rules: *#test* { regular color: blue; + color: blue; } Dumping inherited rules: ==== Style sheet text after clearing the stylesheet and DOM.Undo ====
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-set-style-text-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-set-style-text-expected.txt index 83e3a860..bbf5963d 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-set-style-text-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-set-style-text-expected.txt
@@ -50,16 +50,22 @@ Dumping matched rules: *#test* { regular content: 'EDITED'; + content: "EDITED"; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -97,20 +103,27 @@ color: green; padding: 0 4px; cursor: pointer; + color: green; padding-top: 0px; padding-right: 4px; padding-bottom: 0px; padding-left: 4px; + cursor: pointer; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -146,20 +159,27 @@ color: green; padding: 0 6px; cursor: pointer; + color: green; padding-top: 0px; padding-right: 6px; padding-bottom: 0px; padding-left: 6px; + cursor: pointer; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -195,20 +215,27 @@ color: green; padding: 0 8px; cursor: pointer; + color: green; padding-top: 0px; padding-right: 8px; padding-bottom: 0px; padding-left: 8px; + cursor: pointer; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -220,16 +247,22 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -241,16 +274,22 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -262,16 +301,22 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -307,17 +352,24 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular content: 'EDITED'; color: red; + content: "EDITED"; + color: red; } @media (min-width: 1px) *#test* { regular @@ -349,12 +401,17 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular @@ -369,16 +426,22 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular @@ -390,16 +453,22 @@ Dumping matched rules: *#test* { regular box-sizing: border-box; + box-sizing: border-box; } *#test* { regular line-height: 1; font-family: "Arial"; color: blue; display: flex; + line-height: 1; + font-family: Arial; + color: blue; + display: flex; } @media (min-width: 1px) *#test* { regular font-size: 200%; + font-size: 200%; } @media (min-width: 1px) *#test* { regular
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-shadow-dom-inherits-styles-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-shadow-dom-inherits-styles-expected.txt index 5d1ccfd..8e4bfdbc 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-shadow-dom-inherits-styles-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-shadow-dom-inherits-styles-expected.txt
@@ -3,5 +3,6 @@ Dumping inherited rules: *body* { regular color: blue; + color: blue; }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-shadow-host-rule-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-shadow-host-rule-expected.txt index cf5d0a5..8216ef5 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/css-shadow-host-rule-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/css-shadow-host-rule-expected.txt
@@ -2,6 +2,7 @@ Dumping matched rules: *:host* { regular color: red; + color: red; } Dumping inherited rules:
diff --git a/third_party/blink/web_tests/inspector-protocol/css/cssom-matching-rules-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/cssom-matching-rules-expected.txt index 0c27f21..25f71ee 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/cssom-matching-rules-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/cssom-matching-rules-expected.txt
@@ -5,173 +5,223 @@ Original rule: *#modifyRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#modifyRule* { regular height: 100%; + height: 100%; } *#modifyRule* { regular width: 100%; + width: 100%; } -------------- Modified rule 1: *#modifyRule* { regular box-sizing: border-box; color: red; + box-sizing: border-box; + color: red; } *#modifyRule* { regular height: 100%; + height: 100%; } *#modifyRule* { regular width: 100%; + width: 100%; } --------------- Modified rule 3: *#modifyRule* { regular box-sizing: border-box; color: red; + box-sizing: border-box; + color: red; } *#modifyRule* { regular height: 100%; + height: 100%; } *#modifyRule* { regular width: 100%; color: blue; + width: 100%; + color: blue; } --------------- Modified rule 2: *#modifyRule* { regular box-sizing: border-box; color: red; + box-sizing: border-box; + color: red; } *#modifyRule* { regular height: 100%; color: green; + height: 100%; + color: green; } *#modifyRule* { regular width: 100%; color: blue; + width: 100%; + color: blue; } --------------- Restored rule 2: *#modifyRule* { regular box-sizing: border-box; color: red; + box-sizing: border-box; + color: red; } *#modifyRule* { regular height: 100%; + height: 100%; } *#modifyRule* { regular width: 100%; color: blue; + width: 100%; + color: blue; } ----------------- Restored rule 1,3: *#modifyRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#modifyRule* { regular height: 100%; + height: 100%; } *#modifyRule* { regular width: 100%; + width: 100%; } Running test: testInsertFirstRule Original rule: *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular width: 100%; + width: 100%; } -------------- After inserted rule: *#insertRule* { regular color: red; + color: red; } *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular width: 100%; + width: 100%; } -------------- Restored rule: *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular width: 100%; + width: 100%; } Running test: testInsertMiddleRule Original rule: *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular width: 100%; + width: 100%; } -------------- After inserted rule: *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular color: red; + color: red; } *#insertRule* { regular width: 100%; + width: 100%; } -------------- Restored rule: *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular width: 100%; + width: 100%; } Running test: testInsertLastRule Original rule: *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular width: 100%; + width: 100%; } -------------- After inserted rule: *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular width: 100%; + width: 100%; } *#insertRule* { regular color: red; + color: red; } -------------- Restored rule: *#insertRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#insertRule* { regular width: 100%; + width: 100%; } Running test: testRemoveRule Original rule: *#removeRule* { regular box-sizing: border-box; + box-sizing: border-box; } *#removeRule* { regular width: 100%; + width: 100%; } ------------------- After remove rule 1: *#removeRule* { regular width: 100%; + width: 100%; } ------------------- After remove rule 2:
diff --git a/third_party/blink/web_tests/inspector-protocol/css/cssom-matching-rules-multiple-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/cssom-matching-rules-multiple-expected.txt index 17f5d69..6a38d99cf 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/cssom-matching-rules-multiple-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/cssom-matching-rules-multiple-expected.txt
@@ -4,136 +4,178 @@ Original rule: *#test* { regular color: red; + color: red; } *#test* { regular color: green; + color: green; } *#test* { regular color: blue; + color: blue; } *#test* { regular width: 10%; + width: 10%; } *#test* { regular width: 20%; + width: 20%; } *#test* { regular width: 30%; + width: 30%; } *#test* { regular width: 40%; + width: 40%; } *#test* { regular width: 50%; + width: 50%; } *#test* { regular width: 60%; + width: 60%; } Mutating 3rd: --------------- *#test* { regular color: red; + color: red; } *#test* { regular color: green; + color: green; } *#test* { regular color: blue; + color: blue; } *#test* { regular color: red; + color: red; } *#test* { regular width: 20%; + width: 20%; } *#test* { regular width: 30%; + width: 30%; } *#test* { regular width: 40%; + width: 40%; } *#test* { regular width: 50%; + width: 50%; } *#test* { regular width: 60%; + width: 60%; } Mutating 4th: -------------- *#test* { regular color: red; -} -*#test* { regular - color: green; -} -*#test* { regular - color: blue; -} -*#test* { regular color: red; } *#test* { regular color: green; + color: green; } *#test* { regular + color: blue; + color: blue; +} +*#test* { regular + color: red; + color: red; +} +*#test* { regular + color: green; + color: green; +} +*#test* { regular + width: 30%; width: 30%; } *#test* { regular width: 40%; + width: 40%; } *#test* { regular width: 50%; + width: 50%; } *#test* { regular width: 60%; + width: 60%; } Mutating 5th: -------------- *#test* { regular color: red; -} -*#test* { regular - color: green; -} -*#test* { regular - color: blue; -} -*#test* { regular color: red; } *#test* { regular color: green; + color: green; } *#test* { regular color: blue; + color: blue; +} +*#test* { regular + color: red; + color: red; +} +*#test* { regular + color: green; + color: green; +} +*#test* { regular + color: blue; + color: blue; } *#test* { regular width: 40%; + width: 40%; } *#test* { regular width: 50%; + width: 50%; } *#test* { regular width: 60%; + width: 60%; } Delete first 3: --------------- *#test* { regular color: red; + color: red; } *#test* { regular color: green; + color: green; } *#test* { regular color: blue; + color: blue; } *#test* { regular width: 40%; + width: 40%; } *#test* { regular width: 50%; + width: 50%; } *#test* { regular width: 60%; + width: 60%; }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/reattach-after-editing-styles-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/reattach-after-editing-styles-expected.txt index 36d7e1eb..2bf055dc 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/reattach-after-editing-styles-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/reattach-after-editing-styles-expected.txt
@@ -4,6 +4,7 @@ Dumping matched rules: *#test* { regular background-color: blue; + background-color: blue; } Dumping inherited rules: @@ -22,9 +23,11 @@ Dumping matched rules: *#test* { regular content: 'EDITED'; + content: "EDITED"; } #inspected, *#test* { inspector height: 1; + height: 1px; } Dumping inherited rules: @@ -36,9 +39,11 @@ Dumping matched rules: *#test* { regular content: 'EDITED'; + content: "EDITED"; } #inspected, *#test* { inspector height: 1; + height: 1px; } Dumping inherited rules:
diff --git a/third_party/blink/web_tests/inspector-protocol/css/shadow-dom-rules-restart-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/shadow-dom-rules-restart-expected.txt index 49d3e7a..0e0ff5bb 100644 --- a/third_party/blink/web_tests/inspector-protocol/css/shadow-dom-rules-restart-expected.txt +++ b/third_party/blink/web_tests/inspector-protocol/css/shadow-dom-rules-restart-expected.txt
@@ -9,6 +9,7 @@ Dumping matched rules: *.red* { regular color: red; + color: red; } Dumping inherited rules:
diff --git a/third_party/blink/web_tests/svg/hixie/perf/001-expected.txt b/third_party/blink/web_tests/svg/hixie/perf/001-expected.txt deleted file mode 100644 index 14efa82..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/001-expected.txt +++ /dev/null
@@ -1,2 +0,0 @@ -SVG Performance test. -Test completed
diff --git a/third_party/blink/web_tests/svg/hixie/perf/001.xml b/third_party/blink/web_tests/svg/hixie/perf/001.xml deleted file mode 100644 index fd6b951..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/001.xml +++ /dev/null
@@ -1,295 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="-200 -200 600 600" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> - <script xlink:href="../../../paint/invalidation/resources/text-based-repaint.js"></script> - <script type="text/javascript"> - window.testIsAsync = true; - window.outputRepaintRects = false; - var start = new Date(); - var max = 75; - - // When running in DRT only bounce ten times otherwhise this test takes way too long - if (window.testRunner) - max = 10; - </script> - <rect fill="none" stroke="black" x="-190" y="-190" width="580" height="580" rx="40"/> - <text x="-150" y="-150" font-size="10">SVG Performance test.</text> - <text x="200" y="350" font-size="10">Test not started.</text> - <g> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-122.304 84.285C-122.304 84.285 -122.203 86.179 -123.027 86.16C-123.851 86.141 -140.305 38.066 -160.833 40.309C-160.833 40.309 -143.05 32.956 -122.304 84.285z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-118.774 81.262C-118.774 81.262 -119.323 83.078 -120.092 82.779C-120.86 82.481 -119.977 31.675 -140.043 26.801C-140.043 26.801 -120.82 25.937 -118.774 81.262z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-91.284 123.59C-91.284 123.59 -89.648 124.55 -90.118 125.227C-90.589 125.904 -139.763 113.102 -149.218 131.459C-149.218 131.459 -145.539 112.572 -91.284 123.59z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-94.093 133.801C-94.093 133.801 -92.237 134.197 -92.471 134.988C-92.704 135.779 -143.407 139.121 -146.597 159.522C-146.597 159.522 -149.055 140.437 -94.093 133.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-98.304 128.276C-98.304 128.276 -96.526 128.939 -96.872 129.687C-97.218 130.435 -147.866 126.346 -153.998 146.064C-153.998 146.064 -153.646 126.825 -98.304 128.276z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-109.009 110.072C-109.009 110.072 -107.701 111.446 -108.34 111.967C-108.979 112.488 -152.722 86.634 -166.869 101.676C-166.869 101.676 -158.128 84.533 -109.009 110.072z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-116.554 114.263C-116.554 114.263 -115.098 115.48 -115.674 116.071C-116.25 116.661 -162.638 95.922 -174.992 112.469C-174.992 112.469 -168.247 94.447 -116.554 114.263z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-119.154 118.335C-119.154 118.335 -117.546 119.343 -118.036 120.006C-118.526 120.669 -167.308 106.446 -177.291 124.522C-177.291 124.522 -173.066 105.749 -119.154 118.335z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-108.42 118.949C-108.42 118.949 -107.298 120.48 -107.999 120.915C-108.7 121.35 -148.769 90.102 -164.727 103.207C-164.727 103.207 -153.862 87.326 -108.42 118.949z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-128.2 90C-128.2 90 -127.6 91.8 -128.4 92C-129.2 92.2 -157.8 50.2 -177.001 57.8C-177.001 57.8 -161.8 46 -128.2 90z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-127.505 96.979C-127.505 96.979 -126.53 98.608 -127.269 98.975C-128.007 99.343 -164.992 64.499 -182.101 76.061C-182.101 76.061 -169.804 61.261 -127.505 96.979z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-127.62 101.349C-127.62 101.349 -126.498 102.88 -127.199 103.315C-127.9 103.749 -167.969 72.502 -183.927 85.607C-183.927 85.607 -173.062 69.726 -127.62 101.349z"/> - <path fill="#ffffff" stroke="#000000" d="M-129.83 103.065C-129.327 109.113 -128.339 115.682 -126.6 118.801C-126.6 118.801 -130.2 131.201 -121.4 144.401C-121.4 144.401 -121.8 151.601 -120.2 154.801C-120.2 154.801 -116.2 163.201 -111.4 164.001C-107.516 164.648 -98.793 167.717 -88.932 169.121C-88.932 169.121 -71.8 183.201 -75 196.001C-75 196.001 -75.4 212.401 -79 214.001C-79 214.001 -67.4 202.801 -77 219.601L-81.4 238.401C-81.4 238.401 -55.8 216.801 -71.4 235.201L-81.4 261.201C-81.4 261.201 -61.8 242.801 -69 251.201L-72.2 260.001C-72.2 260.001 -29 232.801 -59.8 262.401C-59.8 262.401 -51.8 258.801 -47.4 261.601C-47.4 261.601 -40.6 260.401 -41.4 262.001C-41.4 262.001 -62.2 272.401 -65.8 290.801C-65.8 290.801 -57.4 280.801 -60.6 291.601L-60.2 303.201C-60.2 303.201 -56.2 281.601 -56.6 319.201C-56.6 319.201 -37.4 301.201 -49 322.001L-49 338.801C-49 338.801 -33.8 322.401 -40.2 335.201C-40.2 335.201 -30.2 326.401 -34.2 341.601C-34.2 341.601 -35 352.001 -30.6 340.801C-30.6 340.801 -14.6 310.201 -20.6 336.401C-20.6 336.401 -21.4 355.601 -16.6 340.801C-16.6 340.801 -16.2 351.201 -7 358.401C-7 358.401 -8.2 307.601 4.6 343.601L8.6 360.001C8.6 360.001 11.4 350.801 11 345.601C11 345.601 25.8 329.201 19 353.601C19 353.601 34.2 330.801 31 344.001C31 344.001 23.4 360.001 25 364.801C25 364.801 41.8 330.001 43 328.401C43 328.401 41 370.802 51.8 334.801C51.8 334.801 57.4 346.801 54.6 351.201C54.6 351.201 62.6 343.201 61.8 340.001C61.8 340.001 66.4 331.801 69.2 345.401C69.2 345.401 71 354.801 72.6 351.601C72.6 351.601 76.6 375.602 77.8 352.801C77.8 352.801 79.4 339.201 72.2 327.601C72.2 327.601 73 324.401 70.2 320.401C70.2 320.401 83.8 342.001 76.6 313.201C76.6 313.201 87.801 321.201 89.001 321.201C89.001 321.201 75.4 298.001 84.2 302.801C84.2 302.801 79 292.401 97.001 304.401C97.001 304.401 81 288.401 98.601 298.001C98.601 298.001 106.601 304.401 99.001 294.401C99.001 294.401 84.6 278.401 106.601 296.401C106.601 296.401 118.201 312.801 119.001 315.601C119.001 315.601 109.001 286.401 104.601 283.601C104.601 283.601 113.001 247.201 154.201 262.801C154.201 262.801 161.001 280.001 165.401 261.601C165.401 261.601 178.201 255.201 189.401 282.801C189.401 282.801 193.401 269.201 192.601 266.401C192.601 266.401 199.401 267.601 198.601 266.401C198.601 266.401 211.801 270.801 213.001 270.001C213.001 270.001 219.801 276.801 220.201 273.201C220.201 273.201 229.401 276.001 227.401 272.401C227.401 272.401 236.201 288.001 236.601 291.601L239.001 277.601L241.001 280.401C241.001 280.401 242.601 272.801 241.801 271.601C241.001 270.401 261.801 278.401 266.601 299.201L268.601 307.601C268.601 307.601 274.601 292.801 273.001 288.801C273.001 288.801 278.201 289.601 278.601 294.001C278.601 294.001 282.601 270.801 277.801 264.801C277.801 264.801 282.201 264.001 283.401 267.601L283.401 260.401C283.401 260.401 290.601 261.201 290.601 258.801C290.601 258.801 295.001 254.801 297.001 259.601C297.001 259.601 284.601 224.401 303.001 243.601C303.001 243.601 310.201 254.401 306.601 235.601C303.001 216.801 299.001 215.201 303.801 214.801C303.801 214.801 304.601 211.201 302.601 209.601C300.601 208.001 303.801 209.601 303.801 209.601C303.801 209.601 308.601 213.601 303.401 191.601C303.401 191.601 309.801 193.201 297.801 164.001C297.801 164.001 300.601 161.601 296.601 153.201C296.601 153.201 304.601 157.601 307.401 156.001C307.401 156.001 307.001 154.401 303.801 150.401C303.801 150.401 282.201 95.6 302.601 117.601C302.601 117.601 314.451 131.151 308.051 108.351C308.051 108.351 298.94 84.341 299.717 80.045L-129.83 103.065z"/> - <path fill="#cc7226" stroke="#000000" d="M299.717 80.245C300.345 80.426 302.551 81.55 303.801 83.2C303.801 83.2 310.601 94 305.401 75.6C305.401 75.6 296.201 46.8 305.001 58C305.001 58 311.001 65.2 307.801 51.6C303.936 35.173 301.401 28.8 301.401 28.8C301.401 28.8 313.001 33.6 286.201 -6L295.001 -2.4C295.001 -2.4 275.401 -42 253.801 -47.2L245.801 -53.2C245.801 -53.2 284.201 -91.2 271.401 -128C271.401 -128 264.601 -133.2 255.001 -124C255.001 -124 248.601 -119.2 242.601 -120.8C242.601 -120.8 211.801 -119.6 209.801 -119.6C207.801 -119.6 173.001 -156.8 107.401 -139.2C107.401 -139.2 102.201 -137.2 97.801 -138.4C97.801 -138.4 79.4 -154.4 30.6 -131.6C30.6 -131.6 20.6 -129.6 19 -129.6C17.4 -129.6 14.6 -129.6 6.6 -123.2C-1.4 -116.8 -1.8 -116 -3.8 -114.4C-3.8 -114.4 -20.2 -103.2 -25 -102.4C-25 -102.4 -36.6 -96 -41 -86L-44.6 -84.8C-44.6 -84.8 -46.2 -77.6 -46.6 -76.4C-46.6 -76.4 -51.4 -72.8 -52.2 -67.2C-52.2 -67.2 -61 -61.2 -60.6 -56.8C-60.6 -56.8 -62.2 -51.6 -63 -46.8C-63 -46.8 -70.2 -42 -69.4 -39.2C-69.4 -39.2 -77 -25.2 -75.8 -18.4C-75.8 -18.4 -82.2 -18.8 -85 -16.4C-85 -16.4 -85.8 -11.6 -87.4 -11.2C-87.4 -11.2 -90.2 -10 -87.8 -6C-87.8 -6 -89.4 -3.2 -89.8 -1.6C-89.8 -1.6 -89 1.2 -93.4 6.8C-93.4 6.8 -99.8 25.6 -97.8 30.8C-97.8 30.8 -97.4 35.6 -100.2 37.2C-100.2 37.2 -103.8 36.8 -95.4 48.8C-95.4 48.8 -94.6 50 -97.8 52.4C-97.8 52.4 -115 56 -117.4 72.4C-117.4 72.4 -131 87.2 -131 92.4C-131 94.705 -130.729 97.852 -130.03 102.465C-130.03 102.465 -130.6 110.801 -103 111.601C-75.4 112.401 299.717 80.245 299.717 80.245z"/> - <path fill="#cc7226" d="M-115.6 102.6C-140.6 63.2 -126.2 119.601 -126.2 119.601C-117.4 154.001 12.2 116.401 12.2 116.401C12.2 116.401 181.001 86 192.201 82C203.401 78 298.601 84.4 298.601 84.4L293.001 67.6C228.201 21.2 209.001 44.4 195.401 40.4C181.801 36.4 184.201 46 181.001 46.8C177.801 47.6 138.601 22.8 132.201 23.6C125.801 24.4 100.459 0.649 115.401 32.4C131.401 66.4 57 71.6 40.2 60.4C23.4 49.2 47.4 78.8 47.4 78.8C65.8 98.8 31.4 82 31.4 82C-3 69.2 -27 94.8 -30.2 95.6C-33.4 96.4 -38.2 99.6 -39 93.2C-39.8 86.8 -47.31 70.099 -79 96.4C-99 113.001 -112.8 91 -112.8 91L-115.6 102.6z"/> - <path fill="#e87f3a" d="M133.51 25.346C127.11 26.146 101.743 2.407 116.71 34.146C133.31 69.346 58.31 73.346 41.51 62.146C24.709 50.946 48.71 80.546 48.71 80.546C67.11 100.546 32.709 83.746 32.709 83.746C-1.691 70.946 -25.691 96.546 -28.891 97.346C-32.091 98.146 -36.891 101.346 -37.691 94.946C-38.491 88.546 -45.87 72.012 -77.691 98.146C-98.927 115.492 -112.418 94.037 -112.418 94.037L-115.618 104.146C-140.618 64.346 -125.546 122.655 -125.546 122.655C-116.745 157.056 13.509 118.146 13.509 118.146C13.509 118.146 182.31 87.746 193.51 83.746C204.71 79.746 299.038 86.073 299.038 86.073L293.51 68.764C228.71 22.364 210.31 46.146 196.71 42.146C183.11 38.146 185.51 47.746 182.31 48.546C179.11 49.346 139.91 24.546 133.51 25.346z"/> - <path fill="#ea8c4d" d="M134.819 27.091C128.419 27.891 103.685 3.862 118.019 35.891C134.219 72.092 59.619 75.092 42.819 63.892C26.019 52.692 50.019 82.292 50.019 82.292C68.419 102.292 34.019 85.492 34.019 85.492C-0.381 72.692 -24.382 98.292 -27.582 99.092C-30.782 99.892 -35.582 103.092 -36.382 96.692C-37.182 90.292 -44.43 73.925 -76.382 99.892C-98.855 117.983 -112.036 97.074 -112.036 97.074L-115.636 105.692C-139.436 66.692 -124.891 125.71 -124.891 125.71C-116.091 160.11 14.819 119.892 14.819 119.892C14.819 119.892 183.619 89.492 194.819 85.492C206.019 81.492 299.474 87.746 299.474 87.746L294.02 69.928C229.219 23.528 211.619 47.891 198.019 43.891C184.419 39.891 186.819 49.491 183.619 50.292C180.419 51.092 141.219 26.291 134.819 27.091z"/> - <path fill="#ec9961" d="M136.128 28.837C129.728 29.637 104.999 5.605 119.328 37.637C136.128 75.193 60.394 76.482 44.128 65.637C27.328 54.437 51.328 84.037 51.328 84.037C69.728 104.037 35.328 87.237 35.328 87.237C0.928 74.437 -23.072 100.037 -26.272 100.837C-29.472 101.637 -34.272 104.837 -35.072 98.437C-35.872 92.037 -42.989 75.839 -75.073 101.637C-98.782 120.474 -111.655 100.11 -111.655 100.11L-115.655 107.237C-137.455 70.437 -124.236 128.765 -124.236 128.765C-115.436 163.165 16.128 121.637 16.128 121.637C16.128 121.637 184.928 91.237 196.129 87.237C207.329 83.237 299.911 89.419 299.911 89.419L294.529 71.092C229.729 24.691 212.929 49.637 199.329 45.637C185.728 41.637 188.128 51.237 184.928 52.037C181.728 52.837 142.528 28.037 136.128 28.837z"/> - <path fill="#eea575" d="M137.438 30.583C131.037 31.383 106.814 7.129 120.637 39.383C137.438 78.583 62.237 78.583 45.437 67.383C28.637 56.183 52.637 85.783 52.637 85.783C71.037 105.783 36.637 88.983 36.637 88.983C2.237 76.183 -21.763 101.783 -24.963 102.583C-28.163 103.383 -32.963 106.583 -33.763 100.183C-34.563 93.783 -41.548 77.752 -73.763 103.383C-98.709 122.965 -111.273 103.146 -111.273 103.146L-115.673 108.783C-135.473 73.982 -123.582 131.819 -123.582 131.819C-114.782 166.22 17.437 123.383 17.437 123.383C17.437 123.383 186.238 92.983 197.438 88.983C208.638 84.983 300.347 91.092 300.347 91.092L295.038 72.255C230.238 25.855 214.238 51.383 200.638 47.383C187.038 43.383 189.438 52.983 186.238 53.783C183.038 54.583 143.838 29.783 137.438 30.583z"/> - <path fill="#f1b288" d="M138.747 32.328C132.347 33.128 106.383 9.677 121.947 41.128C141.147 79.928 63.546 80.328 46.746 69.128C29.946 57.928 53.946 87.528 53.946 87.528C72.346 107.528 37.946 90.728 37.946 90.728C3.546 77.928 -20.454 103.528 -23.654 104.328C-26.854 105.128 -31.654 108.328 -32.454 101.928C-33.254 95.528 -40.108 79.665 -72.454 105.128C-98.636 125.456 -110.891 106.183 -110.891 106.183L-115.691 110.328C-133.691 77.128 -122.927 134.874 -122.927 134.874C-114.127 169.274 18.746 125.128 18.746 125.128C18.746 125.128 187.547 94.728 198.747 90.728C209.947 86.728 300.783 92.764 300.783 92.764L295.547 73.419C230.747 27.019 215.547 53.128 201.947 49.128C188.347 45.128 190.747 54.728 187.547 55.528C184.347 56.328 145.147 31.528 138.747 32.328z"/> - <path fill="#f3bf9c" d="M140.056 34.073C133.655 34.873 107.313 11.613 123.255 42.873C143.656 82.874 64.855 82.074 48.055 70.874C31.255 59.674 55.255 89.274 55.255 89.274C73.655 109.274 39.255 92.474 39.255 92.474C4.855 79.674 -19.145 105.274 -22.345 106.074C-25.545 106.874 -30.345 110.074 -31.145 103.674C-31.945 97.274 -38.668 81.578 -71.145 106.874C-98.564 127.947 -110.509 109.219 -110.509 109.219L-115.709 111.874C-131.709 81.674 -122.273 137.929 -122.273 137.929C-113.473 172.329 20.055 126.874 20.055 126.874C20.055 126.874 188.856 96.474 200.056 92.474C211.256 88.474 301.22 94.437 301.22 94.437L296.056 74.583C231.256 28.183 216.856 54.874 203.256 50.874C189.656 46.873 192.056 56.474 188.856 57.274C185.656 58.074 146.456 33.273 140.056 34.073z"/> - <path fill="#f5ccb0" d="M141.365 35.819C134.965 36.619 107.523 13.944 124.565 44.619C146.565 84.219 66.164 83.819 49.364 72.619C32.564 61.419 56.564 91.019 56.564 91.019C74.964 111.019 40.564 94.219 40.564 94.219C6.164 81.419 -17.836 107.019 -21.036 107.819C-24.236 108.619 -29.036 111.819 -29.836 105.419C-30.636 99.019 -37.227 83.492 -69.836 108.619C-98.491 130.438 -110.127 112.256 -110.127 112.256L-115.727 113.419C-130.128 85.019 -121.618 140.983 -121.618 140.983C-112.818 175.384 21.364 128.619 21.364 128.619C21.364 128.619 190.165 98.219 201.365 94.219C212.565 90.219 301.656 96.11 301.656 96.11L296.565 75.746C231.765 29.346 218.165 56.619 204.565 52.619C190.965 48.619 193.365 58.219 190.165 59.019C186.965 59.819 147.765 35.019 141.365 35.819z"/> - <path fill="#f8d8c4" d="M142.674 37.565C136.274 38.365 108.832 15.689 125.874 46.365C147.874 85.965 67.474 85.565 50.674 74.365C33.874 63.165 57.874 92.765 57.874 92.765C76.274 112.765 41.874 95.965 41.874 95.965C7.473 83.165 -16.527 108.765 -19.727 109.565C-22.927 110.365 -27.727 113.565 -28.527 107.165C-29.327 100.765 -35.786 85.405 -68.527 110.365C-98.418 132.929 -109.745 115.293 -109.745 115.293L-115.745 114.965C-129.346 88.564 -120.963 144.038 -120.963 144.038C-112.163 178.438 22.673 130.365 22.673 130.365C22.673 130.365 191.474 99.965 202.674 95.965C213.874 91.965 302.093 97.783 302.093 97.783L297.075 76.91C232.274 30.51 219.474 58.365 205.874 54.365C192.274 50.365 194.674 59.965 191.474 60.765C188.274 61.565 149.074 36.765 142.674 37.565z"/> - <path fill="#fae5d7" d="M143.983 39.31C137.583 40.11 110.529 17.223 127.183 48.11C149.183 88.91 68.783 87.31 51.983 76.11C35.183 64.91 59.183 94.51 59.183 94.51C77.583 114.51 43.183 97.71 43.183 97.71C8.783 84.91 -15.217 110.51 -18.417 111.31C-21.618 112.11 -26.418 115.31 -27.218 108.91C-28.018 102.51 -34.346 87.318 -67.218 112.11C-98.345 135.42 -109.363 118.329 -109.363 118.329L-115.764 116.51C-128.764 92.51 -120.309 147.093 -120.309 147.093C-111.509 181.493 23.983 132.11 23.983 132.11C23.983 132.11 192.783 101.71 203.983 97.71C215.183 93.71 302.529 99.456 302.529 99.456L297.583 78.074C232.783 31.673 220.783 60.11 207.183 56.11C193.583 52.11 195.983 61.71 192.783 62.51C189.583 63.31 150.383 38.51 143.983 39.31z"/> - <path fill="#fcf2eb" d="M145.292 41.055C138.892 41.855 112.917 18.411 128.492 49.855C149.692 92.656 70.092 89.056 53.292 77.856C36.492 66.656 60.492 96.256 60.492 96.256C78.892 116.256 44.492 99.456 44.492 99.456C10.092 86.656 -13.908 112.256 -17.108 113.056C-20.308 113.856 -25.108 117.056 -25.908 110.656C-26.708 104.256 -32.905 89.232 -65.908 113.856C-98.273 137.911 -108.982 121.365 -108.982 121.365L-115.782 118.056C-128.582 94.856 -119.654 150.147 -119.654 150.147C-110.854 184.547 25.292 133.856 25.292 133.856C25.292 133.856 194.093 103.456 205.293 99.456C216.493 95.456 302.965 101.128 302.965 101.128L298.093 79.237C233.292 32.837 222.093 61.856 208.493 57.856C194.893 53.855 197.293 63.456 194.093 64.256C190.892 65.056 151.692 40.255 145.292 41.055z"/> - <path fill="#ffffff" d="M-115.8 119.601C-128.6 97.6 -119 153.201 -119 153.201C-110.2 187.601 26.6 135.601 26.6 135.601C26.6 135.601 195.401 105.2 206.601 101.2C217.801 97.2 303.401 102.8 303.401 102.8L298.601 80.4C233.801 34 223.401 63.6 209.801 59.6C196.201 55.6 198.601 65.2 195.401 66C192.201 66.8 153.001 42 146.601 42.8C140.201 43.6 114.981 19.793 129.801 51.6C152.028 99.307 69.041 89.227 54.6 79.6C37.8 68.4 61.8 98 61.8 98C80.2 118.001 45.8 101.2 45.8 101.2C11.4 88.4 -12.6 114.001 -15.8 114.801C-19 115.601 -23.8 118.801 -24.6 112.401C-25.4 106 -31.465 91.144 -64.6 115.601C-98.2 140.401 -108.6 124.401 -108.6 124.401L-115.8 119.601z"/> - <path fill="#000000" d="M-74.2 149.601C-74.2 149.601 -81.4 161.201 -60.6 174.401C-60.6 174.401 -59.2 175.801 -77.2 171.601C-77.2 171.601 -83.4 169.601 -85 159.201C-85 159.201 -89.8 154.801 -94.6 149.201C-99.4 143.601 -74.2 149.601 -74.2 149.601z"/> - <path fill="#cccccc" d="M65.8 102C65.8 102 83.498 128.821 82.9 133.601C81.6 144.001 81.4 153.601 84.6 157.601C87.801 161.601 96.601 194.801 96.601 194.801C96.601 194.801 96.201 196.001 108.601 158.001C108.601 158.001 120.201 142.001 100.201 123.601C100.201 123.601 65 94.8 65.8 102z"/> - <path fill="#000000" d="M-54.2 176.401C-54.2 176.401 -43 183.601 -57.4 214.801L-51 212.401C-51 212.401 -51.8 223.601 -55 226.001L-47.8 222.801C-47.8 222.801 -43 230.801 -47 235.601C-47 235.601 -30.2 243.601 -31 250.001C-31 250.001 -24.6 242.001 -28.6 235.601C-32.6 229.201 -39.8 233.201 -39 214.801L-47.8 218.001C-47.8 218.001 -42.2 209.201 -42.2 202.801L-50.2 205.201C-50.2 205.201 -34.731 178.623 -45.4 177.201C-51.4 176.401 -54.2 176.401 -54.2 176.401z"/> - <path fill="#cccccc" d="M-21.8 193.201C-21.8 193.201 -19 188.801 -21.8 189.601C-24.6 190.401 -55.8 205.201 -61.8 214.801C-61.8 214.801 -27.4 190.401 -21.8 193.201z"/> - <path fill="#cccccc" d="M-11.4 201.201C-11.4 201.201 -8.6 196.801 -11.4 197.601C-14.2 198.401 -45.4 213.201 -51.4 222.801C-51.4 222.801 -17 198.401 -11.4 201.201z"/> - <path fill="#cccccc" d="M1.8 186.001C1.8 186.001 4.6 181.601 1.8 182.401C-1 183.201 -32.2 198.001 -38.2 207.601C-38.2 207.601 -3.8 183.201 1.8 186.001z"/> - <path fill="#cccccc" d="M-21.4 229.601C-21.4 229.601 -21.4 223.601 -24.2 224.401C-27 225.201 -63 242.801 -69 252.401C-69 252.401 -27 226.801 -21.4 229.601z"/> - <path fill="#cccccc" d="M-20.2 218.801C-20.2 218.801 -19 214.001 -21.8 214.801C-23.8 214.801 -50.2 226.401 -56.2 236.001C-56.2 236.001 -26.6 214.401 -20.2 218.801z"/> - <path fill="#cccccc" d="M-34.6 266.401L-44.6 274.001C-44.6 274.001 -34.2 266.401 -30.6 267.601C-30.6 267.601 -37.4 278.801 -38.2 284.001C-38.2 284.001 -27.8 271.201 -22.2 271.601C-22.2 271.601 -14.6 272.001 -14.6 282.801C-14.6 282.801 -9 272.401 -5.8 272.801C-5.8 272.801 -4.6 279.201 -5.8 286.001C-5.8 286.001 -1.8 278.401 2.2 280.001C2.2 280.001 8.6 278.001 7.8 289.601C7.8 289.601 7.8 300.001 7 302.801C7 302.801 12.6 276.401 15 276.001C15 276.001 23 274.801 27.8 283.601C27.8 283.601 23.8 276.001 28.6 278.001C28.6 278.001 39.4 279.601 42.6 286.401C42.6 286.401 35.8 274.401 41.4 277.601C41.4 277.601 48.2 277.601 49.4 284.001C49.4 284.001 57.8 305.201 59.8 306.801C59.8 306.801 52.2 285.201 53.8 285.201C53.8 285.201 51.8 273.201 57 288.001C57 288.001 53.8 274.001 59.4 274.801C65 275.601 69.4 285.601 77.8 283.201C77.8 283.201 87.401 288.801 89.401 219.601L-34.6 266.401z"/> - <path fill="#000000" d="M-29.8 173.601C-29.8 173.601 -15 167.601 25 173.601C25 173.601 32.2 174.001 39 165.201C45.8 156.401 72.6 149.201 79 151.201L88.601 157.601L89.401 158.801C89.401 158.801 101.801 169.201 102.201 176.801C102.601 184.401 87.801 232.401 78.2 248.401C68.6 264.401 59 276.801 39.8 274.401C39.8 274.401 19 270.401 -6.6 274.401C-6.6 274.401 -35.8 272.801 -38.6 264.801C-41.4 256.801 -27.4 241.601 -27.4 241.601C-27.4 241.601 -23 233.201 -24.2 218.801C-25.4 204.401 -25 176.401 -29.8 173.601z"/> - <path fill="#e5668c" d="M-7.8 175.601C0.6 194.001 -29 259.201 -29 259.201C-31 260.801 -16.34 266.846 -6.2 264.401C4.746 261.763 45 266.001 45 266.001C68.6 250.401 81.4 206.001 81.4 206.001C81.4 206.001 91.801 182.001 74.2 178.801C56.6 175.601 -7.8 175.601 -7.8 175.601z"/> - <path fill="#b23259" d="M-9.831 206.497C-6.505 193.707 -4.921 181.906 -7.8 175.601C-7.8 175.601 54.6 182.001 65.8 161.201C70.041 153.326 84.801 184.001 84.4 193.601C84.4 193.601 21.4 208.001 6.6 196.801L-9.831 206.497z"/> - <path fill="#a5264c" d="M-5.4 222.801C-5.4 222.801 -3.4 230.001 -5.8 234.001C-5.8 234.001 -7.4 234.801 -8.6 235.201C-8.6 235.201 -7.4 238.801 -1.4 240.401C-1.4 240.401 0.6 244.801 3 245.201C5.4 245.601 10.2 251.201 14.2 250.001C18.2 248.801 29.4 244.801 29.4 244.801C29.4 244.801 35 241.601 43.8 245.201C43.8 245.201 46.175 244.399 46.6 240.401C47.1 235.701 50.2 232.001 52.2 230.001C54.2 228.001 63.8 215.201 62.6 214.801C61.4 214.401 -5.4 222.801 -5.4 222.801z"/> - <path fill="#ff727f" stroke="#000000" d="M-9.8 174.401C-9.8 174.401 -12.6 196.801 -9.4 205.201C-6.2 213.601 -7 215.601 -7.8 219.601C-8.6 223.601 -4.2 233.601 1.4 239.601L13.4 241.201C13.4 241.201 28.6 237.601 37.8 240.401C37.8 240.401 46.794 241.744 50.2 226.801C50.2 226.801 55 220.401 62.2 217.601C69.4 214.801 76.6 173.201 72.6 165.201C68.6 157.201 54.2 152.801 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-8.2 249.201C-8.2 249.201 -9 247.201 -13.4 246.801C-13.4 246.801 -35.8 243.201 -44.2 230.801C-44.2 230.801 -51 225.201 -46.6 236.801C-46.6 236.801 -36.2 257.201 -29.4 260.001C-29.4 260.001 -13 264.001 -8.2 249.201z"/> - <path fill="#cc3f4c" d="M71.742 185.229C72.401 177.323 74.354 168.709 72.6 165.201C66.154 152.307 49.181 157.695 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401C-9.8 174.401 -11.545 188.364 -10.705 198.376C-10.705 198.376 26.6 186.801 27.4 192.401C27.4 192.401 29 189.201 38.2 189.201C47.4 189.201 70.142 188.029 71.742 185.229z"/> - <path stroke="#a51926" stroke-width="2" d="M28.6 175.201C28.6 175.201 33.4 180.001 29.8 189.601C29.8 189.601 15.4 205.601 17.4 219.601"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-19.4 260.001C-19.4 260.001 -23.8 247.201 -15 254.001C-15 254.001 -10.2 256.001 -11.4 257.601C-12.6 259.201 -18.2 263.201 -19.4 260.001z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-14.36 261.201C-14.36 261.201 -17.88 250.961 -10.84 256.401C-10.84 256.401 -6.419 258.849 -7.96 259.281C-12.52 260.561 -7.96 263.121 -14.36 261.201z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-9.56 261.201C-9.56 261.201 -13.08 250.961 -6.04 256.401C-6.04 256.401 -1.665 258.711 -3.16 259.281C-6.52 260.561 -3.16 263.121 -9.56 261.201z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-2.96 261.401C-2.96 261.401 -6.48 251.161 0.56 256.601C0.56 256.601 4.943 258.933 3.441 259.481C0.48 260.561 3.441 263.321 -2.96 261.401z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M3.52 261.321C3.52 261.321 0 251.081 7.041 256.521C7.041 256.521 10.881 258.121 9.921 259.401C8.961 260.681 9.921 263.241 3.52 261.321z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M10.2 262.001C10.2 262.001 5.4 249.601 14.6 256.001C14.6 256.001 19.4 258.001 18.2 259.601C17 261.201 18.2 264.401 10.2 262.001z"/> - <path stroke="#a5264c" stroke-width="2" d="M-18.2 244.801C-18.2 244.801 -5 242.001 1 245.201C1 245.201 7 246.401 8.2 246.001C9.4 245.601 12.6 245.201 12.6 245.201"/> - <path stroke="#a5264c" stroke-width="2" d="M15.8 253.601C15.8 253.601 27.8 240.001 39.8 244.401C46.816 246.974 45.8 243.601 46.6 240.801C47.4 238.001 47.6 233.801 52.6 230.801"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M33 237.601C33 237.601 29 226.801 26.2 239.601C23.4 252.401 20.2 256.001 18.6 258.801C18.6 258.801 18.6 264.001 27 263.601C27 263.601 37.8 263.201 38.2 260.401C38.6 257.601 37 246.001 33 237.601z"/> - <path stroke="#a5264c" stroke-width="2" d="M47 244.801C47 244.801 50.6 242.401 53 243.601"/> - <path stroke="#a5264c" stroke-width="2" d="M53.5 228.401C53.5 228.401 56.4 223.501 61.2 222.701"/> - <path fill="#b2b2b2" d="M-25.8 265.201C-25.8 265.201 -7.8 268.401 -3.4 266.801C-3.4 266.801 5.4 266.801 -3 268.801C-3 268.801 -15.8 268.801 -23.8 267.601C-23.8 267.601 -35.4 262.001 -25.8 265.201z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-11.8 172.001C-11.8 172.001 5.8 172.001 7.8 172.801C7.8 172.801 15 203.601 11.4 211.201C11.4 211.201 10.2 214.001 7.4 208.401C7.4 208.401 -11 175.601 -14.2 173.601C-17.4 171.601 -13 172.001 -11.8 172.001z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-88.9 169.301C-88.9 169.301 -80 171.001 -67.4 173.601C-67.4 173.601 -62.6 196.001 -59.4 200.801C-56.2 205.601 -59.8 205.601 -63.4 202.801C-67 200.001 -81.8 186.001 -83.8 181.601C-85.8 177.201 -88.9 169.301 -88.9 169.301z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-67.039 173.818C-67.039 173.818 -61.239 175.366 -60.23 177.581C-59.222 179.795 -61.432 183.092 -61.432 183.092C-61.432 183.092 -62.432 186.397 -63.634 184.235C-64.836 182.072 -67.708 174.412 -67.039 173.818z"/> - <path fill="#000000" d="M-67 173.601C-67 173.601 -63.4 178.801 -59.8 178.801C-56.2 178.801 -55.818 178.388 -53 179.001C-48.4 180.001 -48.8 178.001 -42.2 179.201C-39.56 179.681 -37 178.801 -34.2 180.001C-31.4 181.201 -28.2 180.401 -27 178.401C-25.8 176.401 -21 172.201 -21 172.201C-21 172.201 -33.8 174.001 -36.6 174.801C-36.6 174.801 -59 176.001 -67 173.601z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-22.4 173.801C-22.4 173.801 -28.85 177.301 -29.25 179.701C-29.65 182.101 -24 185.801 -24 185.801C-24 185.801 -21.25 190.401 -20.65 188.001C-20.05 185.601 -21.6 174.201 -22.4 173.801z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-59.885 179.265C-59.885 179.265 -52.878 190.453 -52.661 179.242C-52.661 179.242 -52.104 177.984 -53.864 177.962C-59.939 177.886 -58.418 173.784 -59.885 179.265z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-52.707 179.514C-52.707 179.514 -44.786 190.701 -45.422 179.421C-45.422 179.421 -45.415 179.089 -47.168 178.936C-51.915 178.522 -51.57 174.004 -52.707 179.514z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-45.494 179.522C-45.494 179.522 -37.534 190.15 -38.203 180.484C-38.203 180.484 -38.084 179.251 -39.738 178.95C-43.63 178.244 -43.841 174.995 -45.494 179.522z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-38.618 179.602C-38.618 179.602 -30.718 191.163 -30.37 181.382C-30.37 181.382 -28.726 180.004 -30.472 179.782C-36.29 179.042 -35.492 174.588 -38.618 179.602z"/> - <path fill="#e5e5b2" d="M-74.792 183.132L-82.45 181.601C-85.05 176.601 -87.15 170.451 -87.15 170.451C-87.15 170.451 -80.8 171.451 -68.3 174.251C-68.3 174.251 -67.424 177.569 -65.952 183.364L-74.792 183.132z"/> - <path fill="#e5e5b2" d="M-9.724 178.47C-11.39 175.964 -12.707 174.206 -13.357 173.8C-16.37 171.917 -12.227 172.294 -11.098 172.294C-11.098 172.294 5.473 172.294 7.356 173.047C7.356 173.047 7.88 175.289 8.564 178.68C8.564 178.68 -1.524 176.67 -9.724 178.47z"/> - <path fill="#cc7226" d="M43.88 40.321C71.601 44.281 97.121 8.641 98.881 -1.04C100.641 -10.72 90.521 -22.6 90.521 -22.6C91.841 -25.68 87.001 -39.76 81.721 -49C76.441 -58.24 60.54 -57.266 43 -58.24C27.16 -59.12 8.68 -35.8 7.36 -34.04C6.04 -32.28 12.2 6.001 13.52 11.721C14.84 17.441 12.2 43.841 12.2 43.841C46.44 34.741 16.16 36.361 43.88 40.321z"/> - <path fill="#ea8e51" d="M8.088 -33.392C6.792 -31.664 12.84 5.921 14.136 11.537C15.432 17.153 12.84 43.073 12.84 43.073C45.512 34.193 16.728 35.729 43.944 39.617C71.161 43.505 96.217 8.513 97.945 -0.992C99.673 -10.496 89.737 -22.16 89.737 -22.16C91.033 -25.184 86.281 -39.008 81.097 -48.08C75.913 -57.152 60.302 -56.195 43.08 -57.152C27.528 -58.016 9.384 -35.12 8.088 -33.392z"/> - <path fill="#efaa7c" d="M8.816 -32.744C7.544 -31.048 13.48 5.841 14.752 11.353C16.024 16.865 13.48 42.305 13.48 42.305C44.884 33.145 17.296 35.097 44.008 38.913C70.721 42.729 95.313 8.385 97.009 -0.944C98.705 -10.272 88.953 -21.72 88.953 -21.72C90.225 -24.688 85.561 -38.256 80.473 -47.16C75.385 -56.064 60.063 -55.125 43.16 -56.064C27.896 -56.912 10.088 -34.44 8.816 -32.744z"/> - <path fill="#f4c6a8" d="M9.544 -32.096C8.296 -30.432 14.12 5.761 15.368 11.169C16.616 16.577 14.12 41.537 14.12 41.537C43.556 32.497 17.864 34.465 44.072 38.209C70.281 41.953 94.409 8.257 96.073 -0.895C97.737 -10.048 88.169 -21.28 88.169 -21.28C89.417 -24.192 84.841 -37.504 79.849 -46.24C74.857 -54.976 59.824 -54.055 43.24 -54.976C28.264 -55.808 10.792 -33.76 9.544 -32.096z"/> - <path fill="#f9e2d3" d="M10.272 -31.448C9.048 -29.816 14.76 5.681 15.984 10.985C17.208 16.289 14.76 40.769 14.76 40.769C42.628 31.849 18.432 33.833 44.136 37.505C69.841 41.177 93.505 8.129 95.137 -0.848C96.769 -9.824 87.385 -20.84 87.385 -20.84C88.609 -23.696 84.121 -36.752 79.225 -45.32C74.329 -53.888 59.585 -52.985 43.32 -53.888C28.632 -54.704 11.496 -33.08 10.272 -31.448z"/> - <path fill="#ffffff" d="M44.2 36.8C69.4 40.4 92.601 8 94.201 -0.8C95.801 -9.6 86.601 -20.4 86.601 -20.4C87.801 -23.2 83.4 -36 78.6 -44.4C73.8 -52.8 59.346 -51.914 43.4 -52.8C29 -53.6 12.2 -32.4 11 -30.8C9.8 -29.2 15.4 5.6 16.6 10.8C17.8 16 15.4 40 15.4 40C40.9 31.4 19 33.2 44.2 36.8z"/> - <path fill="#cccccc" d="M90.601 2.8C90.601 2.8 62.8 10.4 51.2 8.8C51.2 8.8 35.4 2.2 26.6 24C26.6 24 23 31.2 21 33.2C19 35.2 90.601 2.8 90.601 2.8z"/> - <path fill="#000000" d="M94.401 0.6C94.401 0.6 65.4 12.8 55.4 12.4C55.4 12.4 39 7.8 30.6 22.4C30.6 22.4 22.2 31.6 19 33.2C19 33.2 18.6 34.8 25 30.8L35.4 36C35.4 36 50.2 45.6 59.8 29.6C59.8 29.6 63.8 18.4 63.8 16.4C63.8 14.4 85 8.8 86.601 8.4C88.201 8 94.801 3.8 94.401 0.6z"/> - <path fill="#99cc32" d="M47 36.514C40.128 36.514 31.755 32.649 31.755 26.4C31.755 20.152 40.128 13.887 47 13.887C53.874 13.887 59.446 18.952 59.446 25.2C59.446 31.449 53.874 36.514 47 36.514z"/> - <path fill="#659900" d="M43.377 19.83C38.531 20.552 33.442 22.055 33.514 21.839C35.054 17.22 41.415 13.887 47 13.887C51.296 13.887 55.084 15.865 57.32 18.875C57.32 18.875 52.004 18.545 43.377 19.83z"/> - <path fill="#ffffff" d="M55.4 19.6C55.4 19.6 51 16.4 51 18.6C51 18.6 54.6 23 55.4 19.6z"/> - <path fill="#000000" d="M45.4 27.726C42.901 27.726 40.875 25.7 40.875 23.2C40.875 20.701 42.901 18.675 45.4 18.675C47.9 18.675 49.926 20.701 49.926 23.2C49.926 25.7 47.9 27.726 45.4 27.726z"/> - <path fill="#cc7226" d="M-58.6 14.4C-58.6 14.4 -61.8 -6.8 -59.4 -11.2C-59.4 -11.2 -48.6 -21.2 -49 -24.8C-49 -24.8 -49.4 -42.8 -50.6 -43.6C-51.8 -44.4 -59.4 -50.4 -65.4 -44C-65.4 -44 -75.8 -26 -75 -19.6L-75 -17.6C-75 -17.6 -82.6 -18 -84.2 -16C-84.2 -16 -85.4 -10.8 -86.6 -10.4C-86.6 -10.4 -89.4 -8 -87.4 -5.2C-87.4 -5.2 -89.4 -2.8 -89 1.2L-81.4 5.2C-81.4 5.2 -79.4 19.6 -68.6 24.8C-63.764 27.129 -60.6 20.4 -58.6 14.4z"/> - <path fill="#ffffff" d="M-59.6 12.56C-59.6 12.56 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.48 -40.36 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.96 -59.6 12.56z"/> - <path fill="#eb955c" d="M-51.05 -42.61C-52.14 -43.47 -59.63 -49.24 -65.48 -43C-65.48 -43 -75.62 -25.45 -74.84 -19.21L-74.84 -17.26C-74.84 -17.26 -82.25 -17.65 -83.81 -15.7C-83.81 -15.7 -84.98 -10.63 -86.15 -10.24C-86.15 -10.24 -88.88 -7.9 -86.93 -5.17C-86.93 -5.17 -88.88 -2.83 -88.49 1.07L-81.08 4.97C-81.08 4.97 -79.13 19.01 -68.6 24.08C-63.886 26.35 -60.8 19.79 -58.85 13.94C-58.85 13.94 -61.97 -6.73 -59.63 -11.02C-59.63 -11.02 -49.1 -20.77 -49.49 -24.28C-49.49 -24.28 -49.88 -41.83 -51.05 -42.61z"/> - <path fill="#f2b892" d="M-51.5 -41.62C-52.48 -42.54 -59.86 -48.08 -65.56 -42C-65.56 -42 -75.44 -24.9 -74.68 -18.82L-74.68 -16.92C-74.68 -16.92 -81.9 -17.3 -83.42 -15.4C-83.42 -15.4 -84.56 -10.46 -85.7 -10.08C-85.7 -10.08 -88.36 -7.8 -86.46 -5.14C-86.46 -5.14 -88.36 -2.86 -87.98 0.94L-80.76 4.74C-80.76 4.74 -78.86 18.42 -68.6 23.36C-64.006 25.572 -61 19.18 -59.1 13.48C-59.1 13.48 -62.14 -6.66 -59.86 -10.84C-59.86 -10.84 -49.6 -20.34 -49.98 -23.76C-49.98 -23.76 -50.36 -40.86 -51.5 -41.62z"/> - <path fill="#f8dcc8" d="M-51.95 -40.63C-52.82 -41.61 -60.09 -46.92 -65.64 -41C-65.64 -41 -75.26 -24.35 -74.52 -18.43L-74.52 -16.58C-74.52 -16.58 -81.55 -16.95 -83.03 -15.1C-83.03 -15.1 -84.14 -10.29 -85.25 -9.92C-85.25 -9.92 -87.84 -7.7 -85.99 -5.11C-85.99 -5.11 -87.84 -2.89 -87.47 0.81L-80.44 4.51C-80.44 4.51 -78.59 17.83 -68.6 22.64C-64.127 24.794 -61.2 18.57 -59.35 13.02C-59.35 13.02 -62.31 -6.59 -60.09 -10.66C-60.09 -10.66 -50.1 -19.91 -50.47 -23.24C-50.47 -23.24 -50.84 -39.89 -51.95 -40.63z"/> - <path fill="#ffffff" d="M-59.6 12.46C-59.6 12.46 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.16 -40.68 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.86 -59.6 12.46z"/> - <path fill="#cccccc" d="M-62.7 6.2C-62.7 6.2 -84.3 -4 -85.2 -4.8C-85.2 -4.8 -76.1 3.4 -75.3 3.4C-74.5 3.4 -62.7 6.2 -62.7 6.2z"/> - <path fill="#000000" d="M-79.8 0C-79.8 0 -61.4 3.6 -61.4 8C-61.4 10.912 -61.643 24.331 -67 22.8C-75.4 20.4 -71.8 6 -79.8 0z"/> - <path fill="#99cc32" d="M-71.4 3.8C-71.4 3.8 -62.422 5.274 -61.4 8C-60.8 9.6 -60.137 17.908 -65.6 19C-70.152 19.911 -72.382 9.69 -71.4 3.8z"/> - <path fill="#000000" d="M14.595 46.349C14.098 44.607 15.409 44.738 17.2 44.2C19.2 43.6 31.4 39.8 32.2 37.2C33 34.6 46.2 39 46.2 39C48 39.8 52.4 42.4 52.4 42.4C57.2 43.6 63.8 44 63.8 44C66.2 45 69.6 47.8 69.6 47.8C84.2 58 96.601 50.8 96.601 50.8C116.601 44.2 110.601 27 110.601 27C107.601 18 110.801 14.6 110.801 14.6C111.001 10.8 118.201 17.2 118.201 17.2C120.801 21.4 121.601 26.4 121.601 26.4C129.601 37.6 126.201 19.8 126.201 19.8C126.401 18.8 123.601 15.2 123.601 14C123.601 12.8 121.801 9.4 121.801 9.4C118.801 6 121.201 -1 121.201 -1C123.001 -14.8 120.801 -13 120.801 -13C119.601 -14.8 110.401 -4.8 110.401 -4.8C108.201 -1.4 102.201 0.2 102.201 0.2C99.401 2 96.001 0.6 96.001 0.6C93.401 0.2 87.801 7.2 87.801 7.2C90.601 7 93.001 11.4 95.401 11.6C97.801 11.8 99.601 9.2 101.201 8.6C102.801 8 105.601 13.8 105.601 13.8C106.001 16.4 100.401 21.2 100.401 21.2C100.001 25.8 98.401 24.2 98.401 24.2C95.401 23.6 94.201 27.4 93.201 32C92.201 36.6 88.001 37 88.001 37C86.401 44.4 85.2 41.4 85.2 41.4C85 35.8 79 41.6 79 41.6C77.8 43.6 73.2 41.4 73.2 41.4C66.4 39.4 68.8 37.4 68.8 37.4C70.6 35.2 81.8 37.4 81.8 37.4C84 35.8 76 31.8 76 31.8C75.4 30 76.4 25.6 76.4 25.6C77.6 22.4 84.4 16.8 84.4 16.8C93.801 15.6 91.001 14 91.001 14C84.801 8.8 79 16.4 79 16.4C76.8 22.6 59.4 37.6 59.4 37.6C54.6 41 57.2 34.2 53.2 37.6C49.2 41 28.6 32 28.6 32C17.038 30.807 14.306 46.549 10.777 43.429C10.777 43.429 16.195 51.949 14.595 46.349z"/> - <path fill="#000000" d="M209.401 -120C209.401 -120 183.801 -112 181.001 -93.2C181.001 -93.2 178.601 -70.4 199.001 -52.8C199.001 -52.8 199.401 -46.4 201.401 -43.2C201.401 -43.2 199.801 -38.4 218.601 -46L245.801 -54.4C245.801 -54.4 252.201 -56.8 257.401 -65.6C262.601 -74.4 277.801 -93.2 274.201 -118.4C274.201 -118.4 275.401 -129.6 269.401 -130C269.401 -130 261.001 -131.6 253.801 -124C253.801 -124 247.001 -120.8 244.601 -121.2L209.401 -120z"/> - <path fill="#000000" d="M264.022 -120.99C264.022 -120.99 266.122 -129.92 261.282 -125.08C261.282 -125.08 254.242 -119.36 246.761 -119.36C246.761 -119.36 232.241 -117.16 227.841 -103.96C227.841 -103.96 223.881 -77.12 231.801 -71.4C231.801 -71.4 236.641 -63.92 243.681 -70.52C250.722 -77.12 266.222 -107.35 264.022 -120.99z"/> - <path fill="#323232" d="M263.648 -120.632C263.648 -120.632 265.738 -129.376 260.986 -124.624C260.986 -124.624 254.074 -119.008 246.729 -119.008C246.729 -119.008 232.473 -116.848 228.153 -103.888C228.153 -103.888 224.265 -77.536 232.041 -71.92C232.041 -71.92 236.793 -64.576 243.705 -71.056C250.618 -77.536 265.808 -107.24 263.648 -120.632z"/> - <path fill="#666666" d="M263.274 -120.274C263.274 -120.274 265.354 -128.832 260.69 -124.168C260.69 -124.168 253.906 -118.656 246.697 -118.656C246.697 -118.656 232.705 -116.536 228.465 -103.816C228.465 -103.816 224.649 -77.952 232.281 -72.44C232.281 -72.44 236.945 -65.232 243.729 -71.592C250.514 -77.952 265.394 -107.13 263.274 -120.274z"/> - <path fill="#999999" d="M262.9 -119.916C262.9 -119.916 264.97 -128.288 260.394 -123.712C260.394 -123.712 253.738 -118.304 246.665 -118.304C246.665 -118.304 232.937 -116.224 228.777 -103.744C228.777 -103.744 225.033 -78.368 232.521 -72.96C232.521 -72.96 237.097 -65.888 243.753 -72.128C250.41 -78.368 264.98 -107.02 262.9 -119.916z"/> - <path fill="#cccccc" d="M262.526 -119.558C262.526 -119.558 264.586 -127.744 260.098 -123.256C260.098 -123.256 253.569 -117.952 246.633 -117.952C246.633 -117.952 233.169 -115.912 229.089 -103.672C229.089 -103.672 225.417 -78.784 232.761 -73.48C232.761 -73.48 237.249 -66.544 243.777 -72.664C250.305 -78.784 264.566 -106.91 262.526 -119.558z"/> - <path fill="#ffffff" d="M262.151 -119.2C262.151 -119.2 264.201 -127.2 259.801 -122.8C259.801 -122.8 253.401 -117.6 246.601 -117.6C246.601 -117.6 233.401 -115.6 229.401 -103.6C229.401 -103.6 225.801 -79.2 233.001 -74C233.001 -74 237.401 -67.2 243.801 -73.2C250.201 -79.2 264.151 -106.8 262.151 -119.2z"/> - <path fill="#992600" d="M50.6 84C50.6 84 30.2 64.8 22.2 64C22.2 64 -12.2 60 -27 78C-27 78 -9.4 57.6 18.2 63.2C18.2 63.2 -3.4 58.8 -15.8 62C-15.8 62 -32.6 62 -42.2 76L-45 80.8C-45 80.8 -41 66 -22.6 60C-22.6 60 0.2 55.2 11 60C11 60 -10.6 53.2 -20.6 55.2C-20.6 55.2 -51 52.8 -63.8 79.2C-63.8 79.2 -59.8 64.8 -45 57.6C-45 57.6 -31.4 48.8 -11 51.6C-11 51.6 3.4 54.8 8.6 57.2C13.8 59.6 12.6 56.8 4.2 52C4.2 52 -1.4 42 -15.4 42.4C-15.4 42.4 -58.2 46 -68.6 58C-68.6 58 -55 46.8 -44.6 44C-44.6 44 -22.2 36 -13.8 36.8C-13.8 36.8 11 37.8 18.6 33.8C18.6 33.8 7.4 38.8 10.6 42C13.8 45.2 20.6 52.8 20.6 54C20.6 55.2 44.8 77.3 48.4 81.7L50.6 84z"/> - <path fill="#cccccc" d="M189 278C189 278 173.5 241.5 161 232C161 232 187 248 190.5 266C190.5 266 190.5 276 189 278z"/> - <path fill="#cccccc" d="M236 285.5C236 285.5 209.5 230.5 191 206.5C191 206.5 234.5 244 239.5 270.5L240 276L237 273.5C237 273.5 236.5 282.5 236 285.5z"/> - <path fill="#cccccc" d="M292.5 237C292.5 237 230 177.5 228.5 175C228.5 175 289 241 292 248.5C292 248.5 290 239.5 292.5 237z"/> - <path fill="#cccccc" d="M104 280.5C104 280.5 123.5 228.5 142.5 251C142.5 251 157.5 261 157 264C157 264 153 257.5 135 258C135 258 116 255 104 280.5z"/> - <path fill="#cccccc" d="M294.5 153C294.5 153 249.5 124.5 242 123C230.193 120.639 291.5 152 296.5 162.5C296.5 162.5 298.5 160 294.5 153z"/> - <path fill="#000000" d="M143.801 259.601C143.801 259.601 164.201 257.601 171.001 250.801L175.401 254.401L193.001 216.001L196.601 221.201C196.601 221.201 211.001 206.401 210.201 198.401C209.401 190.401 223.001 204.401 223.001 204.401C223.001 204.401 222.201 192.801 229.401 199.601C229.401 199.601 227.001 184.001 235.401 192.001C235.401 192.001 224.864 161.844 247.401 187.601C253.001 194.001 248.601 187.201 248.601 187.201C248.601 187.201 222.601 139.201 244.201 153.601C244.201 153.601 246.201 130.801 245.001 126.401C243.801 122.001 241.801 99.6 237.001 94.4C232.201 89.2 237.401 87.6 243.001 92.8C243.001 92.8 231.801 68.8 245.001 80.8C245.001 80.8 241.401 65.6 237.001 62.8C237.001 62.8 231.401 45.6 246.601 56.4C246.601 56.4 242.201 44 239.001 40.8C239.001 40.8 227.401 13.2 234.601 18L239.001 21.6C239.001 21.6 232.201 7.6 238.601 12C245.001 16.4 245.001 16 245.001 16C245.001 16 223.801 -17.2 244.201 0.4C244.201 0.4 236.042 -13.518 232.601 -20.4C232.601 -20.4 213.801 -40.8 228.201 -34.4L233.001 -32.8C233.001 -32.8 224.201 -42.8 216.201 -44.4C208.201 -46 218.601 -52.4 225.001 -50.4C231.401 -48.4 247.001 -40.8 247.001 -40.8C247.001 -40.8 259.801 -22 263.801 -21.6C263.801 -21.6 243.801 -29.2 249.801 -21.2C249.801 -21.2 264.201 -7.2 257.001 -7.6C257.001 -7.6 251.001 -0.4 255.801 8.4C255.801 8.4 237.342 -9.991 252.201 15.6L259.001 32C259.001 32 234.601 7.2 245.801 29.2C245.801 29.2 263.001 52.8 265.001 53.2C267.001 53.6 271.401 62.4 271.401 62.4L267.001 60.4L272.201 69.2C272.201 69.2 261.001 57.2 267.001 70.4L272.601 84.8C272.601 84.8 252.201 62.8 265.801 92.4C265.801 92.4 249.401 87.2 258.201 104.4C258.201 104.4 256.601 120.401 257.001 125.601C257.401 130.801 258.601 159.201 254.201 167.201C249.801 175.201 260.201 194.401 262.201 198.401C264.201 202.401 267.801 213.201 259.001 204.001C250.201 194.801 254.601 200.401 256.601 209.201C258.601 218.001 264.601 233.601 263.801 239.201C263.801 239.201 262.601 240.401 259.401 236.801C259.401 236.801 244.601 214.001 246.201 228.401C246.201 228.401 245.001 236.401 241.801 245.201C241.801 245.201 238.601 256.001 238.601 247.201C238.601 247.201 235.401 230.401 232.601 238.001C229.801 245.601 226.201 251.601 223.401 254.001C220.601 256.401 215.401 233.601 214.201 244.001C214.201 244.001 202.201 231.601 197.401 248.001L185.801 264.401C185.801 264.401 185.401 252.001 184.201 258.001C184.201 258.001 154.201 264.001 143.801 259.601z"/> - <path fill="#000000" d="M109.401 -97.2C109.401 -97.2 97.801 -105.2 93.801 -104.8C89.801 -104.4 121.401 -113.6 162.601 -86C162.601 -86 167.401 -83.2 171.001 -83.6C171.001 -83.6 174.201 -81.2 171.401 -77.6C171.401 -77.6 162.601 -68 173.801 -56.8C173.801 -56.8 192.201 -50 186.601 -58.8C186.601 -58.8 197.401 -54.8 199.801 -50.8C202.201 -46.8 201.001 -50.8 201.001 -50.8C201.001 -50.8 194.601 -58 188.601 -63.2C188.601 -63.2 183.401 -65.2 180.601 -73.6C177.801 -82 175.401 -92 179.801 -95.2C179.801 -95.2 175.801 -90.8 176.601 -94.8C177.401 -98.8 181.001 -102.4 182.601 -102.8C184.201 -103.2 200.601 -119 207.401 -119.4C207.401 -119.4 198.201 -118 195.201 -119C192.201 -120 165.601 -131.4 159.601 -132.6C159.601 -132.6 142.801 -139.2 154.801 -137.2C154.801 -137.2 190.601 -133.4 208.801 -120.2C208.801 -120.2 201.601 -128.6 183.201 -135.6C183.201 -135.6 161.001 -148.2 125.801 -143.2C125.801 -143.2 108.001 -140 100.201 -138.2C100.201 -138.2 97.601 -138.8 97.001 -139.2C96.401 -139.6 84.6 -148.6 57 -141.6C57 -141.6 40 -137 31.4 -132.2C31.4 -132.2 16.2 -131 12.6 -127.8C12.6 -127.8 -6 -113.2 -8 -112.4C-10 -111.6 -21.4 -104 -22.2 -103.6C-22.2 -103.6 2.4 -110.2 4.8 -112.6C7.2 -115 24.6 -117.6 27 -116.2C29.4 -114.8 37.8 -115.4 28.2 -114.8C28.2 -114.8 103.801 -100 104.601 -98C105.401 -96 109.401 -97.2 109.401 -97.2z"/> - <path fill="#cc7226" d="M180.801 -106.4C180.801 -106.4 170.601 -113.8 168.601 -113.8C166.601 -113.8 154.201 -124 150.001 -123.6C145.801 -123.2 133.601 -133.2 106.201 -125C106.201 -125 105.601 -127 109.201 -127.8C109.201 -127.8 115.601 -130 116.001 -130.6C116.001 -130.6 136.201 -134.8 143.401 -131.2C143.401 -131.2 152.601 -128.6 158.801 -122.4C158.801 -122.4 170.001 -119.2 173.201 -120.2C173.201 -120.2 182.001 -118 182.401 -116.2C182.401 -116.2 188.201 -113.2 186.401 -110.6C186.401 -110.6 186.801 -109 180.801 -106.4z"/> - <path fill="#cc7226" d="M168.33 -108.509C169.137 -107.877 170.156 -107.779 170.761 -106.97C170.995 -106.656 170.706 -106.33 170.391 -106.233C169.348 -105.916 168.292 -106.486 167.15 -105.898C166.748 -105.691 166.106 -105.873 165.553 -106.022C163.921 -106.463 162.092 -106.488 160.401 -105.8C158.416 -106.929 156.056 -106.345 153.975 -107.346C153.917 -107.373 153.695 -107.027 153.621 -107.054C150.575 -108.199 146.832 -107.916 144.401 -110.2C141.973 -110.612 139.616 -111.074 137.188 -111.754C135.37 -112.263 133.961 -113.252 132.341 -114.084C130.964 -114.792 129.507 -115.314 127.973 -115.686C126.11 -116.138 124.279 -116.026 122.386 -116.546C122.293 -116.571 122.101 -116.227 122.019 -116.254C121.695 -116.362 121.405 -116.945 121.234 -116.892C119.553 -116.37 118.065 -117.342 116.401 -117C115.223 -118.224 113.495 -117.979 111.949 -118.421C108.985 -119.269 105.831 -117.999 102.801 -119C106.914 -120.842 111.601 -119.61 115.663 -121.679C117.991 -122.865 120.653 -121.763 123.223 -122.523C123.71 -122.667 124.401 -122.869 124.801 -122.2C124.935 -122.335 125.117 -122.574 125.175 -122.546C127.625 -121.389 129.94 -120.115 132.422 -119.049C132.763 -118.903 133.295 -119.135 133.547 -118.933C135.067 -117.717 137.01 -117.82 138.401 -116.6C140.099 -117.102 141.892 -116.722 143.621 -117.346C143.698 -117.373 143.932 -117.032 143.965 -117.054C145.095 -117.802 146.25 -117.531 147.142 -117.227C147.48 -117.112 148.143 -116.865 148.448 -116.791C149.574 -116.515 150.43 -116.035 151.609 -115.852C151.723 -115.834 151.908 -116.174 151.98 -116.146C153.103 -115.708 154.145 -115.764 154.801 -114.6C154.936 -114.735 155.101 -114.973 155.183 -114.946C156.21 -114.608 156.859 -113.853 157.96 -113.612C158.445 -113.506 159.057 -112.88 159.633 -112.704C162.025 -111.973 163.868 -110.444 166.062 -109.549C166.821 -109.239 167.697 -109.005 168.33 -108.509z"/> - <path fill="#cc7226" d="M91.696 -122.739C89.178 -124.464 86.81 -125.57 84.368 -127.356C84.187 -127.489 83.827 -127.319 83.625 -127.441C82.618 -128.05 81.73 -128.631 80.748 -129.327C80.209 -129.709 79.388 -129.698 78.88 -129.956C76.336 -131.248 73.707 -131.806 71.2 -133C71.882 -133.638 73.004 -133.394 73.6 -134.2C73.795 -133.92 74.033 -133.636 74.386 -133.827C76.064 -134.731 77.914 -134.884 79.59 -134.794C81.294 -134.702 83.014 -134.397 84.789 -134.125C85.096 -134.078 85.295 -133.555 85.618 -133.458C87.846 -132.795 90.235 -133.32 92.354 -132.482C93.945 -131.853 95.515 -131.03 96.754 -129.755C97.006 -129.495 96.681 -129.194 96.401 -129C96.789 -129.109 97.062 -128.903 97.173 -128.59C97.257 -128.351 97.257 -128.049 97.173 -127.81C97.061 -127.498 96.782 -127.397 96.408 -127.346C95.001 -127.156 96.773 -128.536 96.073 -128.088C94.8 -127.274 95.546 -125.868 94.801 -124.6C94.521 -124.794 94.291 -125.012 94.401 -125.4C94.635 -124.878 94.033 -124.588 93.865 -124.272C93.48 -123.547 92.581 -122.132 91.696 -122.739z"/> - <path fill="#cc7226" d="M59.198 -115.391C56.044 -116.185 52.994 -116.07 49.978 -117.346C49.911 -117.374 49.688 -117.027 49.624 -117.054C48.258 -117.648 47.34 -118.614 46.264 -119.66C45.351 -120.548 43.693 -120.161 42.419 -120.648C42.095 -120.772 41.892 -121.284 41.591 -121.323C40.372 -121.48 39.445 -122.429 38.4 -123C40.736 -123.795 43.147 -123.764 45.609 -124.148C45.722 -124.166 45.867 -123.845 46 -123.845C46.136 -123.845 46.266 -124.066 46.4 -124.2C46.595 -123.92 46.897 -123.594 47.154 -123.848C47.702 -124.388 48.258 -124.198 48.798 -124.158C48.942 -124.148 49.067 -123.845 49.2 -123.845C49.336 -123.845 49.467 -124.156 49.6 -124.156C49.736 -124.155 49.867 -123.845 50 -123.845C50.136 -123.845 50.266 -124.066 50.4 -124.2C51.092 -123.418 51.977 -123.972 52.799 -123.793C53.837 -123.566 54.104 -122.418 55.178 -122.12C59.893 -120.816 64.03 -118.671 68.393 -116.584C68.7 -116.437 68.91 -116.189 68.8 -115.8C69.067 -115.8 69.38 -115.888 69.57 -115.756C70.628 -115.024 71.669 -114.476 72.366 -113.378C72.582 -113.039 72.253 -112.632 72.02 -112.684C67.591 -113.679 63.585 -114.287 59.198 -115.391z"/> - <path fill="#cc7226" d="M45.338 -71.179C43.746 -72.398 43.162 -74.429 42.034 -76.221C41.82 -76.561 42.094 -76.875 42.411 -76.964C42.971 -77.123 43.514 -76.645 43.923 -76.443C45.668 -75.581 47.203 -74.339 49.2 -74.2C51.19 -71.966 55.45 -71.581 55.457 -68.2C55.458 -67.341 54.03 -68.259 53.6 -67.4C51.149 -68.403 48.76 -68.3 46.38 -69.767C45.763 -70.148 46.093 -70.601 45.338 -71.179z"/> - <path fill="#cc7226" d="M17.8 -123.756C17.935 -123.755 24.966 -123.522 24.949 -123.408C24.904 -123.099 17.174 -122.05 16.81 -122.22C16.646 -122.296 9.134 -119.866 9 -120C9.268 -120.135 17.534 -123.756 17.8 -123.756z"/> - <path fill="#000000" d="M33.2 -114C33.2 -114 18.4 -112.2 14 -111C9.6 -109.8 -9 -102.2 -12 -100.2C-12 -100.2 -25.4 -94.8 -42.4 -74.8C-42.4 -74.8 -34.8 -78.2 -32.6 -81C-32.6 -81 -19 -93.6 -19.2 -91C-19.2 -91 -7 -99.6 -7.6 -97.4C-7.6 -97.4 16.8 -108.6 14.8 -105.4C14.8 -105.4 36.4 -110 35.4 -108C35.4 -108 54.2 -103.6 51.4 -103.4C51.4 -103.4 45.6 -102.2 52 -98.6C52 -98.6 48.6 -94.2 43.2 -98.2C37.8 -102.2 40.8 -100 35.8 -99C35.8 -99 33.2 -98.2 28.6 -102.2C28.6 -102.2 23 -106.8 14.2 -103.2C14.2 -103.2 -16.4 -90.6 -18.4 -90C-18.4 -90 -22 -87.2 -24.4 -83.6C-24.4 -83.6 -30.2 -79.2 -33.2 -77.8C-33.2 -77.8 -46 -66.2 -47.2 -64.8C-47.2 -64.8 -50.6 -59.6 -51.4 -59.2C-51.4 -59.2 -45 -63 -43 -65C-43 -65 -29 -75 -23.6 -75.8C-23.6 -75.8 -19.2 -78.8 -18.4 -80.2C-18.4 -80.2 -4 -89.4 0.2 -89.4C0.2 -89.4 9.4 -84.2 11.8 -91.2C11.8 -91.2 17.6 -93 23.2 -91.8C23.2 -91.8 26.4 -94.4 25.6 -96.6C25.6 -96.6 27.2 -98.4 28.2 -94.6C28.2 -94.6 31.6 -91 36.4 -93C36.4 -93 40.4 -93.2 38.4 -90.8C38.4 -90.8 34 -87 22.2 -86.8C22.2 -86.8 9.8 -86.2 -6.6 -78.6C-6.6 -78.6 -36.4 -68.2 -45.6 -57.8C-45.6 -57.8 -52 -49 -57.4 -47.8C-57.4 -47.8 -63.2 -47 -69.2 -39.6C-69.2 -39.6 -59.4 -45.4 -50.4 -45.4C-50.4 -45.4 -46.4 -47.8 -50.2 -44.2C-50.2 -44.2 -53.8 -36.6 -52.2 -31.2C-52.2 -31.2 -52.8 -26 -53.6 -24.4C-53.6 -24.4 -61.4 -11.6 -61.4 -9.2C-61.4 -6.8 -60.2 3 -59.8 3.6C-59.4 4.2 -60.8 2 -57 4.4C-53.2 6.8 -50.4 8.4 -49.6 11.2C-48.8 14 -51.6 5.8 -51.8 4C-52 2.2 -56.2 -5 -55.4 -7.4C-55.4 -7.4 -54.4 -6.4 -53.6 -5C-53.6 -5 -54.2 -5.6 -53.6 -9.2C-53.6 -9.2 -52.8 -14.4 -51.4 -17.6C-50 -20.8 -48 -24.6 -47.6 -25.4C-47.2 -26.2 -47.2 -32 -45.8 -29.4L-42.4 -26.8C-42.4 -26.8 -45.2 -29.4 -43 -31.6C-43 -31.6 -44 -37.2 -42.2 -39.8C-42.2 -39.8 -35.2 -48.2 -33.6 -49.2C-32 -50.2 -33.4 -49.8 -33.4 -49.8C-33.4 -49.8 -27.4 -54 -33.2 -52.4C-33.2 -52.4 -37.2 -50.8 -40.2 -50.8C-40.2 -50.8 -47.8 -48.8 -43.8 -53C-39.8 -57.2 -29.8 -62.6 -26 -62.4L-25.2 -60.8L-14 -63.2L-15.2 -62.4C-15.2 -62.4 -15.4 -62.6 -11.2 -63C-7 -63.4 -1.2 -62 0.2 -63.8C1.6 -65.6 5 -66.6 4.6 -65.2C4.2 -63.8 4 -61.8 4 -61.8C4 -61.8 9 -67.6 8.4 -65.4C7.8 -63.2 -0.4 -58 -1.8 -51.8L8.6 -60L12.2 -63C12.2 -63 15.8 -60.8 16 -62.4C16.2 -64 20.8 -69.8 22 -69.6C23.2 -69.4 25.2 -72.2 25 -69.6C24.8 -67 32.4 -61.6 32.4 -61.6C32.4 -61.6 35.6 -63.4 37 -62C38.4 -60.6 42.6 -81.8 42.6 -81.8L67.6 -92.4L111.201 -95.8L94.201 -102.6L33.2 -114z"/> - <path stroke="#4c0000" stroke-width="2" d="M51.4 85C51.4 85 36.4 68.2 28 65.6C28 65.6 14.6 58.8 -10 66.6"/> - <path stroke="#4c0000" stroke-width="2" d="M24.8 64.2C24.8 64.2 -0.4 56.2 -15.8 60.4C-15.8 60.4 -34.2 62.4 -42.6 76.2"/> - <path stroke="#4c0000" stroke-width="2" d="M21.2 63C21.2 63 4.2 55.8 -10.6 53.6C-10.6 53.6 -27.2 51 -43.8 58.2C-43.8 58.2 -56 64.2 -61.4 74.4"/> - <path stroke="#4c0000" stroke-width="2" d="M22.2 63.4C22.2 63.4 6.8 52.4 5.8 51C5.8 51 -1.2 40 -14.2 39.6C-14.2 39.6 -35.6 40.4 -52.8 48.4"/> - <path fill="#000000" d="M20.895 54.407C22.437 55.87 49.4 84.8 49.4 84.8C84.6 121.401 56.6 87.2 56.6 87.2C49 82.4 39.8 63.6 39.8 63.6C38.6 60.8 53.8 70.8 53.8 70.8C57.8 71.6 71.4 90.8 71.4 90.8C64.6 88.4 69.4 95.6 69.4 95.6C72.2 97.6 92.601 113.201 92.601 113.201C96.201 117.201 100.201 118.801 100.201 118.801C114.201 113.601 107.801 126.801 107.801 126.801C110.201 133.601 115.801 122.001 115.801 122.001C127.001 105.2 110.601 107.601 110.601 107.601C80.6 110.401 73.8 94.4 73.8 94.4C71.4 92 80.2 94.4 80.2 94.4C88.601 96.4 73 82 73 82C75.4 82 84.6 88.8 84.6 88.8C95.001 98 97.001 96 97.001 96C115.001 87.2 125.401 94.8 125.401 94.8C127.401 96.4 121.801 103.2 123.401 108.401C125.001 113.601 129.801 126.001 129.801 126.001C127.401 127.601 127.801 138.401 127.801 138.401C144.601 161.601 135.001 159.601 135.001 159.601C119.401 159.201 134.201 166.801 134.201 166.801C137.401 168.801 146.201 176.001 146.201 176.001C143.401 174.801 141.801 180.001 141.801 180.001C146.601 184.001 143.801 188.801 143.801 188.801C137.801 190.001 136.601 194.001 136.601 194.001C143.401 202.001 133.401 202.401 133.401 202.401C137.001 206.801 132.201 218.801 132.201 218.801C127.401 218.801 121.001 224.401 121.001 224.401C123.401 229.201 113.001 234.801 113.001 234.801C104.601 236.401 107.401 243.201 107.401 243.201C99.401 249.201 97.001 265.201 97.001 265.201C96.201 275.601 93.801 278.801 99.001 276.801C104.201 274.801 103.401 262.401 103.401 262.401C98.601 246.801 141.401 230.801 141.401 230.801C145.401 229.201 146.201 224.001 146.201 224.001C148.201 224.401 157.001 232.001 157.001 232.001C164.601 243.201 165.001 234.001 165.001 234.001C166.201 230.401 164.601 224.401 164.601 224.401C170.601 202.801 156.601 196.401 156.601 196.401C146.601 162.801 160.601 171.201 160.601 171.201C163.401 176.801 174.201 182.001 174.201 182.001L177.801 179.601C176.201 174.801 184.601 168.801 184.601 168.801C187.401 175.201 193.401 167.201 193.401 167.201C197.001 142.801 209.401 157.201 209.401 157.201C213.401 158.401 214.601 151.601 214.601 151.601C218.201 141.201 214.601 127.601 214.601 127.601C218.201 127.201 227.801 133.201 227.801 133.201C230.601 129.601 221.401 112.801 225.401 115.201C229.401 117.601 233.801 119.201 233.801 119.201C234.601 117.201 224.601 104.801 224.601 104.801C220.201 102 215.001 81.6 215.001 81.6C222.201 85.2 212.201 70 212.201 70C212.201 66.8 218.201 55.6 218.201 55.6C217.401 48.8 218.201 49.2 218.201 49.2C221.001 50.4 229.001 52 222.201 45.6C215.401 39.2 223.001 34.4 223.001 34.4C227.401 31.6 213.801 32 213.801 32C208.601 27.6 209.001 23.6 209.001 23.6C217.001 25.6 202.601 11.2 200.201 7.6C197.801 4 207.401 -1.2 207.401 -1.2C220.601 -4.8 209.001 -8 209.001 -8C189.401 -7.6 200.201 -18.4 200.201 -18.4C206.201 -18 204.601 -20.4 204.601 -20.4C199.401 -21.6 189.801 -28 189.801 -28C185.801 -31.6 189.401 -30.8 189.401 -30.8C206.201 -29.6 177.401 -40.8 177.401 -40.8C185.401 -40.8 167.401 -51.2 167.401 -51.2C165.401 -52.8 162.201 -60.4 162.201 -60.4C156.201 -65.6 151.401 -72.4 151.401 -72.4C151.001 -76.8 146.201 -81.6 146.201 -81.6C134.601 -95.2 129.001 -94.8 129.001 -94.8C114.201 -98.4 109.001 -97.6 109.001 -97.6L56.2 -93.2C29.8 -80.4 37.6 -59.4 37.6 -59.4C44 -51 53.2 -54.8 53.2 -54.8C57.8 -61 69.4 -58.8 69.4 -58.8C89.801 -55.6 87.201 -59.2 87.201 -59.2C84.801 -63.8 68.6 -70 68.4 -70.6C68.2 -71.2 59.4 -74.6 59.4 -74.6C56.4 -75.8 52 -85 52 -85C48.8 -88.4 64.6 -82.6 64.6 -82.6C63.4 -81.6 70.8 -77.6 70.8 -77.6C88.201 -78.6 98.801 -67.8 98.801 -67.8C109.601 -51.2 109.801 -59.4 109.801 -59.4C112.601 -68.8 100.801 -90 100.801 -90C101.201 -92 109.401 -85.4 109.401 -85.4C110.801 -87.4 111.601 -81.6 111.601 -81.6C111.801 -79.2 115.601 -71.2 115.601 -71.2C118.401 -58.2 122.001 -65.6 122.001 -65.6L126.601 -56.2C128.001 -53.6 122.001 -46 122.001 -46C121.801 -43.2 122.601 -43.4 117.001 -35.8C111.401 -28.2 114.801 -23.8 114.801 -23.8C113.401 -17.2 122.201 -17.6 122.201 -17.6C124.801 -15.4 128.201 -15.4 128.201 -15.4C130.001 -13.4 132.401 -14 132.401 -14C134.001 -17.8 140.201 -15.8 140.201 -15.8C141.601 -18.2 149.801 -18.6 149.801 -18.6C150.801 -21.2 151.201 -22.8 154.601 -23.4C158.001 -24 133.401 -67 133.401 -67C139.801 -67.8 131.601 -80.2 131.601 -80.2C129.401 -86.8 140.801 -72.2 143.001 -70.8C145.201 -69.4 146.201 -67.2 144.601 -67.4C143.001 -67.6 141.201 -65.4 142.601 -65.2C144.001 -65 157.001 -50 160.401 -39.8C163.801 -29.6 169.801 -25.6 176.001 -19.6C182.201 -13.6 181.401 10.6 181.401 10.6C181.001 19.4 187.001 30 187.001 30C189.001 33.8 184.801 52 184.801 52C182.801 54.2 184.201 55 184.201 55C185.201 56.2 192.001 69.4 192.001 69.4C190.201 69.2 193.801 72.8 193.801 72.8C199.001 78.8 192.601 75.8 192.601 75.8C186.601 74.2 193.601 84 193.601 84C194.801 85.8 185.801 81.2 185.801 81.2C176.601 80.6 188.201 87.8 188.201 87.8C196.801 95 185.401 90.6 185.401 90.6C180.801 88.8 184.001 95.6 184.001 95.6C187.201 97.2 204.401 104.2 204.401 104.2C204.801 108.001 201.801 113.001 201.801 113.001C202.201 117.001 200.001 120.401 200.001 120.401C198.801 128.601 198.201 129.401 198.201 129.401C194.001 129.601 186.601 143.401 186.601 143.401C184.801 146.001 174.601 158.001 174.601 158.001C172.601 165.001 154.601 157.801 154.601 157.801C148.001 161.201 150.001 157.801 150.001 157.801C149.601 155.601 154.401 149.601 154.401 149.601C161.401 147.001 158.801 136.201 158.801 136.201C162.801 134.801 151.601 132.001 151.801 130.801C152.001 129.601 157.801 128.201 157.801 128.201C165.801 126.201 161.401 123.801 161.401 123.801C160.801 119.801 163.801 114.201 163.801 114.201C175.401 113.401 163.801 97.2 163.801 97.2C153.001 89.6 152.001 83.8 152.001 83.8C164.601 75.6 156.401 63.2 156.601 59.6C156.801 56 158.001 34.4 158.001 34.4C156.001 28.2 153.001 14.6 153.001 14.6C155.201 9.4 162.601 -3.2 162.601 -3.2C165.401 -7.4 174.201 -12.2 172.001 -15.2C169.801 -18.2 162.001 -16.4 162.001 -16.4C154.201 -17.8 154.801 -12.6 154.801 -12.6C153.201 -11.6 152.401 -6.6 152.401 -6.6C151.68 1.333 142.801 7.6 142.801 7.6C131.601 13.8 140.801 17.8 140.801 17.8C146.801 24.4 137.001 24.6 137.001 24.6C126.001 22.8 134.201 33 134.201 33C145.001 45.8 142.001 48.6 142.001 48.6C131.801 49.6 144.401 58.8 144.401 58.8C144.401 58.8 143.601 56.8 143.801 58.6C144.001 60.4 147.001 64.6 147.801 66.6C148.601 68.6 144.601 68.8 144.601 68.8C145.201 78.4 129.801 74.2 129.801 74.2C129.801 74.2 129.801 74.2 128.201 74.4C126.601 74.6 115.401 73.8 109.601 71.6C103.801 69.4 97.001 69.4 97.001 69.4C97.001 69.4 93.001 71.2 85.4 71C77.8 70.8 69.8 73.6 69.8 73.6C65.4 73.2 74 68.8 74.2 69C74.4 69.2 80 63.6 72 64.2C50.203 65.835 39.4 55.6 39.4 55.6C37.4 54.2 34.8 51.4 34.8 51.4C24.8 49.4 36.2 63.8 36.2 63.8C37.4 65.2 36 66.2 36 66.2C35.2 64.6 27.4 59.2 27.4 59.2C24.589 58.227 23.226 56.893 20.895 54.407z"/> - <path fill="#4c0000" d="M-3 42.8C-3 42.8 8.6 48.4 11.2 51.2C13.8 54 27.8 65.4 27.8 65.4C27.8 65.4 22.4 63.4 19.8 61.6C17.2 59.8 6.4 51.6 6.4 51.6C6.4 51.6 2.6 45.6 -3 42.8z"/> - <path fill="#99cc32" d="M-61.009 11.603C-60.672 11.455 -61.196 8.743 -61.4 8.2C-62.422 5.474 -71.4 4 -71.4 4C-71.627 5.365 -71.682 6.961 -71.576 8.599C-71.576 8.599 -66.708 14.118 -61.009 11.603z"/> - <path fill="#659900" d="M-61.009 11.403C-61.458 11.561 -61.024 8.669 -61.2 8.2C-62.222 5.474 -71.4 3.9 -71.4 3.9C-71.627 5.265 -71.682 6.861 -71.576 8.499C-71.576 8.499 -67.308 13.618 -61.009 11.403z"/> - <path fill="#000000" d="M-65.4 11.546C-66.025 11.546 -66.531 10.406 -66.531 9C-66.531 7.595 -66.025 6.455 -65.4 6.455C-64.775 6.455 -64.268 7.595 -64.268 9C-64.268 10.406 -64.775 11.546 -65.4 11.546z"/> - <path fill="#000000" d="M-65.4 9z"/> - <path fill="#000000" d="M-111 109.601C-111 109.601 -116.6 119.601 -91.8 113.601C-91.8 113.601 -77.8 112.401 -75.4 110.001C-74.2 110.801 -65.834 113.734 -63 114.401C-56.2 116.001 -47.8 106 -47.8 106C-47.8 106 -43.2 95.5 -40.4 95.5C-37.6 95.5 -40.8 97.1 -40.8 97.1C-40.8 97.1 -47.4 107.201 -47 108.801C-47 108.801 -52.2 128.801 -68.2 129.601C-68.2 129.601 -84.35 130.551 -83 136.401C-83 136.401 -74.2 134.001 -71.8 136.401C-71.8 136.401 -61 136.001 -69 142.401L-75.8 154.001C-75.8 154.001 -75.66 157.919 -85.8 154.401C-95.6 151.001 -105.9 138.101 -105.9 138.101C-105.9 138.101 -121.85 123.551 -111 109.601z"/> - <path fill="#e59999" d="M-112.2 113.601C-112.2 113.601 -114.2 123.201 -77.4 112.801C-77.4 112.801 -73 112.801 -70.6 113.601C-68.2 114.401 -56.2 117.201 -54.2 116.001C-54.2 116.001 -61.4 129.601 -73 128.001C-73 128.001 -86.2 129.601 -85.8 134.401C-85.8 134.401 -81.8 141.601 -77 144.001C-77 144.001 -74.2 146.401 -74.6 149.601C-75 152.801 -77.8 154.401 -79.8 155.201C-81.8 156.001 -85 152.801 -86.6 152.801C-88.2 152.801 -96.6 146.401 -101 141.601C-105.4 136.801 -113.8 124.801 -113.4 122.001C-113 119.201 -112.2 113.601 -112.2 113.601z"/> - <path fill="#b26565" d="M-109 131.051C-106.4 135.001 -103.2 139.201 -101 141.601C-96.6 146.401 -88.2 152.801 -86.6 152.801C-85 152.801 -81.8 156.001 -79.8 155.201C-77.8 154.401 -75 152.801 -74.6 149.601C-74.2 146.401 -77 144.001 -77 144.001C-80.066 142.468 -82.806 138.976 -84.385 136.653C-84.385 136.653 -84.2 139.201 -89.4 138.401C-94.6 137.601 -99.8 134.801 -101.4 131.601C-103 128.401 -105.4 126.001 -103.8 129.601C-102.2 133.201 -99.8 136.801 -98.2 137.201C-96.6 137.601 -97 138.801 -99.4 138.401C-101.8 138.001 -104.6 137.601 -109 132.401z"/> - <path fill="#992600" d="M-111.6 110.001C-111.6 110.001 -109.8 96.4 -108.6 92.4C-108.6 92.4 -109.4 85.6 -107 81.4C-104.6 77.2 -102.6 71 -99.6 65.6C-96.6 60.2 -96.4 56.2 -92.4 54.6C-88.4 53 -82.4 44.4 -79.6 43.4C-76.8 42.4 -77 43.2 -77 43.2C-77 43.2 -70.2 28.4 -56.6 32.4C-56.6 32.4 -72.8 29.6 -57 20.2C-57 20.2 -61.8 21.3 -58.5 14.3C-56.299 9.632 -56.8 16.4 -67.8 28.2C-67.8 28.2 -72.8 36.8 -78 39.8C-83.2 42.8 -95.2 49.8 -96.4 53.6C-97.6 57.4 -100.8 63.2 -102.8 64.8C-104.8 66.4 -107.6 70.6 -108 74C-108 74 -109.2 78 -110.6 79.2C-112 80.4 -112.2 83.6 -112.2 85.6C-112.2 87.6 -114.2 90.4 -114 92.8C-114 92.8 -113.2 111.801 -113.6 113.801L-111.6 110.001z"/> - <path fill="#ffffff" d="M-120.2 114.601C-120.2 114.601 -122.2 113.201 -126.6 119.201C-126.6 119.201 -119.3 152.201 -119.3 153.601C-119.3 153.601 -118.2 151.501 -119.5 144.301C-120.8 137.101 -121.7 124.401 -121.7 124.401L-120.2 114.601z"/> - <path fill="#992600" d="M-98.6 54C-98.6 54 -116.2 57.2 -115.8 86.4L-116.6 111.201C-116.6 111.201 -117.8 85.6 -119 84C-120.2 82.4 -116.2 71.2 -119.4 77.2C-119.4 77.2 -133.4 91.2 -125.4 112.401C-125.4 112.401 -123.9 115.701 -126.9 111.101C-126.9 111.101 -131.5 98.5 -130.4 92.1C-130.4 92.1 -130.2 89.9 -128.3 87.1C-128.3 87.1 -119.7 75.4 -117 73.1C-117 73.1 -115.2 58.7 -99.8 53.5C-99.8 53.5 -94.1 51.2 -98.6 54z"/> - <path fill="#000000" d="M40.8 -12.2C41.46 -12.554 41.451 -13.524 42.031 -13.697C43.18 -14.041 43.344 -15.108 43.862 -15.892C44.735 -17.211 44.928 -18.744 45.51 -20.235C45.782 -20.935 45.809 -21.89 45.496 -22.55C44.322 -25.031 43.62 -27.48 42.178 -29.906C41.91 -30.356 41.648 -31.15 41.447 -31.748C40.984 -33.132 39.727 -34.123 38.867 -35.443C38.579 -35.884 39.104 -36.809 38.388 -36.893C37.491 -36.998 36.042 -37.578 35.809 -36.552C35.221 -33.965 36.232 -31.442 37.2 -29C36.418 -28.308 36.752 -27.387 36.904 -26.62C37.614 -23.014 36.416 -19.662 35.655 -16.188C35.632 -16.084 35.974 -15.886 35.946 -15.824C34.724 -13.138 33.272 -10.693 31.453 -8.312C30.695 -7.32 29.823 -6.404 29.326 -5.341C28.958 -4.554 28.55 -3.588 28.8 -2.6C25.365 0.18 23.115 4.025 20.504 7.871C20.042 8.551 20.333 9.76 20.884 10.029C21.697 10.427 22.653 9.403 23.123 8.557C23.512 7.859 23.865 7.209 24.356 6.566C24.489 6.391 24.31 5.972 24.445 5.851C27.078 3.504 28.747 0.568 31.2 -1.8C33.15 -2.129 34.687 -3.127 36.435 -4.14C36.743 -4.319 37.267 -4.07 37.557 -4.265C39.31 -5.442 39.308 -7.478 39.414 -9.388C39.464 -10.272 39.66 -11.589 40.8 -12.2z"/> - <path fill="#000000" d="M31.959 -16.666C32.083 -16.743 31.928 -17.166 32.037 -17.382C32.199 -17.706 32.602 -17.894 32.764 -18.218C32.873 -18.434 32.71 -18.814 32.846 -18.956C35.179 -21.403 35.436 -24.427 34.4 -27.4C35.424 -28.02 35.485 -29.282 35.06 -30.129C34.207 -31.829 34.014 -33.755 33.039 -35.298C32.237 -36.567 30.659 -37.811 29.288 -36.508C28.867 -36.108 28.546 -35.321 28.824 -34.609C28.888 -34.446 29.173 -34.3 29.146 -34.218C29.039 -33.894 28.493 -33.67 28.487 -33.398C28.457 -31.902 27.503 -30.391 28.133 -29.062C28.905 -27.433 29.724 -25.576 30.4 -23.8C29.166 -21.684 30.199 -19.235 28.446 -17.358C28.31 -17.212 28.319 -16.826 28.441 -16.624C28.733 -16.138 29.139 -15.732 29.625 -15.44C29.827 -15.319 30.175 -15.317 30.375 -15.441C30.953 -15.803 31.351 -16.29 31.959 -16.666z"/> - <path fill="#000000" d="M94.771 -26.977C96.16 -25.185 96.45 -22.39 94.401 -21C94.951 -17.691 98.302 -19.67 100.401 -20.2C100.292 -20.588 100.519 -20.932 100.802 -20.937C101.859 -20.952 102.539 -21.984 103.601 -21.8C104.035 -23.357 105.673 -24.059 106.317 -25.439C108.043 -29.134 107.452 -33.407 104.868 -36.653C104.666 -36.907 104.883 -37.424 104.759 -37.786C104.003 -39.997 101.935 -40.312 100.001 -41C98.824 -44.875 98.163 -48.906 96.401 -52.6C94.787 -52.85 94.089 -54.589 92.752 -55.309C91.419 -56.028 90.851 -54.449 90.892 -53.403C90.899 -53.198 91.351 -52.974 91.181 -52.609C91.105 -52.445 90.845 -52.334 90.845 -52.2C90.846 -52.065 91.067 -51.934 91.201 -51.8C90.283 -50.98 88.86 -50.503 88.565 -49.358C87.611 -45.648 90.184 -42.523 91.852 -39.322C92.443 -38.187 91.707 -36.916 90.947 -35.708C90.509 -35.013 90.617 -33.886 90.893 -33.03C91.645 -30.699 93.236 -28.96 94.771 -26.977z"/> - <path fill="#000000" d="M57.611 -8.591C56.124 -6.74 52.712 -4.171 55.629 -2.243C55.823 -2.114 56.193 -2.11 56.366 -2.244C58.387 -3.809 60.39 -4.712 62.826 -5.294C62.95 -5.323 63.224 -4.856 63.593 -5.017C65.206 -5.72 67.216 -5.662 68.4 -7C72.167 -6.776 75.732 -7.892 79.123 -9.2C80.284 -9.648 81.554 -10.207 82.755 -10.709C84.131 -11.285 85.335 -12.213 86.447 -13.354C86.58 -13.49 86.934 -13.4 87.201 -13.4C87.161 -14.263 88.123 -14.39 88.37 -15.012C88.462 -15.244 88.312 -15.64 88.445 -15.742C90.583 -17.372 91.503 -19.39 90.334 -21.767C90.049 -22.345 89.8 -22.963 89.234 -23.439C88.149 -24.35 87.047 -23.496 86 -23.8C85.841 -23.172 85.112 -23.344 84.726 -23.146C83.867 -22.707 82.534 -23.292 81.675 -22.854C80.313 -22.159 79.072 -21.99 77.65 -21.613C77.338 -21.531 76.56 -21.627 76.4 -21C76.266 -21.134 76.118 -21.368 76.012 -21.346C74.104 -20.95 72.844 -20.736 71.543 -19.044C71.44 -18.911 70.998 -19.09 70.839 -18.955C69.882 -18.147 69.477 -16.913 68.376 -16.241C68.175 -16.118 67.823 -16.286 67.629 -16.157C66.983 -15.726 66.616 -15.085 65.974 -14.638C65.645 -14.409 65.245 -14.734 65.277 -14.99C65.522 -16.937 66.175 -18.724 65.6 -20.6C67.677 -23.12 70.194 -25.069 72 -27.8C72.015 -29.966 72.707 -32.112 72.594 -34.189C72.584 -34.382 72.296 -35.115 72.17 -35.462C71.858 -36.316 72.764 -37.382 71.92 -38.106C70.516 -39.309 69.224 -38.433 68.4 -37C66.562 -36.61 64.496 -35.917 62.918 -37.151C61.911 -37.938 61.333 -38.844 60.534 -39.9C59.549 -41.202 59.884 -42.638 59.954 -44.202C59.96 -44.33 59.645 -44.466 59.645 -44.6C59.646 -44.735 59.866 -44.866 60 -45C59.294 -45.626 59.019 -46.684 58 -47C58.305 -48.092 57.629 -48.976 56.758 -49.278C54.763 -49.969 53.086 -48.057 51.194 -47.984C50.68 -47.965 50.213 -49.003 49.564 -49.328C49.132 -49.544 48.428 -49.577 48.066 -49.311C47.378 -48.807 46.789 -48.693 46.031 -48.488C44.414 -48.052 43.136 -46.958 41.656 -46.103C40.171 -45.246 39.216 -43.809 38.136 -42.489C37.195 -41.337 37.059 -38.923 38.479 -38.423C40.322 -37.773 41.626 -40.476 43.592 -40.15C43.904 -40.099 44.11 -39.788 44 -39.4C44.389 -39.291 44.607 -39.52 44.8 -39.8C45.658 -38.781 46.822 -38.444 47.76 -37.571C48.73 -36.667 50.476 -37.085 51.491 -36.088C53.02 -34.586 52.461 -31.905 54.4 -30.6C53.814 -29.287 53.207 -28.01 52.872 -26.583C52.59 -25.377 53.584 -24.18 54.795 -24.271C56.053 -24.365 56.315 -25.124 56.8 -26.2C57.067 -25.933 57.536 -25.636 57.495 -25.42C57.038 -23.033 56.011 -21.04 55.553 -18.609C55.494 -18.292 55.189 -18.09 54.8 -18.2C54.332 -14.051 50.28 -11.657 47.735 -8.492C47.332 -7.99 47.328 -6.741 47.737 -6.338C49.14 -4.951 51.1 -6.497 52.8 -7C53.013 -8.206 53.872 -9.148 55.204 -9.092C55.46 -9.082 55.695 -9.624 56.019 -9.754C56.367 -9.892 56.869 -9.668 57.155 -9.866C58.884 -11.061 60.292 -12.167 62.03 -13.356C62.222 -13.487 62.566 -13.328 62.782 -13.436C63.107 -13.598 63.294 -13.985 63.617 -14.17C63.965 -14.37 64.207 -14.08 64.4 -13.8C63.754 -13.451 63.75 -12.494 63.168 -12.292C62.393 -12.024 61.832 -11.511 61.158 -11.064C60.866 -10.871 60.207 -11.119 60.103 -10.94C59.505 -9.912 58.321 -9.474 57.611 -8.591z"/> - <path fill="#000000" d="M2.2 -58C2.2 -58 -7.038 -60.872 -18.2 -35.2C-18.2 -35.2 -20.6 -30 -23 -28C-25.4 -26 -36.6 -22.4 -38.6 -18.4L-49 -2.4C-49 -2.4 -34.2 -18.4 -31 -20.8C-31 -20.8 -23 -29.2 -26.2 -22.4C-26.2 -22.4 -40.2 -11.6 -39 -2.4C-39 -2.4 -44.6 12 -45.4 14C-45.4 14 -29.4 -18 -27 -19.2C-24.6 -20.4 -23.4 -20.4 -24.6 -16.8C-25.8 -13.2 -26.2 3.2 -29 5.2C-29 5.2 -21 -15.2 -21.8 -18.4C-21.8 -18.4 -18.6 -22 -16.2 -16.8L-17.4 -0.8L-13 11.2C-13 11.2 -15.4 0 -13.8 -15.6C-13.8 -15.6 -15.8 -26 -11.8 -20.4C-7.8 -14.8 1.8 -8.8 1.8 -4C1.8 -4 -3.4 -21.6 -12.6 -26.4L-16.6 -20.4L-17.8 -22.4C-17.8 -22.4 -21.4 -23.2 -17 -30C-12.6 -36.8 -13 -37.6 -13 -37.6C-13 -37.6 -6.6 -30.4 -5 -30.4C-5 -30.4 8.2 -38 9.4 -13.6C9.4 -13.6 16.2 -28 7 -34.8C7 -34.8 -7.8 -36.8 -6.6 -42L0.6 -54.4C4.2 -59.6 2.6 -56.8 2.6 -56.8z"/> - <path fill="#000000" d="M-17.8 -41.6C-17.8 -41.6 -30.6 -41.6 -33.8 -36.4L-41 -26.8C-41 -26.8 -23.8 -36.8 -19.8 -38C-15.8 -39.2 -17.8 -41.6 -17.8 -41.6z"/> - <path fill="#000000" d="M-57.8 -35.2C-57.8 -35.2 -59.8 -34 -60.2 -31.2C-60.6 -28.4 -63 -28 -62.2 -25.2C-61.4 -22.4 -59.4 -20 -59.4 -24C-59.4 -28 -57.8 -30 -57 -31.2C-56.2 -32.4 -54.6 -36.8 -57.8 -35.2z"/> - <path fill="#000000" d="M-66.6 26C-66.6 26 -75 22 -78.2 18.4C-81.4 14.8 -80.948 19.966 -85.8 19.6C-91.647 19.159 -90.6 3.2 -90.6 3.2L-94.6 10.8C-94.6 10.8 -95.8 25.2 -87.8 22.8C-83.893 21.628 -82.6 23.2 -84.2 24C-85.8 24.8 -78.6 25.2 -81.4 26.8C-84.2 28.4 -69.8 23.2 -72.2 33.6L-66.6 26z"/> - <path fill="#000000" d="M-79.2 40.4C-79.2 40.4 -94.6 44.8 -98.2 35.2C-98.2 35.2 -103 37.6 -100.8 40.6C-98.6 43.6 -97.4 44 -97.4 44C-97.4 44 -92 45.2 -92.6 46C-93.2 46.8 -95.6 50.2 -95.6 50.2C-95.6 50.2 -85.4 44.2 -79.2 40.4z"/> - <path fill="#ffffff" d="M149.201 118.601C148.774 120.735 147.103 121.536 145.201 122.201C143.284 121.243 140.686 118.137 138.801 120.201C138.327 119.721 137.548 119.661 137.204 118.999C136.739 118.101 137.011 117.055 136.669 116.257C136.124 114.985 135.415 113.619 135.601 112.201C137.407 111.489 138.002 109.583 137.528 107.82C137.459 107.563 137.03 107.366 137.23 107.017C137.416 106.694 137.734 106.467 138.001 106.2C137.866 106.335 137.721 106.568 137.61 106.548C137 106.442 137.124 105.805 137.254 105.418C137.839 103.672 139.853 103.408 141.201 104.6C141.457 104.035 141.966 104.229 142.401 104.2C142.351 103.621 142.759 103.094 142.957 102.674C143.475 101.576 145.104 102.682 145.901 102.07C146.977 101.245 148.04 100.546 149.118 101.149C150.927 102.162 152.636 103.374 153.835 105.115C154.41 105.949 154.65 107.23 154.592 108.188C154.554 108.835 153.173 108.483 152.83 109.412C152.185 111.16 154.016 111.679 154.772 113.017C154.97 113.366 154.706 113.67 154.391 113.768C153.98 113.896 153.196 113.707 153.334 114.16C154.306 117.353 151.55 118.031 149.201 118.601z"/> - <path fill="#ffffff" d="M139.6 138.201C139.593 136.463 137.992 134.707 139.201 133.001C139.336 133.135 139.467 133.356 139.601 133.356C139.736 133.356 139.867 133.135 140.001 133.001C141.496 135.217 145.148 136.145 145.006 138.991C144.984 139.438 143.897 140.356 144.801 141.001C142.988 142.349 142.933 144.719 142.001 146.601C140.763 146.315 139.551 145.952 138.401 145.401C138.753 143.915 138.636 142.231 139.456 140.911C139.89 140.213 139.603 139.134 139.6 138.201z"/> - <path fill="#cccccc" d="M-26.6 129.201C-26.6 129.201 -43.458 139.337 -29.4 124.001C-20.6 114.401 -10.6 108.801 -10.6 108.801C-10.6 108.801 -0.2 104.4 3.4 103.2C7 102 22.2 96.8 25.4 96.4C28.6 96 38.2 92 45 96C51.8 100 59.8 104.4 59.8 104.4C59.8 104.4 43.4 96 39.8 98.4C36.2 100.8 29 100.4 23 103.6C23 103.6 8.2 108.001 5 110.001C1.8 112.001 -8.6 123.601 -10.2 122.801C-11.8 122.001 -9.8 121.601 -8.6 118.801C-7.4 116.001 -9.4 114.401 -17.4 120.801C-25.4 127.201 -26.6 129.201 -26.6 129.201z"/> - <path fill="#000000" d="M-19.195 123.234C-19.195 123.234 -17.785 110.194 -9.307 111.859C-9.307 111.859 -1.081 107.689 1.641 105.721C1.641 105.721 9.78 104.019 11.09 103.402C29.569 94.702 44.288 99.221 44.835 98.101C45.381 96.982 65.006 104.099 68.615 108.185C69.006 108.628 58.384 102.588 48.686 100.697C40.413 99.083 18.811 100.944 7.905 106.48C4.932 107.989 -4.013 113.773 -6.544 113.662C-9.075 113.55 -19.195 123.234 -19.195 123.234z"/> - <path fill="#cccccc" d="M-23 148.801C-23 148.801 -38.2 146.401 -21.4 144.801C-21.4 144.801 -3.4 142.801 0.6 137.601C0.6 137.601 14.2 128.401 17 128.001C19.8 127.601 49.8 120.401 50.2 118.001C50.6 115.601 56.2 115.601 57.8 116.401C59.4 117.201 58.6 118.401 55.8 119.201C53 120.001 21.8 136.401 15.4 137.601C9 138.801 -2.6 146.401 -7.4 147.601C-12.2 148.801 -23 148.801 -23 148.801z"/> - <path fill="#000000" d="M-3.48 141.403C-3.48 141.403 -12.062 140.574 -3.461 139.755C-3.461 139.755 5.355 136.331 7.403 133.668C7.403 133.668 14.367 128.957 15.8 128.753C17.234 128.548 31.194 124.861 31.399 123.633C31.604 122.404 65.67 109.823 70.09 113.013C73.001 115.114 63.1 113.437 53.466 117.847C52.111 118.467 18.258 133.054 14.981 133.668C11.704 134.283 5.765 138.174 3.307 138.788C0.85 139.403 -3.48 141.403 -3.48 141.403z"/> - <path fill="#000000" d="M-11.4 143.601C-11.4 143.601 -6.2 143.201 -7.4 144.801C-8.6 146.401 -11 145.601 -11 145.601L-11.4 143.601z"/> - <path fill="#000000" d="M-18.6 145.201C-18.6 145.201 -13.4 144.801 -14.6 146.401C-15.8 148.001 -18.2 147.201 -18.2 147.201L-18.6 145.201z"/> - <path fill="#000000" d="M-29 146.801C-29 146.801 -23.8 146.401 -25 148.001C-26.2 149.601 -28.6 148.801 -28.6 148.801L-29 146.801z"/> - <path fill="#000000" d="M-36.6 147.601C-36.6 147.601 -31.4 147.201 -32.6 148.801C-33.8 150.401 -36.2 149.601 -36.2 149.601L-36.6 147.601z"/> - <path fill="#000000" d="M1.8 108.001C1.8 108.001 6.2 108.001 5 109.601C3.8 111.201 0.6 110.801 0.6 110.801L1.8 108.001z"/> - <path fill="#000000" d="M-8.2 113.601C-8.2 113.601 -1.694 111.46 -4.2 114.801C-5.4 116.401 -7.8 115.601 -7.8 115.601L-8.2 113.601z"/> - <path fill="#000000" d="M-19.4 118.401C-19.4 118.401 -14.2 118.001 -15.4 119.601C-16.6 121.201 -19 120.401 -19 120.401L-19.4 118.401z"/> - <path fill="#000000" d="M-27 124.401C-27 124.401 -21.8 124.001 -23 125.601C-24.2 127.201 -26.6 126.401 -26.6 126.401L-27 124.401z"/> - <path fill="#000000" d="M-33.8 129.201C-33.8 129.201 -28.6 128.801 -29.8 130.401C-31 132.001 -33.4 131.201 -33.4 131.201L-33.8 129.201z"/> - <path fill="#000000" d="M5.282 135.598C5.282 135.598 12.203 135.066 10.606 137.195C9.009 139.325 5.814 138.26 5.814 138.26L5.282 135.598z"/> - <path fill="#000000" d="M15.682 130.798C15.682 130.798 22.603 130.266 21.006 132.395C19.409 134.525 16.214 133.46 16.214 133.46L15.682 130.798z"/> - <path fill="#000000" d="M26.482 126.398C26.482 126.398 33.403 125.866 31.806 127.995C30.209 130.125 27.014 129.06 27.014 129.06L26.482 126.398z"/> - <path fill="#000000" d="M36.882 121.598C36.882 121.598 43.803 121.066 42.206 123.195C40.609 125.325 37.414 124.26 37.414 124.26L36.882 121.598z"/> - <path fill="#000000" d="M9.282 103.598C9.282 103.598 16.203 103.066 14.606 105.195C13.009 107.325 9.014 107.06 9.014 107.06L9.282 103.598z"/> - <path fill="#000000" d="M19.282 100.398C19.282 100.398 26.203 99.866 24.606 101.995C23.009 104.125 18.614 103.86 18.614 103.86L19.282 100.398z"/> - <path fill="#000000" d="M-3.4 140.401C-3.4 140.401 1.8 140.001 0.6 141.601C-0.6 143.201 -3 142.401 -3 142.401L-3.4 140.401z"/> - <path fill="#992600" d="M-76.6 41.2C-76.6 41.2 -81 50 -81.4 53.2C-81.4 53.2 -80.6 44.4 -79.4 42.4C-78.2 40.4 -76.6 41.2 -76.6 41.2z"/> - <path fill="#992600" d="M-95 55.2C-95 55.2 -98.2 69.6 -97.8 72.4C-97.8 72.4 -99 60.8 -98.6 59.6C-98.2 58.4 -95 55.2 -95 55.2z"/> - <path fill="#cccccc" d="M-74.2 -19.4L-74.4 -16.2L-76.6 -16C-76.6 -16 -62.4 -3.4 -61.8 4.2C-61.8 4.2 -61 -4 -74.2 -19.4z"/> - <path fill="#000000" d="M-70.216 -18.135C-70.647 -18.551 -70.428 -19.296 -70.836 -19.556C-71.645 -20.072 -69.538 -20.129 -69.766 -20.845C-70.149 -22.051 -69.962 -22.072 -70.084 -23.348C-70.141 -23.946 -69.553 -25.486 -69.168 -25.926C-67.722 -27.578 -69.046 -30.51 -67.406 -32.061C-67.102 -32.35 -66.726 -32.902 -66.441 -33.32C-65.782 -34.283 -64.598 -34.771 -63.648 -35.599C-63.33 -35.875 -63.531 -36.702 -62.962 -36.61C-62.248 -36.495 -61.007 -36.625 -61.052 -35.784C-61.165 -33.664 -62.494 -31.944 -63.774 -30.276C-63.323 -29.572 -63.781 -28.937 -64.065 -28.38C-65.4 -25.76 -65.211 -22.919 -65.385 -20.079C-65.39 -19.994 -65.697 -19.916 -65.689 -19.863C-65.336 -17.528 -64.752 -15.329 -63.873 -13.1C-63.507 -12.17 -63.036 -11.275 -62.886 -10.348C-62.775 -9.662 -62.672 -8.829 -63.08 -8.124C-61.045 -5.234 -62.354 -2.583 -61.185 0.948C-60.978 1.573 -59.286 3.487 -59.749 3.326C-62.262 2.455 -62.374 2.057 -62.551 1.304C-62.697 0.681 -63.027 -0.696 -63.264 -1.298C-63.328 -1.462 -63.499 -3.346 -63.577 -3.468C-65.09 -5.85 -63.732 -5.674 -65.102 -8.032C-66.53 -8.712 -67.496 -9.816 -68.619 -10.978C-68.817 -11.182 -67.674 -11.906 -67.855 -12.119C-68.947 -13.408 -70.1 -14.175 -69.764 -15.668C-69.609 -16.358 -69.472 -17.415 -70.216 -18.135z"/> - <path fill="#000000" d="M-73.8 -16.4C-73.8 -16.4 -73.4 -9.6 -71 -8C-68.6 -6.4 -69.8 -7.2 -73 -8.4C-76.2 -9.6 -75 -10.4 -75 -10.4C-75 -10.4 -77.8 -10 -75.4 -8C-73 -6 -69.4 -3.6 -71 -3.6C-72.6 -3.6 -80.2 -7.6 -80.2 -10.4C-80.2 -13.2 -81.2 -17.3 -81.2 -17.3C-81.2 -17.3 -80.1 -18.1 -75.3 -18C-75.3 -18 -73.9 -17.3 -73.8 -16.4z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-74.6 2.2C-74.6 2.2 -83.12 -0.591 -101.6 2.8C-101.6 2.8 -92.569 0.722 -73.8 3C-63.5 4.25 -74.6 2.2 -74.6 2.2z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-72.502 2.129C-72.502 2.129 -80.748 -1.389 -99.453 0.392C-99.453 0.392 -90.275 -0.897 -71.774 2.995C-61.62 5.131 -72.502 2.129 -72.502 2.129z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-70.714 2.222C-70.714 2.222 -78.676 -1.899 -97.461 -1.514C-97.461 -1.514 -88.213 -2.118 -70.052 3.14C-60.086 6.025 -70.714 2.222 -70.714 2.222z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-69.444 2.445C-69.444 2.445 -76.268 -1.862 -93.142 -2.96C-93.142 -2.96 -84.803 -2.79 -68.922 3.319C-60.206 6.672 -69.444 2.445 -69.444 2.445z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M45.84 12.961C45.84 12.961 44.91 13.605 45.124 12.424C45.339 11.243 73.547 -1.927 77.161 -1.677C77.161 -1.677 46.913 11.529 45.84 12.961z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M42.446 13.6C42.446 13.6 41.57 14.315 41.691 13.121C41.812 11.927 68.899 -3.418 72.521 -3.452C72.521 -3.452 43.404 12.089 42.446 13.6z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M39.16 14.975C39.16 14.975 38.332 15.747 38.374 14.547C38.416 13.348 58.233 -2.149 68.045 -4.023C68.045 -4.023 50.015 4.104 39.16 14.975z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M36.284 16.838C36.284 16.838 35.539 17.532 35.577 16.453C35.615 15.373 53.449 1.426 62.28 -0.26C62.28 -0.26 46.054 7.054 36.284 16.838z"/> - <path fill="#cccccc" d="M4.6 164.801C4.6 164.801 -10.6 162.401 6.2 160.801C6.2 160.801 24.2 158.801 28.2 153.601C28.2 153.601 41.8 144.401 44.6 144.001C47.4 143.601 63.8 140.001 64.2 137.601C64.6 135.201 70.6 132.801 72.2 133.601C73.8 134.401 73.8 143.601 71 144.401C68.2 145.201 49.4 152.401 43 153.601C36.6 154.801 25 162.401 20.2 163.601C15.4 164.801 4.6 164.801 4.6 164.801z"/> - <path fill="#000000" d="M77.6 127.401C77.6 127.401 74.6 129.001 73.4 131.601C73.4 131.601 67 142.201 52.8 145.401C52.8 145.401 29.8 154.401 22 156.401C22 156.401 8.6 161.401 1.2 160.601C1.2 160.601 -5.8 160.801 0.4 162.401C0.4 162.401 20.6 160.401 24 158.601C24 158.601 39.6 153.401 42.6 150.801C45.6 148.201 63.8 143.201 66 141.201C68.2 139.201 78 130.801 77.6 127.401z"/> - <path fill="#000000" d="M18.882 158.911C18.882 158.911 24.111 158.685 22.958 160.234C21.805 161.784 19.357 160.91 19.357 160.91L18.882 158.911z"/> - <path fill="#000000" d="M11.68 160.263C11.68 160.263 16.908 160.037 15.756 161.586C14.603 163.136 12.155 162.263 12.155 162.263L11.68 160.263z"/> - <path fill="#000000" d="M1.251 161.511C1.251 161.511 6.48 161.284 5.327 162.834C4.174 164.383 1.726 163.51 1.726 163.51L1.251 161.511z"/> - <path fill="#000000" d="M-6.383 162.055C-6.383 162.055 -1.154 161.829 -2.307 163.378C-3.46 164.928 -5.908 164.054 -5.908 164.054L-6.383 162.055z"/> - <path fill="#000000" d="M35.415 151.513C35.415 151.513 42.375 151.212 40.84 153.274C39.306 155.336 36.047 154.174 36.047 154.174L35.415 151.513z"/> - <path fill="#000000" d="M45.73 147.088C45.73 147.088 51.689 143.787 51.155 148.849C50.885 151.405 46.362 149.749 46.362 149.749L45.73 147.088z"/> - <path fill="#000000" d="M54.862 144.274C54.862 144.274 62.021 140.573 60.287 146.035C59.509 148.485 55.493 146.935 55.493 146.935L54.862 144.274z"/> - <path fill="#000000" d="M64.376 139.449C64.376 139.449 68.735 134.548 69.801 141.21C70.207 143.748 65.008 142.11 65.008 142.11L64.376 139.449z"/> - <path fill="#000000" d="M26.834 155.997C26.834 155.997 32.062 155.77 30.91 157.32C29.757 158.869 27.308 157.996 27.308 157.996L26.834 155.997z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M62.434 34.603C62.434 34.603 61.708 35.268 61.707 34.197C61.707 33.127 79.191 19.863 88.034 18.479C88.034 18.479 71.935 25.208 62.434 34.603z"/> - <path fill="#000000" d="M65.4 98.4C65.4 98.4 87.401 120.801 96.601 124.401C96.601 124.401 105.801 135.601 101.801 161.601C101.801 161.601 98.601 169.201 95.401 148.401C95.401 148.401 98.601 123.201 87.401 139.201C87.401 139.201 79 129.301 85.4 129.601C85.4 129.601 88.601 131.601 89.001 130.001C89.401 128.401 81.4 114.801 64.2 100.4C47 86 65.4 98.4 65.4 98.4z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M7 137.201C7 137.201 6.8 135.401 8.6 136.201C10.4 137.001 104.601 143.201 136.201 167.201C136.201 167.201 91.001 144.001 7 137.201z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M17.4 132.801C17.4 132.801 17.2 131.001 19 131.801C20.8 132.601 157.401 131.601 181.001 164.001C181.001 164.001 159.001 138.801 17.4 132.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M29 128.801C29 128.801 28.8 127.001 30.6 127.801C32.4 128.601 205.801 115.601 229.401 148.001C229.401 148.001 219.801 122.401 29 128.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M39 124.001C39 124.001 38.8 122.201 40.6 123.001C42.4 123.801 164.601 85.2 188.201 117.601C188.201 117.601 174.801 93 39 124.001z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-19 146.801C-19 146.801 -19.2 145.001 -17.4 145.801C-15.6 146.601 2.2 148.801 4.2 187.601C4.2 187.601 -3 145.601 -19 146.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-27.8 148.401C-27.8 148.401 -28 146.601 -26.2 147.401C-24.4 148.201 -10.2 143.601 -13 182.401C-13 182.401 -11.8 147.201 -27.8 148.401z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-35.8 148.801C-35.8 148.801 -36 147.001 -34.2 147.801C-32.4 148.601 -17 149.201 -29.4 171.601C-29.4 171.601 -19.8 147.601 -35.8 148.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M11.526 104.465C11.526 104.465 11.082 106.464 12.631 105.247C28.699 92.622 61.141 33.72 116.826 28.086C116.826 28.086 78.518 15.976 11.526 104.465z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M22.726 102.665C22.726 102.665 21.363 101.472 23.231 100.847C25.099 100.222 137.541 27.72 176.826 35.686C176.826 35.686 149.719 28.176 22.726 102.665z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M1.885 108.767C1.885 108.767 1.376 110.366 3.087 109.39C12.062 104.27 15.677 47.059 59.254 45.804C59.254 45.804 26.843 31.09 1.885 108.767z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-18.038 119.793C-18.038 119.793 -19.115 121.079 -17.162 120.825C-6.916 119.493 14.489 78.222 58.928 83.301C58.928 83.301 26.962 68.955 -18.038 119.793z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-6.8 113.667C-6.8 113.667 -7.611 115.136 -5.742 114.511C4.057 111.237 17.141 66.625 61.729 63.078C61.729 63.078 27.603 55.135 -6.8 113.667z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-25.078 124.912C-25.078 124.912 -25.951 125.954 -24.369 125.748C-16.07 124.669 1.268 91.24 37.264 95.354C37.264 95.354 11.371 83.734 -25.078 124.912z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-32.677 130.821C-32.677 130.821 -33.682 131.866 -32.091 131.748C-27.923 131.439 2.715 98.36 21.183 113.862C21.183 113.862 9.168 95.139 -32.677 130.821z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M36.855 98.898C36.855 98.898 35.654 97.543 37.586 97.158C39.518 96.774 160.221 39.061 198.184 51.927C198.184 51.927 172.243 41.053 36.855 98.898z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M3.4 163.201C3.4 163.201 3.2 161.401 5 162.201C6.8 163.001 22.2 163.601 9.8 186.001C9.8 186.001 19.4 162.001 3.4 163.201z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M13.8 161.601C13.8 161.601 13.6 159.801 15.4 160.601C17.2 161.401 35 163.601 37 202.401C37 202.401 29.8 160.401 13.8 161.601z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M20.6 160.001C20.6 160.001 20.4 158.201 22.2 159.001C24 159.801 48.6 163.201 72.2 195.601C72.2 195.601 36.6 158.801 20.6 160.001z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M28.225 157.972C28.225 157.972 27.788 156.214 29.678 156.768C31.568 157.322 52.002 155.423 90.099 189.599C90.099 189.599 43.924 154.656 28.225 157.972z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M38.625 153.572C38.625 153.572 38.188 151.814 40.078 152.368C41.968 152.922 76.802 157.423 128.499 192.399C128.499 192.399 54.324 150.256 38.625 153.572z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-1.8 142.001C-1.8 142.001 -2 140.201 -0.2 141.001C1.6 141.801 55 144.401 85.4 171.201C85.4 171.201 50.499 146.426 -1.8 142.001z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-11.8 146.001C-11.8 146.001 -12 144.201 -10.2 145.001C-8.4 145.801 16.2 149.201 39.8 181.601C39.8 181.601 4.2 144.801 -11.8 146.001z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M49.503 148.962C49.503 148.962 48.938 147.241 50.864 147.655C52.79 148.068 87.86 150.004 141.981 181.098C141.981 181.098 64.317 146.704 49.503 148.962z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M57.903 146.562C57.903 146.562 57.338 144.841 59.264 145.255C61.19 145.668 96.26 147.604 150.381 178.698C150.381 178.698 73.317 143.904 57.903 146.562z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M67.503 141.562C67.503 141.562 66.938 139.841 68.864 140.255C70.79 140.668 113.86 145.004 203.582 179.298C203.582 179.298 82.917 138.904 67.503 141.562z"/> - <path fill="#000000" d="M-43.8 148.401C-43.8 148.401 -38.6 148.001 -39.8 149.601C-41 151.201 -43.4 150.401 -43.4 150.401L-43.8 148.401z"/> - <path fill="#000000" d="M-13 162.401C-13 162.401 -7.8 162.001 -9 163.601C-10.2 165.201 -12.6 164.401 -12.6 164.401L-13 162.401z"/> - <path fill="#000000" d="M-21.8 162.001C-21.8 162.001 -16.6 161.601 -17.8 163.201C-19 164.801 -21.4 164.001 -21.4 164.001L-21.8 162.001z"/> - <path fill="#000000" d="M-117.169 150.182C-117.169 150.182 -112.124 151.505 -113.782 152.624C-115.439 153.744 -117.446 152.202 -117.446 152.202L-117.169 150.182z"/> - <path fill="#000000" d="M-115.169 140.582C-115.169 140.582 -110.124 141.905 -111.782 143.024C-113.439 144.144 -115.446 142.602 -115.446 142.602L-115.169 140.582z"/> - <path fill="#000000" d="M-122.369 136.182C-122.369 136.182 -117.324 137.505 -118.982 138.624C-120.639 139.744 -122.646 138.202 -122.646 138.202L-122.369 136.182z"/> - <path fill="#cccccc" d="M-42.6 211.201C-42.6 211.201 -44.2 211.201 -48.2 213.201C-50.2 213.201 -61.4 216.801 -67 226.801C-67 226.801 -54.6 217.201 -42.6 211.201z"/> - <path fill="#cccccc" d="M45.116 303.847C45.257 304.105 45.312 304.525 45.604 304.542C46.262 304.582 47.495 304.883 47.37 304.247C46.522 299.941 45.648 295.004 41.515 293.197C40.876 292.918 39.434 293.331 39.36 294.215C39.233 295.739 39.116 297.088 39.425 298.554C39.725 299.975 41.883 299.985 42.8 298.601C43.736 300.273 44.168 302.116 45.116 303.847z"/> - <path fill="#cccccc" d="M34.038 308.581C34.786 309.994 34.659 311.853 36.074 312.416C36.814 312.71 38.664 311.735 38.246 310.661C37.444 308.6 37.056 306.361 35.667 304.55C35.467 304.288 35.707 303.755 35.547 303.427C34.953 302.207 33.808 301.472 32.4 301.801C31.285 304.004 32.433 306.133 33.955 307.842C34.091 307.994 33.925 308.37 34.038 308.581z"/> - <path fill="#cccccc" d="M-5.564 303.391C-5.672 303.014 -5.71 302.551 -5.545 302.23C-5.014 301.197 -4.221 300.075 -4.558 299.053C-4.906 297.997 -6.022 298.179 -6.672 298.748C-7.807 299.742 -7.856 301.568 -8.547 302.927C-8.743 303.313 -8.692 303.886 -9.133 304.277C-9.607 304.698 -10.047 306.222 -9.951 306.793C-9.898 307.106 -10.081 317.014 -9.859 316.751C-9.24 316.018 -6.19 306.284 -6.121 305.392C-6.064 304.661 -5.332 304.196 -5.564 303.391z"/> - <path fill="#cccccc" d="M-31.202 296.599C-28.568 294.1 -25.778 291.139 -26.22 287.427C-26.336 286.451 -28.111 286.978 -28.298 287.824C-29.1 291.449 -31.139 294.11 -33.707 296.502C-35.903 298.549 -37.765 304.893 -38 305.401C-34.303 300.145 -32.046 297.399 -31.202 296.599z"/> - <path fill="#cccccc" d="M-44.776 290.635C-44.253 290.265 -44.555 289.774 -44.338 289.442C-43.385 287.984 -42.084 286.738 -42.066 285C-42.063 284.723 -42.441 284.414 -42.776 284.638C-43.053 284.822 -43.395 284.952 -43.503 285.082C-45.533 287.531 -46.933 290.202 -48.376 293.014C-48.559 293.371 -49.703 297.862 -49.39 297.973C-49.151 298.058 -47.431 293.877 -47.221 293.763C-45.958 293.077 -45.946 291.462 -44.776 290.635z"/> - <path fill="#cccccc" d="M-28.043 310.179C-27.599 309.31 -26.023 308.108 -26.136 307.219C-26.254 306.291 -25.786 304.848 -26.698 305.536C-27.955 306.484 -31.404 307.833 -31.674 313.641C-31.7 314.212 -28.726 311.519 -28.043 310.179z"/> - <path fill="#cccccc" d="M-13.6 293.001C-13.2 292.333 -12.492 292.806 -12.033 292.543C-11.385 292.171 -10.774 291.613 -10.482 290.964C-9.512 288.815 -7.743 286.995 -7.6 284.601C-9.091 283.196 -9.77 285.236 -10.4 286.201C-11.723 284.554 -12.722 286.428 -14.022 286.947C-14.092 286.975 -14.305 286.628 -14.38 286.655C-15.557 287.095 -16.237 288.176 -17.235 288.957C-17.406 289.091 -17.811 288.911 -17.958 289.047C-18.61 289.65 -19.583 289.975 -19.863 290.657C-20.973 293.364 -24.113 295.459 -26 303.001C-25.619 303.91 -21.488 296.359 -21.001 295.661C-20.165 294.465 -20.047 297.322 -18.771 296.656C-18.72 296.629 -18.534 296.867 -18.4 297.001C-18.206 296.721 -17.988 296.492 -17.6 296.601C-17.6 296.201 -17.734 295.645 -17.533 295.486C-16.296 294.509 -16.38 293.441 -15.6 292.201C-15.142 292.99 -14.081 292.271 -13.6 293.001z"/> - <path fill="#cccccc" d="M46.2 347.401C46.2 347.401 53.6 327.001 49.2 315.801C49.2 315.801 60.6 337.401 56 348.601C56 348.601 55.6 338.201 51.6 333.201C51.6 333.201 47.6 346.001 46.2 347.401z"/> - <path fill="#cccccc" d="M31.4 344.801C31.4 344.801 36.8 336.001 28.8 317.601C28.8 317.601 28 338.001 21.2 349.001C21.2 349.001 35.4 328.801 31.4 344.801z"/> - <path fill="#cccccc" d="M21.4 342.801C21.4 342.801 21.2 322.801 21.6 319.801C21.6 319.801 17.8 336.401 7.6 346.001C7.6 346.001 22 334.001 21.4 342.801z"/> - <path fill="#cccccc" d="M11.8 310.801C11.8 310.801 17.8 324.401 7.8 342.801C7.8 342.801 14.2 330.601 9.4 323.601C9.4 323.601 12 320.201 11.8 310.801z"/> - <path fill="#cccccc" d="M-7.4 342.401C-7.4 342.401 -8.4 326.801 -6.6 324.601C-6.6 324.601 -6.4 318.201 -6.8 317.201C-6.8 317.201 -2.8 311.001 -2.6 318.401C-2.6 318.401 -1.2 326.201 1.6 330.801C1.6 330.801 5.2 336.201 5 342.601C5 342.601 -5 312.401 -7.4 342.401z"/> - <path fill="#cccccc" d="M-11 314.801C-11 314.801 -17.6 325.601 -19.4 344.601C-19.4 344.601 -20.8 338.401 -17 324.001C-17 324.001 -12.8 308.601 -11 314.801z"/> - <path fill="#cccccc" d="M-32.8 334.601C-32.8 334.601 -27.8 329.201 -26.4 324.201C-26.4 324.201 -22.8 308.401 -29.2 317.001C-29.2 317.001 -29 325.001 -37.2 332.401C-37.2 332.401 -32.4 330.001 -32.8 334.601z"/> - <path fill="#cccccc" d="M-38.6 329.601C-38.6 329.601 -35.2 312.201 -34.4 311.401C-34.4 311.401 -32.6 308.001 -35.4 311.201C-35.4 311.201 -44.2 330.401 -48.2 337.001C-48.2 337.001 -40.2 327.801 -38.6 329.601z"/> - <path fill="#cccccc" d="M-44.4 313.001C-44.4 313.001 -32.8 290.601 -54.6 316.401C-54.6 316.401 -43.6 306.601 -44.4 313.001z"/> - <path fill="#cccccc" d="M-59.8 298.401C-59.8 298.401 -55 279.601 -52.4 279.801C-52.4 279.801 -44.2 270.801 -50.8 281.401C-50.8 281.401 -56.8 291.001 -56.2 300.801C-56.2 300.801 -56.8 291.201 -59.8 298.401z"/> - <path fill="#cccccc" d="M270.5 287C270.5 287 258.5 277 256 273.5C256 273.5 269.5 292 269.5 299C269.5 299 272 291.5 270.5 287z"/> - <path fill="#cccccc" d="M276 265C276 265 255 250 251.5 242.5C251.5 242.5 278 272 278 276.5C278 276.5 278.5 267.5 276 265z"/> - <path fill="#cccccc" d="M293 111C293 111 281 103 279.5 105C279.5 105 290 111.5 292.5 120C292.5 120 291 111 293 111z"/> - <path fill="#cccccc" d="M301.5 191.5L284 179.5C284 179.5 303 196.5 303.5 200.5L301.5 191.5z"/> - <path stroke="#000000" d="M-89.25 169L-67.25 173.75"/> - <path stroke="#000000" d="M-39 331C-39 331 -39.5 327.5 -48.5 338"/> - <path stroke="#000000" d="M-33.5 336C-33.5 336 -31.5 329.5 -38 334"/> - <path stroke="#000000" d="M20.5 344.5C20.5 344.5 22 333.5 10.5 346.5"/> - </g> - <circle id="ball" cx="130" cy="-50" r="50" fill="yellow"/> - <script type="text/javascript"><![CDATA[ - var svg = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'svg')[0]; - var c = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'circle')[0]; - var t = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[1]; - var cx = parseInt(c.getAttribute('cx')); - var cy = parseInt(c.getAttribute('cy')); - var r = parseInt(c.getAttribute('r')); - var dx = 5; - var dy = -5; - var count = 0; - function repaintTest() { - if ((cx + r + dx > 390) || (cx - r + dx < -190)) - dx =- dx; - cx += dx; - if ((cy + r + dy > 390) || (cy - r + dy < -190)) - dy =- dy; - cy += dy; - c.setAttribute('cx', cx); - c.setAttribute('cy', cy); - ++count; - if (count < max) { - window.setTimeout(repaintTest, 0); - t.firstChild.data = 'Test in progress... ' + count + ' of ' + max; - } else { - if (window.testRunner) - t.firstChild.data = 'Test completed'; - else { - var end = new Date(); - var elapsed = (end - start) / 1000; - t.firstChild.data = 'Test completed in ' + elapsed.toFixed(2) + 's.'; - if (parent.reportResults) parent.reportResults(end - start); - } - finishRepaintTest(); - } - } - ]]></script> -</svg>
diff --git a/third_party/blink/web_tests/svg/hixie/perf/002-expected.txt b/third_party/blink/web_tests/svg/hixie/perf/002-expected.txt deleted file mode 100644 index 14efa82..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/002-expected.txt +++ /dev/null
@@ -1,2 +0,0 @@ -SVG Performance test. -Test completed
diff --git a/third_party/blink/web_tests/svg/hixie/perf/002.xml b/third_party/blink/web_tests/svg/hixie/perf/002.xml deleted file mode 100644 index 13b2cee..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/002.xml +++ /dev/null
@@ -1,295 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="-200 -200 600 600" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> - <script xlink:href="../../../paint/invalidation/resources/text-based-repaint.js"></script> - <script type="text/javascript"> - window.testIsAsync = true; - window.outputRepaintRects = false; - var start = new Date(); - var max = 75; - - // When running in DRT only bounce ten times otherwhise this test takes way too long - if (window.testRunner) - max = 10; - </script> - <rect fill="none" stroke="black" x="-190" y="-190" width="580" height="580" rx="40"/> - <text x="-150" y="-150" font-size="10">SVG Performance test.</text> - <text x="200" y="350" font-size="10">Test not started.</text> - <g> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-122.304 84.285C-122.304 84.285 -122.203 86.179 -123.027 86.16C-123.851 86.141 -140.305 38.066 -160.833 40.309C-160.833 40.309 -143.05 32.956 -122.304 84.285z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-118.774 81.262C-118.774 81.262 -119.323 83.078 -120.092 82.779C-120.86 82.481 -119.977 31.675 -140.043 26.801C-140.043 26.801 -120.82 25.937 -118.774 81.262z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-91.284 123.59C-91.284 123.59 -89.648 124.55 -90.118 125.227C-90.589 125.904 -139.763 113.102 -149.218 131.459C-149.218 131.459 -145.539 112.572 -91.284 123.59z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-94.093 133.801C-94.093 133.801 -92.237 134.197 -92.471 134.988C-92.704 135.779 -143.407 139.121 -146.597 159.522C-146.597 159.522 -149.055 140.437 -94.093 133.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-98.304 128.276C-98.304 128.276 -96.526 128.939 -96.872 129.687C-97.218 130.435 -147.866 126.346 -153.998 146.064C-153.998 146.064 -153.646 126.825 -98.304 128.276z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-109.009 110.072C-109.009 110.072 -107.701 111.446 -108.34 111.967C-108.979 112.488 -152.722 86.634 -166.869 101.676C-166.869 101.676 -158.128 84.533 -109.009 110.072z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-116.554 114.263C-116.554 114.263 -115.098 115.48 -115.674 116.071C-116.25 116.661 -162.638 95.922 -174.992 112.469C-174.992 112.469 -168.247 94.447 -116.554 114.263z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-119.154 118.335C-119.154 118.335 -117.546 119.343 -118.036 120.006C-118.526 120.669 -167.308 106.446 -177.291 124.522C-177.291 124.522 -173.066 105.749 -119.154 118.335z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-108.42 118.949C-108.42 118.949 -107.298 120.48 -107.999 120.915C-108.7 121.35 -148.769 90.102 -164.727 103.207C-164.727 103.207 -153.862 87.326 -108.42 118.949z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-128.2 90C-128.2 90 -127.6 91.8 -128.4 92C-129.2 92.2 -157.8 50.2 -177.001 57.8C-177.001 57.8 -161.8 46 -128.2 90z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-127.505 96.979C-127.505 96.979 -126.53 98.608 -127.269 98.975C-128.007 99.343 -164.992 64.499 -182.101 76.061C-182.101 76.061 -169.804 61.261 -127.505 96.979z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.172" d="M-127.62 101.349C-127.62 101.349 -126.498 102.88 -127.199 103.315C-127.9 103.749 -167.969 72.502 -183.927 85.607C-183.927 85.607 -173.062 69.726 -127.62 101.349z"/> - <path fill="#ffffff" stroke="#000000" d="M-129.83 103.065C-129.327 109.113 -128.339 115.682 -126.6 118.801C-126.6 118.801 -130.2 131.201 -121.4 144.401C-121.4 144.401 -121.8 151.601 -120.2 154.801C-120.2 154.801 -116.2 163.201 -111.4 164.001C-107.516 164.648 -98.793 167.717 -88.932 169.121C-88.932 169.121 -71.8 183.201 -75 196.001C-75 196.001 -75.4 212.401 -79 214.001C-79 214.001 -67.4 202.801 -77 219.601L-81.4 238.401C-81.4 238.401 -55.8 216.801 -71.4 235.201L-81.4 261.201C-81.4 261.201 -61.8 242.801 -69 251.201L-72.2 260.001C-72.2 260.001 -29 232.801 -59.8 262.401C-59.8 262.401 -51.8 258.801 -47.4 261.601C-47.4 261.601 -40.6 260.401 -41.4 262.001C-41.4 262.001 -62.2 272.401 -65.8 290.801C-65.8 290.801 -57.4 280.801 -60.6 291.601L-60.2 303.201C-60.2 303.201 -56.2 281.601 -56.6 319.201C-56.6 319.201 -37.4 301.201 -49 322.001L-49 338.801C-49 338.801 -33.8 322.401 -40.2 335.201C-40.2 335.201 -30.2 326.401 -34.2 341.601C-34.2 341.601 -35 352.001 -30.6 340.801C-30.6 340.801 -14.6 310.201 -20.6 336.401C-20.6 336.401 -21.4 355.601 -16.6 340.801C-16.6 340.801 -16.2 351.201 -7 358.401C-7 358.401 -8.2 307.601 4.6 343.601L8.6 360.001C8.6 360.001 11.4 350.801 11 345.601C11 345.601 25.8 329.201 19 353.601C19 353.601 34.2 330.801 31 344.001C31 344.001 23.4 360.001 25 364.801C25 364.801 41.8 330.001 43 328.401C43 328.401 41 370.802 51.8 334.801C51.8 334.801 57.4 346.801 54.6 351.201C54.6 351.201 62.6 343.201 61.8 340.001C61.8 340.001 66.4 331.801 69.2 345.401C69.2 345.401 71 354.801 72.6 351.601C72.6 351.601 76.6 375.602 77.8 352.801C77.8 352.801 79.4 339.201 72.2 327.601C72.2 327.601 73 324.401 70.2 320.401C70.2 320.401 83.8 342.001 76.6 313.201C76.6 313.201 87.801 321.201 89.001 321.201C89.001 321.201 75.4 298.001 84.2 302.801C84.2 302.801 79 292.401 97.001 304.401C97.001 304.401 81 288.401 98.601 298.001C98.601 298.001 106.601 304.401 99.001 294.401C99.001 294.401 84.6 278.401 106.601 296.401C106.601 296.401 118.201 312.801 119.001 315.601C119.001 315.601 109.001 286.401 104.601 283.601C104.601 283.601 113.001 247.201 154.201 262.801C154.201 262.801 161.001 280.001 165.401 261.601C165.401 261.601 178.201 255.201 189.401 282.801C189.401 282.801 193.401 269.201 192.601 266.401C192.601 266.401 199.401 267.601 198.601 266.401C198.601 266.401 211.801 270.801 213.001 270.001C213.001 270.001 219.801 276.801 220.201 273.201C220.201 273.201 229.401 276.001 227.401 272.401C227.401 272.401 236.201 288.001 236.601 291.601L239.001 277.601L241.001 280.401C241.001 280.401 242.601 272.801 241.801 271.601C241.001 270.401 261.801 278.401 266.601 299.201L268.601 307.601C268.601 307.601 274.601 292.801 273.001 288.801C273.001 288.801 278.201 289.601 278.601 294.001C278.601 294.001 282.601 270.801 277.801 264.801C277.801 264.801 282.201 264.001 283.401 267.601L283.401 260.401C283.401 260.401 290.601 261.201 290.601 258.801C290.601 258.801 295.001 254.801 297.001 259.601C297.001 259.601 284.601 224.401 303.001 243.601C303.001 243.601 310.201 254.401 306.601 235.601C303.001 216.801 299.001 215.201 303.801 214.801C303.801 214.801 304.601 211.201 302.601 209.601C300.601 208.001 303.801 209.601 303.801 209.601C303.801 209.601 308.601 213.601 303.401 191.601C303.401 191.601 309.801 193.201 297.801 164.001C297.801 164.001 300.601 161.601 296.601 153.201C296.601 153.201 304.601 157.601 307.401 156.001C307.401 156.001 307.001 154.401 303.801 150.401C303.801 150.401 282.201 95.6 302.601 117.601C302.601 117.601 314.451 131.151 308.051 108.351C308.051 108.351 298.94 84.341 299.717 80.045L-129.83 103.065z"/> - <path fill="#cc7226" stroke="#000000" d="M299.717 80.245C300.345 80.426 302.551 81.55 303.801 83.2C303.801 83.2 310.601 94 305.401 75.6C305.401 75.6 296.201 46.8 305.001 58C305.001 58 311.001 65.2 307.801 51.6C303.936 35.173 301.401 28.8 301.401 28.8C301.401 28.8 313.001 33.6 286.201 -6L295.001 -2.4C295.001 -2.4 275.401 -42 253.801 -47.2L245.801 -53.2C245.801 -53.2 284.201 -91.2 271.401 -128C271.401 -128 264.601 -133.2 255.001 -124C255.001 -124 248.601 -119.2 242.601 -120.8C242.601 -120.8 211.801 -119.6 209.801 -119.6C207.801 -119.6 173.001 -156.8 107.401 -139.2C107.401 -139.2 102.201 -137.2 97.801 -138.4C97.801 -138.4 79.4 -154.4 30.6 -131.6C30.6 -131.6 20.6 -129.6 19 -129.6C17.4 -129.6 14.6 -129.6 6.6 -123.2C-1.4 -116.8 -1.8 -116 -3.8 -114.4C-3.8 -114.4 -20.2 -103.2 -25 -102.4C-25 -102.4 -36.6 -96 -41 -86L-44.6 -84.8C-44.6 -84.8 -46.2 -77.6 -46.6 -76.4C-46.6 -76.4 -51.4 -72.8 -52.2 -67.2C-52.2 -67.2 -61 -61.2 -60.6 -56.8C-60.6 -56.8 -62.2 -51.6 -63 -46.8C-63 -46.8 -70.2 -42 -69.4 -39.2C-69.4 -39.2 -77 -25.2 -75.8 -18.4C-75.8 -18.4 -82.2 -18.8 -85 -16.4C-85 -16.4 -85.8 -11.6 -87.4 -11.2C-87.4 -11.2 -90.2 -10 -87.8 -6C-87.8 -6 -89.4 -3.2 -89.8 -1.6C-89.8 -1.6 -89 1.2 -93.4 6.8C-93.4 6.8 -99.8 25.6 -97.8 30.8C-97.8 30.8 -97.4 35.6 -100.2 37.2C-100.2 37.2 -103.8 36.8 -95.4 48.8C-95.4 48.8 -94.6 50 -97.8 52.4C-97.8 52.4 -115 56 -117.4 72.4C-117.4 72.4 -131 87.2 -131 92.4C-131 94.705 -130.729 97.852 -130.03 102.465C-130.03 102.465 -130.6 110.801 -103 111.601C-75.4 112.401 299.717 80.245 299.717 80.245z"/> - <path fill="#cc7226" d="M-115.6 102.6C-140.6 63.2 -126.2 119.601 -126.2 119.601C-117.4 154.001 12.2 116.401 12.2 116.401C12.2 116.401 181.001 86 192.201 82C203.401 78 298.601 84.4 298.601 84.4L293.001 67.6C228.201 21.2 209.001 44.4 195.401 40.4C181.801 36.4 184.201 46 181.001 46.8C177.801 47.6 138.601 22.8 132.201 23.6C125.801 24.4 100.459 0.649 115.401 32.4C131.401 66.4 57 71.6 40.2 60.4C23.4 49.2 47.4 78.8 47.4 78.8C65.8 98.8 31.4 82 31.4 82C-3 69.2 -27 94.8 -30.2 95.6C-33.4 96.4 -38.2 99.6 -39 93.2C-39.8 86.8 -47.31 70.099 -79 96.4C-99 113.001 -112.8 91 -112.8 91L-115.6 102.6z"/> - <path fill="#e87f3a" d="M133.51 25.346C127.11 26.146 101.743 2.407 116.71 34.146C133.31 69.346 58.31 73.346 41.51 62.146C24.709 50.946 48.71 80.546 48.71 80.546C67.11 100.546 32.709 83.746 32.709 83.746C-1.691 70.946 -25.691 96.546 -28.891 97.346C-32.091 98.146 -36.891 101.346 -37.691 94.946C-38.491 88.546 -45.87 72.012 -77.691 98.146C-98.927 115.492 -112.418 94.037 -112.418 94.037L-115.618 104.146C-140.618 64.346 -125.546 122.655 -125.546 122.655C-116.745 157.056 13.509 118.146 13.509 118.146C13.509 118.146 182.31 87.746 193.51 83.746C204.71 79.746 299.038 86.073 299.038 86.073L293.51 68.764C228.71 22.364 210.31 46.146 196.71 42.146C183.11 38.146 185.51 47.746 182.31 48.546C179.11 49.346 139.91 24.546 133.51 25.346z"/> - <path fill="#ea8c4d" d="M134.819 27.091C128.419 27.891 103.685 3.862 118.019 35.891C134.219 72.092 59.619 75.092 42.819 63.892C26.019 52.692 50.019 82.292 50.019 82.292C68.419 102.292 34.019 85.492 34.019 85.492C-0.381 72.692 -24.382 98.292 -27.582 99.092C-30.782 99.892 -35.582 103.092 -36.382 96.692C-37.182 90.292 -44.43 73.925 -76.382 99.892C-98.855 117.983 -112.036 97.074 -112.036 97.074L-115.636 105.692C-139.436 66.692 -124.891 125.71 -124.891 125.71C-116.091 160.11 14.819 119.892 14.819 119.892C14.819 119.892 183.619 89.492 194.819 85.492C206.019 81.492 299.474 87.746 299.474 87.746L294.02 69.928C229.219 23.528 211.619 47.891 198.019 43.891C184.419 39.891 186.819 49.491 183.619 50.292C180.419 51.092 141.219 26.291 134.819 27.091z"/> - <path fill="#ec9961" d="M136.128 28.837C129.728 29.637 104.999 5.605 119.328 37.637C136.128 75.193 60.394 76.482 44.128 65.637C27.328 54.437 51.328 84.037 51.328 84.037C69.728 104.037 35.328 87.237 35.328 87.237C0.928 74.437 -23.072 100.037 -26.272 100.837C-29.472 101.637 -34.272 104.837 -35.072 98.437C-35.872 92.037 -42.989 75.839 -75.073 101.637C-98.782 120.474 -111.655 100.11 -111.655 100.11L-115.655 107.237C-137.455 70.437 -124.236 128.765 -124.236 128.765C-115.436 163.165 16.128 121.637 16.128 121.637C16.128 121.637 184.928 91.237 196.129 87.237C207.329 83.237 299.911 89.419 299.911 89.419L294.529 71.092C229.729 24.691 212.929 49.637 199.329 45.637C185.728 41.637 188.128 51.237 184.928 52.037C181.728 52.837 142.528 28.037 136.128 28.837z"/> - <path fill="#eea575" d="M137.438 30.583C131.037 31.383 106.814 7.129 120.637 39.383C137.438 78.583 62.237 78.583 45.437 67.383C28.637 56.183 52.637 85.783 52.637 85.783C71.037 105.783 36.637 88.983 36.637 88.983C2.237 76.183 -21.763 101.783 -24.963 102.583C-28.163 103.383 -32.963 106.583 -33.763 100.183C-34.563 93.783 -41.548 77.752 -73.763 103.383C-98.709 122.965 -111.273 103.146 -111.273 103.146L-115.673 108.783C-135.473 73.982 -123.582 131.819 -123.582 131.819C-114.782 166.22 17.437 123.383 17.437 123.383C17.437 123.383 186.238 92.983 197.438 88.983C208.638 84.983 300.347 91.092 300.347 91.092L295.038 72.255C230.238 25.855 214.238 51.383 200.638 47.383C187.038 43.383 189.438 52.983 186.238 53.783C183.038 54.583 143.838 29.783 137.438 30.583z"/> - <path fill="#f1b288" d="M138.747 32.328C132.347 33.128 106.383 9.677 121.947 41.128C141.147 79.928 63.546 80.328 46.746 69.128C29.946 57.928 53.946 87.528 53.946 87.528C72.346 107.528 37.946 90.728 37.946 90.728C3.546 77.928 -20.454 103.528 -23.654 104.328C-26.854 105.128 -31.654 108.328 -32.454 101.928C-33.254 95.528 -40.108 79.665 -72.454 105.128C-98.636 125.456 -110.891 106.183 -110.891 106.183L-115.691 110.328C-133.691 77.128 -122.927 134.874 -122.927 134.874C-114.127 169.274 18.746 125.128 18.746 125.128C18.746 125.128 187.547 94.728 198.747 90.728C209.947 86.728 300.783 92.764 300.783 92.764L295.547 73.419C230.747 27.019 215.547 53.128 201.947 49.128C188.347 45.128 190.747 54.728 187.547 55.528C184.347 56.328 145.147 31.528 138.747 32.328z"/> - <path fill="#f3bf9c" d="M140.056 34.073C133.655 34.873 107.313 11.613 123.255 42.873C143.656 82.874 64.855 82.074 48.055 70.874C31.255 59.674 55.255 89.274 55.255 89.274C73.655 109.274 39.255 92.474 39.255 92.474C4.855 79.674 -19.145 105.274 -22.345 106.074C-25.545 106.874 -30.345 110.074 -31.145 103.674C-31.945 97.274 -38.668 81.578 -71.145 106.874C-98.564 127.947 -110.509 109.219 -110.509 109.219L-115.709 111.874C-131.709 81.674 -122.273 137.929 -122.273 137.929C-113.473 172.329 20.055 126.874 20.055 126.874C20.055 126.874 188.856 96.474 200.056 92.474C211.256 88.474 301.22 94.437 301.22 94.437L296.056 74.583C231.256 28.183 216.856 54.874 203.256 50.874C189.656 46.873 192.056 56.474 188.856 57.274C185.656 58.074 146.456 33.273 140.056 34.073z"/> - <path fill="#f5ccb0" d="M141.365 35.819C134.965 36.619 107.523 13.944 124.565 44.619C146.565 84.219 66.164 83.819 49.364 72.619C32.564 61.419 56.564 91.019 56.564 91.019C74.964 111.019 40.564 94.219 40.564 94.219C6.164 81.419 -17.836 107.019 -21.036 107.819C-24.236 108.619 -29.036 111.819 -29.836 105.419C-30.636 99.019 -37.227 83.492 -69.836 108.619C-98.491 130.438 -110.127 112.256 -110.127 112.256L-115.727 113.419C-130.128 85.019 -121.618 140.983 -121.618 140.983C-112.818 175.384 21.364 128.619 21.364 128.619C21.364 128.619 190.165 98.219 201.365 94.219C212.565 90.219 301.656 96.11 301.656 96.11L296.565 75.746C231.765 29.346 218.165 56.619 204.565 52.619C190.965 48.619 193.365 58.219 190.165 59.019C186.965 59.819 147.765 35.019 141.365 35.819z"/> - <path fill="#f8d8c4" d="M142.674 37.565C136.274 38.365 108.832 15.689 125.874 46.365C147.874 85.965 67.474 85.565 50.674 74.365C33.874 63.165 57.874 92.765 57.874 92.765C76.274 112.765 41.874 95.965 41.874 95.965C7.473 83.165 -16.527 108.765 -19.727 109.565C-22.927 110.365 -27.727 113.565 -28.527 107.165C-29.327 100.765 -35.786 85.405 -68.527 110.365C-98.418 132.929 -109.745 115.293 -109.745 115.293L-115.745 114.965C-129.346 88.564 -120.963 144.038 -120.963 144.038C-112.163 178.438 22.673 130.365 22.673 130.365C22.673 130.365 191.474 99.965 202.674 95.965C213.874 91.965 302.093 97.783 302.093 97.783L297.075 76.91C232.274 30.51 219.474 58.365 205.874 54.365C192.274 50.365 194.674 59.965 191.474 60.765C188.274 61.565 149.074 36.765 142.674 37.565z"/> - <path fill="#fae5d7" d="M143.983 39.31C137.583 40.11 110.529 17.223 127.183 48.11C149.183 88.91 68.783 87.31 51.983 76.11C35.183 64.91 59.183 94.51 59.183 94.51C77.583 114.51 43.183 97.71 43.183 97.71C8.783 84.91 -15.217 110.51 -18.417 111.31C-21.618 112.11 -26.418 115.31 -27.218 108.91C-28.018 102.51 -34.346 87.318 -67.218 112.11C-98.345 135.42 -109.363 118.329 -109.363 118.329L-115.764 116.51C-128.764 92.51 -120.309 147.093 -120.309 147.093C-111.509 181.493 23.983 132.11 23.983 132.11C23.983 132.11 192.783 101.71 203.983 97.71C215.183 93.71 302.529 99.456 302.529 99.456L297.583 78.074C232.783 31.673 220.783 60.11 207.183 56.11C193.583 52.11 195.983 61.71 192.783 62.51C189.583 63.31 150.383 38.51 143.983 39.31z"/> - <path fill="#fcf2eb" d="M145.292 41.055C138.892 41.855 112.917 18.411 128.492 49.855C149.692 92.656 70.092 89.056 53.292 77.856C36.492 66.656 60.492 96.256 60.492 96.256C78.892 116.256 44.492 99.456 44.492 99.456C10.092 86.656 -13.908 112.256 -17.108 113.056C-20.308 113.856 -25.108 117.056 -25.908 110.656C-26.708 104.256 -32.905 89.232 -65.908 113.856C-98.273 137.911 -108.982 121.365 -108.982 121.365L-115.782 118.056C-128.582 94.856 -119.654 150.147 -119.654 150.147C-110.854 184.547 25.292 133.856 25.292 133.856C25.292 133.856 194.093 103.456 205.293 99.456C216.493 95.456 302.965 101.128 302.965 101.128L298.093 79.237C233.292 32.837 222.093 61.856 208.493 57.856C194.893 53.855 197.293 63.456 194.093 64.256C190.892 65.056 151.692 40.255 145.292 41.055z"/> - <path fill="#ffffff" d="M-115.8 119.601C-128.6 97.6 -119 153.201 -119 153.201C-110.2 187.601 26.6 135.601 26.6 135.601C26.6 135.601 195.401 105.2 206.601 101.2C217.801 97.2 303.401 102.8 303.401 102.8L298.601 80.4C233.801 34 223.401 63.6 209.801 59.6C196.201 55.6 198.601 65.2 195.401 66C192.201 66.8 153.001 42 146.601 42.8C140.201 43.6 114.981 19.793 129.801 51.6C152.028 99.307 69.041 89.227 54.6 79.6C37.8 68.4 61.8 98 61.8 98C80.2 118.001 45.8 101.2 45.8 101.2C11.4 88.4 -12.6 114.001 -15.8 114.801C-19 115.601 -23.8 118.801 -24.6 112.401C-25.4 106 -31.465 91.144 -64.6 115.601C-98.2 140.401 -108.6 124.401 -108.6 124.401L-115.8 119.601z"/> - <path fill="#000000" d="M-74.2 149.601C-74.2 149.601 -81.4 161.201 -60.6 174.401C-60.6 174.401 -59.2 175.801 -77.2 171.601C-77.2 171.601 -83.4 169.601 -85 159.201C-85 159.201 -89.8 154.801 -94.6 149.201C-99.4 143.601 -74.2 149.601 -74.2 149.601z"/> - <path fill="#cccccc" d="M65.8 102C65.8 102 83.498 128.821 82.9 133.601C81.6 144.001 81.4 153.601 84.6 157.601C87.801 161.601 96.601 194.801 96.601 194.801C96.601 194.801 96.201 196.001 108.601 158.001C108.601 158.001 120.201 142.001 100.201 123.601C100.201 123.601 65 94.8 65.8 102z"/> - <path fill="#000000" d="M-54.2 176.401C-54.2 176.401 -43 183.601 -57.4 214.801L-51 212.401C-51 212.401 -51.8 223.601 -55 226.001L-47.8 222.801C-47.8 222.801 -43 230.801 -47 235.601C-47 235.601 -30.2 243.601 -31 250.001C-31 250.001 -24.6 242.001 -28.6 235.601C-32.6 229.201 -39.8 233.201 -39 214.801L-47.8 218.001C-47.8 218.001 -42.2 209.201 -42.2 202.801L-50.2 205.201C-50.2 205.201 -34.731 178.623 -45.4 177.201C-51.4 176.401 -54.2 176.401 -54.2 176.401z"/> - <path fill="#cccccc" d="M-21.8 193.201C-21.8 193.201 -19 188.801 -21.8 189.601C-24.6 190.401 -55.8 205.201 -61.8 214.801C-61.8 214.801 -27.4 190.401 -21.8 193.201z"/> - <path fill="#cccccc" d="M-11.4 201.201C-11.4 201.201 -8.6 196.801 -11.4 197.601C-14.2 198.401 -45.4 213.201 -51.4 222.801C-51.4 222.801 -17 198.401 -11.4 201.201z"/> - <path fill="#cccccc" d="M1.8 186.001C1.8 186.001 4.6 181.601 1.8 182.401C-1 183.201 -32.2 198.001 -38.2 207.601C-38.2 207.601 -3.8 183.201 1.8 186.001z"/> - <path fill="#cccccc" d="M-21.4 229.601C-21.4 229.601 -21.4 223.601 -24.2 224.401C-27 225.201 -63 242.801 -69 252.401C-69 252.401 -27 226.801 -21.4 229.601z"/> - <path fill="#cccccc" d="M-20.2 218.801C-20.2 218.801 -19 214.001 -21.8 214.801C-23.8 214.801 -50.2 226.401 -56.2 236.001C-56.2 236.001 -26.6 214.401 -20.2 218.801z"/> - <path fill="#cccccc" d="M-34.6 266.401L-44.6 274.001C-44.6 274.001 -34.2 266.401 -30.6 267.601C-30.6 267.601 -37.4 278.801 -38.2 284.001C-38.2 284.001 -27.8 271.201 -22.2 271.601C-22.2 271.601 -14.6 272.001 -14.6 282.801C-14.6 282.801 -9 272.401 -5.8 272.801C-5.8 272.801 -4.6 279.201 -5.8 286.001C-5.8 286.001 -1.8 278.401 2.2 280.001C2.2 280.001 8.6 278.001 7.8 289.601C7.8 289.601 7.8 300.001 7 302.801C7 302.801 12.6 276.401 15 276.001C15 276.001 23 274.801 27.8 283.601C27.8 283.601 23.8 276.001 28.6 278.001C28.6 278.001 39.4 279.601 42.6 286.401C42.6 286.401 35.8 274.401 41.4 277.601C41.4 277.601 48.2 277.601 49.4 284.001C49.4 284.001 57.8 305.201 59.8 306.801C59.8 306.801 52.2 285.201 53.8 285.201C53.8 285.201 51.8 273.201 57 288.001C57 288.001 53.8 274.001 59.4 274.801C65 275.601 69.4 285.601 77.8 283.201C77.8 283.201 87.401 288.801 89.401 219.601L-34.6 266.401z"/> - <path fill="#000000" d="M-29.8 173.601C-29.8 173.601 -15 167.601 25 173.601C25 173.601 32.2 174.001 39 165.201C45.8 156.401 72.6 149.201 79 151.201L88.601 157.601L89.401 158.801C89.401 158.801 101.801 169.201 102.201 176.801C102.601 184.401 87.801 232.401 78.2 248.401C68.6 264.401 59 276.801 39.8 274.401C39.8 274.401 19 270.401 -6.6 274.401C-6.6 274.401 -35.8 272.801 -38.6 264.801C-41.4 256.801 -27.4 241.601 -27.4 241.601C-27.4 241.601 -23 233.201 -24.2 218.801C-25.4 204.401 -25 176.401 -29.8 173.601z"/> - <path fill="#e5668c" d="M-7.8 175.601C0.6 194.001 -29 259.201 -29 259.201C-31 260.801 -16.34 266.846 -6.2 264.401C4.746 261.763 45 266.001 45 266.001C68.6 250.401 81.4 206.001 81.4 206.001C81.4 206.001 91.801 182.001 74.2 178.801C56.6 175.601 -7.8 175.601 -7.8 175.601z"/> - <path fill="#b23259" d="M-9.831 206.497C-6.505 193.707 -4.921 181.906 -7.8 175.601C-7.8 175.601 54.6 182.001 65.8 161.201C70.041 153.326 84.801 184.001 84.4 193.601C84.4 193.601 21.4 208.001 6.6 196.801L-9.831 206.497z"/> - <path fill="#a5264c" d="M-5.4 222.801C-5.4 222.801 -3.4 230.001 -5.8 234.001C-5.8 234.001 -7.4 234.801 -8.6 235.201C-8.6 235.201 -7.4 238.801 -1.4 240.401C-1.4 240.401 0.6 244.801 3 245.201C5.4 245.601 10.2 251.201 14.2 250.001C18.2 248.801 29.4 244.801 29.4 244.801C29.4 244.801 35 241.601 43.8 245.201C43.8 245.201 46.175 244.399 46.6 240.401C47.1 235.701 50.2 232.001 52.2 230.001C54.2 228.001 63.8 215.201 62.6 214.801C61.4 214.401 -5.4 222.801 -5.4 222.801z"/> - <path fill="#ff727f" stroke="#000000" d="M-9.8 174.401C-9.8 174.401 -12.6 196.801 -9.4 205.201C-6.2 213.601 -7 215.601 -7.8 219.601C-8.6 223.601 -4.2 233.601 1.4 239.601L13.4 241.201C13.4 241.201 28.6 237.601 37.8 240.401C37.8 240.401 46.794 241.744 50.2 226.801C50.2 226.801 55 220.401 62.2 217.601C69.4 214.801 76.6 173.201 72.6 165.201C68.6 157.201 54.2 152.801 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-8.2 249.201C-8.2 249.201 -9 247.201 -13.4 246.801C-13.4 246.801 -35.8 243.201 -44.2 230.801C-44.2 230.801 -51 225.201 -46.6 236.801C-46.6 236.801 -36.2 257.201 -29.4 260.001C-29.4 260.001 -13 264.001 -8.2 249.201z"/> - <path fill="#cc3f4c" d="M71.742 185.229C72.401 177.323 74.354 168.709 72.6 165.201C66.154 152.307 49.181 157.695 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401C-9.8 174.401 -11.545 188.364 -10.705 198.376C-10.705 198.376 26.6 186.801 27.4 192.401C27.4 192.401 29 189.201 38.2 189.201C47.4 189.201 70.142 188.029 71.742 185.229z"/> - <path stroke="#a51926" stroke-width="2" d="M28.6 175.201C28.6 175.201 33.4 180.001 29.8 189.601C29.8 189.601 15.4 205.601 17.4 219.601"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-19.4 260.001C-19.4 260.001 -23.8 247.201 -15 254.001C-15 254.001 -10.2 256.001 -11.4 257.601C-12.6 259.201 -18.2 263.201 -19.4 260.001z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-14.36 261.201C-14.36 261.201 -17.88 250.961 -10.84 256.401C-10.84 256.401 -6.419 258.849 -7.96 259.281C-12.52 260.561 -7.96 263.121 -14.36 261.201z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-9.56 261.201C-9.56 261.201 -13.08 250.961 -6.04 256.401C-6.04 256.401 -1.665 258.711 -3.16 259.281C-6.52 260.561 -3.16 263.121 -9.56 261.201z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-2.96 261.401C-2.96 261.401 -6.48 251.161 0.56 256.601C0.56 256.601 4.943 258.933 3.441 259.481C0.48 260.561 3.441 263.321 -2.96 261.401z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M3.52 261.321C3.52 261.321 0 251.081 7.041 256.521C7.041 256.521 10.881 258.121 9.921 259.401C8.961 260.681 9.921 263.241 3.52 261.321z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M10.2 262.001C10.2 262.001 5.4 249.601 14.6 256.001C14.6 256.001 19.4 258.001 18.2 259.601C17 261.201 18.2 264.401 10.2 262.001z"/> - <path stroke="#a5264c" stroke-width="2" d="M-18.2 244.801C-18.2 244.801 -5 242.001 1 245.201C1 245.201 7 246.401 8.2 246.001C9.4 245.601 12.6 245.201 12.6 245.201"/> - <path stroke="#a5264c" stroke-width="2" d="M15.8 253.601C15.8 253.601 27.8 240.001 39.8 244.401C46.816 246.974 45.8 243.601 46.6 240.801C47.4 238.001 47.6 233.801 52.6 230.801"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M33 237.601C33 237.601 29 226.801 26.2 239.601C23.4 252.401 20.2 256.001 18.6 258.801C18.6 258.801 18.6 264.001 27 263.601C27 263.601 37.8 263.201 38.2 260.401C38.6 257.601 37 246.001 33 237.601z"/> - <path stroke="#a5264c" stroke-width="2" d="M47 244.801C47 244.801 50.6 242.401 53 243.601"/> - <path stroke="#a5264c" stroke-width="2" d="M53.5 228.401C53.5 228.401 56.4 223.501 61.2 222.701"/> - <path fill="#b2b2b2" d="M-25.8 265.201C-25.8 265.201 -7.8 268.401 -3.4 266.801C-3.4 266.801 5.4 266.801 -3 268.801C-3 268.801 -15.8 268.801 -23.8 267.601C-23.8 267.601 -35.4 262.001 -25.8 265.201z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-11.8 172.001C-11.8 172.001 5.8 172.001 7.8 172.801C7.8 172.801 15 203.601 11.4 211.201C11.4 211.201 10.2 214.001 7.4 208.401C7.4 208.401 -11 175.601 -14.2 173.601C-17.4 171.601 -13 172.001 -11.8 172.001z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-88.9 169.301C-88.9 169.301 -80 171.001 -67.4 173.601C-67.4 173.601 -62.6 196.001 -59.4 200.801C-56.2 205.601 -59.8 205.601 -63.4 202.801C-67 200.001 -81.8 186.001 -83.8 181.601C-85.8 177.201 -88.9 169.301 -88.9 169.301z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-67.039 173.818C-67.039 173.818 -61.239 175.366 -60.23 177.581C-59.222 179.795 -61.432 183.092 -61.432 183.092C-61.432 183.092 -62.432 186.397 -63.634 184.235C-64.836 182.072 -67.708 174.412 -67.039 173.818z"/> - <path fill="#000000" d="M-67 173.601C-67 173.601 -63.4 178.801 -59.8 178.801C-56.2 178.801 -55.818 178.388 -53 179.001C-48.4 180.001 -48.8 178.001 -42.2 179.201C-39.56 179.681 -37 178.801 -34.2 180.001C-31.4 181.201 -28.2 180.401 -27 178.401C-25.8 176.401 -21 172.201 -21 172.201C-21 172.201 -33.8 174.001 -36.6 174.801C-36.6 174.801 -59 176.001 -67 173.601z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-22.4 173.801C-22.4 173.801 -28.85 177.301 -29.25 179.701C-29.65 182.101 -24 185.801 -24 185.801C-24 185.801 -21.25 190.401 -20.65 188.001C-20.05 185.601 -21.6 174.201 -22.4 173.801z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-59.885 179.265C-59.885 179.265 -52.878 190.453 -52.661 179.242C-52.661 179.242 -52.104 177.984 -53.864 177.962C-59.939 177.886 -58.418 173.784 -59.885 179.265z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-52.707 179.514C-52.707 179.514 -44.786 190.701 -45.422 179.421C-45.422 179.421 -45.415 179.089 -47.168 178.936C-51.915 178.522 -51.57 174.004 -52.707 179.514z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-45.494 179.522C-45.494 179.522 -37.534 190.15 -38.203 180.484C-38.203 180.484 -38.084 179.251 -39.738 178.95C-43.63 178.244 -43.841 174.995 -45.494 179.522z"/> - <path fill="#ffffcc" stroke="#000000" stroke-width="0.5" d="M-38.618 179.602C-38.618 179.602 -30.718 191.163 -30.37 181.382C-30.37 181.382 -28.726 180.004 -30.472 179.782C-36.29 179.042 -35.492 174.588 -38.618 179.602z"/> - <path fill="#e5e5b2" d="M-74.792 183.132L-82.45 181.601C-85.05 176.601 -87.15 170.451 -87.15 170.451C-87.15 170.451 -80.8 171.451 -68.3 174.251C-68.3 174.251 -67.424 177.569 -65.952 183.364L-74.792 183.132z"/> - <path fill="#e5e5b2" d="M-9.724 178.47C-11.39 175.964 -12.707 174.206 -13.357 173.8C-16.37 171.917 -12.227 172.294 -11.098 172.294C-11.098 172.294 5.473 172.294 7.356 173.047C7.356 173.047 7.88 175.289 8.564 178.68C8.564 178.68 -1.524 176.67 -9.724 178.47z"/> - <path fill="#cc7226" d="M43.88 40.321C71.601 44.281 97.121 8.641 98.881 -1.04C100.641 -10.72 90.521 -22.6 90.521 -22.6C91.841 -25.68 87.001 -39.76 81.721 -49C76.441 -58.24 60.54 -57.266 43 -58.24C27.16 -59.12 8.68 -35.8 7.36 -34.04C6.04 -32.28 12.2 6.001 13.52 11.721C14.84 17.441 12.2 43.841 12.2 43.841C46.44 34.741 16.16 36.361 43.88 40.321z"/> - <path fill="#ea8e51" d="M8.088 -33.392C6.792 -31.664 12.84 5.921 14.136 11.537C15.432 17.153 12.84 43.073 12.84 43.073C45.512 34.193 16.728 35.729 43.944 39.617C71.161 43.505 96.217 8.513 97.945 -0.992C99.673 -10.496 89.737 -22.16 89.737 -22.16C91.033 -25.184 86.281 -39.008 81.097 -48.08C75.913 -57.152 60.302 -56.195 43.08 -57.152C27.528 -58.016 9.384 -35.12 8.088 -33.392z"/> - <path fill="#efaa7c" d="M8.816 -32.744C7.544 -31.048 13.48 5.841 14.752 11.353C16.024 16.865 13.48 42.305 13.48 42.305C44.884 33.145 17.296 35.097 44.008 38.913C70.721 42.729 95.313 8.385 97.009 -0.944C98.705 -10.272 88.953 -21.72 88.953 -21.72C90.225 -24.688 85.561 -38.256 80.473 -47.16C75.385 -56.064 60.063 -55.125 43.16 -56.064C27.896 -56.912 10.088 -34.44 8.816 -32.744z"/> - <path fill="#f4c6a8" d="M9.544 -32.096C8.296 -30.432 14.12 5.761 15.368 11.169C16.616 16.577 14.12 41.537 14.12 41.537C43.556 32.497 17.864 34.465 44.072 38.209C70.281 41.953 94.409 8.257 96.073 -0.895C97.737 -10.048 88.169 -21.28 88.169 -21.28C89.417 -24.192 84.841 -37.504 79.849 -46.24C74.857 -54.976 59.824 -54.055 43.24 -54.976C28.264 -55.808 10.792 -33.76 9.544 -32.096z"/> - <path fill="#f9e2d3" d="M10.272 -31.448C9.048 -29.816 14.76 5.681 15.984 10.985C17.208 16.289 14.76 40.769 14.76 40.769C42.628 31.849 18.432 33.833 44.136 37.505C69.841 41.177 93.505 8.129 95.137 -0.848C96.769 -9.824 87.385 -20.84 87.385 -20.84C88.609 -23.696 84.121 -36.752 79.225 -45.32C74.329 -53.888 59.585 -52.985 43.32 -53.888C28.632 -54.704 11.496 -33.08 10.272 -31.448z"/> - <path fill="#ffffff" d="M44.2 36.8C69.4 40.4 92.601 8 94.201 -0.8C95.801 -9.6 86.601 -20.4 86.601 -20.4C87.801 -23.2 83.4 -36 78.6 -44.4C73.8 -52.8 59.346 -51.914 43.4 -52.8C29 -53.6 12.2 -32.4 11 -30.8C9.8 -29.2 15.4 5.6 16.6 10.8C17.8 16 15.4 40 15.4 40C40.9 31.4 19 33.2 44.2 36.8z"/> - <path fill="#cccccc" d="M90.601 2.8C90.601 2.8 62.8 10.4 51.2 8.8C51.2 8.8 35.4 2.2 26.6 24C26.6 24 23 31.2 21 33.2C19 35.2 90.601 2.8 90.601 2.8z"/> - <path fill="#000000" d="M94.401 0.6C94.401 0.6 65.4 12.8 55.4 12.4C55.4 12.4 39 7.8 30.6 22.4C30.6 22.4 22.2 31.6 19 33.2C19 33.2 18.6 34.8 25 30.8L35.4 36C35.4 36 50.2 45.6 59.8 29.6C59.8 29.6 63.8 18.4 63.8 16.4C63.8 14.4 85 8.8 86.601 8.4C88.201 8 94.801 3.8 94.401 0.6z"/> - <path fill="#99cc32" d="M47 36.514C40.128 36.514 31.755 32.649 31.755 26.4C31.755 20.152 40.128 13.887 47 13.887C53.874 13.887 59.446 18.952 59.446 25.2C59.446 31.449 53.874 36.514 47 36.514z"/> - <path fill="#659900" d="M43.377 19.83C38.531 20.552 33.442 22.055 33.514 21.839C35.054 17.22 41.415 13.887 47 13.887C51.296 13.887 55.084 15.865 57.32 18.875C57.32 18.875 52.004 18.545 43.377 19.83z"/> - <path fill="#ffffff" d="M55.4 19.6C55.4 19.6 51 16.4 51 18.6C51 18.6 54.6 23 55.4 19.6z"/> - <path fill="#000000" d="M45.4 27.726C42.901 27.726 40.875 25.7 40.875 23.2C40.875 20.701 42.901 18.675 45.4 18.675C47.9 18.675 49.926 20.701 49.926 23.2C49.926 25.7 47.9 27.726 45.4 27.726z"/> - <path fill="#cc7226" d="M-58.6 14.4C-58.6 14.4 -61.8 -6.8 -59.4 -11.2C-59.4 -11.2 -48.6 -21.2 -49 -24.8C-49 -24.8 -49.4 -42.8 -50.6 -43.6C-51.8 -44.4 -59.4 -50.4 -65.4 -44C-65.4 -44 -75.8 -26 -75 -19.6L-75 -17.6C-75 -17.6 -82.6 -18 -84.2 -16C-84.2 -16 -85.4 -10.8 -86.6 -10.4C-86.6 -10.4 -89.4 -8 -87.4 -5.2C-87.4 -5.2 -89.4 -2.8 -89 1.2L-81.4 5.2C-81.4 5.2 -79.4 19.6 -68.6 24.8C-63.764 27.129 -60.6 20.4 -58.6 14.4z"/> - <path fill="#ffffff" d="M-59.6 12.56C-59.6 12.56 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.48 -40.36 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.96 -59.6 12.56z"/> - <path fill="#eb955c" d="M-51.05 -42.61C-52.14 -43.47 -59.63 -49.24 -65.48 -43C-65.48 -43 -75.62 -25.45 -74.84 -19.21L-74.84 -17.26C-74.84 -17.26 -82.25 -17.65 -83.81 -15.7C-83.81 -15.7 -84.98 -10.63 -86.15 -10.24C-86.15 -10.24 -88.88 -7.9 -86.93 -5.17C-86.93 -5.17 -88.88 -2.83 -88.49 1.07L-81.08 4.97C-81.08 4.97 -79.13 19.01 -68.6 24.08C-63.886 26.35 -60.8 19.79 -58.85 13.94C-58.85 13.94 -61.97 -6.73 -59.63 -11.02C-59.63 -11.02 -49.1 -20.77 -49.49 -24.28C-49.49 -24.28 -49.88 -41.83 -51.05 -42.61z"/> - <path fill="#f2b892" d="M-51.5 -41.62C-52.48 -42.54 -59.86 -48.08 -65.56 -42C-65.56 -42 -75.44 -24.9 -74.68 -18.82L-74.68 -16.92C-74.68 -16.92 -81.9 -17.3 -83.42 -15.4C-83.42 -15.4 -84.56 -10.46 -85.7 -10.08C-85.7 -10.08 -88.36 -7.8 -86.46 -5.14C-86.46 -5.14 -88.36 -2.86 -87.98 0.94L-80.76 4.74C-80.76 4.74 -78.86 18.42 -68.6 23.36C-64.006 25.572 -61 19.18 -59.1 13.48C-59.1 13.48 -62.14 -6.66 -59.86 -10.84C-59.86 -10.84 -49.6 -20.34 -49.98 -23.76C-49.98 -23.76 -50.36 -40.86 -51.5 -41.62z"/> - <path fill="#f8dcc8" d="M-51.95 -40.63C-52.82 -41.61 -60.09 -46.92 -65.64 -41C-65.64 -41 -75.26 -24.35 -74.52 -18.43L-74.52 -16.58C-74.52 -16.58 -81.55 -16.95 -83.03 -15.1C-83.03 -15.1 -84.14 -10.29 -85.25 -9.92C-85.25 -9.92 -87.84 -7.7 -85.99 -5.11C-85.99 -5.11 -87.84 -2.89 -87.47 0.81L-80.44 4.51C-80.44 4.51 -78.59 17.83 -68.6 22.64C-64.127 24.794 -61.2 18.57 -59.35 13.02C-59.35 13.02 -62.31 -6.59 -60.09 -10.66C-60.09 -10.66 -50.1 -19.91 -50.47 -23.24C-50.47 -23.24 -50.84 -39.89 -51.95 -40.63z"/> - <path fill="#ffffff" d="M-59.6 12.46C-59.6 12.46 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.16 -40.68 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.86 -59.6 12.46z"/> - <path fill="#cccccc" d="M-62.7 6.2C-62.7 6.2 -84.3 -4 -85.2 -4.8C-85.2 -4.8 -76.1 3.4 -75.3 3.4C-74.5 3.4 -62.7 6.2 -62.7 6.2z"/> - <path fill="#000000" d="M-79.8 0C-79.8 0 -61.4 3.6 -61.4 8C-61.4 10.912 -61.643 24.331 -67 22.8C-75.4 20.4 -71.8 6 -79.8 0z"/> - <path fill="#99cc32" d="M-71.4 3.8C-71.4 3.8 -62.422 5.274 -61.4 8C-60.8 9.6 -60.137 17.908 -65.6 19C-70.152 19.911 -72.382 9.69 -71.4 3.8z"/> - <path fill="#000000" d="M14.595 46.349C14.098 44.607 15.409 44.738 17.2 44.2C19.2 43.6 31.4 39.8 32.2 37.2C33 34.6 46.2 39 46.2 39C48 39.8 52.4 42.4 52.4 42.4C57.2 43.6 63.8 44 63.8 44C66.2 45 69.6 47.8 69.6 47.8C84.2 58 96.601 50.8 96.601 50.8C116.601 44.2 110.601 27 110.601 27C107.601 18 110.801 14.6 110.801 14.6C111.001 10.8 118.201 17.2 118.201 17.2C120.801 21.4 121.601 26.4 121.601 26.4C129.601 37.6 126.201 19.8 126.201 19.8C126.401 18.8 123.601 15.2 123.601 14C123.601 12.8 121.801 9.4 121.801 9.4C118.801 6 121.201 -1 121.201 -1C123.001 -14.8 120.801 -13 120.801 -13C119.601 -14.8 110.401 -4.8 110.401 -4.8C108.201 -1.4 102.201 0.2 102.201 0.2C99.401 2 96.001 0.6 96.001 0.6C93.401 0.2 87.801 7.2 87.801 7.2C90.601 7 93.001 11.4 95.401 11.6C97.801 11.8 99.601 9.2 101.201 8.6C102.801 8 105.601 13.8 105.601 13.8C106.001 16.4 100.401 21.2 100.401 21.2C100.001 25.8 98.401 24.2 98.401 24.2C95.401 23.6 94.201 27.4 93.201 32C92.201 36.6 88.001 37 88.001 37C86.401 44.4 85.2 41.4 85.2 41.4C85 35.8 79 41.6 79 41.6C77.8 43.6 73.2 41.4 73.2 41.4C66.4 39.4 68.8 37.4 68.8 37.4C70.6 35.2 81.8 37.4 81.8 37.4C84 35.8 76 31.8 76 31.8C75.4 30 76.4 25.6 76.4 25.6C77.6 22.4 84.4 16.8 84.4 16.8C93.801 15.6 91.001 14 91.001 14C84.801 8.8 79 16.4 79 16.4C76.8 22.6 59.4 37.6 59.4 37.6C54.6 41 57.2 34.2 53.2 37.6C49.2 41 28.6 32 28.6 32C17.038 30.807 14.306 46.549 10.777 43.429C10.777 43.429 16.195 51.949 14.595 46.349z"/> - <path fill="#000000" d="M209.401 -120C209.401 -120 183.801 -112 181.001 -93.2C181.001 -93.2 178.601 -70.4 199.001 -52.8C199.001 -52.8 199.401 -46.4 201.401 -43.2C201.401 -43.2 199.801 -38.4 218.601 -46L245.801 -54.4C245.801 -54.4 252.201 -56.8 257.401 -65.6C262.601 -74.4 277.801 -93.2 274.201 -118.4C274.201 -118.4 275.401 -129.6 269.401 -130C269.401 -130 261.001 -131.6 253.801 -124C253.801 -124 247.001 -120.8 244.601 -121.2L209.401 -120z"/> - <path fill="#000000" d="M264.022 -120.99C264.022 -120.99 266.122 -129.92 261.282 -125.08C261.282 -125.08 254.242 -119.36 246.761 -119.36C246.761 -119.36 232.241 -117.16 227.841 -103.96C227.841 -103.96 223.881 -77.12 231.801 -71.4C231.801 -71.4 236.641 -63.92 243.681 -70.52C250.722 -77.12 266.222 -107.35 264.022 -120.99z"/> - <path fill="#323232" d="M263.648 -120.632C263.648 -120.632 265.738 -129.376 260.986 -124.624C260.986 -124.624 254.074 -119.008 246.729 -119.008C246.729 -119.008 232.473 -116.848 228.153 -103.888C228.153 -103.888 224.265 -77.536 232.041 -71.92C232.041 -71.92 236.793 -64.576 243.705 -71.056C250.618 -77.536 265.808 -107.24 263.648 -120.632z"/> - <path fill="#666666" d="M263.274 -120.274C263.274 -120.274 265.354 -128.832 260.69 -124.168C260.69 -124.168 253.906 -118.656 246.697 -118.656C246.697 -118.656 232.705 -116.536 228.465 -103.816C228.465 -103.816 224.649 -77.952 232.281 -72.44C232.281 -72.44 236.945 -65.232 243.729 -71.592C250.514 -77.952 265.394 -107.13 263.274 -120.274z"/> - <path fill="#999999" d="M262.9 -119.916C262.9 -119.916 264.97 -128.288 260.394 -123.712C260.394 -123.712 253.738 -118.304 246.665 -118.304C246.665 -118.304 232.937 -116.224 228.777 -103.744C228.777 -103.744 225.033 -78.368 232.521 -72.96C232.521 -72.96 237.097 -65.888 243.753 -72.128C250.41 -78.368 264.98 -107.02 262.9 -119.916z"/> - <path fill="#cccccc" d="M262.526 -119.558C262.526 -119.558 264.586 -127.744 260.098 -123.256C260.098 -123.256 253.569 -117.952 246.633 -117.952C246.633 -117.952 233.169 -115.912 229.089 -103.672C229.089 -103.672 225.417 -78.784 232.761 -73.48C232.761 -73.48 237.249 -66.544 243.777 -72.664C250.305 -78.784 264.566 -106.91 262.526 -119.558z"/> - <path fill="#ffffff" d="M262.151 -119.2C262.151 -119.2 264.201 -127.2 259.801 -122.8C259.801 -122.8 253.401 -117.6 246.601 -117.6C246.601 -117.6 233.401 -115.6 229.401 -103.6C229.401 -103.6 225.801 -79.2 233.001 -74C233.001 -74 237.401 -67.2 243.801 -73.2C250.201 -79.2 264.151 -106.8 262.151 -119.2z"/> - <path fill="#992600" d="M50.6 84C50.6 84 30.2 64.8 22.2 64C22.2 64 -12.2 60 -27 78C-27 78 -9.4 57.6 18.2 63.2C18.2 63.2 -3.4 58.8 -15.8 62C-15.8 62 -32.6 62 -42.2 76L-45 80.8C-45 80.8 -41 66 -22.6 60C-22.6 60 0.2 55.2 11 60C11 60 -10.6 53.2 -20.6 55.2C-20.6 55.2 -51 52.8 -63.8 79.2C-63.8 79.2 -59.8 64.8 -45 57.6C-45 57.6 -31.4 48.8 -11 51.6C-11 51.6 3.4 54.8 8.6 57.2C13.8 59.6 12.6 56.8 4.2 52C4.2 52 -1.4 42 -15.4 42.4C-15.4 42.4 -58.2 46 -68.6 58C-68.6 58 -55 46.8 -44.6 44C-44.6 44 -22.2 36 -13.8 36.8C-13.8 36.8 11 37.8 18.6 33.8C18.6 33.8 7.4 38.8 10.6 42C13.8 45.2 20.6 52.8 20.6 54C20.6 55.2 44.8 77.3 48.4 81.7L50.6 84z"/> - <path fill="#cccccc" d="M189 278C189 278 173.5 241.5 161 232C161 232 187 248 190.5 266C190.5 266 190.5 276 189 278z"/> - <path fill="#cccccc" d="M236 285.5C236 285.5 209.5 230.5 191 206.5C191 206.5 234.5 244 239.5 270.5L240 276L237 273.5C237 273.5 236.5 282.5 236 285.5z"/> - <path fill="#cccccc" d="M292.5 237C292.5 237 230 177.5 228.5 175C228.5 175 289 241 292 248.5C292 248.5 290 239.5 292.5 237z"/> - <path fill="#cccccc" d="M104 280.5C104 280.5 123.5 228.5 142.5 251C142.5 251 157.5 261 157 264C157 264 153 257.5 135 258C135 258 116 255 104 280.5z"/> - <path fill="#cccccc" d="M294.5 153C294.5 153 249.5 124.5 242 123C230.193 120.639 291.5 152 296.5 162.5C296.5 162.5 298.5 160 294.5 153z"/> - <path fill="#000000" d="M143.801 259.601C143.801 259.601 164.201 257.601 171.001 250.801L175.401 254.401L193.001 216.001L196.601 221.201C196.601 221.201 211.001 206.401 210.201 198.401C209.401 190.401 223.001 204.401 223.001 204.401C223.001 204.401 222.201 192.801 229.401 199.601C229.401 199.601 227.001 184.001 235.401 192.001C235.401 192.001 224.864 161.844 247.401 187.601C253.001 194.001 248.601 187.201 248.601 187.201C248.601 187.201 222.601 139.201 244.201 153.601C244.201 153.601 246.201 130.801 245.001 126.401C243.801 122.001 241.801 99.6 237.001 94.4C232.201 89.2 237.401 87.6 243.001 92.8C243.001 92.8 231.801 68.8 245.001 80.8C245.001 80.8 241.401 65.6 237.001 62.8C237.001 62.8 231.401 45.6 246.601 56.4C246.601 56.4 242.201 44 239.001 40.8C239.001 40.8 227.401 13.2 234.601 18L239.001 21.6C239.001 21.6 232.201 7.6 238.601 12C245.001 16.4 245.001 16 245.001 16C245.001 16 223.801 -17.2 244.201 0.4C244.201 0.4 236.042 -13.518 232.601 -20.4C232.601 -20.4 213.801 -40.8 228.201 -34.4L233.001 -32.8C233.001 -32.8 224.201 -42.8 216.201 -44.4C208.201 -46 218.601 -52.4 225.001 -50.4C231.401 -48.4 247.001 -40.8 247.001 -40.8C247.001 -40.8 259.801 -22 263.801 -21.6C263.801 -21.6 243.801 -29.2 249.801 -21.2C249.801 -21.2 264.201 -7.2 257.001 -7.6C257.001 -7.6 251.001 -0.4 255.801 8.4C255.801 8.4 237.342 -9.991 252.201 15.6L259.001 32C259.001 32 234.601 7.2 245.801 29.2C245.801 29.2 263.001 52.8 265.001 53.2C267.001 53.6 271.401 62.4 271.401 62.4L267.001 60.4L272.201 69.2C272.201 69.2 261.001 57.2 267.001 70.4L272.601 84.8C272.601 84.8 252.201 62.8 265.801 92.4C265.801 92.4 249.401 87.2 258.201 104.4C258.201 104.4 256.601 120.401 257.001 125.601C257.401 130.801 258.601 159.201 254.201 167.201C249.801 175.201 260.201 194.401 262.201 198.401C264.201 202.401 267.801 213.201 259.001 204.001C250.201 194.801 254.601 200.401 256.601 209.201C258.601 218.001 264.601 233.601 263.801 239.201C263.801 239.201 262.601 240.401 259.401 236.801C259.401 236.801 244.601 214.001 246.201 228.401C246.201 228.401 245.001 236.401 241.801 245.201C241.801 245.201 238.601 256.001 238.601 247.201C238.601 247.201 235.401 230.401 232.601 238.001C229.801 245.601 226.201 251.601 223.401 254.001C220.601 256.401 215.401 233.601 214.201 244.001C214.201 244.001 202.201 231.601 197.401 248.001L185.801 264.401C185.801 264.401 185.401 252.001 184.201 258.001C184.201 258.001 154.201 264.001 143.801 259.601z"/> - <path fill="#000000" d="M109.401 -97.2C109.401 -97.2 97.801 -105.2 93.801 -104.8C89.801 -104.4 121.401 -113.6 162.601 -86C162.601 -86 167.401 -83.2 171.001 -83.6C171.001 -83.6 174.201 -81.2 171.401 -77.6C171.401 -77.6 162.601 -68 173.801 -56.8C173.801 -56.8 192.201 -50 186.601 -58.8C186.601 -58.8 197.401 -54.8 199.801 -50.8C202.201 -46.8 201.001 -50.8 201.001 -50.8C201.001 -50.8 194.601 -58 188.601 -63.2C188.601 -63.2 183.401 -65.2 180.601 -73.6C177.801 -82 175.401 -92 179.801 -95.2C179.801 -95.2 175.801 -90.8 176.601 -94.8C177.401 -98.8 181.001 -102.4 182.601 -102.8C184.201 -103.2 200.601 -119 207.401 -119.4C207.401 -119.4 198.201 -118 195.201 -119C192.201 -120 165.601 -131.4 159.601 -132.6C159.601 -132.6 142.801 -139.2 154.801 -137.2C154.801 -137.2 190.601 -133.4 208.801 -120.2C208.801 -120.2 201.601 -128.6 183.201 -135.6C183.201 -135.6 161.001 -148.2 125.801 -143.2C125.801 -143.2 108.001 -140 100.201 -138.2C100.201 -138.2 97.601 -138.8 97.001 -139.2C96.401 -139.6 84.6 -148.6 57 -141.6C57 -141.6 40 -137 31.4 -132.2C31.4 -132.2 16.2 -131 12.6 -127.8C12.6 -127.8 -6 -113.2 -8 -112.4C-10 -111.6 -21.4 -104 -22.2 -103.6C-22.2 -103.6 2.4 -110.2 4.8 -112.6C7.2 -115 24.6 -117.6 27 -116.2C29.4 -114.8 37.8 -115.4 28.2 -114.8C28.2 -114.8 103.801 -100 104.601 -98C105.401 -96 109.401 -97.2 109.401 -97.2z"/> - <path fill="#cc7226" d="M180.801 -106.4C180.801 -106.4 170.601 -113.8 168.601 -113.8C166.601 -113.8 154.201 -124 150.001 -123.6C145.801 -123.2 133.601 -133.2 106.201 -125C106.201 -125 105.601 -127 109.201 -127.8C109.201 -127.8 115.601 -130 116.001 -130.6C116.001 -130.6 136.201 -134.8 143.401 -131.2C143.401 -131.2 152.601 -128.6 158.801 -122.4C158.801 -122.4 170.001 -119.2 173.201 -120.2C173.201 -120.2 182.001 -118 182.401 -116.2C182.401 -116.2 188.201 -113.2 186.401 -110.6C186.401 -110.6 186.801 -109 180.801 -106.4z"/> - <path fill="#cc7226" d="M168.33 -108.509C169.137 -107.877 170.156 -107.779 170.761 -106.97C170.995 -106.656 170.706 -106.33 170.391 -106.233C169.348 -105.916 168.292 -106.486 167.15 -105.898C166.748 -105.691 166.106 -105.873 165.553 -106.022C163.921 -106.463 162.092 -106.488 160.401 -105.8C158.416 -106.929 156.056 -106.345 153.975 -107.346C153.917 -107.373 153.695 -107.027 153.621 -107.054C150.575 -108.199 146.832 -107.916 144.401 -110.2C141.973 -110.612 139.616 -111.074 137.188 -111.754C135.37 -112.263 133.961 -113.252 132.341 -114.084C130.964 -114.792 129.507 -115.314 127.973 -115.686C126.11 -116.138 124.279 -116.026 122.386 -116.546C122.293 -116.571 122.101 -116.227 122.019 -116.254C121.695 -116.362 121.405 -116.945 121.234 -116.892C119.553 -116.37 118.065 -117.342 116.401 -117C115.223 -118.224 113.495 -117.979 111.949 -118.421C108.985 -119.269 105.831 -117.999 102.801 -119C106.914 -120.842 111.601 -119.61 115.663 -121.679C117.991 -122.865 120.653 -121.763 123.223 -122.523C123.71 -122.667 124.401 -122.869 124.801 -122.2C124.935 -122.335 125.117 -122.574 125.175 -122.546C127.625 -121.389 129.94 -120.115 132.422 -119.049C132.763 -118.903 133.295 -119.135 133.547 -118.933C135.067 -117.717 137.01 -117.82 138.401 -116.6C140.099 -117.102 141.892 -116.722 143.621 -117.346C143.698 -117.373 143.932 -117.032 143.965 -117.054C145.095 -117.802 146.25 -117.531 147.142 -117.227C147.48 -117.112 148.143 -116.865 148.448 -116.791C149.574 -116.515 150.43 -116.035 151.609 -115.852C151.723 -115.834 151.908 -116.174 151.98 -116.146C153.103 -115.708 154.145 -115.764 154.801 -114.6C154.936 -114.735 155.101 -114.973 155.183 -114.946C156.21 -114.608 156.859 -113.853 157.96 -113.612C158.445 -113.506 159.057 -112.88 159.633 -112.704C162.025 -111.973 163.868 -110.444 166.062 -109.549C166.821 -109.239 167.697 -109.005 168.33 -108.509z"/> - <path fill="#cc7226" d="M91.696 -122.739C89.178 -124.464 86.81 -125.57 84.368 -127.356C84.187 -127.489 83.827 -127.319 83.625 -127.441C82.618 -128.05 81.73 -128.631 80.748 -129.327C80.209 -129.709 79.388 -129.698 78.88 -129.956C76.336 -131.248 73.707 -131.806 71.2 -133C71.882 -133.638 73.004 -133.394 73.6 -134.2C73.795 -133.92 74.033 -133.636 74.386 -133.827C76.064 -134.731 77.914 -134.884 79.59 -134.794C81.294 -134.702 83.014 -134.397 84.789 -134.125C85.096 -134.078 85.295 -133.555 85.618 -133.458C87.846 -132.795 90.235 -133.32 92.354 -132.482C93.945 -131.853 95.515 -131.03 96.754 -129.755C97.006 -129.495 96.681 -129.194 96.401 -129C96.789 -129.109 97.062 -128.903 97.173 -128.59C97.257 -128.351 97.257 -128.049 97.173 -127.81C97.061 -127.498 96.782 -127.397 96.408 -127.346C95.001 -127.156 96.773 -128.536 96.073 -128.088C94.8 -127.274 95.546 -125.868 94.801 -124.6C94.521 -124.794 94.291 -125.012 94.401 -125.4C94.635 -124.878 94.033 -124.588 93.865 -124.272C93.48 -123.547 92.581 -122.132 91.696 -122.739z"/> - <path fill="#cc7226" d="M59.198 -115.391C56.044 -116.185 52.994 -116.07 49.978 -117.346C49.911 -117.374 49.688 -117.027 49.624 -117.054C48.258 -117.648 47.34 -118.614 46.264 -119.66C45.351 -120.548 43.693 -120.161 42.419 -120.648C42.095 -120.772 41.892 -121.284 41.591 -121.323C40.372 -121.48 39.445 -122.429 38.4 -123C40.736 -123.795 43.147 -123.764 45.609 -124.148C45.722 -124.166 45.867 -123.845 46 -123.845C46.136 -123.845 46.266 -124.066 46.4 -124.2C46.595 -123.92 46.897 -123.594 47.154 -123.848C47.702 -124.388 48.258 -124.198 48.798 -124.158C48.942 -124.148 49.067 -123.845 49.2 -123.845C49.336 -123.845 49.467 -124.156 49.6 -124.156C49.736 -124.155 49.867 -123.845 50 -123.845C50.136 -123.845 50.266 -124.066 50.4 -124.2C51.092 -123.418 51.977 -123.972 52.799 -123.793C53.837 -123.566 54.104 -122.418 55.178 -122.12C59.893 -120.816 64.03 -118.671 68.393 -116.584C68.7 -116.437 68.91 -116.189 68.8 -115.8C69.067 -115.8 69.38 -115.888 69.57 -115.756C70.628 -115.024 71.669 -114.476 72.366 -113.378C72.582 -113.039 72.253 -112.632 72.02 -112.684C67.591 -113.679 63.585 -114.287 59.198 -115.391z"/> - <path fill="#cc7226" d="M45.338 -71.179C43.746 -72.398 43.162 -74.429 42.034 -76.221C41.82 -76.561 42.094 -76.875 42.411 -76.964C42.971 -77.123 43.514 -76.645 43.923 -76.443C45.668 -75.581 47.203 -74.339 49.2 -74.2C51.19 -71.966 55.45 -71.581 55.457 -68.2C55.458 -67.341 54.03 -68.259 53.6 -67.4C51.149 -68.403 48.76 -68.3 46.38 -69.767C45.763 -70.148 46.093 -70.601 45.338 -71.179z"/> - <path fill="#cc7226" d="M17.8 -123.756C17.935 -123.755 24.966 -123.522 24.949 -123.408C24.904 -123.099 17.174 -122.05 16.81 -122.22C16.646 -122.296 9.134 -119.866 9 -120C9.268 -120.135 17.534 -123.756 17.8 -123.756z"/> - <path fill="#000000" d="M33.2 -114C33.2 -114 18.4 -112.2 14 -111C9.6 -109.8 -9 -102.2 -12 -100.2C-12 -100.2 -25.4 -94.8 -42.4 -74.8C-42.4 -74.8 -34.8 -78.2 -32.6 -81C-32.6 -81 -19 -93.6 -19.2 -91C-19.2 -91 -7 -99.6 -7.6 -97.4C-7.6 -97.4 16.8 -108.6 14.8 -105.4C14.8 -105.4 36.4 -110 35.4 -108C35.4 -108 54.2 -103.6 51.4 -103.4C51.4 -103.4 45.6 -102.2 52 -98.6C52 -98.6 48.6 -94.2 43.2 -98.2C37.8 -102.2 40.8 -100 35.8 -99C35.8 -99 33.2 -98.2 28.6 -102.2C28.6 -102.2 23 -106.8 14.2 -103.2C14.2 -103.2 -16.4 -90.6 -18.4 -90C-18.4 -90 -22 -87.2 -24.4 -83.6C-24.4 -83.6 -30.2 -79.2 -33.2 -77.8C-33.2 -77.8 -46 -66.2 -47.2 -64.8C-47.2 -64.8 -50.6 -59.6 -51.4 -59.2C-51.4 -59.2 -45 -63 -43 -65C-43 -65 -29 -75 -23.6 -75.8C-23.6 -75.8 -19.2 -78.8 -18.4 -80.2C-18.4 -80.2 -4 -89.4 0.2 -89.4C0.2 -89.4 9.4 -84.2 11.8 -91.2C11.8 -91.2 17.6 -93 23.2 -91.8C23.2 -91.8 26.4 -94.4 25.6 -96.6C25.6 -96.6 27.2 -98.4 28.2 -94.6C28.2 -94.6 31.6 -91 36.4 -93C36.4 -93 40.4 -93.2 38.4 -90.8C38.4 -90.8 34 -87 22.2 -86.8C22.2 -86.8 9.8 -86.2 -6.6 -78.6C-6.6 -78.6 -36.4 -68.2 -45.6 -57.8C-45.6 -57.8 -52 -49 -57.4 -47.8C-57.4 -47.8 -63.2 -47 -69.2 -39.6C-69.2 -39.6 -59.4 -45.4 -50.4 -45.4C-50.4 -45.4 -46.4 -47.8 -50.2 -44.2C-50.2 -44.2 -53.8 -36.6 -52.2 -31.2C-52.2 -31.2 -52.8 -26 -53.6 -24.4C-53.6 -24.4 -61.4 -11.6 -61.4 -9.2C-61.4 -6.8 -60.2 3 -59.8 3.6C-59.4 4.2 -60.8 2 -57 4.4C-53.2 6.8 -50.4 8.4 -49.6 11.2C-48.8 14 -51.6 5.8 -51.8 4C-52 2.2 -56.2 -5 -55.4 -7.4C-55.4 -7.4 -54.4 -6.4 -53.6 -5C-53.6 -5 -54.2 -5.6 -53.6 -9.2C-53.6 -9.2 -52.8 -14.4 -51.4 -17.6C-50 -20.8 -48 -24.6 -47.6 -25.4C-47.2 -26.2 -47.2 -32 -45.8 -29.4L-42.4 -26.8C-42.4 -26.8 -45.2 -29.4 -43 -31.6C-43 -31.6 -44 -37.2 -42.2 -39.8C-42.2 -39.8 -35.2 -48.2 -33.6 -49.2C-32 -50.2 -33.4 -49.8 -33.4 -49.8C-33.4 -49.8 -27.4 -54 -33.2 -52.4C-33.2 -52.4 -37.2 -50.8 -40.2 -50.8C-40.2 -50.8 -47.8 -48.8 -43.8 -53C-39.8 -57.2 -29.8 -62.6 -26 -62.4L-25.2 -60.8L-14 -63.2L-15.2 -62.4C-15.2 -62.4 -15.4 -62.6 -11.2 -63C-7 -63.4 -1.2 -62 0.2 -63.8C1.6 -65.6 5 -66.6 4.6 -65.2C4.2 -63.8 4 -61.8 4 -61.8C4 -61.8 9 -67.6 8.4 -65.4C7.8 -63.2 -0.4 -58 -1.8 -51.8L8.6 -60L12.2 -63C12.2 -63 15.8 -60.8 16 -62.4C16.2 -64 20.8 -69.8 22 -69.6C23.2 -69.4 25.2 -72.2 25 -69.6C24.8 -67 32.4 -61.6 32.4 -61.6C32.4 -61.6 35.6 -63.4 37 -62C38.4 -60.6 42.6 -81.8 42.6 -81.8L67.6 -92.4L111.201 -95.8L94.201 -102.6L33.2 -114z"/> - <path stroke="#4c0000" stroke-width="2" d="M51.4 85C51.4 85 36.4 68.2 28 65.6C28 65.6 14.6 58.8 -10 66.6"/> - <path stroke="#4c0000" stroke-width="2" d="M24.8 64.2C24.8 64.2 -0.4 56.2 -15.8 60.4C-15.8 60.4 -34.2 62.4 -42.6 76.2"/> - <path stroke="#4c0000" stroke-width="2" d="M21.2 63C21.2 63 4.2 55.8 -10.6 53.6C-10.6 53.6 -27.2 51 -43.8 58.2C-43.8 58.2 -56 64.2 -61.4 74.4"/> - <path stroke="#4c0000" stroke-width="2" d="M22.2 63.4C22.2 63.4 6.8 52.4 5.8 51C5.8 51 -1.2 40 -14.2 39.6C-14.2 39.6 -35.6 40.4 -52.8 48.4"/> - <path fill="#000000" d="M20.895 54.407C22.437 55.87 49.4 84.8 49.4 84.8C84.6 121.401 56.6 87.2 56.6 87.2C49 82.4 39.8 63.6 39.8 63.6C38.6 60.8 53.8 70.8 53.8 70.8C57.8 71.6 71.4 90.8 71.4 90.8C64.6 88.4 69.4 95.6 69.4 95.6C72.2 97.6 92.601 113.201 92.601 113.201C96.201 117.201 100.201 118.801 100.201 118.801C114.201 113.601 107.801 126.801 107.801 126.801C110.201 133.601 115.801 122.001 115.801 122.001C127.001 105.2 110.601 107.601 110.601 107.601C80.6 110.401 73.8 94.4 73.8 94.4C71.4 92 80.2 94.4 80.2 94.4C88.601 96.4 73 82 73 82C75.4 82 84.6 88.8 84.6 88.8C95.001 98 97.001 96 97.001 96C115.001 87.2 125.401 94.8 125.401 94.8C127.401 96.4 121.801 103.2 123.401 108.401C125.001 113.601 129.801 126.001 129.801 126.001C127.401 127.601 127.801 138.401 127.801 138.401C144.601 161.601 135.001 159.601 135.001 159.601C119.401 159.201 134.201 166.801 134.201 166.801C137.401 168.801 146.201 176.001 146.201 176.001C143.401 174.801 141.801 180.001 141.801 180.001C146.601 184.001 143.801 188.801 143.801 188.801C137.801 190.001 136.601 194.001 136.601 194.001C143.401 202.001 133.401 202.401 133.401 202.401C137.001 206.801 132.201 218.801 132.201 218.801C127.401 218.801 121.001 224.401 121.001 224.401C123.401 229.201 113.001 234.801 113.001 234.801C104.601 236.401 107.401 243.201 107.401 243.201C99.401 249.201 97.001 265.201 97.001 265.201C96.201 275.601 93.801 278.801 99.001 276.801C104.201 274.801 103.401 262.401 103.401 262.401C98.601 246.801 141.401 230.801 141.401 230.801C145.401 229.201 146.201 224.001 146.201 224.001C148.201 224.401 157.001 232.001 157.001 232.001C164.601 243.201 165.001 234.001 165.001 234.001C166.201 230.401 164.601 224.401 164.601 224.401C170.601 202.801 156.601 196.401 156.601 196.401C146.601 162.801 160.601 171.201 160.601 171.201C163.401 176.801 174.201 182.001 174.201 182.001L177.801 179.601C176.201 174.801 184.601 168.801 184.601 168.801C187.401 175.201 193.401 167.201 193.401 167.201C197.001 142.801 209.401 157.201 209.401 157.201C213.401 158.401 214.601 151.601 214.601 151.601C218.201 141.201 214.601 127.601 214.601 127.601C218.201 127.201 227.801 133.201 227.801 133.201C230.601 129.601 221.401 112.801 225.401 115.201C229.401 117.601 233.801 119.201 233.801 119.201C234.601 117.201 224.601 104.801 224.601 104.801C220.201 102 215.001 81.6 215.001 81.6C222.201 85.2 212.201 70 212.201 70C212.201 66.8 218.201 55.6 218.201 55.6C217.401 48.8 218.201 49.2 218.201 49.2C221.001 50.4 229.001 52 222.201 45.6C215.401 39.2 223.001 34.4 223.001 34.4C227.401 31.6 213.801 32 213.801 32C208.601 27.6 209.001 23.6 209.001 23.6C217.001 25.6 202.601 11.2 200.201 7.6C197.801 4 207.401 -1.2 207.401 -1.2C220.601 -4.8 209.001 -8 209.001 -8C189.401 -7.6 200.201 -18.4 200.201 -18.4C206.201 -18 204.601 -20.4 204.601 -20.4C199.401 -21.6 189.801 -28 189.801 -28C185.801 -31.6 189.401 -30.8 189.401 -30.8C206.201 -29.6 177.401 -40.8 177.401 -40.8C185.401 -40.8 167.401 -51.2 167.401 -51.2C165.401 -52.8 162.201 -60.4 162.201 -60.4C156.201 -65.6 151.401 -72.4 151.401 -72.4C151.001 -76.8 146.201 -81.6 146.201 -81.6C134.601 -95.2 129.001 -94.8 129.001 -94.8C114.201 -98.4 109.001 -97.6 109.001 -97.6L56.2 -93.2C29.8 -80.4 37.6 -59.4 37.6 -59.4C44 -51 53.2 -54.8 53.2 -54.8C57.8 -61 69.4 -58.8 69.4 -58.8C89.801 -55.6 87.201 -59.2 87.201 -59.2C84.801 -63.8 68.6 -70 68.4 -70.6C68.2 -71.2 59.4 -74.6 59.4 -74.6C56.4 -75.8 52 -85 52 -85C48.8 -88.4 64.6 -82.6 64.6 -82.6C63.4 -81.6 70.8 -77.6 70.8 -77.6C88.201 -78.6 98.801 -67.8 98.801 -67.8C109.601 -51.2 109.801 -59.4 109.801 -59.4C112.601 -68.8 100.801 -90 100.801 -90C101.201 -92 109.401 -85.4 109.401 -85.4C110.801 -87.4 111.601 -81.6 111.601 -81.6C111.801 -79.2 115.601 -71.2 115.601 -71.2C118.401 -58.2 122.001 -65.6 122.001 -65.6L126.601 -56.2C128.001 -53.6 122.001 -46 122.001 -46C121.801 -43.2 122.601 -43.4 117.001 -35.8C111.401 -28.2 114.801 -23.8 114.801 -23.8C113.401 -17.2 122.201 -17.6 122.201 -17.6C124.801 -15.4 128.201 -15.4 128.201 -15.4C130.001 -13.4 132.401 -14 132.401 -14C134.001 -17.8 140.201 -15.8 140.201 -15.8C141.601 -18.2 149.801 -18.6 149.801 -18.6C150.801 -21.2 151.201 -22.8 154.601 -23.4C158.001 -24 133.401 -67 133.401 -67C139.801 -67.8 131.601 -80.2 131.601 -80.2C129.401 -86.8 140.801 -72.2 143.001 -70.8C145.201 -69.4 146.201 -67.2 144.601 -67.4C143.001 -67.6 141.201 -65.4 142.601 -65.2C144.001 -65 157.001 -50 160.401 -39.8C163.801 -29.6 169.801 -25.6 176.001 -19.6C182.201 -13.6 181.401 10.6 181.401 10.6C181.001 19.4 187.001 30 187.001 30C189.001 33.8 184.801 52 184.801 52C182.801 54.2 184.201 55 184.201 55C185.201 56.2 192.001 69.4 192.001 69.4C190.201 69.2 193.801 72.8 193.801 72.8C199.001 78.8 192.601 75.8 192.601 75.8C186.601 74.2 193.601 84 193.601 84C194.801 85.8 185.801 81.2 185.801 81.2C176.601 80.6 188.201 87.8 188.201 87.8C196.801 95 185.401 90.6 185.401 90.6C180.801 88.8 184.001 95.6 184.001 95.6C187.201 97.2 204.401 104.2 204.401 104.2C204.801 108.001 201.801 113.001 201.801 113.001C202.201 117.001 200.001 120.401 200.001 120.401C198.801 128.601 198.201 129.401 198.201 129.401C194.001 129.601 186.601 143.401 186.601 143.401C184.801 146.001 174.601 158.001 174.601 158.001C172.601 165.001 154.601 157.801 154.601 157.801C148.001 161.201 150.001 157.801 150.001 157.801C149.601 155.601 154.401 149.601 154.401 149.601C161.401 147.001 158.801 136.201 158.801 136.201C162.801 134.801 151.601 132.001 151.801 130.801C152.001 129.601 157.801 128.201 157.801 128.201C165.801 126.201 161.401 123.801 161.401 123.801C160.801 119.801 163.801 114.201 163.801 114.201C175.401 113.401 163.801 97.2 163.801 97.2C153.001 89.6 152.001 83.8 152.001 83.8C164.601 75.6 156.401 63.2 156.601 59.6C156.801 56 158.001 34.4 158.001 34.4C156.001 28.2 153.001 14.6 153.001 14.6C155.201 9.4 162.601 -3.2 162.601 -3.2C165.401 -7.4 174.201 -12.2 172.001 -15.2C169.801 -18.2 162.001 -16.4 162.001 -16.4C154.201 -17.8 154.801 -12.6 154.801 -12.6C153.201 -11.6 152.401 -6.6 152.401 -6.6C151.68 1.333 142.801 7.6 142.801 7.6C131.601 13.8 140.801 17.8 140.801 17.8C146.801 24.4 137.001 24.6 137.001 24.6C126.001 22.8 134.201 33 134.201 33C145.001 45.8 142.001 48.6 142.001 48.6C131.801 49.6 144.401 58.8 144.401 58.8C144.401 58.8 143.601 56.8 143.801 58.6C144.001 60.4 147.001 64.6 147.801 66.6C148.601 68.6 144.601 68.8 144.601 68.8C145.201 78.4 129.801 74.2 129.801 74.2C129.801 74.2 129.801 74.2 128.201 74.4C126.601 74.6 115.401 73.8 109.601 71.6C103.801 69.4 97.001 69.4 97.001 69.4C97.001 69.4 93.001 71.2 85.4 71C77.8 70.8 69.8 73.6 69.8 73.6C65.4 73.2 74 68.8 74.2 69C74.4 69.2 80 63.6 72 64.2C50.203 65.835 39.4 55.6 39.4 55.6C37.4 54.2 34.8 51.4 34.8 51.4C24.8 49.4 36.2 63.8 36.2 63.8C37.4 65.2 36 66.2 36 66.2C35.2 64.6 27.4 59.2 27.4 59.2C24.589 58.227 23.226 56.893 20.895 54.407z"/> - <path fill="#4c0000" d="M-3 42.8C-3 42.8 8.6 48.4 11.2 51.2C13.8 54 27.8 65.4 27.8 65.4C27.8 65.4 22.4 63.4 19.8 61.6C17.2 59.8 6.4 51.6 6.4 51.6C6.4 51.6 2.6 45.6 -3 42.8z"/> - <path fill="#99cc32" d="M-61.009 11.603C-60.672 11.455 -61.196 8.743 -61.4 8.2C-62.422 5.474 -71.4 4 -71.4 4C-71.627 5.365 -71.682 6.961 -71.576 8.599C-71.576 8.599 -66.708 14.118 -61.009 11.603z"/> - <path fill="#659900" d="M-61.009 11.403C-61.458 11.561 -61.024 8.669 -61.2 8.2C-62.222 5.474 -71.4 3.9 -71.4 3.9C-71.627 5.265 -71.682 6.861 -71.576 8.499C-71.576 8.499 -67.308 13.618 -61.009 11.403z"/> - <path fill="#000000" d="M-65.4 11.546C-66.025 11.546 -66.531 10.406 -66.531 9C-66.531 7.595 -66.025 6.455 -65.4 6.455C-64.775 6.455 -64.268 7.595 -64.268 9C-64.268 10.406 -64.775 11.546 -65.4 11.546z"/> - <path fill="#000000" d="M-65.4 9z"/> - <path fill="#000000" d="M-111 109.601C-111 109.601 -116.6 119.601 -91.8 113.601C-91.8 113.601 -77.8 112.401 -75.4 110.001C-74.2 110.801 -65.834 113.734 -63 114.401C-56.2 116.001 -47.8 106 -47.8 106C-47.8 106 -43.2 95.5 -40.4 95.5C-37.6 95.5 -40.8 97.1 -40.8 97.1C-40.8 97.1 -47.4 107.201 -47 108.801C-47 108.801 -52.2 128.801 -68.2 129.601C-68.2 129.601 -84.35 130.551 -83 136.401C-83 136.401 -74.2 134.001 -71.8 136.401C-71.8 136.401 -61 136.001 -69 142.401L-75.8 154.001C-75.8 154.001 -75.66 157.919 -85.8 154.401C-95.6 151.001 -105.9 138.101 -105.9 138.101C-105.9 138.101 -121.85 123.551 -111 109.601z"/> - <path fill="#e59999" d="M-112.2 113.601C-112.2 113.601 -114.2 123.201 -77.4 112.801C-77.4 112.801 -73 112.801 -70.6 113.601C-68.2 114.401 -56.2 117.201 -54.2 116.001C-54.2 116.001 -61.4 129.601 -73 128.001C-73 128.001 -86.2 129.601 -85.8 134.401C-85.8 134.401 -81.8 141.601 -77 144.001C-77 144.001 -74.2 146.401 -74.6 149.601C-75 152.801 -77.8 154.401 -79.8 155.201C-81.8 156.001 -85 152.801 -86.6 152.801C-88.2 152.801 -96.6 146.401 -101 141.601C-105.4 136.801 -113.8 124.801 -113.4 122.001C-113 119.201 -112.2 113.601 -112.2 113.601z"/> - <path fill="#b26565" d="M-109 131.051C-106.4 135.001 -103.2 139.201 -101 141.601C-96.6 146.401 -88.2 152.801 -86.6 152.801C-85 152.801 -81.8 156.001 -79.8 155.201C-77.8 154.401 -75 152.801 -74.6 149.601C-74.2 146.401 -77 144.001 -77 144.001C-80.066 142.468 -82.806 138.976 -84.385 136.653C-84.385 136.653 -84.2 139.201 -89.4 138.401C-94.6 137.601 -99.8 134.801 -101.4 131.601C-103 128.401 -105.4 126.001 -103.8 129.601C-102.2 133.201 -99.8 136.801 -98.2 137.201C-96.6 137.601 -97 138.801 -99.4 138.401C-101.8 138.001 -104.6 137.601 -109 132.401z"/> - <path fill="#992600" d="M-111.6 110.001C-111.6 110.001 -109.8 96.4 -108.6 92.4C-108.6 92.4 -109.4 85.6 -107 81.4C-104.6 77.2 -102.6 71 -99.6 65.6C-96.6 60.2 -96.4 56.2 -92.4 54.6C-88.4 53 -82.4 44.4 -79.6 43.4C-76.8 42.4 -77 43.2 -77 43.2C-77 43.2 -70.2 28.4 -56.6 32.4C-56.6 32.4 -72.8 29.6 -57 20.2C-57 20.2 -61.8 21.3 -58.5 14.3C-56.299 9.632 -56.8 16.4 -67.8 28.2C-67.8 28.2 -72.8 36.8 -78 39.8C-83.2 42.8 -95.2 49.8 -96.4 53.6C-97.6 57.4 -100.8 63.2 -102.8 64.8C-104.8 66.4 -107.6 70.6 -108 74C-108 74 -109.2 78 -110.6 79.2C-112 80.4 -112.2 83.6 -112.2 85.6C-112.2 87.6 -114.2 90.4 -114 92.8C-114 92.8 -113.2 111.801 -113.6 113.801L-111.6 110.001z"/> - <path fill="#ffffff" d="M-120.2 114.601C-120.2 114.601 -122.2 113.201 -126.6 119.201C-126.6 119.201 -119.3 152.201 -119.3 153.601C-119.3 153.601 -118.2 151.501 -119.5 144.301C-120.8 137.101 -121.7 124.401 -121.7 124.401L-120.2 114.601z"/> - <path fill="#992600" d="M-98.6 54C-98.6 54 -116.2 57.2 -115.8 86.4L-116.6 111.201C-116.6 111.201 -117.8 85.6 -119 84C-120.2 82.4 -116.2 71.2 -119.4 77.2C-119.4 77.2 -133.4 91.2 -125.4 112.401C-125.4 112.401 -123.9 115.701 -126.9 111.101C-126.9 111.101 -131.5 98.5 -130.4 92.1C-130.4 92.1 -130.2 89.9 -128.3 87.1C-128.3 87.1 -119.7 75.4 -117 73.1C-117 73.1 -115.2 58.7 -99.8 53.5C-99.8 53.5 -94.1 51.2 -98.6 54z"/> - <path fill="#000000" d="M40.8 -12.2C41.46 -12.554 41.451 -13.524 42.031 -13.697C43.18 -14.041 43.344 -15.108 43.862 -15.892C44.735 -17.211 44.928 -18.744 45.51 -20.235C45.782 -20.935 45.809 -21.89 45.496 -22.55C44.322 -25.031 43.62 -27.48 42.178 -29.906C41.91 -30.356 41.648 -31.15 41.447 -31.748C40.984 -33.132 39.727 -34.123 38.867 -35.443C38.579 -35.884 39.104 -36.809 38.388 -36.893C37.491 -36.998 36.042 -37.578 35.809 -36.552C35.221 -33.965 36.232 -31.442 37.2 -29C36.418 -28.308 36.752 -27.387 36.904 -26.62C37.614 -23.014 36.416 -19.662 35.655 -16.188C35.632 -16.084 35.974 -15.886 35.946 -15.824C34.724 -13.138 33.272 -10.693 31.453 -8.312C30.695 -7.32 29.823 -6.404 29.326 -5.341C28.958 -4.554 28.55 -3.588 28.8 -2.6C25.365 0.18 23.115 4.025 20.504 7.871C20.042 8.551 20.333 9.76 20.884 10.029C21.697 10.427 22.653 9.403 23.123 8.557C23.512 7.859 23.865 7.209 24.356 6.566C24.489 6.391 24.31 5.972 24.445 5.851C27.078 3.504 28.747 0.568 31.2 -1.8C33.15 -2.129 34.687 -3.127 36.435 -4.14C36.743 -4.319 37.267 -4.07 37.557 -4.265C39.31 -5.442 39.308 -7.478 39.414 -9.388C39.464 -10.272 39.66 -11.589 40.8 -12.2z"/> - <path fill="#000000" d="M31.959 -16.666C32.083 -16.743 31.928 -17.166 32.037 -17.382C32.199 -17.706 32.602 -17.894 32.764 -18.218C32.873 -18.434 32.71 -18.814 32.846 -18.956C35.179 -21.403 35.436 -24.427 34.4 -27.4C35.424 -28.02 35.485 -29.282 35.06 -30.129C34.207 -31.829 34.014 -33.755 33.039 -35.298C32.237 -36.567 30.659 -37.811 29.288 -36.508C28.867 -36.108 28.546 -35.321 28.824 -34.609C28.888 -34.446 29.173 -34.3 29.146 -34.218C29.039 -33.894 28.493 -33.67 28.487 -33.398C28.457 -31.902 27.503 -30.391 28.133 -29.062C28.905 -27.433 29.724 -25.576 30.4 -23.8C29.166 -21.684 30.199 -19.235 28.446 -17.358C28.31 -17.212 28.319 -16.826 28.441 -16.624C28.733 -16.138 29.139 -15.732 29.625 -15.44C29.827 -15.319 30.175 -15.317 30.375 -15.441C30.953 -15.803 31.351 -16.29 31.959 -16.666z"/> - <path fill="#000000" d="M94.771 -26.977C96.16 -25.185 96.45 -22.39 94.401 -21C94.951 -17.691 98.302 -19.67 100.401 -20.2C100.292 -20.588 100.519 -20.932 100.802 -20.937C101.859 -20.952 102.539 -21.984 103.601 -21.8C104.035 -23.357 105.673 -24.059 106.317 -25.439C108.043 -29.134 107.452 -33.407 104.868 -36.653C104.666 -36.907 104.883 -37.424 104.759 -37.786C104.003 -39.997 101.935 -40.312 100.001 -41C98.824 -44.875 98.163 -48.906 96.401 -52.6C94.787 -52.85 94.089 -54.589 92.752 -55.309C91.419 -56.028 90.851 -54.449 90.892 -53.403C90.899 -53.198 91.351 -52.974 91.181 -52.609C91.105 -52.445 90.845 -52.334 90.845 -52.2C90.846 -52.065 91.067 -51.934 91.201 -51.8C90.283 -50.98 88.86 -50.503 88.565 -49.358C87.611 -45.648 90.184 -42.523 91.852 -39.322C92.443 -38.187 91.707 -36.916 90.947 -35.708C90.509 -35.013 90.617 -33.886 90.893 -33.03C91.645 -30.699 93.236 -28.96 94.771 -26.977z"/> - <path fill="#000000" d="M57.611 -8.591C56.124 -6.74 52.712 -4.171 55.629 -2.243C55.823 -2.114 56.193 -2.11 56.366 -2.244C58.387 -3.809 60.39 -4.712 62.826 -5.294C62.95 -5.323 63.224 -4.856 63.593 -5.017C65.206 -5.72 67.216 -5.662 68.4 -7C72.167 -6.776 75.732 -7.892 79.123 -9.2C80.284 -9.648 81.554 -10.207 82.755 -10.709C84.131 -11.285 85.335 -12.213 86.447 -13.354C86.58 -13.49 86.934 -13.4 87.201 -13.4C87.161 -14.263 88.123 -14.39 88.37 -15.012C88.462 -15.244 88.312 -15.64 88.445 -15.742C90.583 -17.372 91.503 -19.39 90.334 -21.767C90.049 -22.345 89.8 -22.963 89.234 -23.439C88.149 -24.35 87.047 -23.496 86 -23.8C85.841 -23.172 85.112 -23.344 84.726 -23.146C83.867 -22.707 82.534 -23.292 81.675 -22.854C80.313 -22.159 79.072 -21.99 77.65 -21.613C77.338 -21.531 76.56 -21.627 76.4 -21C76.266 -21.134 76.118 -21.368 76.012 -21.346C74.104 -20.95 72.844 -20.736 71.543 -19.044C71.44 -18.911 70.998 -19.09 70.839 -18.955C69.882 -18.147 69.477 -16.913 68.376 -16.241C68.175 -16.118 67.823 -16.286 67.629 -16.157C66.983 -15.726 66.616 -15.085 65.974 -14.638C65.645 -14.409 65.245 -14.734 65.277 -14.99C65.522 -16.937 66.175 -18.724 65.6 -20.6C67.677 -23.12 70.194 -25.069 72 -27.8C72.015 -29.966 72.707 -32.112 72.594 -34.189C72.584 -34.382 72.296 -35.115 72.17 -35.462C71.858 -36.316 72.764 -37.382 71.92 -38.106C70.516 -39.309 69.224 -38.433 68.4 -37C66.562 -36.61 64.496 -35.917 62.918 -37.151C61.911 -37.938 61.333 -38.844 60.534 -39.9C59.549 -41.202 59.884 -42.638 59.954 -44.202C59.96 -44.33 59.645 -44.466 59.645 -44.6C59.646 -44.735 59.866 -44.866 60 -45C59.294 -45.626 59.019 -46.684 58 -47C58.305 -48.092 57.629 -48.976 56.758 -49.278C54.763 -49.969 53.086 -48.057 51.194 -47.984C50.68 -47.965 50.213 -49.003 49.564 -49.328C49.132 -49.544 48.428 -49.577 48.066 -49.311C47.378 -48.807 46.789 -48.693 46.031 -48.488C44.414 -48.052 43.136 -46.958 41.656 -46.103C40.171 -45.246 39.216 -43.809 38.136 -42.489C37.195 -41.337 37.059 -38.923 38.479 -38.423C40.322 -37.773 41.626 -40.476 43.592 -40.15C43.904 -40.099 44.11 -39.788 44 -39.4C44.389 -39.291 44.607 -39.52 44.8 -39.8C45.658 -38.781 46.822 -38.444 47.76 -37.571C48.73 -36.667 50.476 -37.085 51.491 -36.088C53.02 -34.586 52.461 -31.905 54.4 -30.6C53.814 -29.287 53.207 -28.01 52.872 -26.583C52.59 -25.377 53.584 -24.18 54.795 -24.271C56.053 -24.365 56.315 -25.124 56.8 -26.2C57.067 -25.933 57.536 -25.636 57.495 -25.42C57.038 -23.033 56.011 -21.04 55.553 -18.609C55.494 -18.292 55.189 -18.09 54.8 -18.2C54.332 -14.051 50.28 -11.657 47.735 -8.492C47.332 -7.99 47.328 -6.741 47.737 -6.338C49.14 -4.951 51.1 -6.497 52.8 -7C53.013 -8.206 53.872 -9.148 55.204 -9.092C55.46 -9.082 55.695 -9.624 56.019 -9.754C56.367 -9.892 56.869 -9.668 57.155 -9.866C58.884 -11.061 60.292 -12.167 62.03 -13.356C62.222 -13.487 62.566 -13.328 62.782 -13.436C63.107 -13.598 63.294 -13.985 63.617 -14.17C63.965 -14.37 64.207 -14.08 64.4 -13.8C63.754 -13.451 63.75 -12.494 63.168 -12.292C62.393 -12.024 61.832 -11.511 61.158 -11.064C60.866 -10.871 60.207 -11.119 60.103 -10.94C59.505 -9.912 58.321 -9.474 57.611 -8.591z"/> - <path fill="#000000" d="M2.2 -58C2.2 -58 -7.038 -60.872 -18.2 -35.2C-18.2 -35.2 -20.6 -30 -23 -28C-25.4 -26 -36.6 -22.4 -38.6 -18.4L-49 -2.4C-49 -2.4 -34.2 -18.4 -31 -20.8C-31 -20.8 -23 -29.2 -26.2 -22.4C-26.2 -22.4 -40.2 -11.6 -39 -2.4C-39 -2.4 -44.6 12 -45.4 14C-45.4 14 -29.4 -18 -27 -19.2C-24.6 -20.4 -23.4 -20.4 -24.6 -16.8C-25.8 -13.2 -26.2 3.2 -29 5.2C-29 5.2 -21 -15.2 -21.8 -18.4C-21.8 -18.4 -18.6 -22 -16.2 -16.8L-17.4 -0.8L-13 11.2C-13 11.2 -15.4 0 -13.8 -15.6C-13.8 -15.6 -15.8 -26 -11.8 -20.4C-7.8 -14.8 1.8 -8.8 1.8 -4C1.8 -4 -3.4 -21.6 -12.6 -26.4L-16.6 -20.4L-17.8 -22.4C-17.8 -22.4 -21.4 -23.2 -17 -30C-12.6 -36.8 -13 -37.6 -13 -37.6C-13 -37.6 -6.6 -30.4 -5 -30.4C-5 -30.4 8.2 -38 9.4 -13.6C9.4 -13.6 16.2 -28 7 -34.8C7 -34.8 -7.8 -36.8 -6.6 -42L0.6 -54.4C4.2 -59.6 2.6 -56.8 2.6 -56.8z"/> - <path fill="#000000" d="M-17.8 -41.6C-17.8 -41.6 -30.6 -41.6 -33.8 -36.4L-41 -26.8C-41 -26.8 -23.8 -36.8 -19.8 -38C-15.8 -39.2 -17.8 -41.6 -17.8 -41.6z"/> - <path fill="#000000" d="M-57.8 -35.2C-57.8 -35.2 -59.8 -34 -60.2 -31.2C-60.6 -28.4 -63 -28 -62.2 -25.2C-61.4 -22.4 -59.4 -20 -59.4 -24C-59.4 -28 -57.8 -30 -57 -31.2C-56.2 -32.4 -54.6 -36.8 -57.8 -35.2z"/> - <path fill="#000000" d="M-66.6 26C-66.6 26 -75 22 -78.2 18.4C-81.4 14.8 -80.948 19.966 -85.8 19.6C-91.647 19.159 -90.6 3.2 -90.6 3.2L-94.6 10.8C-94.6 10.8 -95.8 25.2 -87.8 22.8C-83.893 21.628 -82.6 23.2 -84.2 24C-85.8 24.8 -78.6 25.2 -81.4 26.8C-84.2 28.4 -69.8 23.2 -72.2 33.6L-66.6 26z"/> - <path fill="#000000" d="M-79.2 40.4C-79.2 40.4 -94.6 44.8 -98.2 35.2C-98.2 35.2 -103 37.6 -100.8 40.6C-98.6 43.6 -97.4 44 -97.4 44C-97.4 44 -92 45.2 -92.6 46C-93.2 46.8 -95.6 50.2 -95.6 50.2C-95.6 50.2 -85.4 44.2 -79.2 40.4z"/> - <path fill="#ffffff" d="M149.201 118.601C148.774 120.735 147.103 121.536 145.201 122.201C143.284 121.243 140.686 118.137 138.801 120.201C138.327 119.721 137.548 119.661 137.204 118.999C136.739 118.101 137.011 117.055 136.669 116.257C136.124 114.985 135.415 113.619 135.601 112.201C137.407 111.489 138.002 109.583 137.528 107.82C137.459 107.563 137.03 107.366 137.23 107.017C137.416 106.694 137.734 106.467 138.001 106.2C137.866 106.335 137.721 106.568 137.61 106.548C137 106.442 137.124 105.805 137.254 105.418C137.839 103.672 139.853 103.408 141.201 104.6C141.457 104.035 141.966 104.229 142.401 104.2C142.351 103.621 142.759 103.094 142.957 102.674C143.475 101.576 145.104 102.682 145.901 102.07C146.977 101.245 148.04 100.546 149.118 101.149C150.927 102.162 152.636 103.374 153.835 105.115C154.41 105.949 154.65 107.23 154.592 108.188C154.554 108.835 153.173 108.483 152.83 109.412C152.185 111.16 154.016 111.679 154.772 113.017C154.97 113.366 154.706 113.67 154.391 113.768C153.98 113.896 153.196 113.707 153.334 114.16C154.306 117.353 151.55 118.031 149.201 118.601z"/> - <path fill="#ffffff" d="M139.6 138.201C139.593 136.463 137.992 134.707 139.201 133.001C139.336 133.135 139.467 133.356 139.601 133.356C139.736 133.356 139.867 133.135 140.001 133.001C141.496 135.217 145.148 136.145 145.006 138.991C144.984 139.438 143.897 140.356 144.801 141.001C142.988 142.349 142.933 144.719 142.001 146.601C140.763 146.315 139.551 145.952 138.401 145.401C138.753 143.915 138.636 142.231 139.456 140.911C139.89 140.213 139.603 139.134 139.6 138.201z"/> - <path fill="#cccccc" d="M-26.6 129.201C-26.6 129.201 -43.458 139.337 -29.4 124.001C-20.6 114.401 -10.6 108.801 -10.6 108.801C-10.6 108.801 -0.2 104.4 3.4 103.2C7 102 22.2 96.8 25.4 96.4C28.6 96 38.2 92 45 96C51.8 100 59.8 104.4 59.8 104.4C59.8 104.4 43.4 96 39.8 98.4C36.2 100.8 29 100.4 23 103.6C23 103.6 8.2 108.001 5 110.001C1.8 112.001 -8.6 123.601 -10.2 122.801C-11.8 122.001 -9.8 121.601 -8.6 118.801C-7.4 116.001 -9.4 114.401 -17.4 120.801C-25.4 127.201 -26.6 129.201 -26.6 129.201z"/> - <path fill="#000000" d="M-19.195 123.234C-19.195 123.234 -17.785 110.194 -9.307 111.859C-9.307 111.859 -1.081 107.689 1.641 105.721C1.641 105.721 9.78 104.019 11.09 103.402C29.569 94.702 44.288 99.221 44.835 98.101C45.381 96.982 65.006 104.099 68.615 108.185C69.006 108.628 58.384 102.588 48.686 100.697C40.413 99.083 18.811 100.944 7.905 106.48C4.932 107.989 -4.013 113.773 -6.544 113.662C-9.075 113.55 -19.195 123.234 -19.195 123.234z"/> - <path fill="#cccccc" d="M-23 148.801C-23 148.801 -38.2 146.401 -21.4 144.801C-21.4 144.801 -3.4 142.801 0.6 137.601C0.6 137.601 14.2 128.401 17 128.001C19.8 127.601 49.8 120.401 50.2 118.001C50.6 115.601 56.2 115.601 57.8 116.401C59.4 117.201 58.6 118.401 55.8 119.201C53 120.001 21.8 136.401 15.4 137.601C9 138.801 -2.6 146.401 -7.4 147.601C-12.2 148.801 -23 148.801 -23 148.801z"/> - <path fill="#000000" d="M-3.48 141.403C-3.48 141.403 -12.062 140.574 -3.461 139.755C-3.461 139.755 5.355 136.331 7.403 133.668C7.403 133.668 14.367 128.957 15.8 128.753C17.234 128.548 31.194 124.861 31.399 123.633C31.604 122.404 65.67 109.823 70.09 113.013C73.001 115.114 63.1 113.437 53.466 117.847C52.111 118.467 18.258 133.054 14.981 133.668C11.704 134.283 5.765 138.174 3.307 138.788C0.85 139.403 -3.48 141.403 -3.48 141.403z"/> - <path fill="#000000" d="M-11.4 143.601C-11.4 143.601 -6.2 143.201 -7.4 144.801C-8.6 146.401 -11 145.601 -11 145.601L-11.4 143.601z"/> - <path fill="#000000" d="M-18.6 145.201C-18.6 145.201 -13.4 144.801 -14.6 146.401C-15.8 148.001 -18.2 147.201 -18.2 147.201L-18.6 145.201z"/> - <path fill="#000000" d="M-29 146.801C-29 146.801 -23.8 146.401 -25 148.001C-26.2 149.601 -28.6 148.801 -28.6 148.801L-29 146.801z"/> - <path fill="#000000" d="M-36.6 147.601C-36.6 147.601 -31.4 147.201 -32.6 148.801C-33.8 150.401 -36.2 149.601 -36.2 149.601L-36.6 147.601z"/> - <path fill="#000000" d="M1.8 108.001C1.8 108.001 6.2 108.001 5 109.601C3.8 111.201 0.6 110.801 0.6 110.801L1.8 108.001z"/> - <path fill="#000000" d="M-8.2 113.601C-8.2 113.601 -1.694 111.46 -4.2 114.801C-5.4 116.401 -7.8 115.601 -7.8 115.601L-8.2 113.601z"/> - <path fill="#000000" d="M-19.4 118.401C-19.4 118.401 -14.2 118.001 -15.4 119.601C-16.6 121.201 -19 120.401 -19 120.401L-19.4 118.401z"/> - <path fill="#000000" d="M-27 124.401C-27 124.401 -21.8 124.001 -23 125.601C-24.2 127.201 -26.6 126.401 -26.6 126.401L-27 124.401z"/> - <path fill="#000000" d="M-33.8 129.201C-33.8 129.201 -28.6 128.801 -29.8 130.401C-31 132.001 -33.4 131.201 -33.4 131.201L-33.8 129.201z"/> - <path fill="#000000" d="M5.282 135.598C5.282 135.598 12.203 135.066 10.606 137.195C9.009 139.325 5.814 138.26 5.814 138.26L5.282 135.598z"/> - <path fill="#000000" d="M15.682 130.798C15.682 130.798 22.603 130.266 21.006 132.395C19.409 134.525 16.214 133.46 16.214 133.46L15.682 130.798z"/> - <path fill="#000000" d="M26.482 126.398C26.482 126.398 33.403 125.866 31.806 127.995C30.209 130.125 27.014 129.06 27.014 129.06L26.482 126.398z"/> - <path fill="#000000" d="M36.882 121.598C36.882 121.598 43.803 121.066 42.206 123.195C40.609 125.325 37.414 124.26 37.414 124.26L36.882 121.598z"/> - <path fill="#000000" d="M9.282 103.598C9.282 103.598 16.203 103.066 14.606 105.195C13.009 107.325 9.014 107.06 9.014 107.06L9.282 103.598z"/> - <path fill="#000000" d="M19.282 100.398C19.282 100.398 26.203 99.866 24.606 101.995C23.009 104.125 18.614 103.86 18.614 103.86L19.282 100.398z"/> - <path fill="#000000" d="M-3.4 140.401C-3.4 140.401 1.8 140.001 0.6 141.601C-0.6 143.201 -3 142.401 -3 142.401L-3.4 140.401z"/> - <path fill="#992600" d="M-76.6 41.2C-76.6 41.2 -81 50 -81.4 53.2C-81.4 53.2 -80.6 44.4 -79.4 42.4C-78.2 40.4 -76.6 41.2 -76.6 41.2z"/> - <path fill="#992600" d="M-95 55.2C-95 55.2 -98.2 69.6 -97.8 72.4C-97.8 72.4 -99 60.8 -98.6 59.6C-98.2 58.4 -95 55.2 -95 55.2z"/> - <path fill="#cccccc" d="M-74.2 -19.4L-74.4 -16.2L-76.6 -16C-76.6 -16 -62.4 -3.4 -61.8 4.2C-61.8 4.2 -61 -4 -74.2 -19.4z"/> - <path fill="#000000" d="M-70.216 -18.135C-70.647 -18.551 -70.428 -19.296 -70.836 -19.556C-71.645 -20.072 -69.538 -20.129 -69.766 -20.845C-70.149 -22.051 -69.962 -22.072 -70.084 -23.348C-70.141 -23.946 -69.553 -25.486 -69.168 -25.926C-67.722 -27.578 -69.046 -30.51 -67.406 -32.061C-67.102 -32.35 -66.726 -32.902 -66.441 -33.32C-65.782 -34.283 -64.598 -34.771 -63.648 -35.599C-63.33 -35.875 -63.531 -36.702 -62.962 -36.61C-62.248 -36.495 -61.007 -36.625 -61.052 -35.784C-61.165 -33.664 -62.494 -31.944 -63.774 -30.276C-63.323 -29.572 -63.781 -28.937 -64.065 -28.38C-65.4 -25.76 -65.211 -22.919 -65.385 -20.079C-65.39 -19.994 -65.697 -19.916 -65.689 -19.863C-65.336 -17.528 -64.752 -15.329 -63.873 -13.1C-63.507 -12.17 -63.036 -11.275 -62.886 -10.348C-62.775 -9.662 -62.672 -8.829 -63.08 -8.124C-61.045 -5.234 -62.354 -2.583 -61.185 0.948C-60.978 1.573 -59.286 3.487 -59.749 3.326C-62.262 2.455 -62.374 2.057 -62.551 1.304C-62.697 0.681 -63.027 -0.696 -63.264 -1.298C-63.328 -1.462 -63.499 -3.346 -63.577 -3.468C-65.09 -5.85 -63.732 -5.674 -65.102 -8.032C-66.53 -8.712 -67.496 -9.816 -68.619 -10.978C-68.817 -11.182 -67.674 -11.906 -67.855 -12.119C-68.947 -13.408 -70.1 -14.175 -69.764 -15.668C-69.609 -16.358 -69.472 -17.415 -70.216 -18.135z"/> - <path fill="#000000" d="M-73.8 -16.4C-73.8 -16.4 -73.4 -9.6 -71 -8C-68.6 -6.4 -69.8 -7.2 -73 -8.4C-76.2 -9.6 -75 -10.4 -75 -10.4C-75 -10.4 -77.8 -10 -75.4 -8C-73 -6 -69.4 -3.6 -71 -3.6C-72.6 -3.6 -80.2 -7.6 -80.2 -10.4C-80.2 -13.2 -81.2 -17.3 -81.2 -17.3C-81.2 -17.3 -80.1 -18.1 -75.3 -18C-75.3 -18 -73.9 -17.3 -73.8 -16.4z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-74.6 2.2C-74.6 2.2 -83.12 -0.591 -101.6 2.8C-101.6 2.8 -92.569 0.722 -73.8 3C-63.5 4.25 -74.6 2.2 -74.6 2.2z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-72.502 2.129C-72.502 2.129 -80.748 -1.389 -99.453 0.392C-99.453 0.392 -90.275 -0.897 -71.774 2.995C-61.62 5.131 -72.502 2.129 -72.502 2.129z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-70.714 2.222C-70.714 2.222 -78.676 -1.899 -97.461 -1.514C-97.461 -1.514 -88.213 -2.118 -70.052 3.14C-60.086 6.025 -70.714 2.222 -70.714 2.222z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-69.444 2.445C-69.444 2.445 -76.268 -1.862 -93.142 -2.96C-93.142 -2.96 -84.803 -2.79 -68.922 3.319C-60.206 6.672 -69.444 2.445 -69.444 2.445z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M45.84 12.961C45.84 12.961 44.91 13.605 45.124 12.424C45.339 11.243 73.547 -1.927 77.161 -1.677C77.161 -1.677 46.913 11.529 45.84 12.961z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M42.446 13.6C42.446 13.6 41.57 14.315 41.691 13.121C41.812 11.927 68.899 -3.418 72.521 -3.452C72.521 -3.452 43.404 12.089 42.446 13.6z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M39.16 14.975C39.16 14.975 38.332 15.747 38.374 14.547C38.416 13.348 58.233 -2.149 68.045 -4.023C68.045 -4.023 50.015 4.104 39.16 14.975z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M36.284 16.838C36.284 16.838 35.539 17.532 35.577 16.453C35.615 15.373 53.449 1.426 62.28 -0.26C62.28 -0.26 46.054 7.054 36.284 16.838z"/> - <path fill="#cccccc" d="M4.6 164.801C4.6 164.801 -10.6 162.401 6.2 160.801C6.2 160.801 24.2 158.801 28.2 153.601C28.2 153.601 41.8 144.401 44.6 144.001C47.4 143.601 63.8 140.001 64.2 137.601C64.6 135.201 70.6 132.801 72.2 133.601C73.8 134.401 73.8 143.601 71 144.401C68.2 145.201 49.4 152.401 43 153.601C36.6 154.801 25 162.401 20.2 163.601C15.4 164.801 4.6 164.801 4.6 164.801z"/> - <path fill="#000000" d="M77.6 127.401C77.6 127.401 74.6 129.001 73.4 131.601C73.4 131.601 67 142.201 52.8 145.401C52.8 145.401 29.8 154.401 22 156.401C22 156.401 8.6 161.401 1.2 160.601C1.2 160.601 -5.8 160.801 0.4 162.401C0.4 162.401 20.6 160.401 24 158.601C24 158.601 39.6 153.401 42.6 150.801C45.6 148.201 63.8 143.201 66 141.201C68.2 139.201 78 130.801 77.6 127.401z"/> - <path fill="#000000" d="M18.882 158.911C18.882 158.911 24.111 158.685 22.958 160.234C21.805 161.784 19.357 160.91 19.357 160.91L18.882 158.911z"/> - <path fill="#000000" d="M11.68 160.263C11.68 160.263 16.908 160.037 15.756 161.586C14.603 163.136 12.155 162.263 12.155 162.263L11.68 160.263z"/> - <path fill="#000000" d="M1.251 161.511C1.251 161.511 6.48 161.284 5.327 162.834C4.174 164.383 1.726 163.51 1.726 163.51L1.251 161.511z"/> - <path fill="#000000" d="M-6.383 162.055C-6.383 162.055 -1.154 161.829 -2.307 163.378C-3.46 164.928 -5.908 164.054 -5.908 164.054L-6.383 162.055z"/> - <path fill="#000000" d="M35.415 151.513C35.415 151.513 42.375 151.212 40.84 153.274C39.306 155.336 36.047 154.174 36.047 154.174L35.415 151.513z"/> - <path fill="#000000" d="M45.73 147.088C45.73 147.088 51.689 143.787 51.155 148.849C50.885 151.405 46.362 149.749 46.362 149.749L45.73 147.088z"/> - <path fill="#000000" d="M54.862 144.274C54.862 144.274 62.021 140.573 60.287 146.035C59.509 148.485 55.493 146.935 55.493 146.935L54.862 144.274z"/> - <path fill="#000000" d="M64.376 139.449C64.376 139.449 68.735 134.548 69.801 141.21C70.207 143.748 65.008 142.11 65.008 142.11L64.376 139.449z"/> - <path fill="#000000" d="M26.834 155.997C26.834 155.997 32.062 155.77 30.91 157.32C29.757 158.869 27.308 157.996 27.308 157.996L26.834 155.997z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M62.434 34.603C62.434 34.603 61.708 35.268 61.707 34.197C61.707 33.127 79.191 19.863 88.034 18.479C88.034 18.479 71.935 25.208 62.434 34.603z"/> - <path fill="#000000" d="M65.4 98.4C65.4 98.4 87.401 120.801 96.601 124.401C96.601 124.401 105.801 135.601 101.801 161.601C101.801 161.601 98.601 169.201 95.401 148.401C95.401 148.401 98.601 123.201 87.401 139.201C87.401 139.201 79 129.301 85.4 129.601C85.4 129.601 88.601 131.601 89.001 130.001C89.401 128.401 81.4 114.801 64.2 100.4C47 86 65.4 98.4 65.4 98.4z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M7 137.201C7 137.201 6.8 135.401 8.6 136.201C10.4 137.001 104.601 143.201 136.201 167.201C136.201 167.201 91.001 144.001 7 137.201z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M17.4 132.801C17.4 132.801 17.2 131.001 19 131.801C20.8 132.601 157.401 131.601 181.001 164.001C181.001 164.001 159.001 138.801 17.4 132.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M29 128.801C29 128.801 28.8 127.001 30.6 127.801C32.4 128.601 205.801 115.601 229.401 148.001C229.401 148.001 219.801 122.401 29 128.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M39 124.001C39 124.001 38.8 122.201 40.6 123.001C42.4 123.801 164.601 85.2 188.201 117.601C188.201 117.601 174.801 93 39 124.001z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-19 146.801C-19 146.801 -19.2 145.001 -17.4 145.801C-15.6 146.601 2.2 148.801 4.2 187.601C4.2 187.601 -3 145.601 -19 146.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-27.8 148.401C-27.8 148.401 -28 146.601 -26.2 147.401C-24.4 148.201 -10.2 143.601 -13 182.401C-13 182.401 -11.8 147.201 -27.8 148.401z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-35.8 148.801C-35.8 148.801 -36 147.001 -34.2 147.801C-32.4 148.601 -17 149.201 -29.4 171.601C-29.4 171.601 -19.8 147.601 -35.8 148.801z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M11.526 104.465C11.526 104.465 11.082 106.464 12.631 105.247C28.699 92.622 61.141 33.72 116.826 28.086C116.826 28.086 78.518 15.976 11.526 104.465z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M22.726 102.665C22.726 102.665 21.363 101.472 23.231 100.847C25.099 100.222 137.541 27.72 176.826 35.686C176.826 35.686 149.719 28.176 22.726 102.665z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M1.885 108.767C1.885 108.767 1.376 110.366 3.087 109.39C12.062 104.27 15.677 47.059 59.254 45.804C59.254 45.804 26.843 31.09 1.885 108.767z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-18.038 119.793C-18.038 119.793 -19.115 121.079 -17.162 120.825C-6.916 119.493 14.489 78.222 58.928 83.301C58.928 83.301 26.962 68.955 -18.038 119.793z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-6.8 113.667C-6.8 113.667 -7.611 115.136 -5.742 114.511C4.057 111.237 17.141 66.625 61.729 63.078C61.729 63.078 27.603 55.135 -6.8 113.667z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-25.078 124.912C-25.078 124.912 -25.951 125.954 -24.369 125.748C-16.07 124.669 1.268 91.24 37.264 95.354C37.264 95.354 11.371 83.734 -25.078 124.912z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-32.677 130.821C-32.677 130.821 -33.682 131.866 -32.091 131.748C-27.923 131.439 2.715 98.36 21.183 113.862C21.183 113.862 9.168 95.139 -32.677 130.821z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M36.855 98.898C36.855 98.898 35.654 97.543 37.586 97.158C39.518 96.774 160.221 39.061 198.184 51.927C198.184 51.927 172.243 41.053 36.855 98.898z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M3.4 163.201C3.4 163.201 3.2 161.401 5 162.201C6.8 163.001 22.2 163.601 9.8 186.001C9.8 186.001 19.4 162.001 3.4 163.201z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M13.8 161.601C13.8 161.601 13.6 159.801 15.4 160.601C17.2 161.401 35 163.601 37 202.401C37 202.401 29.8 160.401 13.8 161.601z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M20.6 160.001C20.6 160.001 20.4 158.201 22.2 159.001C24 159.801 48.6 163.201 72.2 195.601C72.2 195.601 36.6 158.801 20.6 160.001z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M28.225 157.972C28.225 157.972 27.788 156.214 29.678 156.768C31.568 157.322 52.002 155.423 90.099 189.599C90.099 189.599 43.924 154.656 28.225 157.972z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M38.625 153.572C38.625 153.572 38.188 151.814 40.078 152.368C41.968 152.922 76.802 157.423 128.499 192.399C128.499 192.399 54.324 150.256 38.625 153.572z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-1.8 142.001C-1.8 142.001 -2 140.201 -0.2 141.001C1.6 141.801 55 144.401 85.4 171.201C85.4 171.201 50.499 146.426 -1.8 142.001z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M-11.8 146.001C-11.8 146.001 -12 144.201 -10.2 145.001C-8.4 145.801 16.2 149.201 39.8 181.601C39.8 181.601 4.2 144.801 -11.8 146.001z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M49.503 148.962C49.503 148.962 48.938 147.241 50.864 147.655C52.79 148.068 87.86 150.004 141.981 181.098C141.981 181.098 64.317 146.704 49.503 148.962z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M57.903 146.562C57.903 146.562 57.338 144.841 59.264 145.255C61.19 145.668 96.26 147.604 150.381 178.698C150.381 178.698 73.317 143.904 57.903 146.562z"/> - <path fill="#ffffff" stroke="#000000" stroke-width="0.1" d="M67.503 141.562C67.503 141.562 66.938 139.841 68.864 140.255C70.79 140.668 113.86 145.004 203.582 179.298C203.582 179.298 82.917 138.904 67.503 141.562z"/> - <path fill="#000000" d="M-43.8 148.401C-43.8 148.401 -38.6 148.001 -39.8 149.601C-41 151.201 -43.4 150.401 -43.4 150.401L-43.8 148.401z"/> - <path fill="#000000" d="M-13 162.401C-13 162.401 -7.8 162.001 -9 163.601C-10.2 165.201 -12.6 164.401 -12.6 164.401L-13 162.401z"/> - <path fill="#000000" d="M-21.8 162.001C-21.8 162.001 -16.6 161.601 -17.8 163.201C-19 164.801 -21.4 164.001 -21.4 164.001L-21.8 162.001z"/> - <path fill="#000000" d="M-117.169 150.182C-117.169 150.182 -112.124 151.505 -113.782 152.624C-115.439 153.744 -117.446 152.202 -117.446 152.202L-117.169 150.182z"/> - <path fill="#000000" d="M-115.169 140.582C-115.169 140.582 -110.124 141.905 -111.782 143.024C-113.439 144.144 -115.446 142.602 -115.446 142.602L-115.169 140.582z"/> - <path fill="#000000" d="M-122.369 136.182C-122.369 136.182 -117.324 137.505 -118.982 138.624C-120.639 139.744 -122.646 138.202 -122.646 138.202L-122.369 136.182z"/> - <path fill="#cccccc" d="M-42.6 211.201C-42.6 211.201 -44.2 211.201 -48.2 213.201C-50.2 213.201 -61.4 216.801 -67 226.801C-67 226.801 -54.6 217.201 -42.6 211.201z"/> - <path fill="#cccccc" d="M45.116 303.847C45.257 304.105 45.312 304.525 45.604 304.542C46.262 304.582 47.495 304.883 47.37 304.247C46.522 299.941 45.648 295.004 41.515 293.197C40.876 292.918 39.434 293.331 39.36 294.215C39.233 295.739 39.116 297.088 39.425 298.554C39.725 299.975 41.883 299.985 42.8 298.601C43.736 300.273 44.168 302.116 45.116 303.847z"/> - <path fill="#cccccc" d="M34.038 308.581C34.786 309.994 34.659 311.853 36.074 312.416C36.814 312.71 38.664 311.735 38.246 310.661C37.444 308.6 37.056 306.361 35.667 304.55C35.467 304.288 35.707 303.755 35.547 303.427C34.953 302.207 33.808 301.472 32.4 301.801C31.285 304.004 32.433 306.133 33.955 307.842C34.091 307.994 33.925 308.37 34.038 308.581z"/> - <path fill="#cccccc" d="M-5.564 303.391C-5.672 303.014 -5.71 302.551 -5.545 302.23C-5.014 301.197 -4.221 300.075 -4.558 299.053C-4.906 297.997 -6.022 298.179 -6.672 298.748C-7.807 299.742 -7.856 301.568 -8.547 302.927C-8.743 303.313 -8.692 303.886 -9.133 304.277C-9.607 304.698 -10.047 306.222 -9.951 306.793C-9.898 307.106 -10.081 317.014 -9.859 316.751C-9.24 316.018 -6.19 306.284 -6.121 305.392C-6.064 304.661 -5.332 304.196 -5.564 303.391z"/> - <path fill="#cccccc" d="M-31.202 296.599C-28.568 294.1 -25.778 291.139 -26.22 287.427C-26.336 286.451 -28.111 286.978 -28.298 287.824C-29.1 291.449 -31.139 294.11 -33.707 296.502C-35.903 298.549 -37.765 304.893 -38 305.401C-34.303 300.145 -32.046 297.399 -31.202 296.599z"/> - <path fill="#cccccc" d="M-44.776 290.635C-44.253 290.265 -44.555 289.774 -44.338 289.442C-43.385 287.984 -42.084 286.738 -42.066 285C-42.063 284.723 -42.441 284.414 -42.776 284.638C-43.053 284.822 -43.395 284.952 -43.503 285.082C-45.533 287.531 -46.933 290.202 -48.376 293.014C-48.559 293.371 -49.703 297.862 -49.39 297.973C-49.151 298.058 -47.431 293.877 -47.221 293.763C-45.958 293.077 -45.946 291.462 -44.776 290.635z"/> - <path fill="#cccccc" d="M-28.043 310.179C-27.599 309.31 -26.023 308.108 -26.136 307.219C-26.254 306.291 -25.786 304.848 -26.698 305.536C-27.955 306.484 -31.404 307.833 -31.674 313.641C-31.7 314.212 -28.726 311.519 -28.043 310.179z"/> - <path fill="#cccccc" d="M-13.6 293.001C-13.2 292.333 -12.492 292.806 -12.033 292.543C-11.385 292.171 -10.774 291.613 -10.482 290.964C-9.512 288.815 -7.743 286.995 -7.6 284.601C-9.091 283.196 -9.77 285.236 -10.4 286.201C-11.723 284.554 -12.722 286.428 -14.022 286.947C-14.092 286.975 -14.305 286.628 -14.38 286.655C-15.557 287.095 -16.237 288.176 -17.235 288.957C-17.406 289.091 -17.811 288.911 -17.958 289.047C-18.61 289.65 -19.583 289.975 -19.863 290.657C-20.973 293.364 -24.113 295.459 -26 303.001C-25.619 303.91 -21.488 296.359 -21.001 295.661C-20.165 294.465 -20.047 297.322 -18.771 296.656C-18.72 296.629 -18.534 296.867 -18.4 297.001C-18.206 296.721 -17.988 296.492 -17.6 296.601C-17.6 296.201 -17.734 295.645 -17.533 295.486C-16.296 294.509 -16.38 293.441 -15.6 292.201C-15.142 292.99 -14.081 292.271 -13.6 293.001z"/> - <path fill="#cccccc" d="M46.2 347.401C46.2 347.401 53.6 327.001 49.2 315.801C49.2 315.801 60.6 337.401 56 348.601C56 348.601 55.6 338.201 51.6 333.201C51.6 333.201 47.6 346.001 46.2 347.401z"/> - <path fill="#cccccc" d="M31.4 344.801C31.4 344.801 36.8 336.001 28.8 317.601C28.8 317.601 28 338.001 21.2 349.001C21.2 349.001 35.4 328.801 31.4 344.801z"/> - <path fill="#cccccc" d="M21.4 342.801C21.4 342.801 21.2 322.801 21.6 319.801C21.6 319.801 17.8 336.401 7.6 346.001C7.6 346.001 22 334.001 21.4 342.801z"/> - <path fill="#cccccc" d="M11.8 310.801C11.8 310.801 17.8 324.401 7.8 342.801C7.8 342.801 14.2 330.601 9.4 323.601C9.4 323.601 12 320.201 11.8 310.801z"/> - <path fill="#cccccc" d="M-7.4 342.401C-7.4 342.401 -8.4 326.801 -6.6 324.601C-6.6 324.601 -6.4 318.201 -6.8 317.201C-6.8 317.201 -2.8 311.001 -2.6 318.401C-2.6 318.401 -1.2 326.201 1.6 330.801C1.6 330.801 5.2 336.201 5 342.601C5 342.601 -5 312.401 -7.4 342.401z"/> - <path fill="#cccccc" d="M-11 314.801C-11 314.801 -17.6 325.601 -19.4 344.601C-19.4 344.601 -20.8 338.401 -17 324.001C-17 324.001 -12.8 308.601 -11 314.801z"/> - <path fill="#cccccc" d="M-32.8 334.601C-32.8 334.601 -27.8 329.201 -26.4 324.201C-26.4 324.201 -22.8 308.401 -29.2 317.001C-29.2 317.001 -29 325.001 -37.2 332.401C-37.2 332.401 -32.4 330.001 -32.8 334.601z"/> - <path fill="#cccccc" d="M-38.6 329.601C-38.6 329.601 -35.2 312.201 -34.4 311.401C-34.4 311.401 -32.6 308.001 -35.4 311.201C-35.4 311.201 -44.2 330.401 -48.2 337.001C-48.2 337.001 -40.2 327.801 -38.6 329.601z"/> - <path fill="#cccccc" d="M-44.4 313.001C-44.4 313.001 -32.8 290.601 -54.6 316.401C-54.6 316.401 -43.6 306.601 -44.4 313.001z"/> - <path fill="#cccccc" d="M-59.8 298.401C-59.8 298.401 -55 279.601 -52.4 279.801C-52.4 279.801 -44.2 270.801 -50.8 281.401C-50.8 281.401 -56.8 291.001 -56.2 300.801C-56.2 300.801 -56.8 291.201 -59.8 298.401z"/> - <path fill="#cccccc" d="M270.5 287C270.5 287 258.5 277 256 273.5C256 273.5 269.5 292 269.5 299C269.5 299 272 291.5 270.5 287z"/> - <path fill="#cccccc" d="M276 265C276 265 255 250 251.5 242.5C251.5 242.5 278 272 278 276.5C278 276.5 278.5 267.5 276 265z"/> - <path fill="#cccccc" d="M293 111C293 111 281 103 279.5 105C279.5 105 290 111.5 292.5 120C292.5 120 291 111 293 111z"/> - <path fill="#cccccc" d="M301.5 191.5L284 179.5C284 179.5 303 196.5 303.5 200.5L301.5 191.5z"/> - <path stroke="#000000" d="M-89.25 169L-67.25 173.75"/> - <path stroke="#000000" d="M-39 331C-39 331 -39.5 327.5 -48.5 338"/> - <path stroke="#000000" d="M-33.5 336C-33.5 336 -31.5 329.5 -38 334"/> - <path stroke="#000000" d="M20.5 344.5C20.5 344.5 22 333.5 10.5 346.5"/> - </g> - <circle id="ball" cx="130" cy="-50" r="50" fill="yellow" fill-opacity="0.5"/> - <script type="text/javascript"><![CDATA[ - var svg = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'svg')[0]; - var c = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'circle')[0]; - var t = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[1]; - var cx = parseInt(c.getAttribute('cx')); - var cy = parseInt(c.getAttribute('cy')); - var r = parseInt(c.getAttribute('r')); - var dx = 5; - var dy = -5; - var count = 0; - function repaintTest() { - if ((cx + r + dx > 390) || (cx - r + dx < -190)) - dx =- dx; - cx += dx; - if ((cy + r + dy > 390) || (cy - r + dy < -190)) - dy =- dy; - cy += dy; - c.setAttribute('cx', cx); - c.setAttribute('cy', cy); - ++count; - if (count < max) { - window.setTimeout(repaintTest, 0); - t.firstChild.data = 'Test in progress... ' + count + ' of ' + max; - } else { - if (window.testRunner) - t.firstChild.data = 'Test completed'; - else { - var end = new Date(); - var elapsed = (end - start) / 1000; - t.firstChild.data = 'Test completed in ' + elapsed.toFixed(2) + 's.'; - if (parent.reportResults) parent.reportResults(end - start); - } - finishRepaintTest(); - } - } - ]]></script> -</svg>
diff --git a/third_party/blink/web_tests/svg/hixie/perf/003-expected.txt b/third_party/blink/web_tests/svg/hixie/perf/003-expected.txt deleted file mode 100644 index 71edda1..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/003-expected.txt +++ /dev/null
@@ -1,102 +0,0 @@ -SVG Performance test. -Test completed -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 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99
diff --git a/third_party/blink/web_tests/svg/hixie/perf/003.xml b/third_party/blink/web_tests/svg/hixie/perf/003.xml deleted file mode 100644 index 9dfc933..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/003.xml +++ /dev/null
@@ -1,80 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="400" height="400" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> - <script xlink:href="../../../paint/invalidation/resources/text-based-repaint.js"></script> - <script type="text/javascript"> - window.testIsAsync = true; - window.outputRepaintRects = false; - var start = new Date(); - </script> - <text x="10" y="15" font-weight="900" font-size="5">SVG Performance test.</text> - <text x="10" y="95" font-weight="900" font-size="5">Test not started.</text> - <rect x="0" y="0" height="100" width="100" stroke="black" fill="none"/> - <script type="text/javascript"><![CDATA[ - var svg = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'svg')[0]; - var t = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[1]; - - var Xs = new Array(9, 65, 92, 30, 92, 40, 65, 47, 79, 10, 77, 45, - 27, 13, 43, 52, 55, 46, 1, 24, 42, 11, 15, 18, 42, 49, 50, 30, 69, - 95, 36, 49, 46, 85, 54, 26, 15, 56, 18, 92, 40, 41, 66, 85, 7, 47, - 66, 13, 72, 29, 48, 57, 61, 46, 70, 3, 62, 34, 74, 13, 32, 20, 8, - 2, 60, 97, 58, 1, 0, 89, 85, 48, 52, 98, 12, 26, 5, 5, 48, 19, 22, - 34, 83, 13, 65, 77, 23, 40, 56, 65, 13, 54, 81, 10, 53, 25, 93, - 61, 14, 7); - - var Ys = new Array(42, 80, 93, 30, 54, 33, 76, 56, 2, 79, 37, 80, - 80, 19, 99, 31, 89, 22, 23, 42, 27, 81, 26, 19, 80, 6, 62, 67, 73, - 18, 69, 10, 42, 88, 100, 99, 47, 88, 26, 46, 49, 60, 7, 10, 48, 29, - 25, 26, 33, 73, 84, 24, 42, 74, 5, 49, 69, 81, 19.5, 67, 10, 53, 79, - 56, 32, 98, 78, 7, 3, 68, 12, 80, 42, 24, 82, 69, 9, 43, 47, 19, - 69, 45, 41, 64, 1, 39, 25, 84, 35, 77, 26, 43, 32, 75, 89, 66, 48, - 80, 1, 70); - - var Ss = new Array(5, 3, 1, 3, 1, 8, 8, 7, 8, 5, 1, 4, 4, 2, 1, 2, - 2, 6, 4, 3, 1, 5, 1, 2, 6, 1, 5, 7, 3, 6, 6, 4, 7, 2, 5, 3, 5, 3, - 5, 2, 8, 1, 2, 1, 6, 4, 3, 2, 4, 8, 3, 5, 8, 8, 2, 2, 2, 8, 5, 6, - 4, 8, 5, 3, 6, 2, 3, 2, 3, 6, 3, 5, 8, 7, 2, 4, 8, 8, 6, 4, 6, 1, - 8, 6, 7, 4, 7, 8, 3, 7, 7, 8, 4, 2, 2, 8, 2, 8, 7, 3); - - var Rs = new Array(157, 142, 37, 13, 349, 83, 158, 214, 34, 353, - 196, 29, 296, 225, 124, 355, 68, 305, 315, 190, 146, 274, 167, - 132, 298, 272, 266, 265, 28, 213, 99, 260, 323, 233, 111, 270, - 165, 177, 58, 350, 322, 137, 163, 80, 206, 138, 20, 355, 32, 310, - 309, 260, 153, 309, 151, 189, 52, 170, 326, 157, 65, 41, 28, 92, - 96, 196, 250, 313, 125, 226, 63, 245, 158, 196, 7, 169, 96, 224, - 222, 273, 37, 26, 331, 302, 57, 55, 171, 347, 319, 54, 83, 189, - 281, 79, 75, 138, 223, 138, 238, 69); - - var delay = 1; - var idealTime = 50; - var maxPerBlock = Xs.length / (idealTime / delay); - var maxBlocks = Xs.length / maxPerBlock; - var count = 0; - function repaintTest() { - for (var subcount = 0; subcount < maxPerBlock; subcount += 1) { - var index = count * maxPerBlock + subcount; - var newT = document.createElementNS('http://www.w3.org/2000/svg', 'text'); - newT.setAttribute('x', Xs[index]); - newT.setAttribute('y', Ys[index]); - newT.setAttribute('font-size', Ss[index]); - newT.setAttribute('fill', 'aqua'); - newT.setAttribute('transform', 'translate(50, 50) rotate(' + Rs[index] + ') translate(-50, -50)'); - newT.appendChild(document.createTextNode(index)); - svg.appendChild(newT); - } - ++count; - if (count < maxBlocks) { - window.setTimeout(repaintTest, delay); - t.firstChild.data = 'Test in progress... ' + count + ' of ' + maxBlocks; - } else { - if (window.testRunner) - t.firstChild.data = 'Test completed'; - else { - var end = new Date(); - var elapsed = (end - start) / 1000; - t.firstChild.data = 'Test completed in ' + elapsed.toFixed(2) + 's.'; - if (parent.reportResults) parent.reportResults(end - start); - } - finishRepaintTest(); - } - } - ]]></script> -</svg>
diff --git a/third_party/blink/web_tests/svg/hixie/perf/004-expected.txt b/third_party/blink/web_tests/svg/hixie/perf/004-expected.txt deleted file mode 100644 index 14efa82..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/004-expected.txt +++ /dev/null
@@ -1,2 +0,0 @@ -SVG Performance test. -Test completed
diff --git a/third_party/blink/web_tests/svg/hixie/perf/004.xml b/third_party/blink/web_tests/svg/hixie/perf/004.xml deleted file mode 100644 index 4eb2043..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/004.xml +++ /dev/null
@@ -1,81 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="400" height="400" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> - <script xlink:href="../../../paint/invalidation/resources/text-based-repaint.js"></script> - <script type="text/javascript"> - window.testIsAsync = true; - window.outputRepaintRects = false; - var start = new Date(); - </script> - <text x="10" y="15" font-weight="900" font-size="5">SVG Performance test.</text> - <text x="10" y="95" font-weight="900" font-size="5">Test not started.</text> - <rect x="0" y="0" height="100" width="100" stroke="black" fill="none"/> - <script type="text/javascript"><![CDATA[ - var svg = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'svg')[0]; - var t = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[1]; - - var Xs = new Array(9, 65, 92, 30, 92, 40, 65, 47, 79, 10, 77, 45, - 27, 13, 43, 52, 55, 46, 1, 24, 42, 11, 15, 18, 42, 49, 50, 30, 69, - 95, 36, 49, 46, 85, 54, 26, 15, 56, 18, 92, 40, 41, 66, 85, 7, 47, - 66, 13, 72, 29, 48, 57, 61, 46, 70, 3, 62, 34, 74, 13, 32, 20, 8, - 2, 60, 97, 58, 1, 0, 89, 85, 48, 52, 98, 12, 26, 5, 5, 48, 19, 22, - 34, 83, 13, 65, 77, 23, 40, 56, 65, 13, 54, 81, 10, 53, 25, 93, - 61, 14, 7); - - var Ys = new Array(42, 80, 93, 30, 54, 33, 76, 56, 2, 79, 37, 80, - 80, 19, 99, 31, 89, 22, 23, 42, 27, 81, 26, 19, 80, 6, 62, 67, 73, - 18, 69, 10, 42, 88, 100, 99, 47, 88, 26, 46, 49, 60, 7, 10, 48, 29, - 25, 26, 33, 73, 84, 24, 42, 74, 5, 49, 69, 81, 19.5, 67, 10, 53, 79, - 56, 32, 98, 78, 7, 3, 68, 12, 80, 42, 24, 82, 69, 9, 43, 47, 19, - 69, 45, 41, 64, 1, 39, 25, 84, 35, 77, 26, 43, 32, 75, 89, 66, 48, - 80, 1, 70); - - var Ss = new Array(5, 3, 1, 3, 1, 8, 8, 7, 8, 5, 1, 4, 4, 2, 1, 2, - 2, 6, 4, 3, 1, 5, 1, 2, 6, 1, 5, 7, 3, 6, 6, 4, 7, 2, 5, 3, 5, 3, - 5, 2, 8, 1, 2, 1, 6, 4, 3, 2, 4, 8, 3, 5, 8, 8, 2, 2, 2, 8, 5, 6, - 4, 8, 5, 3, 6, 2, 3, 2, 3, 6, 3, 5, 8, 7, 2, 4, 8, 8, 6, 4, 6, 1, - 8, 6, 7, 4, 7, 8, 3, 7, 7, 8, 4, 2, 2, 8, 2, 8, 7, 3); - - var Rs = new Array(157, 142, 37, 13, 349, 83, 158, 214, 34, 353, - 196, 29, 296, 225, 124, 355, 68, 305, 315, 190, 146, 274, 167, - 132, 298, 272, 266, 265, 28, 213, 99, 260, 323, 233, 111, 270, - 165, 177, 58, 350, 322, 137, 163, 80, 206, 138, 20, 355, 32, 310, - 309, 260, 153, 309, 151, 189, 52, 170, 326, 157, 65, 41, 28, 92, - 96, 196, 250, 313, 125, 226, 63, 245, 158, 196, 7, 169, 96, 224, - 222, 273, 37, 26, 331, 302, 57, 55, 171, 347, 319, 54, 83, 189, - 281, 79, 75, 138, 223, 138, 238, 69); - - var delay = 1; - var idealTime = 50; - var maxPerBlock = Xs.length / (idealTime / delay); - var maxBlocks = Xs.length / maxPerBlock; - var count = 0; - function repaintTest() { - for (var subcount = 0; subcount < maxPerBlock; subcount += 1) { - var index = count * maxPerBlock + subcount; - var newI = document.createElementNS('http://www.w3.org/2000/svg', 'image'); - newI.setAttribute('x', Xs[index] - (99 / Ss[index]) / 2); - newI.setAttribute('y', Ys[index] - (195 / Ss[index]) / 2); - newI.setAttribute('height', 195 / Ss[index]); - newI.setAttribute('width', 99 / Ss[index]); - newI.setAttributeNS('http://www.w3.org/1999/xlink', 'href', 'resources/smallcats.gif'); - newI.setAttribute('transform', 'translate(50, 50) rotate(' + Rs[index] + ') translate(-50, -50)'); - newI.appendChild(document.createTextNode(index)); // 'TEST')); - svg.insertBefore(newI, t); - } - ++count; - if (count < maxBlocks) { - window.setTimeout(repaintTest, delay); - t.firstChild.data = 'Test in progress... ' + count + ' of ' + maxBlocks; - } else { - if (window.testRunner) - t.firstChild.data = 'Test completed'; - else { - var end = new Date(); - var elapsed = (end - start) / 1000; - t.firstChild.data = 'Test completed in ' + elapsed.toFixed(2) + 's.'; - if (parent.reportResults) parent.reportResults(end - start); - } - finishRepaintTest(); - } - } - ]]></script> -</svg>
diff --git a/third_party/blink/web_tests/svg/hixie/perf/005-expected.txt b/third_party/blink/web_tests/svg/hixie/perf/005-expected.txt deleted file mode 100644 index 14efa82..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/005-expected.txt +++ /dev/null
@@ -1,2 +0,0 @@ -SVG Performance test. -Test completed
diff --git a/third_party/blink/web_tests/svg/hixie/perf/005.xml b/third_party/blink/web_tests/svg/hixie/perf/005.xml deleted file mode 100644 index dafcbec1..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/005.xml +++ /dev/null
@@ -1,87 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="400" height="400" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> - <script xlink:href="../../../paint/invalidation/resources/text-based-repaint.js"></script> - <script type="text/javascript"> - window.testIsAsync = true; - window.outputRepaintRects = false; - var start = new Date(); - </script> - <text x="10" y="15" font-weight="900" font-size="5">SVG Performance test.</text> - <text x="10" y="95" font-weight="900" font-size="5">Test not started.</text> - <rect x="0" y="0" height="100" width="100" stroke="black" fill="none"/> - <linearGradient id="gradient"> - <stop offset="0%" stop-color="#00F" /> - <stop offset="10%" stop-color="#F60" /> - <stop offset="90%" stop-color="#FF6" /> - <stop offset="100%" stop-color="#00F" /> - </linearGradient> - <script type="text/javascript"><![CDATA[ - var svg = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'svg')[0]; - var t = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[1]; - - var Xs = new Array(9, 65, 92, 30, 92, 40, 65, 47, 79, 10, 77, 45, - 27, 13, 43, 52, 55, 46, 1, 24, 42, 11, 15, 18, 42, 49, 50, 30, 69, - 95, 36, 49, 46, 85, 54, 26, 15, 56, 18, 92, 40, 41, 66, 85, 7, 47, - 66, 13, 72, 29, 48, 57, 61, 46, 70, 3, 62, 34, 74, 13, 32, 20, 8, - 2, 60, 97, 58, 1, 0, 89, 85, 48, 52, 98, 12, 26, 5, 5, 48, 19, 22, - 34, 83, 13, 65, 77, 23, 40, 56, 65, 13, 54, 81, 10, 53, 25, 93, - 61, 14, 7); - - var Ys = new Array(42, 80, 93, 30, 54, 33, 76, 56, 2, 79, 37, 80, - 80, 19, 99, 31, 89, 22, 23, 42, 27, 81, 26, 19, 80, 6, 62, 67, 73, - 18, 69, 10, 42, 88, 100, 99, 47, 88, 26, 46, 49, 60, 7, 10, 48, 29, - 25, 26, 33, 73, 84, 24, 42, 74, 5, 49, 69, 81, 19.5, 67, 10, 53, 79, - 56, 32, 98, 78, 7, 3, 68, 12, 80, 42, 24, 82, 69, 9, 43, 47, 19, - 69, 45, 41, 64, 1, 39, 25, 84, 35, 77, 26, 43, 32, 75, 89, 66, 48, - 80, 1, 70); - - var Ss = new Array(5, 3, 1, 3, 1, 8, 8, 7, 8, 5, 1, 4, 4, 2, 1, 2, - 2, 6, 4, 3, 1, 5, 1, 2, 6, 1, 5, 7, 3, 6, 6, 4, 7, 2, 5, 3, 5, 3, - 5, 2, 8, 1, 2, 1, 6, 4, 3, 2, 4, 8, 3, 5, 8, 8, 2, 2, 2, 8, 5, 6, - 4, 8, 5, 3, 6, 2, 3, 2, 3, 6, 3, 5, 8, 7, 2, 4, 8, 8, 6, 4, 6, 1, - 8, 6, 7, 4, 7, 8, 3, 7, 7, 8, 4, 2, 2, 8, 2, 8, 7, 3); - - var Rs = new Array(157, 142, 37, 13, 349, 83, 158, 214, 34, 353, - 196, 29, 296, 225, 124, 355, 68, 305, 315, 190, 146, 274, 167, - 132, 298, 272, 266, 265, 28, 213, 99, 260, 323, 233, 111, 270, - 165, 177, 58, 350, 322, 137, 163, 80, 206, 138, 20, 355, 32, 310, - 309, 260, 153, 309, 151, 189, 52, 170, 326, 157, 65, 41, 28, 92, - 96, 196, 250, 313, 125, 226, 63, 245, 158, 196, 7, 169, 96, 224, - 222, 273, 37, 26, 331, 302, 57, 55, 171, 347, 319, 54, 83, 189, - 281, 79, 75, 138, 223, 138, 238, 69); - - var delay = 1; - var idealTime = 50; - var maxPerBlock = Xs.length / (idealTime / delay); - var maxBlocks = Xs.length / maxPerBlock; - var count = 0; - function repaintTest() { - for (var subcount = 0; subcount < maxPerBlock; subcount += 1) { - var index = count * maxPerBlock + subcount; - var newI = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); - newI.setAttribute('x', Xs[index] - (99 / Ss[index]) / 2); - newI.setAttribute('y', Ys[index] - (195 / Ss[index]) / 2); - newI.setAttribute('height', 195 / Ss[index]); - newI.setAttribute('width', 99 / Ss[index]); - newI.setAttribute('fill', 'url(#gradient)'); - newI.setAttribute('transform', 'translate(50, 50) rotate(' + Rs[index] + ') translate(-50, -50)'); - newI.appendChild(document.createTextNode(index)); - svg.insertBefore(newI, t); - } - ++count; - if (count < maxBlocks) { - window.setTimeout(repaintTest, delay); - t.firstChild.data = 'Test in progress... ' + count + ' of ' + maxBlocks; - } else { - if (window.testRunner) - t.firstChild.data = 'Test completed'; - else { - var end = new Date(); - var elapsed = (end - start) / 1000; - t.firstChild.data = 'Test completed in ' + elapsed.toFixed(2) + 's.'; - if (parent.reportResults) parent.reportResults(end - start); - } - finishRepaintTest(); - } - } - ]]></script> -</svg>
diff --git a/third_party/blink/web_tests/svg/hixie/perf/006-expected.txt b/third_party/blink/web_tests/svg/hixie/perf/006-expected.txt deleted file mode 100644 index 14efa82..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/006-expected.txt +++ /dev/null
@@ -1,2 +0,0 @@ -SVG Performance test. -Test completed
diff --git a/third_party/blink/web_tests/svg/hixie/perf/006.xml b/third_party/blink/web_tests/svg/hixie/perf/006.xml deleted file mode 100644 index d8d4ca1..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/006.xml +++ /dev/null
@@ -1,87 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="400" height="400" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> - <script xlink:href="../../../paint/invalidation/resources/text-based-repaint.js"></script> - <script type="text/javascript"> - window.testIsAsync = true; - window.outputRepaintRects = false; - var start = new Date(); - </script> - <text x="10" y="15" font-weight="900" font-size="5">SVG Performance test.</text> - <text x="10" y="95" font-weight="900" font-size="5">Test not started.</text> - <rect x="0" y="0" height="100" width="100" stroke="black" fill="none"/> - <radialGradient id="gradient"> - <stop offset="0%" stop-color="#00F" /> - <stop offset="10%" stop-color="#F60" /> - <stop offset="90%" stop-color="#FF6" /> - <stop offset="100%" stop-color="#00F" /> - </radialGradient> - <script type="text/javascript"><![CDATA[ - var svg = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'svg')[0]; - var t = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[1]; - - var Xs = new Array(9, 65, 92, 30, 92, 40, 65, 47, 79, 10, 77, 45, - 27, 13, 43, 52, 55, 46, 1, 24, 42, 11, 15, 18, 42, 49, 50, 30, 69, - 95, 36, 49, 46, 85, 54, 26, 15, 56, 18, 92, 40, 41, 66, 85, 7, 47, - 66, 13, 72, 29, 48, 57, 61, 46, 70, 3, 62, 34, 74, 13, 32, 20, 8, - 2, 60, 97, 58, 1, 0, 89, 85, 48, 52, 98, 12, 26, 5, 5, 48, 19, 22, - 34, 83, 13, 65, 77, 23, 40, 56, 65, 13, 54, 81, 10, 53, 25, 93, - 61, 14, 7); - - var Ys = new Array(42, 80, 93, 30, 54, 33, 76, 56, 2, 79, 37, 80, - 80, 19, 99, 31, 89, 22, 23, 42, 27, 81, 26, 19, 80, 6, 62, 67, 73, - 18, 69, 10, 42, 88, 100, 99, 47, 88, 26, 46, 49, 60, 7, 10, 48, 29, - 25, 26, 33, 73, 84, 24, 42, 74, 5, 49, 69, 81, 19.5, 67, 10, 53, 79, - 56, 32, 98, 78, 7, 3, 68, 12, 80, 42, 24, 82, 69, 9, 43, 47, 19, - 69, 45, 41, 64, 1, 39, 25, 84, 35, 77, 26, 43, 32, 75, 89, 66, 48, - 80, 1, 70); - - var Ss = new Array(5, 3, 1, 3, 1, 8, 8, 7, 8, 5, 1, 4, 4, 2, 1, 2, - 2, 6, 4, 3, 1, 5, 1, 2, 6, 1, 5, 7, 3, 6, 6, 4, 7, 2, 5, 3, 5, 3, - 5, 2, 8, 1, 2, 1, 6, 4, 3, 2, 4, 8, 3, 5, 8, 8, 2, 2, 2, 8, 5, 6, - 4, 8, 5, 3, 6, 2, 3, 2, 3, 6, 3, 5, 8, 7, 2, 4, 8, 8, 6, 4, 6, 1, - 8, 6, 7, 4, 7, 8, 3, 7, 7, 8, 4, 2, 2, 8, 2, 8, 7, 3); - - var Rs = new Array(157, 142, 37, 13, 349, 83, 158, 214, 34, 353, - 196, 29, 296, 225, 124, 355, 68, 305, 315, 190, 146, 274, 167, - 132, 298, 272, 266, 265, 28, 213, 99, 260, 323, 233, 111, 270, - 165, 177, 58, 350, 322, 137, 163, 80, 206, 138, 20, 355, 32, 310, - 309, 260, 153, 309, 151, 189, 52, 170, 326, 157, 65, 41, 28, 92, - 96, 196, 250, 313, 125, 226, 63, 245, 158, 196, 7, 169, 96, 224, - 222, 273, 37, 26, 331, 302, 57, 55, 171, 347, 319, 54, 83, 189, - 281, 79, 75, 138, 223, 138, 238, 69); - - var delay = 1; - var idealTime = 50; - var maxPerBlock = Xs.length / (idealTime / delay); - var maxBlocks = Xs.length / maxPerBlock; - var count = 0; - function repaintTest() { - for (var subcount = 0; subcount < maxPerBlock; subcount += 1) { - var index = count * maxPerBlock + subcount; - var newI = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); - newI.setAttribute('x', Xs[index] - (99 / Ss[index]) / 2); - newI.setAttribute('y', Ys[index] - (195 / Ss[index]) / 2); - newI.setAttribute('height', 195 / Ss[index]); - newI.setAttribute('width', 99 / Ss[index]); - newI.setAttribute('fill', 'url(#gradient)'); - newI.setAttribute('transform', 'translate(50, 50) rotate(' + Rs[index] + ') translate(-50, -50)'); - newI.appendChild(document.createTextNode(index)); - svg.insertBefore(newI, t); - } - ++count; - if (count < maxBlocks) { - window.setTimeout(repaintTest, delay); - t.firstChild.data = 'Test in progress... ' + count + ' of ' + maxBlocks; - } else { - if (window.testRunner) - t.firstChild.data = 'Test completed'; - else { - var end = new Date(); - var elapsed = (end - start) / 1000; - t.firstChild.data = 'Test completed in ' + elapsed.toFixed(2) + 's.'; - if (parent.reportResults) parent.reportResults(end - start); - } - finishRepaintTest(); - } - } - ]]></script> -</svg>
diff --git a/third_party/blink/web_tests/svg/hixie/perf/007-expected.txt b/third_party/blink/web_tests/svg/hixie/perf/007-expected.txt deleted file mode 100644 index 95bda580..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/007-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -Other -Based on map data marked © copyright iMapping Ltd. Used without permission under the auspices of Fair Use to improve interoperability. Source: http://www.wherearewe.co.nz/svg.html -Test completed
diff --git a/third_party/blink/web_tests/svg/hixie/perf/007.xml b/third_party/blink/web_tests/svg/hixie/perf/007.xml deleted file mode 100644 index bb09579..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/007.xml +++ /dev/null
@@ -1,282 +0,0 @@ - <svg viewBox="0 0 800 400" width="200" xmlns="http://www.w3.org/2000/svg" xmlns:country="http://example.com/" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> - <script xlink:href="../../../paint/invalidation/resources/text-based-repaint.js"></script> - <script type="text/javascript"> - window.testIsAsync = true; - window.outputRepaintRects = false; - var start = new Date(); - </script> - <style type="text/css"> - svg { fill: none; stroke: none; } - text { fill: gray; stroke: none; } - #messages { fill: red; } - #countries > * { fill: silver; stroke-width: 0.2px; stroke: gray; } - #countries #BE { fill: rgb(0.00%, 2.35%, 0.00%); } - #countries #FR { fill: rgb(0.00%, 9.41%, 0.00%); } - #countries #BG { fill: rgb(0.00%, 13.68%, 0.00%); } - #countries #DK { fill: rgb(0.00%, 29.49%, 0.00%); } - #countries #HR { fill: rgb(0.00%, 1.04%, 0.00%); } - #countries #DE { fill: rgb(0.00%, 23.02%, 0.00%); } - #countries #JP { fill: rgb(0.00%, 26.38%, 0.00%); } - #countries #HU { fill: rgb(0.00%, 17.02%, 0.00%); } - #countries #HK { fill: rgb(0.00%, 3.46%, 0.00%); } - #countries #BR { fill: rgb(0.00%, 5.36%, 0.00%); } - #countries #FI { fill: rgb(0.00%, 8.42%, 0.00%); } - #countries #YU { fill: rgb(0.00%, 36.65%, 0.00%); } - #countries #GR { fill: rgb(0.00%, 9.88%, 0.00%); } - #countries #CN { fill: rgb(0.00%, 0.20%, 0.00%); } - #countries #RU { fill: rgb(0.00%, 100.00%, 0.00%); } - #countries #NL { fill: rgb(0.00%, 15.12%, 0.00%); } - #countries #PT { fill: rgb(0.00%, 4.36%, 0.00%); } - #countries #NO { fill: rgb(0.00%, 19.63%, 0.00%); } - #countries #TW { fill: rgb(0.00%, 2.09%, 0.00%); } - #countries #TR { fill: rgb(0.00%, 0.87%, 0.00%); } - #countries #LT { fill: rgb(0.00%, 23.96%, 0.00%); } - #countries #LV { fill: rgb(0.00%, 8.62%, 0.00%); } - #countries #NZ { fill: rgb(0.00%, 5.49%, 0.00%); } - #countries #LU { fill: rgb(0.00%, 11.40%, 0.00%); } - #countries #TH { fill: rgb(0.00%, 0.00%, 0.00%); } - #countries #PE { fill: rgb(0.00%, 0.94%, 0.00%); } - #countries #PH { fill: rgb(0.00%, 10.36%, 0.00%); } - #countries #RO { fill: rgb(0.00%, 16.37%, 0.00%); } - #countries #AE { fill: rgb(0.00%, 20.83%, 0.00%); } - #countries #CA { fill: rgb(0.00%, 7.12%, 0.00%); } - #countries #PL { fill: rgb(0.00%, 12.44%, 0.00%); } - #countries #CH { fill: rgb(0.00%, 4.94%, 0.00%); } - #countries #CO { fill: rgb(0.00%, 6.90%, 0.00%); } - #countries #VE { fill: rgb(0.00%, 6.01%, 0.00%); } - #countries #CL { fill: rgb(0.00%, 2.69%, 0.00%); } - #countries #EG { fill: rgb(0.00%, 0.05%, 0.00%); } - #countries #IR { fill: rgb(0.00%, 3.39%, 0.00%); } - #countries #IT { fill: rgb(0.00%, 5.59%, 0.00%); } - #countries #EC { fill: rgb(0.00%, 23.82%, 0.00%); } - #countries #ZA { fill: rgb(0.00%, 50.75%, 0.00%); } - #countries #CZ { fill: rgb(0.00%, 30.60%, 0.00%); } - #countries #AR { fill: rgb(0.00%, 12.67%, 0.00%); } - #countries #AU { fill: rgb(0.00%, 4.09%, 0.00%); } - #countries #AT { fill: rgb(0.00%, 50.10%, 0.00%); } - #countries #IN { fill: rgb(0.00%, 26.15%, 0.00%); } - #countries #VN { fill: rgb(0.00%, 6.68%, 0.00%); } - #countries #IE { fill: rgb(0.00%, 9.16%, 0.00%); } - #countries #ID { fill: rgb(0.00%, 20.91%, 0.00%); } - #countries #ES { fill: rgb(0.00%, 8.76%, 0.00%); } - #countries #MA { fill: rgb(0.00%, 0.53%, 0.00%); } - #countries #SG { fill: rgb(0.00%, 4.34%, 0.00%); } - #countries #MY { fill: rgb(0.00%, 6.67%, 0.00%); } - #countries #US { fill: rgb(0.00%, 20.40%, 0.00%); } - #countries #SK { fill: rgb(0.00%, 21.98%, 0.00%); } - #countries #KR { fill: rgb(0.00%, 3.46%, 0.00%); } - #countries #SI { fill: rgb(0.00%, 6.56%, 0.00%); } - #countries #OTHER { fill: rgb(0.00%, 15.43%, 0.00%); } - #countries #UK { fill: rgb(0.00%, 6.08%, 0.00%); } - #countries #SA { fill: rgb(0.00%, 4.58%, 0.00%); } - #countries #UA { fill: rgb(0.00%, 17.83%, 0.00%); } - #countries #MX { fill: rgb(0.00%, 5.61%, 0.00%); } - #countries #SE { fill: rgb(0.00%, 7.33%, 0.00%); } - #countries #IL { fill: rgb(0.00%, 4.05%, 0.00%); } - </style> - <rect id="water" x="0" y="0" height="400" width="800"/> - <g id="countries"> - <path id="LU" country:name="Luxembourg" d="M413.519,90.071l0.136-0.348l-0.31-0.204l-0.017-0.327l0.213-0.322l0.245-0.147l0.142-0.08l0.225,0.072l0.062,0.301l0.41,0.312l0.466,0.096l-0.044,0.288l-0.248,0.144l0.074,0.353l-0.145-0.063l-0.568-0.011l-0.642-0.063z"/> - <path id="CH" country:name="Switzerland" d="M421.683,94.397l0.193,0.336l-0.266,0.274l0.214,0.288l-0.09,0.192l0.622,0.062l0.008,0.144l0.55,0.242l0.579-0.332l0.215,0.117l-0.029,0.171l-0.126,0.309l0.112,0.212l-0.038,0.192l-0.315-0.051l-0.176-0.162l-0.283,0.091l-0.081,0.273l0.244,0.131l-0.228,0.415l-0.244-0.333l-0.469,0.05l-0.071,0.122l-0.216,0.03l-0.23-0.142l-0.143-0.354l-0.371,0.081l0.019,0.333l-0.425,0.384l-0.018,0.535l-0.285,0.151l-0.385-0.312l0.098-0.182l-0.311-0.071l-0.534-0.363l-0.016-0.415l-0.777,0.404l0.103,0.212l-0.349,0.432l-0.275,0.16l-0.629-0.168l-0.627,0.204l-0.599-0.062l-0.102-0.424l-0.312-0.806l-0.616,0.147l-0.854,0.668l-0.369-0.111l0.238-0.226l0.013-0.322l-0.08-0.137l0.089-0.294l0.718-0.418l-0.038-0.315l0.575-0.24l0.012-0.076l0.528-0.494l0.173-0.035l-0.116-0.089l-0.153-0.028l0.221-0.302l0.446,0.007l-0.005,0.096l0.473,0.007l0.385-0.309l0.271,0.089l0.272-0.117l0.271,0.096l0.567-0.158l0.278,0.11l0.354-0.021l-0.179-0.199l0.709-0.199l0.017,0.151l0.199-0.014l0.149,0.089l0.852,0.007l0.664,0.261z"/> - <path id="FR" country:name="France" d="M421.394,104.558l0.104,0.175l0.04,0.256l-0.06,0.475l0.118,0.054l0.062,0.333l-0.076,0.795l-0.211,0.327l-0.118,0.724l-0.292,0.501l-0.298-0.043l-0.057-0.196l-0.41-0.076l-0.227-0.152l0.284-0.207l-0.07-0.076l-0.437-0.098l0.257-0.332l-0.11-0.071l-0.291,0.071l-0.053-0.147l0.115-0.022l0.175-0.158l-0.094-0.153l-0.257-0.082l0.015-0.164l0.247-0.12l-0.284-0.218l0.241-0.284l0.6-0.305l0.27-0.022l0.04-0.125l0.292-0.043l0.195,0.104l0.096-0.142l-0.022-0.344l0.072-0.224l0.143-0.011zM396.323,103.853l0.375-0.122l0.411-0.365l0.549-2.299l0.397-0.091l-0.21-0.29l-0.226,0.259l0.125-1.144l0.223-0.826l0.115,0.153l0.496,0.306l0.191,0.382l0.191,0.229l-0.281-0.673l-0.63-0.582l-0.242-0.233l0.024-0.249l0.359-0.477l-0.202-0.375l-0.2-0.274l-0.326-0.216l-0.685-0.1l-0.515-0.571l-0.416-0.323l0.278-0.426l-0.233-0.181l-0.343-0.131l-0.511-0.142l-0.184-0.173l0.247-0.376l-0.329-0.173l-0.509,0.179l-0.489-0.249l-0.824-0.251l-0.619-0.181l-0.325,0.014l-0.215-0.25l-0.91,0.167l-0.059-0.25l-0.265-0.125l-0.367-0.042l-0.056-0.104l0.861-0.083l-0.085-0.229l-0.526-0.104l0.442-0.104l0.086-0.205l-0.275,0.017l-0.263-0.021l-0.417,0.083l0.04-0.438l0.303,0.012l0.305-0.146l0.526-0.088l0.562-0.174l0.215,0.188l0.18-0.167l0.474,0.063l0.112-0.26l0.272-0.059l0.764-0.078l0.393,0.366l0.275,0.26l0.342,0.083l0.652-0.271l0.317,0.167l0.276-0.127l0.457-0.124l0.029,0.23l0.591-0.065l0.3-0.103l-0.265-0.188l-0.028-0.251l0.056-0.345l-0.037-0.428l-0.131,0.021l-0.562-0.682l-0.11-0.407l0.927,0.126l0.607-0.105l-0.084,0.397l0.248,0.419l0.342-0.146l1.241,0.104l0.501,0.146l0.079-0.014l0.525-0.093l0.662-0.27l-0.534-0.124l0.055-0.204l0.166-0.175l0.753-0.322l0.756-0.181l0.902-0.215l0.314-0.235l0.302-0.264l-0.053-0.775l0.135-0.542l0.521-0.25l0.46-0.16l0.916-0.092l0.177-0.096l0.208,0.447l0.311,0.335l0.266,0.127l0.141-0.071l0.41-0.208l0.153,0.17l0.202,0.458l0.194,0.133l0.518-0.012l0.159,0.301l0.259-0.012l0.576,0.048l0.375,0.168l-0.159,0.241l0.091,0.175l-0.072,0.198l0.285,0.122l0.406-0.075l0.446-0.035l0.193-0.313l0.245-0.072l-0.119,0.373l0.146,0.18l-0.039,0.228l0.529,0.048l0.341,0.192l0.371,0.204l0.127,0.228l0.694-0.174l0.079,0.114l0.642,0.063l0.568,0.011l0.145,0.063l0.428,0.319l0.337,0.277l0.395-0.055l0.045,0.145l0.689-0.062l0.072-0.048l0.233,0.007l0.095,0.186l0.456,0.09l0.479-0.014l0.605,0.193l-0.954,0.806l-0.054,0.213l-0.054,0.358l-0.321,0.372l-0.075,0.295l0.091,0.076l-0.216,0.701l0.135,0.233l-0.385,0.309l-0.473-0.007l0.005-0.096L415.96,94.5l-0.221,0.302l0.153,0.028l0.116,0.089l-0.173,0.035l-0.528,0.494l-0.012,0.076l-0.575,0.24l0.038,0.315l-0.718,0.418l-0.089,0.294l0.08,0.137l-0.013,0.322l-0.238,0.226l0.369,0.111l0.854-0.668l0.616-0.147l0.312,0.806l0.102,0.424l-0.624,0.301l0.532,0.344l0.025,0.292l0.43,0.192l-0.199,0.272l-0.541,0.353l-0.183-0.111l-0.437,0.186l0.352,0.358l0.616,0.191l0.135,0.331l-0.175,0.01l-0.315,0.371l0.193,0.442l0.754,0.391l0.849-0.07l0.062,0.281l-0.146,0.469l-0.346,0.23l-0.221,0.215l-0.833,0.488l-0.889,0.659l-0.427,0.087l-0.318,0.043l-0.798,0.159l-0.405-0.028l-0.471-0.156l-0.851-0.499l-0.315-0.085l-0.354,0.029l-0.231,0.072l-0.511-0.056l-0.752-0.313l-0.602,0.044l-0.731,0.345l-0.357,0.258l-0.555,0.559l-0.147,0.386l0.099,0.514l0.091,0.379l-0.334-0.091l-0.75,0.137l-0.039,0.136l-0.485-0.015l-0.427-0.197l-0.395,0.167l-0.261-0.015l-0.036-0.152l-0.335-0.091l-0.206,0.03l-0.374,0.076l-0.187-0.076l-0.035-0.289l-0.091-0.213l-1.252-0.304h-0.355l0.017,0.319l-0.542-0.015l-0.337,0.061l-0.037-0.122l-0.767,0.03l-0.084-0.114l-0.028-0.038l-0.431-0.152l-0.131,0.076l-0.262-0.03l-0.056,0.076l-0.507-0.395l-0.15,0.061l-1.088-0.334l-0.112,0.106l-0.15-0.03l-0.094-0.106l0.205-0.243l-0.058-0.122l-0.469,0.03l-0.472-0.243z"/> - <path id="KR" country:name="Korea, Republic of" country:shortname="Korea Rep" d="M681.312,116.395l0.235-0.171l0.283-0.256l0.633-0.738l0.315-0.157l0.595,0.011l0.579,0.068l0.511,0.096l0.309-0.115l0.571-0.678l0.682,0.621l1.178,1.611l0.329,0.495l0.269,0.664l0.002,0.75l-0.034,0.947l-0.129,0.637l0.143,0.113l0.5-0.043l-0.121,0.41l-0.282,0.523l-0.5,0.75l-0.316,0.312l-0.243,0.043l-0.567-0.211l-0.256,0.1l-0.607,0.58l-0.431-0.083l-0.289-0.225l-0.544,0.1l-0.526,0.199l-1.188,0.835l-0.462,0.043l-0.46,0.312l-0.055-0.564l-0.056-0.324l-0.163-0.705l-0.137-0.395l0.167-0.453l0.499-0.468v-0.353l0.226-0.425l-0.044-0.141l-0.378-0.311l-0.095-0.296l0.015-0.467l-0.087-0.339l-0.289-0.126l-0.603-0.084l0.654-0.411l0.303-0.114l0.654,0.268l0.254-0.241l-0.029-0.283l-0.764-0.89l-0.113-0.311l-0.137-0.105z"/> - <path id="CY" country:name="Cyprus" d="M475.646,121.847l-0.018,0.175l0.338,0.391l-0.295-0.009l-0.132,0.108l-0.104-0.059l-0.327-0.021l-0.121,0.33l-0.783,0.257l-0.384,0.046l-0.099,0.053v0.21l-0.217,0.006l-0.072-0.192l-0.402,0.023l-0.547-0.146l-0.191-0.087v-0.21l-0.161-0.105l-0.122-0.403l0.082-0.035l0.12,0.1l0.147-0.006l0.405-0.304l0.253-0.006l0.328,0.092l0.077-0.086l0.088-0.286l-0.053-0.175l0.627,0.093l0.658,0.027l0.367-0.056l0.818-0.233l0.689-0.304l0.535-0.158l-0.475,0.295l-0.436,0.231l-0.596,0.444z"/> - <path id="JP" country:name="Japan" d="M704.404,117.274l0.197-0.099l1.108-0.271l0.057,0.354l-0.481,0.284l-0.232,0.241l-0.068,0.453l0.139,0.367l0.291,0.056l0.221-0.114l0.418-0.354l0.24-0.085l1.656-0.697l0.389-0.213l0.46-0.326l0.349-0.638l0.76-0.412l0.347-0.327l0.191-0.269l0.142-0.51l0.538-0.582l-0.01-0.142l0.344-0.567l0.159-0.468l0.139-0.609l-0.043-0.467l-0.33-0.198l-0.128-0.24l0.234-0.213l0.166-0.284l-0.155-1.023l0.544-0.343l0.176-0.242l0.327-0.328l0.192,0l0.21,0.355l0.199,0.227l0.303-0.058l0.799-0.257l-0.169-0.526l-0.311-0.028l-0.36-0.312l0.694-0.415l0.441,0.156l0.336,0.227l0.025,0.199l-0.016,0.868l0.058,0.611l0.22,0.127l0.243,0.312l0.717,1.432l0.001,0.496l-0.246,0.709l-0.709,0.766l-0.226,0.439l0.064,0.368l-0.15,0.071l-0.737,0.285l-0.161,0.113l-0.164,0.199l-0.174,0.453l0.02,0.396l0.094,0.254l0.131,0.792l-0.04,0.693l-0.686,0.751l-0.242,0.736l0.02,0.707l0.198,0.296l0.422,0.353l-0.617,0.298l-0.193,0.127l-0.166,0.17l-0.174,0.834l-1.081,0.439l-0.094-0.282l0.294-0.665l0.184-0.523l-0.198-0.126l-0.514,0.241l-0.578,0.623l-0.476,0.001l-0.346,0.312l-0.066,0.748l-0.354,0.269l-0.188-0.028l-0.066-0.155l0.003-0.606l-0.149-0.155l-0.211,0.042l-0.309,0.156l-0.344,0.311l-0.325,0.523l-0.866-0.055l-0.505,0.057l-0.631,0.1l-0.458-0.549l-0.685-0.323l-0.26,0.254l-0.067,0.184l-0.177,0.353l0.037,0.056l0.417,0.197l0.416,0.323l-0.293,0.198l-0.829,0.129l-0.433,0.241l-0.463,0.622l-0.522,0.847l-0.688-0.365l-0.565-0.21l-0.285-0.197l-0.014-0.169l-0.194-0.818l0.099-0.155l0.495-0.325l0.179-0.269l-0.067-0.282l-0.18-0.042l-0.601,0.17l-0.341-0.028l-0.789-0.167l-0.475,0.128l-0.427,0.227l-0.437,0.184l-0.269-0.098l-0.256-0.027l-1.647,0.398l-0.814,0.298l-0.21-0.31l-0.452-0.042l-0.413,0.438l-0.006,0.635l-0.756-0.238l-0.579-0.055l-1.1,0.073l-0.267-0.14l0.072-0.339l0.179-0.283l0.483,0.013l0.499-0.114l0.751-0.467l2.201-1.953l0.28-0.015l0.427-0.128l0.056,0.424l0.495-0.128l1.278-0.257l0.933-0.058l1.183-0.172l0.892-0.256l0.068,0.452l0.377,0.268l0.167-0.085l0.654-0.199l0.446-0.34l-0.003-0.353l0.114-0.467l0.465-0.51l0.698-0.581l0.371-0.453l-0.062-1.117l0.182-0.213z M695.464,127.756l-0.292-0.197l-0.223-0.268l-0.101-0.381l-0.177-0.395l-0.492-0.535l0.731-0.382l0.287-0.269l0.456-0.593l0.409,0.253l0.615-0.015l0.483-0.185l0.311-0.339l0.451-0.311l0.454-0.029l0.316,0.169l0.862,0.224l0.153,0.254l-0.1,0.127l-0.102,0.423l-0.292,0.24l-0.864,0.876l-0.181-0.211l-0.424-0.295l-0.467-0.042l-0.612,0.213l-0.193,0.184l-0.245,0.495l-0.165,0.508l-0.153,0.212l-0.448,0.269z M691.12,131.448l-0.366-0.042l-0.056-0.141l0.268-0.537l0.128-0.593l-0.334-0.112l-0.239,0.198l-0.155,0.466l-0.381,0.452l-0.326-0.211l-0.059-0.211l0.322-0.466l0.032-0.296l-0.356-0.917l0.169-0.113l0.687-0.58l0.083-0.141l0.034-0.466l-0.532-0.789l-0.333-0.042l-0.162,0.269l-0.419,0.495l-0.249-0.112l-0.23-0.508l-0.376-0.267l-0.261-0.366l0.41-0.325l0.733,0.083l0.706-0.171l0.315-0.466l0.241-0.283l0.484-0.058l0.478,0.056l0.249,0.38l0.27,0.168l0.43,0.084l0.628-0.213l0.225,0.395l-0.569,0.438l0.405,0.239l0.443,0.437l0.079,0.254l-0.596,0.58l-0.242,0.41l-0.104,0.367l-0.085,0.621l-0.109,0.649l-0.242,0.353l-0.194,0.099l-0.165,0.071l-0.197,0.184l-0.479,0.678z M711.938,108.369l-0.222-0.241l-0.077-0.271l0.325-0.642l-0.055-0.342l-0.549-0.198l-0.168-0.171l-0.146-0.812l0.583-0.386l0.522-0.172l0.646-0.373l0.037-0.356l-0.318-0.285l0.277-0.3l0.224-0.015l0.661,0.427l0.373,0.085l0.532-0.201l-0.004-1.186l0.455-0.187l0.45-0.244l0.074-0.743l0.007-0.844l-0.398-0.758l-0.098-0.473l0.166-0.216l0.618-0.346l0.063,0.072l0.507,0.43l0.904,0.816l1.07,0.842l1.083,0.684l0.627,0.285l0.528,0.17l1.02,0.198l0.282,0.042l0.304-0.086l0.866-0.66l0.461-0.144l0.002,0.1l-0.308,0.358l-0.335,0.558l0.198,0.414l0.469,0.599l0.197,0.356l-0.561,0.272l-0.447,0.244l-0.534,0.158l-0.365,0.015l-0.488-0.199l-0.453,0.015l-0.363,0.144l-0.345,0.229l-0.754,0.786l-0.396,0.5l-0.26,0.599l-0.4-0.07l-0.425-0.241l-2.031-0.965l-0.461-0.085l-0.72,0.044l-1.038,0.587l-0.153-0.299l-0.372-0.356l-0.339,0.029l-0.266,0.115l-0.439,0.272l0.049,0.299l1.16,0.497l0.56,0.298l0.302,0.27l-0.391,0.214l-0.303,0.029l-0.305-0.128l-0.261,0.043l-0.324,0.314l-0.388,0.471l-0.347,0.114z"/> - <path id="BT" country:name="Bhutan" d="M597.917,139.685l1.251-1.545l0.609-0.539l0.348-0.239l0.149-0.103l0.417-0.016l0.309,0.294l0.479,0.208l1.659,0.047l0.371,0.041l0.312,0.209l0.329,0.619l-0.07,0.156l0.042,0.24l0.326,0.294l0.313,0.069l0.258,0.238l0.017,0.282l-0.217,0.58l-0.624,0.06l-1.036,0.062l-1.238-0.063l-0.335-0.125l-0.301-0.055l-0.531,0.313l-0.544,0.074l-0.085-0.021l-0.869-0.214l-0.559-0.081l-0.637-0.18l-0.235-0.493l0.092-0.113z"/> - <path id="EH" country:name="Western Sahara" country:shortname="W Sahara" d="M362.764,152.723l0.072-0.625l0.395-0.876l0.52-0.552l0.488-0.566l0.244-0.509l1.175-2.559l0.238-0.241l1.404-1.175l0.345-0.495l0.051-0.918l0.305-1.088l0.651-1.075l0.399-0.34l0.404-0.198l0.838-0.51l0.361-0.495l0.334-0.777l0.428-0.851l1.635-0.04l2.511,0l2.677-0.001l1.718,0.004l1.42-0.008l0.027,0.876l-0.03,1.752l0.002,0.65l-0.104,0.396l-0.56-0.011l-6.005-0.022l-0.557,0.074l-0.047,0.509l-0.07,2.261l-0.099,2.6l-0.144,0.128l-0.809,0.287l-0.726,0.315l-0.575,0.427l-0.249,0.383l-0.01,0.707l0.164,1.539l0.051,1.102l-0.212-0.027l-0.732,0.033l-2.396-0.014l-5.055-0.056l-0.474-0.013z"/> - <path id="QA" country:name="Qatar" d="M514.551,145.841l-0.374,0.027l-0.336-0.083l-0.008-0.615l-0.153-0.437l-0.108-0.791l0.187-0.607l0.188-0.11l-0.059-0.187l0.177-0.607l0.33-0.269l0.312,0.083l0.069,0.315l0.26,0.093l0.063,0.199l0.116,0.326l-0.106,0.42l0.031,0.708l0.118,0.254l-0.104,0.381l-0.327,0.467l-0.275,0.433z"/> - <path id="AE" country:name="United Arab Emirates" country:shortname="Untd Arab Em" d="M514.177,145.868l0.374-0.027l0.008,0.288l0.361,0.14l0.153,0.128l0.186-0.093l-0.046,0.443l0.397,0.001l0.402,0.127l0.687-0.093l0.103-0.21l0.183-0.058l0.218,0.117l0.424-0.042l0.595,0.112l0.224-0.035l0.079-0.105l1.358,0.222l0.732-0.14l-0.022-0.292l0.225,0.175l0.375-0.016l0.157-0.099l0.312-0.422l0.232-0.073l0.267-0.495l0.131-0.297l0.711-0.637l0.813-0.889l0.163,0.105l0.229-0.178l0.85-0.708l0.313-0.433l0.15,0.161l-0.248,0.42l-0.107,0.299l-0.004,0.176l0.099,0.064l0.121-0.024l0.454,0.042l0.09,0.324l0.001,0.508l-0.003,0.358l-0.49,0.034l-0.401-0.083l-0.107,0.396l0.073,1.326l-0.199,0.34l-0.536,0.596l0.003,0.946l0.024,2.075l0.063,0.183l-0.152,0.057l-0.584,0.469l-0.839-0.108l-3.387-0.446l-3.362-0.375l-0.261-0.902l-0.548-1.154l-1.043-2.198z"/> - <path id="TW" country:name="Taiwan" d="M668.627,151.365l-0.102-0.056l-0.107-0.325l-0.922-1.212l-0.332-0.987l-0.03-0.438l0.156-0.749l0.546-0.792l1.312-1.852l0.259-0.184l0.425-0.128l0.229-0.184l0.358-0.227l0.228,0.127l0.554,0.394l-0.334,0.424l-0.084,0.142l0.023,0.31l-0.067,0.622l-0.203,0.296l-0.182,0.354l-0.065,0.692l-0.1,0.494l-0.317,0.805l-0.473,0.707l-0.417,0.833l-0.014,0.353l-0.114,0.438l-0.228,0.142z"/> - <path id="ML" country:name="Mali" d="M389.765,144.543l0.1,0.084l0.895,0.531l2.054,1.344l0.811,0.575l3.283,2.241l1.924,1.26l1.292,0.824l0.397,0.253l2.472,1.469l0.181,0.253l-0.096,0.396l0.082,0.183l0.393,0.28l1.111,1.039l0.229,0.027l0.47-0.314l0.588,0.562l0.375,0.167l0.748,0.024l0.309,0.111l0.277,0.352l0.099,0.522l-0.161,0.679l0.146,0.564l2.176-0.408l0.064,1.017l0.034,2.203l0.001,0.96l-0.08,0.89l-0.145,0.919l-0.434,1.246l-0.596,0.794l-0.339,0.271l-0.29,0.129l-2.533,0.085l-1.808,0.124l-0.209,0.072l-0.562,0.427l-0.579,0.272l-0.678-0.053l-0.581-0.081l-1.062-0.173l-0.36-0.059l-0.356-0.125l-0.37,0.073l-1.22,0.713l-0.947,0.458l-0.304,0.228l-0.314,0.793l-0.274-0.027l-0.324-0.182l-0.518-0.209l-0.272,0.101l-0.638,0.625l-0.492,0.667l-0.393,0.822l-0.174,0.227l-0.45,0.102l-0.551-0.364l-0.293-0.281l-0.273,0.058l-0.397,0.384l-0.355,1.217l-0.292,1.047l-0.317,0.369l-0.543,0.271l-0.448,0.158l-0.257,0.016l-0.141,0.255l0.058,0.749l-0.133,0.876l-0.261,0.92l-0.172,0.326l-0.046,0.156l-0.08,0.043l-0.159,0.1l-0.604,0.399l-0.352,0.059l-0.148-0.239l-0.117-0.381l-0.004-0.297l-0.147-0.211l-0.257-0.041l-0.239,0.114l-0.571,0.483l-0.362,0.469l-0.35,0.228l-0.455-0.436l-0.566-0.321l-0.352,0.059l-0.522,0.54l-0.559-0.901l-0.194-1.143l-0.349-0.718l-0.474-0.478l-0.265-0.451l-0.271-0.832l-0.022-0.339l-0.246-0.281l-0.323-0.055l-0.684,0.428l-0.3,0.327l-0.43,0.243l-0.565-0.152l-0.356-0.153l-0.338-0.026l-0.475,0.413l-0.252,0.256l-0.536-0.265l-0.882-0.715l-0.18-0.183l-0.113-0.028l0.062-0.142l0.004-0.565l-0.082-0.833l-0.265-0.337l-0.554-0.322l-0.181-0.197l-0.22-0.479l-0.144-0.663l-0.251-1.1l0.057-0.339l0.506-0.399l0.332-0.284l0.018-0.607l0.181-0.552l0.252-0.256l0.402-0.073l0.261,0.111l0.568,0.83l0.214,0.168l0.454,0.082l0.107-0.269l-0.055-0.296l0.06-0.212l0.535,0.124l0.713,0.137l0.485,0.054l0.387-0.031l0.945-0.344l1.953-0.026l6.457-0.01l0.379-1.613l-0.724-0.787l-0.186-1.468l-0.202-2.386l-0.325-2.753l-0.178-1.736l-0.19-1.468l-0.908-7.962l-0.049-0.776l3.231-0.089l0.523-0.13z"/> - <path id="OM" country:name="Oman" d="M525.37,142.384l0.312-0.429l0.155-0.17l0.084,0.833l-0.423,0.707l-0.118,0.156l-0.121,0.024l-0.099-0.064l0.004-0.176l0.107-0.299l0.248-0.42l-0.15-0.161z M525.923,144.712v0.22l0.456,0.762l0.408,0.465l0.782,0.634l0.677,0.394l1.008,0.52l0.392,0.154l0.277,0.014l0.576-0.029l0.364,0.112l0.873,0.973l0.518,0.648l0.46,0.422l0.81,0.365l0.025,0.212l-0.67,1.06l-0.615,0.721l-0.883,0.807l-0.776,1.541l-0.242,0.142l-0.562-0.083l-0.235-0.084l-0.252,0.071l-0.278,0.509l-0.062,1.115l0.001,0.791l0.134,0.621l-0.403,0.142l-1.046,0.073l-0.627,0.27l-0.367,0.283l-0.29,0.495l-0.131,0.551l-0.204,0.283l-0.444,0.255l-0.544,0.1l-0.292,0l-0.386-0.042l-0.326,0.029l-0.382,0.283l-0.22,0.297l-0.125,0.508l0.003,0.353l-0.091,0.311l-0.631,0.396l-0.344,0.043l-0.776-0.21l-0.717,0.058l-0.896,0.27l-0.768,0.298l-0.283,0.099l-0.416,0.145l-0.241-0.306l-0.483-0.689l0.006-0.296l-0.127-0.253l-0.933-1.364l-0.604-0.971l-0.226-0.634l-0.092-0.663l1.691-0.815l2.35-1.213l5.346-2.982l-0.155-1.453l-0.581-0.914l-0.063-0.183l-0.024-2.075l-0.003-0.946l0.536-0.596l0.199-0.34l-0.073-1.326l0.107-0.396l0.401,0.083l0.49-0.034z"/> - <path id="NE" country:name="Niger" d="M405.733,173.04l-0.568-0.971l-0.562-0.025l-0.37,0.044l-0.516-0.181l-0.97-0.757l-0.114-0.226l0.335-0.439l-0.018-0.212l-0.179-0.268l-0.502-0.42l-0.389-0.266l-0.422-0.492l-0.426-0.93l-0.019-0.396l0.173-0.665l0.581,0.081l0.678,0.053l0.579-0.272l0.562-0.427l0.209-0.072l1.808-0.124l2.533-0.085l0.29-0.129l0.339-0.271l0.596-0.794l0.434-1.246l0.145-0.919l0.08-0.89l-0.001-0.96l-0.034-2.203l-0.064-1.017l1.672-0.321l1.82-0.364l3.084-2.617l0.834-0.655l2.308-1.454l1.607-0.956l4.012-2.241l1.632-0.843l0.265-0.186l0.832,0.137l1.646,0.442l1.008,0.333l0.258,0.182l1.192,0.911l0.231-0.157l1.519-0.729l0.364,2.145l0.169,1.298l0.42,1.028l0.554,0.802l0.703,0.604l-0.388,0.722l-0.265,0.99l-0.168,1.088l-0.084,0.989l0.022,0.537l-0.062,0.707l-0.019,1.045l-0.034,1.088l-0.056,0.466l-2.43,2.613l-0.591,0.78l-0.87,1.333l-0.572,0.794l-0.007,0.678l0.123,0.719l0.014,0.269l-0.951,0.034l-0.437,0.2l-0.453,0.299l-0.761,0.697l-0.259,0.058l-0.609-0.208l-0.724-0.193l-0.884-0.221l-0.531-0.04l-0.709,0.047l-0.628,0.103l-0.774,0.287l-0.403,0.327l-0.629,0.399l-0.273,0.059l-0.934,0.005l-0.965-0.277l-1.173-0.742l-0.354-0.083l-0.467,0.116l-1.337,0.544l-0.37,0.002l-0.209-0.098l-1.095-1.223l-0.821-0.277l-1.111-0.121l-1.174,0.108l-1.064,0.188l-0.676,0.4l-0.687,1.614l-0.353,0.482l-0.158,0.849l-0.092,0.961l-0.902-0.503l-0.727-0.589l-0.339-0.28l-0.321,0.073l-0.577,0.3z"/> - <path id="TD" country:name="Chad" d="M431.763,171.063l-0.351-0.407l-0.575-0.52l-0.173-0.394l-0.014-0.269l-0.123-0.719l0.007-0.678l0.572-0.794l0.87-1.333l0.591-0.78l2.43-2.613l0.056-0.466l0.034-1.088l0.019-1.045l0.062-0.707l-0.022-0.537l0.084-0.989l0.168-1.088l0.265-0.99l0.388-0.722l-0.703-0.604l-0.554-0.802l-0.42-1.028l-0.169-1.298l-0.364-2.145l1.818-0.858l0.41-0.059l5.231,2.554l4.941,2.372l5.577,2.792l1.981,0.963l-0.02,1.045l-0.016,0.946l-0.036,0.636l0.085,2.5l-0.038,0.749l0.036,1.002l0.031,1.229l-0.04,0.283l-0.839-0.009l-1.245,0.05l-0.229,0.143l-0.417,1.245l-0.583,0.809l-0.122,0.438l0.131,0.677l-0.149,0.212l-0.718,0.428l-0.053,0.24l0.342,0.662l-0.087,0.34l-0.542,0.596l-0.316,0.609l0.219,0.352l0.517-0.088l0.338,0.012l0.141,0.225l0.221,1.228l0.137,0.522l0.155,0.295l0.444,0.407l0.266,0.465l0.026,0.367l-0.15,0.425l-0.559-0.208l-0.321-0.012l-0.322,0.086l-0.939,0.613l-0.372,0.228l-0.165,0.382l-0.005,0.41l-0.196,0.284l-2.649,2.275l-0.386,0.087l-2.181,0.055l-0.434,0.059l-0.209,0.199l-0.117,0.806l-0.646,1.176l-0.258,0.143l-0.368,0.031l-0.881-0.009l-0.818,0.273l-0.754,0.386l-0.466,0.271l-0.224,0.03l-0.225-0.069l-0.494-0.661l-1.363,0.686l-0.449,0.158l-0.24-0.027l-0.096-0.084l-0.208-0.183l-0.382-1.057l-0.638-1.07l-1.343-1.179l-1.088-1.067l0.323-0.539l0.29-0.312l0.24-0.1l0.481,0.082l1.187,0.191l0.674-0.032l0.225-0.143l-0.047-0.127l-0.208-0.21l-0.381-0.633l-0.205-0.578l-0.169-1.228l0.134-0.651l-0.119-1.2l-0.395-0.887l-0.923-1.238l-0.208-0.083l-0.627-0.109z"/> - <path id="VN" country:name="Vietnam" d="M627.173,150.012l0.483-0.229l0.515-0.13l0.341,0.012l0.597,0.392l0.325,0.097l0.584-0.413l0.332-0.115l1.595-0.052l0.807-0.117l0.341-0.157l0.696-0.554l0.521-0.328l0.298-0.101l0.623,0.575l0.771,0.235l0.66,0.053l0.777-0.047l0.237,0.21l0.056,0.38l-0.472,0.75l0.096,0.521l0.273,0.365l0.943,0.615l0.621,0.166l0.909,0.107l0.197,0.143l-0.19,0.132l-0.826,0.482l0.106,0.465l-0.203,0.212l-1.261-0.054l-0.136,0.198l0.057,0.395l-0.283,0.382l-0.585,0.792l-0.221,0.142l-0.533,0.241l-0.171,0.127l-0.27,0.396l-0.303,0.932l-0.388,0.975l0.268,0.225l0.469,0.563l1.112,1.071l0.023,0.24l0.042,0.522l0.087,0.254l0.42,0.493l1.096,0.83l1.282,1.296l0.26,0.197l0.636,0.069l0.313,0.38l0.282,1.016l0.302,0.578l0.638,0.605l0.293,0.663l0.341,1.382l0.524,2.809l-0.295,0.438l-0.235,0.495l0.05,0.819l-0.095,0.41l0.056,0.664l-0.027,0.099l-0.364,0.551l-0.447,0.439l-0.254,0.127l-0.509,0.1l-0.419,0.17l-0.501,0.354l-0.591,0.622l-0.579,0.354l-0.325,0.043l-0.512-0.197l-0.404-0.31l-0.179-0.141l-0.153,0.424l0.051,0.494l0.048,0.353l-0.205,0.721l-0.388,0.424l-0.326,0.071l-0.235-0.07l-0.246,0.481l-0.427,0.326l-0.523,0.142l-0.417,0.213l-0.459,0.565l-0.196,0.269l-0.406,0.297l-0.264,0.099l-0.365-0.042l0.078-0.861l0.1-1.313l0.151-0.494l0.215-0.283l-0.02-0.353l-0.475-0.437l-0.749-0.238l-0.091-0.066l0.3-0.289l0.646-0.229l0.915-0.528l0.599-0.229l0.497,0.011l0.688,0.194l0.17-0.27l-0.03-0.197l-0.568-0.435l-0.216-0.422l0.234-0.425l0.99-0.571l0.521-0.229l0.932-0.443l0.599-0.187l0.385-0.285l0.217-0.509l-0.054-1.073l0.05-0.424l0.076-0.367l-0.455-1.014l-0.029-0.663l0.215-0.905l0.155-0.918l-0.064-0.578l-0.214-0.437l-0.529-0.477l-0.072-0.282l0.226-0.439l-0.136-0.395l-0.358-0.308l-0.685-0.391l-0.471-0.52l-0.57-0.914l-1.683-2.121l-0.698-0.772l-0.637-0.646l-0.632-0.476l-1.234-0.741l-0.162-0.098l-0.043-0.494l0.277-0.369l0.311-0.101l0.476,0.068l0.287-0.058l0.261-0.185l0.255-0.326l-0.009-0.508l-0.87-0.968l-0.434-0.675l-0.262-0.083l-0.39,0.171l-0.509,0.483l-0.287,0.058l-0.47-0.195l-0.607-0.434l-0.334-0.689l-0.338-0.929l-0.543-0.604l-0.613-0.575l-0.45-0.745z"/> - <path id="CU" country:name="Cuba" d="M217.961,150.385l0.304-0.043l0.84-0.27l-0.17-0.254l-0.312-0.112l-0.369-0.056l-0.651,0.016l-0.497-0.042l-0.645,0.157l-1.193,0.92l-0.371,0.029l-0.653,0.001l-0.211,0.113l-0.189,0.452l-0.396,0.284l-0.32,0.043l-0.786,0.086l0.259-0.325l0.473-0.312l-0.128-0.593l0.282-0.382l0.114-0.099l1.258-0.61l1.625-0.47l1.164-0.087l0.842-0.157l0.825,0.041l0.566-0.044l0.73,0.168l0.848,0.083l0.603,0.197l0.557,0.112l0.477,0.013l0.499,0.268l0.573,0.536l0.382,0.253l0.581,0.168l0.768,0.111l1.229,0.351l1.02,0.492l0.453,0.31l0.374,0.55l0.33,0.141l0.479,0.041l1.704,0.519l1.018,0.167l0.327,0.239l-0.344,0.58l0.233,0.155l0.559,0.042l0.756-0.072l0.495,0.168l0.507,0.38l0.591,0.281l0.381,0.296l-0.233,0.085l-0.981,0.087l-1.15,0.398l-0.626,0.058l-1.054-0.209l-0.9-0.041l-0.934,0.186l-0.943,0.115l-0.484,0.029l-0.449-0.07l0.353-0.382l0.728-0.623l0.173-0.396L229,154.204l-0.181-0.127l-0.622-0.14l-0.7,0.001l-0.603-0.112l-0.651-0.338l-0.141-0.748l-0.258-0.536l-0.218-0.155l-0.396-0.027l-1.005,0.044l-0.836-0.139l-0.621-0.225l-0.956-0.493l-0.739-0.238l-0.615-0.069l-1.154-0.068l-0.489-0.098l-0.855-0.352z"/> - <path id="LA" country:name="Laos" d="M634.036,168.444l0.808-0.64l0.121-0.438l-0.002-0.945l-0.157-0.507l-0.419-0.703l-0.979-1.279l-0.255-0.464l-0.107-0.366l-0.058-1.524l-0.435-0.632l-0.688-0.659l-0.285-0.535l-0.052-0.282l-0.266-0.153l-0.893-0.192l-0.403-0.012l-0.286,0.453l-0.2,0.538l-0.543,0.257l-0.223,0.072l-0.59-0.265l-0.835-0.348l-0.346,0.03l-1.173,1.178l-0.37,0.411l-0.481-0.138l-0.145-0.324l0.027-0.494l0.117-0.438l0.528-1.569l0.085-0.41l-0.249-1.311l-0.045-0.113l-0.414,0.045l-0.489,0.2l-0.423,0.003l-0.186-0.154l-0.066-0.367l0.106-0.805l-0.01-0.423l-0.118-0.168l-0.295-0.182l-0.541-0.166l0.193-0.185l0.582-0.455l0.442-0.581l0.53-0.61l0.502-0.355l0.178,0.196l0.321,0.21l0.769,0.08l0.266-0.213l0.109-0.339l-0.119-0.521l-0.228-0.366l-0.138-0.592l0.043-0.325l0.24-0.241l0.679-0.314l0.45,0.745l0.613,0.575l0.543,0.604l0.338,0.929l0.334,0.689l0.607,0.434l0.47,0.195l0.287-0.058l0.509-0.483l0.39-0.171l0.262,0.083l0.434,0.675l0.87,0.968l0.009,0.508l-0.255,0.326l-0.261,0.185l-0.287,0.058l-0.476-0.068l-0.311,0.101l-0.277,0.369l0.043,0.494l0.162,0.098l1.234,0.741l0.632,0.476l0.637,0.646l0.698,0.772l1.683,2.121l0.57,0.914l0.471,0.52l0.685,0.391l0.358,0.308l0.136,0.395l-0.226,0.439l0.072,0.282l0.529,0.477l0.214,0.437l0.064,0.578l-0.155,0.918l-0.209,0.114l-0.975,0.429l-0.3,0.072l-0.373-0.351l-0.444-0.181l-0.476,0.186l-0.392,0.285l0.107,0.296l0.187,0.182l0.103,0.211l-0.095,0.24l-0.248,0.058l-0.469-0.251l-0.341-0.111l-0.736-0.165l-0.533-0.251z"/> - <path id="US" country:name="United States" country:shortname="US" d="M60.074,72.607l-0.099,0.228l-0.491,0.472l-0.395,0.183l-0.462,0.062L58,73.461l-0.961-0.362l-0.153-0.197l0.169-0.289l0.54-0.274l0.341-0.32l0.716,0.364l0.3,0.091l0.465-0.26l0.215-0.213l0.064-0.366l0.485-0.047l1.107,0.135l0.536,0.334l0.133,0.213l-0.756,0.062l-0.429,0l-0.59,0.184l-0.11,0.092z M40.092,77.571l-0.729-0.029l-0.097-0.24l0.011-0.3l0.802-0.243l0.326-0.211l0.593-0.423l0.448-0.137l0.646-0.077l1.427,0.253l0.711,0.24l-0.079,0.211l-0.303,0.046l-0.754-0.074l-0.496,0.031l-1.077,0.183l-0.269,0.226l-1.161,0.543z M38.426,77.979l-0.515-0.209l-0.139-0.285l0.381-0.227l0.674,0.27l0.093,0.195l-0.122,0.15l-0.372,0.105z M37.896,78.449l-0.256,0.084l-0.558,0.151l-1.109-0.058l-0.387,0.135l-0.398,0.434l-0.31,0.15l-0.854-0.207l-0.135-0.224l0.497-0.359l0.5-0.315l0.955-0.166l0.863-0.346l0.39,0.089l0.461,0.224l0.341,0.409z M29.628,81.29l-0.168-0.594l-0.324-0.476l0.839-0.136l0.424,0.088l0.436,0.238l-0.244,0.268l-0.26,0.06l-0.073,0.297l-0.22,0.09l-0.412,0.164z M27.543,81.591l-0.39,0.031l-0.741,0.165l-0.311-0.133l-0.088-0.178l0.104-0.119l0.336-0.268l0.294-0.09l0.584,0.222l0.212,0.371z M54.394,157.986l-0.559-0.356l-0.044-0.884l-0.243-0.677l0.482-0.402l-0.035-0.2l-0.156-0.26l0.052-0.149l0.173-0.046l0.354,0.158l0.652,0.279l0.593,0.425l-0.015,0.275l0.238,0.046l0.12,0.287l0.306,0.149l-0.062,0.161L56,156.933l-0.172,0.204l-0.766,0.195l-0.374,0.23l-0.295,0.425z M23.015,59.92l-1.613-0.646l-0.75-0.205l-0.792-0.062l-0.9,0.065l-0.291-0.095l-0.431-0.222l0.179-0.287l0.516-0.049l1.135,0.221l0.579-0.001l0.543-0.081l0.538-0.001l0.828,0.285l1.725,0.362l0.429,0.237l0.046,0.111l-0.569-0.03l-0.646,0.033l-0.527,0.365z M99.855,70.993l0.467,0.929l-0.071,0.167l-0.879-0.272l-0.621-0.075l0.067,0.441l-0.056,0.228l-0.935-0.607L97.03,71.41l0.396-0.458l0.263-0.153l0.612-0.078l0.784,0.38l0.771-0.108z M100.975,73.606l0.128,0.272l-0.086,0.273l-0.318,0.483l-0.559-0.815l-0.597-0.909l-0.04-0.228l0.095-0.213l0.407,0.029l0.568,0.197l0.402,0.91z M106.858,78.207l-1.872-1.166l-0.566-0.555l0.01-0.467l-0.559-0.843l0.071-0.106l0.456,0.06l0.274,0.256l1.165,0.48l0.086,0.196l-0.059,0.136l-0.149,0.226l0.296,0.436l0.839,0.374l0.007,0.974z M140.191,127.819l-0.043-0.094l-0.198-0.36l-0.049-0.067l-0.032,0.042l-0.028,0.05l-0.04-0.092l0.002-0.664l-0.331-0.604l-0.472-0.451l-0.661-0.451l-0.512-0.197l-0.114-0.052l-0.145,0.034l0.002,0.092l-0.088,0.025l-0.1-0.042l-0.146-0.143l0.076-0.076l-0.073-0.202l-0.228-0.252l-0.283-0.025l-0.312,0.084l-0.932-0.336l-0.286-0.328l-0.428-0.244l-0.383,0.042l-0.932-0.16l-0.721,0.051l-0.12-0.185l-0.234-0.067l-0.046-0.177l0.094-0.117l-0.157-0.504l0.133-0.464l-0.227-0.096l-0.127,0.008l-0.249-0.134l0-0.101l0.075-0.093l-0.029-0.219l-0.347-0.185l-0.254-0.286l-0.415-0.219l-0.391-0.623l-0.202-0.076l-0.203-0.311l-0.409-0.219l-0.156-0.529l-0.002-0.227l0.178,0.007l0.147-0.164l0.029-0.326l-0.208-0.251l-0.192-0.045l-0.22,0.037l-0.303-0.126l-0.535-0.514l0.078-0.21l-0.091-0.312l-0.129-0.067l-0.044-0.463l0.058-0.152l0.119-0.025l0.099,0.067l0.073,0.076l-0.086,0.101l0.153,0.202l0.285,0.126l0.116,0.118l0.203,0.017l-0.385-0.564l-0.183-0.144l-0.021-0.236l-0.184-0.109l-0.051-0.344l-0.13,0.006l-0.011,0.144l0.048,0.446l-0.093,0.017l-0.293-0.194l-0.119,0.042l-0.516-0.404l-0.136-0.363l-0.377-0.514l-0.531-0.379l-0.624-0.583l-0.123-0.142l0.114-0.101l-0.327-0.751l0.161-0.43l-0.254-0.479l-0.22-0.355l-0.738-0.782l-0.104-0.299l0.099-0.627l0.252-0.628l0.166-0.357l0.059-0.856l-0.215-0.785l-0.692-1.486l-0.153-0.916l0.096-0.287l0.231-0.244l0.402-0.201l0.365-0.717l-0.365-0.573l-0.066-0.33l0.424-1.593l0.153-0.575l0.061-0.634l0.091-0.778l0.019-0.179l-0.153-0.16l0.08-0.231l-0.103-0.167l0.157-0.077l-0.03-0.186l-0.046-0.186l-0.031-0.103l-0.004-0.058l0.322,0.096l0.209-0.019l0.062-0.097l-0.211,0.006l-0.614-0.122l0.062-0.707l-0.103-0.328l0.017-0.277l0.587-0.225l-0.345-0.019l-0.16-0.142h-0.129l-0.053,0.045l0.042,0.116l-0.12,0.052l-0.133-0.979l-0.927-1.463l-0.017-0.465l0.129-0.131l0.544,0.086l0.632,0.217l0.785,0.114l0.641,0.028l0.546-0.044l0.415,0.086l0.547,0.318l0.039,0.435l-0.42,0.407l-0.413,0.347l0.532,0.146l0.184,0.188l0.251,0.169l0.029-0.228l0.161-0.232l0.393-0.305l0.21-0.581l0.102-0.465l-0.064-0.421l-0.356-0.958l-0.158-0.305l-0.655-0.516l0.194,0.013l2.579,0.001l1.335,0.022l4.588-0.025l3.938,0.008l2.87-0.001l1.687,0.006l5.117-0.028l0.74,0.011l4.13,0.021l1.089-0.035l3.821,0.023l0.875-0.005l3.617-0.004l4.84,0.018l0.601-0.003l2.935,0.014l2.131-0.012l2.781,0.029l2.915-0.016l2.105,0.003l1.348-0.007l2.798,0.029l2.687-0.029l0.68,0.003l-0.387-0.588l-0.131-0.347l0.501-0.036l0.896,0.748l0.279,0.371l0.468,0.46l0.833,0.451l0.518-0.076l1.425,0.208l0.02,0.185l0.271-0.012l0.338,0.48l0.16-0.247l0.502,0.013l0.241,0.271l0.469,0.086l0.064,0.185l0.506,0.098l0.573-0.141l0.219-0.06l0.412-0.191l0.373-0.075l0.028,0.282l0.197,0.116l0.855-0.083l0.474,0.041l0.156,0.115l0.196,0.144l0.542-0.049l0.707,0.074l1.469-0.592l0.805-0.189l0.797,0.227l0.977,0.386l3.975,1.576l2.15,1.061l0.101,0.429l0.46,0.465l0.628-0.024l0.178,0.135l0.184,0.294l0.916,0.181l0.307,0.235l-0.11,0.318l0.26,0.33l2.529,1.05l0.876,3.16l0.054,0.545l-0.028,0.746l-0.377,0.576l-0.294,0.544l-0.264,0.433l-0.414,0.294l-0.707,0.525l-0.044,0.218l0.012,0.33l0.371,0.427l0.497,0.169l0.573,0.068l0.524-0.117l0.925-0.506l0.939-0.478l0.88-0.262l0.919-0.062l0.944-0.163l1.464-0.452l0.875-0.427l-0.047-0.362l-0.16-0.471l-0.018-0.319l0.162-0.375l0.47-0.203l0.93-0.091l1.123,0.01l1.305,0.138l1.156-0.197l0.44-0.275l0.163-0.512l0.146-0.434l0.545-0.164l1.754-0.814l0.534-0.305l0.968-0.523l1.76-0.009l2.508,0.029l1.855,0.004l1.093,0.095l0.174-0.375l0.363-0.435l0.402-0.06l1.161,0.124l1.139-1.45l1.139-2.22l0.514-0.626l0.632-0.526l0.273,0.085l0.505,0.36l0.381,0.085l0.41-0.176l0.771,0.025l0.488,0.288l0.174,0.274l0.31,2.819l-0.077,0.229l0.606,0.231h0.224l0.042,0.154l-0.143,0.069l0.02,0.256l-0.192,0.077l0.16,0.291l0.188-0.153l0.349,0.495l-0.268,0.281l0.299-0.04l0.171,0.093l-0.511,0.374l-0.509,0.093l-0.297-0.12l-0.013,0.253l-0.138,0.067l-0.077-0.107l-0.231-0.08l-0.277,0.133l-0.101,0.28l-0.171-0.013l-0.15,0.16l-0.175-0.347l-0.746,0.28l-0.204-0.093l0.12,0.413l-0.666-0.213l0.199-0.48l-0.149-0.04l-0.364,0.52l-0.332,0.56l-0.342,0.333l-0.324-0.227l-0.249,0.439l-0.346-0.08l0.122-0.307l-0.325,0.253l0.165,0.16l-0.326,0.293l-0.318-0.133l0.105-0.226l-0.654,0.253l0.065,0.359l-0.264,0.04l-0.161,0.373l-0.352,0.106l-0.333,0.679l-0.404,0.505l0.173,0.146l0.068,0.212l0.168,0.053l0.083-0.08l0.169,0.013l-0.122,0.146l-0.547,0.106l0.053,0.093l-0.392,0.292l-0.068,0.159l0.337,0.027l0.282,0.093l0.599,0.704l0.055,0.398l0.399,0.106l0.691-0.239l-0.022-0.186l-0.14-0.027l-0.254-0.279l-0.097-0.04l-0.009-0.066h0.196l0.23,0.133l0.218,0.358l0.031,0.425l-1.599,0.292l-0.032-0.385l-0.124-0.066l-0.109,0.226l-0.164,0.04l-0.03,0.093l-0.105-0.106l-0.159,0.266l-0.164,0.04l-0.294,0.04l-0.045-0.332l0.198-0.332l-0.443,0.119l-0.154-0.146l-0.082,0.252l-0.087,0.664l-1.429,0.132l-1.694,0.159l-1.182,0.345l-0.787,0.358l-0.097,0.212l-0.32,0.053l-0.144,0.172l-0.032-0.04l0.308-0.756l0.024-0.106l-0.071,0.027l-0.41,0.994l-0.079-0.08l-0.406,0.292l0.218,0.318l0.553,0.093l-0.46,1.515l-0.302,0.429l-0.259-0.092l0.043,0.251l-0.062,0.185l-0.237,0.145l-0.462,0.501l-0.292,0.304l-0.167,0.026l-0.075-0.119l0.177-0.31l-0.113-0.178l-0.43,0.013l-0.447-0.343l-0.148-0.053l-0.329-0.541l0.315-0.257l0.151-0.245l-0.271,0.119l-0.362,0.37l0.489,0.845l0.033,0.356l0.387,0.581l0.28,0.066l0.104,0.765l-0.101,0.238l-0.151,0.23l-0.125-0.013l-0.487,0.666l-0.396,0.798l0.034,0.053l-0.13,0.132l-0.107-0.125l-0.374,0.725l0.026,0.125l-0.226,0.04l-0.137-0.263l0.342-0.864l0.195-0.29l0.247-0.119l0.061-0.237l-0.093-0.059l-0.374,0.119l0.226-0.383l-0.218,0.04l-0.176-0.093l0.012-0.191l0.242-0.04l-0.077-0.33l-0.439,0.296l-0.241-0.204l-0.157,0.053l-0.23-0.396l0.355-0.171l0.357-0.053l-0.005-0.06l-0.604-0.316l-0.092,0.165h-0.072l0.107-0.323l0.089-0.02l0.21,0.159l0.131-0.06l-0.098-0.224l-0.353-0.066l-0.065-0.112l0.096-0.112l0.336,0.02l0.193-0.284l-0.281,0.046l-0.158-0.059l0.241-0.37l0.652-0.152l-0.328-0.06l0.146-0.409l-0.28,0.093l-0.096,0.132l0.11,0.079l-0.315,0.191l-0.035-0.224l-0.093,0.053l0.051,0.224l-0.081,0.086l-0.051-0.158l-0.097-0.066l-0.103,0.416l-0.447-0.079l0.402,0.501l-0.294,0.666l0.07,0.237l0.272,0.488l-0.055,0.139l-0.466-0.317l-0.1-0.211l0.026,0.205l0.174,0.218l0.421,0.237l0.132,0.508l-0.631-0.402l-0.354-0.007l-0.118-0.283l-0.155-0.053l0.066,0.25l-0.541-0.323l-0.33,0.04l0.015-0.29l0.427-0.323l-0.428,0.079l-0.19,0.468l0.204,0.231l0.457,0.046l0.202,0.25l0.954,0.297l-0.047,0.092l0.554,0.165l0.158,0.132l-0.22,0.468l-0.227,0.06l-1.042-0.804l0.708,0.811l0.626,0.171l-0.248,0.092l0.323,0.079l-0.045,0.079l0.061,0.06l-0.034,0.25l-0.312-0.191l-0.071,0.073l0.104,0.211l-0.216,0.02l-0.656-0.56l-0.023,0.026l0.419,0.475l0.309,0.158l0.182-0.026l0.191,0.21l0.018,0.31l-0.298,0.059l-0.492-0.534l-0.474-0.198l-0.199,0.16l0.046,0.044l0.44,0.145l0.488,0.382l-0.047,0.237l0.442-0.033l0.031-0.119l0.748,0.119l0.151,0.382l0.406,1.212l0.448,0.803l-0.14-0.092l-0.262-0.349l-0.059-0.132l-0.359-1.172l-0.147-0.277l-0.056,0.31h0.135l0.034,0.198l-0.292-0.066l0.173,0.283l0.144,0.099l0.228,0.58l-0.144-0.053l-0.211-0.382l0.002,0.224l-0.52-0.303l-0.06,0.059l0.266,0.303l-0.247,0.119l-0.526-0.204l0.225,0.204l-0.375,0.211l-0.173-0.02l-0.251-0.21l-0.024-0.217l0.083-0.158l-0.081-0.053l-0.091,0.204l0.044,0.23l0.116,0.211l-0.107,0.158l0.894,0.02l0.571-0.145l0.125,0.165l-0.113,0.191l-0.072,0.369l0.14,0.066l0.092-0.257l0.135-0.369l0.18-0.105l0.266,0.31l0.047,0.296l-0.166,0.25l-0.163-0.013l-0.063-0.099l-0.316,0.474l-0.254,0.197l-0.483-0.053l-0.203-0.065l-0.147-0.066l-0.136-0.245l-0.151,0.014l0.141,0.244l-0.075,0.013l-0.538-0.125l-0.436-0.151l0.162,0.185l0.269,0.026l0.833,0.335l-0.034,0.119l-0.396,0.145l0.247,0.007l-0.19,0.25l-0.281,0.138h-0.149l-0.481-0.375l0.242,0.395l0.43,0.164l0.302-0.171l0.292,0.026l0.11-0.204l0.04,0.178l0.217,0.04l0.048,0.079l-0.428,0.322l-0.013,0.085l-0.261,0.072l-1.498,0.214l-0.865,0.895l-0.487,0.609l-0.13,0.127l-0.935,0.143l-0.528,0.128l-0.617,0.241l-0.678,0.539l-0.225,0.424l-0.096,0.354l-0.819,0.694l-0.693,0.383l-0.429,0.199l-0.797,0.086l-0.35,0.58l-0.177,0.198l-0.809,1.125l-0.273,0.781l-0.459,1.249l0.236,1.455l0.387,0.925l0.456,0.873l0.934,1.562l0.352,1.746l0.486,1.194l-0.075,0.092l0.287,0.276l0.123,0.333l0.062,0.827l-0.301,1.536l-0.064,0.278l-0.31,0.415l0.108,0.424l-0.02,0.252l-0.393,0.551l-0.017-0.092l0.129-0.241l-0.025-0.138l-0.256,0.035l-0.38,0.137l-0.291-0.126l-0.509,0.138l-0.12-0.329l0.014-0.233l-0.567-1.068l-0.764-0.138l-0.204-0.352l-0.113-0.819l-0.423-0.229l-0.144-0.702l-0.373,0.093l-0.608-1.08l-0.375-0.482h0.296l0.375-0.438l0.048-0.226l-0.167-0.226l-0.471,0.407l-0.277-0.208l0.126-0.573l0.147-0.758l0.158-1.043l-0.293-0.452l-0.258-0.169l-0.496-0.126l-0.832-0.987l-0.875-0.804l-0.528-0.168l-0.43,0.072l-0.536,0.298l-0.456,0.354l-1.202,0.299l-0.273-0.213l-0.131-0.62l-0.253-0.254l-0.264-0.113l-0.752-0.069l-0.516-0.296l-0.22-0.233l-0.504,0.138l-1.052,0.115l-0.653-0.184l-0.047,0.298l-0.64,0.099h-0.183l-0.578-0.926l-0.238,0.781l-0.447-0.135l-0.65,0.001l-1.328-0.04l-0.672,0.439l-0.39,0.055l-1-0.459l-0.096,0.009l-0.142,0.014l-0.362,0.528l0.201,0.229h0.303h0.211l0.537-0.207l0.406,0.092l0.676,0.482l-0.68,0.373l0.02,0.254l0.263,0.353l0.593,0.146l0.229,0.217l0.35,0.334l-0.533,0.136l-0.503-0.084l-0.276-0.419l-0.79-0.271l-0.224-0.211l-0.265-0.056l-0.013,0.02l-0.209,0.32l0.209,0.154l0.248,0.183l-0.248,0.179l-0.069,0.05l-0.447-0.459l-0.476,0.192l-0.287,0.291l-1.025-0.472l-0.419-0.494l-1.16-0.642l-0.615,0.066l0.554,0.393l-0.307,0.187l-1.17-0.083l-0.886-0.252l-0.896-0.168l-1.547,0.173l-0.632,0.328l-0.392-0.015l-0.433-0.031l-0.135-0.49l-0.333,0.057l-0.112,0.184l0.474,0.731l-0.877,0.64l-0.808,0.577l-0.915,0.317l-0.419,0.043l-0.414-0.056l-0.728-0.111l-0.126,0.198l0.437,0.437l-0.239,0.396l-0.327,0.199l-0.631,0.114l-0.737,0.27l-0.268,0.17l0.558,0.352l0.111,0.169l-0.659,0.694l-0.154,0.297l-0.012,0.848l0.144,0.636l0.271,0.762l0.425,0.903l-0.347-0.119l-0.816-0.377l-0.296,0.001l-0.416,0.116l-0.264-0.069l-1.029-0.56l-0.921-0.32l-0.375-0.365l-0.336-0.592l-0.332-0.932l-0.078-0.467l-0.268-0.253l-0.657-0.576l-0.845-1.042l-0.744-1.227l-0.663-1.029l-0.363-0.366l-0.412-0.252l-0.783-0.321l-0.475-0.082l-0.643,0.018l-0.468,0.201l-0.576,0.541l-0.418,0.413l-0.283,0.37l-0.416,0.158l-0.501-0.011l-0.337-0.069l-1.104-0.503l-1.092-0.659l-0.445-0.549l-0.318-0.847l-0.284-0.678l-0.179-0.226l-0.708-0.491l-0.837-0.519l-0.766-0.632l-0.631-0.662l-0.209-0.112l-1.892-0.046l-1.858-0.003l-0.096,0.892l-0.213,0.101l-1.867,0.011l-0.966-0.037l-1.544-0.02l-1.662-0.019l-0.338-0.055l-3.516-1.112l-2.811-0.933l-1.186-0.39l-0.267-0.154l-0.316-0.31l-2.381,0.084l-2.367,0.155l-0.34,0.017z M49.818,152.776l-0.122,0.086l-0.279,0.03l-0.111-0.131l-0.177-0.005l-0.324,0.051l-0.304-0.39l-0.071-0.263l0.339-0.01l0.299-0.253l0.188,0.218l0.106,0.294l0.223,0.096l0.233,0.279z M52.785,154.312l-0.155-0.081l-0.085-0.356l-0.461-0.321l0.095-0.229l0.143-0.058l0.366,0.209l0.344,0.055l0.616,0.356l-0.005,0.172l-0.294,0.184l-0.563,0.069zM111.683,77.224l-0.138,0.415l-0.45,0.067l-0.324,0.113l-0.295,0.247l-0.321-0.137l-0.185-0.21l0.087-0.443l0.086-0.443l-0.438-0.675l-0.463-0.319l-0.199-0.271l-1.281,0.055l-0.437,0.098l-0.153,0.161l-0.496,0.097l-0.019-0.193l-0.034-0.432l0.212-0.272l0.184-0.212l-0.378-0.347l-0.641-0.438l-0.693-0.696l-0.723-0.317l-0.453-0.136l0.132-0.35l-0.569-0.592l-0.099-0.213l0.371-0.229l-0.068-0.122l-0.301-0.152l-0.445-0.076l-0.392-0.274l-0.237-0.259l-0.57-0.305l-1-0.411l-0.479-0.765l-0.217-0.583l-0.367-0.399l-0.357,0.016l-0.101,0.814l0.42,0.873l0.104,0.306l-0.047,0.153l-0.701-0.136l-0.272-0.076l-0.511-0.504l-0.4-0.459l-0.537,0.139l-1.219-0.228l1.263,0.718l0.032,0.214l-1.62,0.171l-1.093-0.35l-1.388-0.948l-0.543-0.292l-0.664-0.043l-0.079,0l-0.933-0.213l-1.3-0.536l0.928-0.248l0.135-0.169L90.8,67.129l-0.384-0.153l-0.792,0.156l-0.454,0.14l-0.656,0.017l-1.058-0.06l-1.068-0.245l0.027-0.247l-0.148-0.186l-0.325-0.108l-0.359,0.016l-0.47,0.202l-1.036,0.049l-1.465-0.122L80.46,66.64l-0.786-0.091l-0.248-0.108l-0.651-0.387l-0.427-0.527l-0.301,0.218l-0.788,0.157l-0.89-0.293l-0.234-0.326l-0.417-0.139l-0.872-0.248l-1.538-0.23l-0.817-0.248l-0.671-0.342l-0.553,0.235l-0.675,0.079l0.06,0.437l-0.193,0.062l-0.389,0.25l-0.249,0.405l1.119,0.293l0.174,0.294l-0.096,0.388l-0.428,0.449l-0.458,0.001l-0.804-0.214l-0.586-0.061l-0.568,0.094l-0.978,0.603l-1.066,0.217l-0.936,0.448l-1.035,0.448l-1.095,0.109l0.178-0.308l0.063-0.123l0.72-0.401l-0.093-0.385l-0.655-0.523l0.004-0.108L64.1,66.19l0.411-0.482l0.157-0.42l0.736-0.312l0.87-0.235l1.165-0.018l1.085,0.123l0.239-0.156l-1.239-0.466l-0.971-0.389l-1.043,0.049l-0.226,0.219l-0.449,0.095l-0.573,0.438l-0.865,0.375l-1.019,0.282L61.553,65.9l-0.406,0.094l-0.298,0.14l0.131,0.325l-0.177,0.526l-0.563,0.34l-0.564,0.078L59,67.544l-0.592,0.278l-0.681,0.601l-0.035,0.292l0.38,0.168l0.36,0.03l0.667,0.106l0.465,0.229l-0.075,0.184l-0.43,0.338l-0.625,0.2l-0.557,0.277l-0.423,0.398l-0.544,0.383l-0.675,0.093l-1.434,0.308l-0.678,0.397l-1.036,0.337l-0.7,0.367l0.52,0.5l-0.1,0.167l-1.106,0.412l-0.897,0.153l-0.778,0.168L49.51,74.19l-1.214,0.456L48.1,74.828l-0.274,0.394l-0.753,0.439l-1.193,0.229l-1.234,0.184l-0.973-0.345l0.001-0.181l0.332-0.348l0.763-0.273l0.306-0.212l0.445-0.364l1.171-0.441l1.403,0.073l-0.12-0.212l0.02-0.516l0.47-0.304l0.725-0.291l0.754-0.366l0.266-0.214l0.002-0.731l0.246-0.749l0.693-0.49l0.194-0.398l0.034-0.412l-0.633,0.122l-1.251,0.186l-0.676-0.029l-0.5-0.597l-0.266,0.062l-0.613,0.216l-0.136,0.23l0.239,0.352l0.021,0.352l-0.169,0.046L47,70.115l-0.567-0.32l-0.487-0.397l-0.509-0.291l-0.56-0.03l-0.812-0.106l-0.91,0.094l0.028,0.138l-0.644,0.338l-1.175,0.14l-0.649-0.09l-0.064-0.123l-0.082-0.107l-0.125-1.028l0.3-0.508l-0.142-0.431l-0.864-1.002l-1.43,0.437l-0.738,0.078l-0.406,0.202l-1.091,0.094l-0.4-0.23l-0.394-0.355l-0.466-0.325l-1.007-0.463l-0.179-0.28l0.292-0.171l0.337-0.437l0.704,0.139l1.312,0.309l0.69,0.03l0.238-0.234l-0.375-0.482l-0.458-0.264l-0.363,0l-0.541,0.22l-0.528-0.015l-1.342-0.513l-0.623-0.186l-0.197,0.016l-0.858-0.029l-0.024-0.078l-0.623-0.985l0.79-0.19l0.071-0.456l0.495-0.221l0.102-0.299l0.227-0.347l0.893-0.491l0.337-0.38l0.386-0.301l0.527-0.476l0.39-0.175l0.719,0.109l0.98,0.268l0.485,0.094l0.752-0.144l0.427-0.254l0.675-0.429l1.252-0.257l0.774-0.033l0.955-0.049l0.354-0.175l0.187-0.478l-0.259-0.669l-0.814-0.686l0.026-0.096l0.927-0.034l0.343-0.256l-0.25-0.384l-0.497-0.256l-0.367-0.08l-1.88,0.389L39.33,56.53l-0.534,0.289l-0.496,0.065l-1.907-0.333l-0.848-0.031L34.8,56.49l-1.27,0.162l-1.265-0.029l-1.349-0.174l-0.53-0.207l-0.183-0.788l0.144-0.146l0.636-0.033l1.008-0.002l0.446-0.179l-1.057-0.241l-1.912-0.304L28.13,54.31l-1.285-0.208l0.219-0.114l0.781-0.262l1.568-0.214l1.325-0.328l0.958-0.214l1.058-0.361l0.953-0.23l1.399-0.281l1.513,0.128l-0.158,0.523l0.023,0.277l1.051,0.161l1.359,0.095l1.074-0.019l0.657-0.099l0.784-0.246l0.55-0.295l0.262-0.083l0.752,0.064l0.751,0.113l1.021-0.051l0.2-0.327l0.007-0.18l-0.689-0.064l-1.946-0.292l-1.283-0.047l-0.312-0.755l-1.473-0.162l-0.96-0.031l-1.573-0.096l-0.194-0.511l-0.484-0.312l-1.042-0.461l-0.512-0.148l-2.66-0.659l-2.008-0.545l0.317-0.167l0.812-0.402l0.086-0.485l2.136-0.054l0.99-0.069l1.829-0.288l0.784-0.354l0.452-0.623l0.788-0.575l0.616-0.525l0.818-0.41l0.742-0.224l1.066-0.104l1.133-0.241l1.047-0.036l1.804,0.065l0.146-0.188l-0.156-0.205L44.47,42.83l0.018-0.206l1.936-0.089l1.143,0.032l0.974-0.054l1.344-0.14l1.098-0.416l0.918-0.417l0.957-0.019l0.282,0.051l0.675,0.241l0.156,0.172l-0.383,0.139l0.017,0.344l1.049,0.136l0.424,0.034l0.536-0.293l0.297-0.208l1.419,0.187l1.534,0.049l1.062,0.049l0.715,0.033l0.711,0.257l0.359,0.274l0.783,0.358l0.494,0.085l0.421-0.086l1.292,0.117l1.124,0.015l1.556-0.054l1.449-0.088l1.213,0.1l1.377,0.254l0.883,0.118l3.424,0.13l1.279,0.168l0.743,0.169l2.027-0.038l2.339-0.141l1.123,0.236l2.441,0.791l1.206,0.301l0.227,0.008l0.102,0.483l-0.003,2.855l0.039,2.259l0.052,2.335l0.129,2.796l-0.026,2.183l-0.043,4.334l0.026,2.167l0.089,1.046l0.196,0.279l0.84,0.074l2.424-0.122l0.739,0.059l0.332,0.388l0.173,0.387l0.348,0.292l2.162,1.318l0.945,0.673l0.238-0.325l0.848-0.205l1.225-0.67l0.731-0.498l0.495-0.126l0.832,0.073l0.316,0.199l0.371,0.492l0.35,0.322l2.048,1.175l0.814,0.58l1.769,1.768l1.67,1.882l0.512,0.393l0.189,0.029l0.98,0.314l2.025,0.763l0.402,0.255l-0.163,0.788l0.393,0.777z"/> - <path id="CN" country:name="China" d="M643.755,159.873l-1.092-0.52l-0.637-0.337l-0.203-1.284l0.036-0.282l0.24-0.241l0.42-0.241l0.721-0.623l0.493,0.056l0.049-0.17l0.24-0.396l0.239,0.028l0.573,0.225l0.321-0.312l0.439-0.001l0.798-0.171l0.596,0.69l-0.163,0.17l-0.443,0.354l-0.412,0.538l-0.285,0.734l0.14,0.296l-0.22,0.311l-0.292,0.085l-1.026,0.383l-0.532,0.707z M627.173,150.012l-0.679,0.314l-0.24,0.241l-0.043,0.325l0.138,0.592l0.228,0.366l0.119,0.521l-0.109,0.339l-0.266,0.213l-0.769-0.08l-0.321-0.21l-0.178-0.196l-0.153-0.239l-0.111-0.38l-0.628,0.413l-0.647,0.159l-0.246-0.083l-0.378-0.266l-0.341-0.746l-0.291-0.379l-0.481,0.045l-0.507,0.003l-0.228-0.098l-0.117-0.352l0.729-1.584l-0.033-0.268l-0.521-0.096l-0.554,0.074l-0.202-0.324l-0.277-1.762l-0.156-0.126l-0.479,0.017l-0.771,0.089l-0.819,0.442l-0.312,0.086l-0.216-0.069v-0.268l0.224-0.58l-0.163-0.705l-0.075-0.465l0.617-0.85l0.191-0.198l0.487-0.271l0.611-0.525l0.429-0.722l0.353-0.862l-0.02-0.875l-0.195-1.649l-0.146-0.14l-0.504,0.031l-0.287-0.041l-0.217-0.309l-0.243-0.901l-0.397-0.435l-0.504-0.279l-0.277,0.044l-0.306,0.34l-0.001,0.127l-0.624-0.081l-0.73-0.179l-0.657-0.081l-0.3-0.055l-0.102-0.056l0.138-0.269l0.354-0.454l-0.046-0.38l-0.716-0.715l-0.455-0.392l-1.377,0.84l-0.377,0.044l-0.975-0.319l-0.286-0.167l-0.355,0.087l-0.546,0.299l-1.105,0.726l-0.829,0.258l-0.543,0.37l-1.123,1.107l-0.397,0.27l-0.714,0.216l-0.784,0.033l-0.189,0.1l-0.329-0.619l-0.312-0.209l-0.371-0.041l-1.659-0.047L601,137.538l-0.309-0.294l-0.417,0.016l-0.149,0.103l-0.348,0.239l-0.609,0.539l-1.251,1.545l-0.212-0.662l0.052-0.861l-0.139-0.183l-0.231-0.069l-0.471,0.102l-0.345,0.129l-0.655-0.159l-0.339,0.281l-0.341-0.116l-0.849,0.066l-0.319-0.364l-0.63-0.281h-0.407l-0.08,0.331l-0.271,0.083l-0.685-0.38l0.01,0.364l-0.237,0.099l-0.141-0.463l-0.54-0.496l-0.365,0.066l-0.935-0.066l-0.014-0.265l0.175-0.396l-0.326-0.017l-0.333,0.248l-1.451-0.893l0.069-0.281l-0.178-0.38l-0.289-0.166l-0.71,0.116l-0.158,0.166l-0.657-0.794l-0.454-0.281l-0.15,0.132l-0.472-0.215l-0.726-0.595l-0.867-0.264l-0.132-0.612l-1.079-0.199l-0.186,0.182l-0.275-0.066l-0.134,0.513l-0.276,0.314l-0.299-0.05l-0.24-0.43l-0.859-0.596l-0.154,0.066l-0.756-0.248l0.116-0.364l-1.078-0.579l-0.363,0.116l-0.772-0.843l-0.383-0.248l-0.477,0.314l-0.198-0.066l-0.099-0.43l0.215-0.215l-0.272-0.364l0.104-0.446l-0.579-0.595l-0.157-0.694l0.785-0.198l0.033,0.364l0.337,0.264l0.368-0.049l0.376-0.281l0.578-0.364l-0.367-0.694l0.104-0.414l-0.68-0.099l-0.044-0.182l-0.092-0.078l-0.718-0.096l-0.294-0.221l-0.037-0.552l-0.073-0.589l0.184-0.184l0.331-0.221l-0.221-0.258l-0.441-0.405l-0.81-0.11l-0.221-0.515l-0.441-1.03v-0.515l-0.502,0.152l-0.147-0.126l-0.305-0.111l-1.337-0.104l-0.565-0.436l-0.178-0.09l-0.104-0.199h-0.239l-0.52,0.196l-0.252-0.281l-0.198-0.218l-0.301-0.07l0.312-0.516l-0.007-0.501l-0.213-0.247l-0.373-0.323l-0.625,0.009l-0.282,0.128l-0.004-0.456l-0.554-0.117l-0.296-0.047l-0.281,0.21l-0.105-0.112l-0.313-0.14l-0.048-0.088l-0.236-0.012l-0.01-0.269l0.574,0.059l0.192-0.145l0.354-0.136l0.08-0.249l0.181-0.185l-0.2-0.163l0.152-0.36l-0.245-0.237l0.126-0.428l-0.049-0.123l-0.152-0.012l-0.028-0.246l0.009-0.284l-0.295-0.494l-0.273-0.154l-0.692-0.039l-0.22-0.06l-0.229,0.162l-0.463,0.045l-0.325-0.394l-0.077-0.305l0.207-0.223l-0.023-1.031l0.011-0.069l0.139-0.739l0.129-0.213l0.274-0.186l1.422-0.704l1.737-0.734l0.359-0.03l0.06,0.071l0.183,0.567l0.344,0.055l0.507-0.145l0.885-0.132l0.268-0.243l0.463-0.784l0.467-0.472l0.238-0.03l1.248,0.235l0.459-0.017l0.478-0.102l0.646-0.345l0.638-0.701l0.405-0.301l0.445-0.145l1.338-0.349l0.97-0.219l0.325-0.187l0.051-0.157l-0.031-0.194l-0.139-0.86l0.02-0.399l0.32-0.401l0.705-0.546l0.222-0.33l-0.119-0.47l-0.29-0.441l-0.345-0.627l-0.03-1.357l-0.483-0.141l-0.366,0.06l-0.232-0.185l0.068-0.215l0.215-0.302l0.393-0.188l1.799-0.254l1.082-0.207l0.35-0.06l0.5,0.184l1.133,0.238l0.394-0.074l0.231-0.145l0.156-0.245l-0.126-0.286l-0.622-0.514l0.137-0.418l0.286-0.605l0.438-0.794l0.516-1.141l0.427-0.507l1.096,0.254l0.721,0.141l0.594,0.141l1.402,0.079l0.718-0.062l0.417-0.103l0.444-0.392l0.157-0.39l-0.213-0.707l-0.097-0.75l0.34-0.581l0.428-0.277l1.199-0.093l0.289-0.06l0.306-0.219l0.035-0.478l0.011-0.275l0.279-0.262l0.542-0.148l0.551-0.034l0.228-0.014l0.569-0.003l0.244-0.074l0.062,0.145l0.131,0.405l0.24,0.563l0.371,0.433l1.301,0.745l0.834,0.415l0.614,0.069l0.731,0.167l0.633,0.144l0.354,0.143l0.568,0.618l1.07,1.451l0.401,0.66l-0.215,0.447l-0.237,0.75l-0.214,0.389l-0.369,0.347l-0.035,0.129l0.105,0.43l0.233,0.229l0.724,0.312l1.062,0.181l1.505,0.021l0.995,0.038l0.668,0.083l0.998,0.224l0.632,0.268l1.645,0.806l0.839,0.31l0.744,0.096l0.105,0.542l1.571,2.161l0.467,0.439l0.444,0.254l1.979,0.018l1.241,0.207l0.802,0.109l1.165,0.022l2.861-0.059l0.937,0.023l1.164,0.022l1.69,0.119l0.521,0.168l0.815,0.551l1.006,0.365l1.599,0.433l0.929,0.123l0.663-0.061l0.61,0.067l0.253,0.297l0.433,0.197l0.481-0.017l0.686-0.289l1.44-0.534l0.303-0.101l0.736-0.274l0.816-0.289l1.204-0.349l1.339-0.007l1.514-0.065l0.987,0.08l0.651-0.061l1.941-0.737l0.265-0.172l1.111-1.046l0.67-0.389l1.265-0.292l0.326-0.259l0.123-0.271l-0.188-0.228l-0.599-0.411l-0.389-0.569l-0.003-0.343l0.214-0.401l0.539-0.589l0.457-0.231l0.316-0.073l0.718,0.154l0.668,0.382l0.592,0.125l0.982-0.005l0.744-0.047l0.742-0.433l1.192-0.91l0.224,0.013l0.438,0.012l0.624,0.054l0.896-0.134l0.638-0.248l0.347-0.188l0.241-0.216l0.312-0.82l0.363-0.333l0.47-0.204l0.464-0.045l0.483,0.127l0.353-0.189l0.831-0.278l0.539-0.146l0.937-0.221l0.854-0.033l0.432,0.099l1.074,0.008l0.464,0.127l0.414-0.218l0.107-0.217l-0.048-0.273l-0.599-0.501l-0.879-0.99l-0.797-0.5l-0.538-0.199l-0.928-0.212l-0.438,0.002l-1.191,0.786l-0.292-0.07l-0.431-0.416l-0.317-0.085l-0.576,0.018l-0.754,0.062l-0.929,0.395l-0.342,0.045l-0.051-0.029l-0.269-0.836l0.381-0.58l1.224-1.959l0.687-1.207l0.295-0.31l0.046,0.018l0.452,0.172l1.126,0.574l0.343-0.016l0.438-0.089l2.44-0.752l0.779-0.339l0.123-0.233l-0.056-0.306l-0.35-0.348l-0.062-0.146l0.103-0.249l0.422-0.426l0.416-0.543l0.667-0.779l0.599-0.545l1.371-0.608l0.167-0.794l-0.107-0.249l-0.465-0.306l-0.558-0.026l-0.822,0.078l0.119-0.25l0.375-0.282l1.193-0.787l0.478-0.165l0.602-0.136l1.854-0.143l0.836-0.123l1.203-0.109l0.917-0.049l1.148,0.215l1.037,0.481l0.683,0.188l1.386-0.125l0.539,0.026l0.763,0.467l0.742,0.952l1.087,2.384l0.94,1.588l0.927,1.903l0.436,0.389l0.507,0.2l1.247,0.341l1.523,0.253l2.659,0.839l0.205,0.144l0.297,0.866l0.44,1.283l0.261,0.446l0.68-0.033l0.649-0.018l1.657-0.052l0.604-0.22l0.953-0.308l1.357-0.31l1.181-0.208l0.902-0.034l0.246,0.114l0.064,0.259l0.116,0.389l0.017,0.504l-0.566,0.407l-0.66,0.393l-0.291,0.707l-0.278,0.893l-0.538,1.066l-0.627,1.08l-0.329,0.432l-0.551,0.69l-0.47,0.347l-0.547-0.098l-0.679-0.225l-0.685-0.24l-0.396-0.041l-1.664,0.982l-0.048,0.557l0.332,0.897l0.062,0.656l-0.006,0.613l-0.025,0.385l-0.097,0.128l0.112,0.299l-0.156,0.329l-0.511,0.43l-1.252,0.462l-0.111,0.058l-0.579-0.68l-0.247,0.001l-0.253,0.129l-0.383,0.358l-0.23,0.713l-0.955,0.532l-0.62,0.259l-0.538,0.017l-0.452-0.054l-0.333-0.126l-0.392,0.059l-0.273,0.243l-0.025,0.342l0.508,0.765l0.046,0.113l-0.527,0.159l-0.975,0.048l-0.508-0.153l-0.493-0.253l-0.273-0.396l-0.448,0.017l-0.386,0.13l-0.686,1.027l-0.636,0.543l-1.032,0.545l-1.533,0.604l-0.52,0.329l-0.415,0.442l-0.379,0.528l-0.066-0.092l-0.417,0.171l-1.222,0.13l-0.728,0.171l-2.248,0.925l-0.632,0.37l-0.566,0.469l-0.604,0.271l-0.336,0.015l0.13-0.255l0.862-0.682l0.33-0.354l-0.47-0.113l-0.37,0.072l-0.153-0.297l0.058-0.156l0.953-0.781l0.269-0.384l0.55-0.413l0.159-0.2l-0.057-0.298l-0.73-0.553l-0.727-0.283l-0.131-0.014l-0.628,0.03l-0.166,0.015l-0.494,0.371l-1.146,1.183l-0.355,0.157l-0.643,0.086l-0.613,0.243l-0.36,0.199L665.49,112l-0.136,0.411l-0.131,0.255l-0.251,0.255l-0.437,0.128l-0.493-0.013l-0.326,0.27l-0.307,0.114l-0.455-0.565l-0.355-0.014l-0.349,0.128l-0.396,0.638l-0.301,0.694l0.088,0.34l0.245,0.368l0.558,0.268l0.8,0.268l1.21-0.045l0.29,0.254l-0.019,0.538l-0.123,0.581l0.057,0.538l0.261,0.283l0.733,0.069l0.698-0.157l0.76-0.525l0.509-0.497l0.552-0.228l0.534-0.128l0.287,0.07l0.895,0.621l0.543,0.197l1.023-0.087l0.361,0.027l0.471,0.141l0.274,0l-0.248,0.708l-0.057,0.552l-0.612-0.197l-0.297-0.084l-0.525,0.058l-1.677,0.555l-0.707,0.44l-0.072,0.735l-0.522,0.157l-0.146-0.113l-0.017-0.269l-0.127-0.084l-0.501,0.114l0.138,0.466l-0.152,0.368l-0.485,0.496l-1.397,1.119l-0.126,0.226l0.039,0.55l0.62,0.225l0.712,0.492l0.785,0.521l0.391,0.535l0.424,1.241l0.668,0.647l0.175,0.437l-0.13,0.677l0.172,0.183l0.694,0.295l0.399,0.592l0.562,0.253l0.272,0.268l0.087,0.31l-0.049,0.155l-0.789,0.369l0.088,0.07l0.425,0.31l0.314,0.79l-0.019,0.296l-0.141,0.184l-0.534,0.043l-0.651,0.213l-0.948,0.552l-0.849,0.213l-0.629,0.297l0.72,0.21l0.378,0.056l0.944-0.425l0.488-0.058l0.162,0.056l0.524,0.592l0.387,0.168l0.456,0.027l0.009,0.155l-0.231,0.311l-0.382,0.227l-0.304,0.241l0.11,0.155l0.326-0.029l0.202,0.084l-0.184,0.325l-0.298,0.749l-0.192,0.649l0.028,0.353l-0.22,0.452l-0.209,0.127l-0.35-0.338l-0.146,0.142l-0.569,0.763l-0.401,0.622l-0.215,0.622l-0.127,0.296l-0.595,0.425l-0.251,0.438l-0.254,0.184l-0.569,0.029l-0.382,0.227l0.279,0.719l-0.264,0.508l0.076,0.593l-0.093,0.269l-0.207,0.269l-0.532,0.199l-0.161,0.282l-0.174,0.396l-0.294,0.636l-0.626,0.354l-0.412,0.495l-0.492-0.14l-0.443-0.069l-0.142,0.113l-0.145,0.198l0.118,0.833l-0.213,0.142l-0.772,0.651l-0.356,0.127l-0.628,0.171l-0.563,0.467l-0.571,0.213l-0.107,0.113l-0.008,0.48l-0.133,0.156l-0.568,0.058l-0.5,0.114l-0.341,0.438l-0.364-0.126l-0.52-0.168l-0.274,0.057l-0.315,0.326l-0.435,0.198l-0.643,0.1l-0.047-0.465l-0.52,0.057l-0.699,0.213l-0.32,0.198l-0.285-0.042l-0.401-0.493l-0.163-0.155l-0.191,0.283l0.095,0.169l-0.045,0.212l-0.047,0.691l-0.209,0.297l-0.416,0.114l-0.501-0.182l-0.123,0.282l-0.001,0.24l-0.146,0.155l-0.615,0.058l-0.366,0.114l-0.596,0.043l-0.463-0.211l-0.217,0.1l-0.439,0.48l-0.227,0.071l-0.774-0.041l-0.747,0.227l-0.406,0.326l-0.451-0.027l-0.277-0.084l-0.011,0.057l-0.069,0.353l-0.29,0.396l0.011,0.113l0.48,0.634l0.269,0.126l0.043,0.198l-0.36,0.269l-0.763,0.157l-0.481-0.719l-0.241-0.691l0.012-0.395l0.396-0.777l-0.015-0.169l-0.587-0.253l-0.226,0.071l-0.206,0.297l-0.454,0.072l-0.676-0.21l-0.574-0.733l-0.196,0.085l-0.017,0.169l-0.159,0.396l-0.27,0.128l-0.332-0.056l-0.481,0.043l-0.055,0.038l-0.197-0.143l-0.909-0.107l-0.621-0.166l-0.943-0.615l-0.273-0.365l-0.096-0.521l0.472-0.75l-0.056-0.38l-0.237-0.21l-0.777,0.047l-0.66-0.053l-0.771-0.235l-0.623-0.575l-0.298,0.101l-0.521,0.328l-0.696,0.554l-0.341,0.157l-0.807,0.117l-1.595,0.052l-0.332,0.115l-0.584,0.413l-0.325-0.097l-0.597-0.392l-0.341-0.012l-0.515,0.13l-0.483,0.229z"/> - <path id="HT" country:name="Haiti" d="M241.073,156.152l0.017,0.52l0.098,1.215l0.012,0.212l-0.379,0.455l-0.011,0.17l0.485,1.358l-0.669-0.577l-0.445-0.056l-0.761,0.143l-0.877-0.012l-0.666-0.14l-0.574-0.056l-0.474,0.1l-0.378,0.354l-0.135-0.042l-0.993-0.549l-0.171-0.325l0.04-0.198l0.269-0.184l1.051,0.097l0.631,0.111l1.125,0.167l0.654,0.041l0.61-0.185l0.386-0.156l-0.198-0.155l-0.692-0.464l-0.136-0.296l0.184-0.707l-0.202-0.296l-0.394-0.154l-0.913-0.14l-0.305-0.211l0.04-0.184l0.119-0.085l0.344-0.1l0.724-0.058l0.781,0.125l1.081,0.294l0.576,0.056l0.147-0.089z"/> - <path id="DO" country:name="Dominican Republic" country:shortname="Dominican Rp" d="M241.295,160.082l-0.485-1.358l0.011-0.17l0.379-0.455l-0.012-0.212l-0.098-1.215l-0.017-0.52l0.503-0.279l0.393,0.14l0.342,0l0.384-0.17l0.369-0.043l0.14,0.198l0.177,0.112l1,0.309l0.657-0.072l0.213,0.395l0.335,0.338l0.528,0.324l0.335,0.084l0.643,0.21l0.916,0.45l0.399,0.352l0.231,0.311l-0.191,0.17l-0.144,0.297l-0.314,0.368l-0.238-0.098l-0.476-0.592l-0.378-0.042l-0.788,0.058l-0.288-0.098l-0.373,0l-0.329,0.1l-0.763,0.539l-0.396-0.056l-0.319-0.494l-0.166-0.028l-0.155,0.057l-0.658,0.326l-0.344,0.778l-0.41,0.65l-0.289-0.112l-0.325-0.551z"/> - <path id="PH" country:name="Philippines" d="M668.053,167.796l-0.131-0.099l-0.74-0.732l-0.444-1.255l0.037-0.424l0.054-0.706l-0.292-0.465l0.18-0.382l0.978,0.704l0.202-0.424l0.023-0.41l-0.101-0.438l-0.026-0.579l0.145-0.438l0.025-0.664l0.082-0.861l0.074-0.636l0.38-0.862l0.188-0.127l0.337-0.142l0.523,0.055l1.21,0.52l0.576,0.042l0.188-0.212l0.277-0.17l0.199,0.141l0.018,0.396l-0.266,0.438l-0.045,0.48l0.14,0.79l0.541,0.394l0.182,0.325l-0.427,1.271l-0.31,0.467l-0.834,0.608l-0.555,0.312l-0.082,0.099l0.003,0.268l-0.078,0.565l-0.28,0.424l0.127,0.211l0.35,0.733l0.345,1.101l0.26,0.62l0.093,0.028l0.451,0.324l0.296,0.07l0.161-0.325l0.485-0.537l0.197-0.029l0.418,0.112l0.226,0.211l0.179,0.635l0.286,0.353l0.326,0.084l0.505-0.58l0.621,0.267l0.141,0.028l0.078,0.127l-0.168,0.156l-0.378,0.156l-0.208,0.212l0.936,1.226l-0.315,0.184l-0.568-0.196l-0.404-0.098l-0.094-0.48l-0.229-0.31l-0.599-0.535l-0.753-0.577l-0.258,0l-0.099,0.226l0.371,0.776l-0.218,0.283l-0.727-0.775l-0.982-0.548l-0.309,0.015l-0.344,0.142l-0.182,0.255l-0.14,0.071l-0.395,0.057l-0.322-0.225l-0.591-0.366l-0.195-0.423l0.64-0.608l0.323,0.211l0.358,0.084l0.4-0.199l-0.151-0.169l-0.713-0.295l-0.422-0.395l-0.522-0.168l-0.239,0.607z M669.676,172.974l-0.452-0.366l-0.349-0.408l-0.051-0.226l-0.364-1.114l-0.459-0.521l0.685-0.058l0.868,0.012l0.314,0.169l0.274,0.451l0.028,0.861l-0.097,0.48l-0.214,0.283l-0.185,0.438z M679.073,175.368l-0.562-0.267l-0.178-0.254l-0.237-0.169l-0.064-0.127l0.139-0.339l-0.091-0.423l-0.55-0.352l-0.662-0.479l-0.147-0.466l0.513-0.1l1.017-0.143l0.371,0.112l0.283,0.409l0.069,0.818l0.123,0.805l0.257,0.79l-0.112,0.127l-0.167,0.057z M671.406,176.824l0.022-0.353l0.186-1.342l0.061-1.172l0.482,0.395l0.576,0.281l0.366,0.028l0.634-0.185l0.027,0.438l-0.079,0.396l-0.24,0.269l-0.184,0.198l-0.908,0.651l-0.943,0.397z M664.721,177.812l-0.366-0.027l0.127-0.297l0.202-0.099l0.314-0.396l0.265-0.523l0.082-0.607l0.138-0.509l0.326-0.184l0.14,0.183l-0.16,0.283l0.276,0.55l0.212,0.564l-0.108,0.113l-0.664,0.354l-0.406,0.368l-0.377,0.227z M673.781,179.981l-0.385-0.366l-0.828-0.591l-0.206-0.38l0.099-0.368l0.565-0.213l0.22-0.269l0.487-1.822l0.438-0.185l0.271,0.028l0.113,0.126l0.049,0.282l-0.373,0.905l-0.089,0.226l-0.315,1.413l0.165,0.296l0.214,0.465l-0.213,0.41l-0.212,0.043zM661.179,181.308l-0.317-0.042l0.215-0.48l0.343-0.467l0.35-0.34l0.592-0.354l0.636-0.496l0.933-1.089l0.11,0.55l-0.118,0.424l-0.267,0.297l-0.24,0.184l-0.516,0.213l-0.172,0.127l-0.244,0.622l-0.327,0.269l-0.591,0.171l-0.386,0.41z M680.678,185.402l-0.201-0.098l-0.098-0.438l-0.361-0.748l-0.297-0.112l-0.381,0.608l-0.361,0.82l0.246,0.38l0.166,0.395l0.148,0.677l-0.158,0.495l-0.383,0.509l-0.305-0.253l-0.176-0.268l0.201-0.41l-0.076-0.325l-0.363-0.07l-0.361,0.665l-0.173-0.056l-1.114-0.619l-0.557-0.549l-0.206-0.508l-0.037-0.635l0.466-0.905l-0.108-0.479l-0.466-0.409l-0.778-0.295l-0.292,0.043l-0.062,0.17l-0.129,0.226l-0.5,0.255l-0.661,0.058l-0.027-0.494l-0.174-0.24l-0.399,0.199l-0.504,0.961l-0.525,0.863l-0.219-0.084l-0.119-0.127l-0.034-0.197l0.054-0.311l0.359-0.749l0.185-0.537l0.263-0.283l0.383-0.184l0.564-0.044l0.219-0.127l0.134-0.466l0.205-0.156l0.549-0.241l0.777-0.101l0.292,0.353l0.102,0.72l0.317-0.156l0.485-0.058l0.207-0.184l0.207-0.565l0.358-0.255l0.479,0.21l0.186,0.084l0.158-1.087l0.29-0.015l0.264,0.465l0.315-0.481l0.205-0.142l0.392,0.098l0.133-0.227l-0.048-0.706l-0.172-0.564l0.146-0.353l0.413,0.549l0.711,0.803l0.229,0.48l0.083,0.324l-0.336,0.735l0.237,0.226l0.537-0.1l0.076,0.423l-0.114,0.424l0.056,0.692l0.207,0.437l-0.002,0.438l-0.111,0.424l-0.283,0.579l-0.332,0.622z"/> - <path id="PR" country:name="Puerto Rico" d="M251.898,160.229l-0.547-0.112l-0.073-0.212l0.051-0.551l-0.109-0.24l0.11-0.17l0.235-0.071l0.543,0.069l0.404-0.015l1.505,0.11l0.393,0.168l0.113,0.141l-0.188,0.354l-0.07,0.099l-0.283,0.227l-0.335,0.043l-0.739-0.083l-0.657,0.072l-0.354,0.17z"/> - <path id="JM" country:name="Jamaica" d="M228.82,160.519l-0.299-0.056l-0.693-0.224l-0.229-0.268l-0.47-0.366l-0.465-0.084l-0.142-0.211l0.53-0.284l0.704-0.072l1.364,0.251l0.97,0.351l0.651,0.267l0.279,0.282l-0.04,0.198l-0.332,0.071l-0.751-0.295l-0.543,0.058l-0.227,0.255l-0.308,0.128z"/> - <path id="BF" country:name="Burkina Faso" d="M400.72,175.499l-0.595-0.119l-0.161-0.032l-0.976,0.458l-1.429-0.006l-0.867-0.037l-2.119,0.041l-0.271,0.157l-0.125,0.34l0.261,1.934l0.02,0.41l-0.191,0.17l-0.63-0.434l-0.644-0.166l-0.769,0.075l-0.608,0.159l-0.446,0.257l-0.368,0.115l-0.354-0.083l-0.452-0.223l-0.52-0.562l-0.15-0.465l-0.308-0.252l-0.545,0.003l-0.259-0.168l0.08-0.043l0.046-0.156l0.172-0.326l0.261-0.92l0.133-0.876l-0.058-0.749l0.141-0.255l0.257-0.016l0.448-0.158l0.543-0.271l0.317-0.369l0.292-1.047l0.355-1.217l0.397-0.384l0.273-0.058l0.293,0.281l0.551,0.364l0.45-0.102l0.174-0.227l0.393-0.822l0.492-0.667l0.638-0.625l0.272-0.101l0.518,0.209l0.324,0.182l0.274,0.027l0.314-0.793l0.304-0.228l0.947-0.458l1.22-0.713l0.37-0.073l0.356,0.125l0.36,0.059l1.062,0.173l-0.173,0.665l0.019,0.396l0.426,0.93l0.422,0.492l0.389,0.266l0.502,0.42l0.179,0.268l0.018,0.212l-0.335,0.439l0.114,0.226l0.97,0.757l0.516,0.181l0.37-0.044l0.562,0.025l0.568,0.971l0.131,0.367l-0.237,0.764l-0.415,0.468l-0.337,0.158l-0.739-0.095l-0.418,0.045l-0.415,0.271l-0.366,0.553l-0.24,0.157l-0.062,0.142l-0.29-0.041l-0.611-0.166l-1.013-0.163z"/> - <path id="NI" country:name="Nicaragua" d="M209.823,175.47l-0.388-0.645l-0.932-0.888l-1.003-1.085l-0.837-0.817l-0.723-0.464l-0.196-0.183l-0.023-0.226l0.625-0.03l1.001-0.125l0.29-0.143l0.293-0.412l0.005-0.961l0.882-0.034l0.513-0.583l0.725,0.42l1.207-0.997l0.503-0.794l0.294-0.242l0.259,0.013l0.328,0.182l0.463,0.097l0.248-0.086l0.424-0.229l1.425-0.486l0.23,0.519l0.038,0.339l-0.057,0.509l-0.214,0.707l-0.543,0.806l-0.1,0.749l0.042,0.904l-0.245,1.13l-0.188,0.735l-0.101,1.385l0.031,0.55l0.184,0.466l0.188,0.363l-0.281,0.274l-0.767-0.149l-0.241-0.46l-0.285,0.077l-0.394-0.107l-0.603,0.25l-1.651-0.599l-0.43,0.271z"/> - <path id="KH" country:name="Cambodia" d="M634.036,168.444l0.533,0.251l0.736,0.165l0.341,0.111l0.469,0.251l0.248-0.058l0.095-0.24l-0.103-0.211l-0.187-0.182l-0.107-0.296l0.392-0.285l0.476-0.186l0.444,0.181l0.373,0.351l0.3-0.072l0.975-0.429l0.209-0.114l-0.215,0.905l0.029,0.663l0.455,1.014l-0.076,0.367l-0.05,0.424l0.054,1.073l-0.217,0.509l-0.385,0.285l-0.599,0.187l-0.932,0.443l-0.521,0.229l-0.99,0.571l-0.234,0.425l0.216,0.422l0.568,0.435l0.03,0.197l-0.17,0.27l-0.688-0.194l-0.497-0.011l-0.599,0.229l-0.915,0.528l-0.646,0.229l-0.3,0.289l-0.256-0.188l-0.248-0.268l-0.35-0.042l-0.382,0.142l-0.205-0.042l-0.293,0.043l-0.183-0.113l0.142-0.311l0.182-0.226l-0.04-0.254l-0.283-0.395l-0.277,0.043l-0.462,0.298l-0.339,0.015l-0.171-1.044l-0.649-1.488l0.146-0.176l-0.16-0.479l-0.487-0.717l-0.219-0.648l-0.026-0.635l0.076-0.382l0.146-0.297l0.92-1.233l0.521-0.441l0.383-0.101l1.172-0.091l0.798,0.066l0.558-0.074l0.575,0.039l0.599,0.109l0.301,0.167z"/> - <path id="CR" country:name="Costa Rica" d="M214.474,175.913l0.821,0.884l0.385,0.623l0.314,0.322l0.225,0.046l0.465,0.645l0.441,0.352l-0.014,0.006l-0.074,0.123l-0.478-0.184l-0.219,0.205l-0.014,0.321l0,0.58l0.507,0.307l-0.396,0.368l0.125,0.532l-0.374,0.369l0.243,0.184l-0.204,0.609l0.003-0.466l-0.296-0.307l0.01-0.568l-0.377-0.148l-0.238-0.102l-0.111,0.082l0.325,0.41l0.084,0.225l-0.113,0.062l-0.726-0.299l-0.13-0.282l0.251-0.339l0.04-0.382l-0.182-0.338l-0.486-0.324l-0.695-0.287l-0.079-0.144l-0.689-0.103l-0.316-0.327l0.007-0.421l-0.146-0.255l-0.249-0.098l-0.576-0.353l-0.416-0.266l0.225,0.512l0.086,0.222l0.422,0.044l0.181,0.266l-0.544,0.573l-0.144-0.262l-0.356-0.282l-0.561-0.211l-0.323-0.239l-0.147-0.24l-0.104-0.494l0.128-0.421l0.332-0.225l-0.008-0.389l-0.554-0.225l0.363-0.123l-0.057-0.227l-0.238,0.017l0.43-0.271l1.651,0.599l0.603-0.25l0.394,0.107l0.285-0.077l0.241,0.46l0.767,0.149l0.281-0.274z"/> - <path id="CF" country:name="Central African Republic" country:shortname="Cent Af Rep" d="M436.304,195.359l-0.209-0.451l-0.194-0.804l-0.498-0.802l-1.217-1.236l-0.112-0.324l-0.064-0.791l-0.432-0.605l-0.4-0.661l-0.207-0.592l-0.273-1.185l-0.112-0.776l0.064-0.424l0.144-0.198l0.528-0.399l0.4-0.511l0.866-1.743l0.354-0.327l0.208-0.114l0.096,0.084l0.24,0.027l0.449-0.158l1.363-0.686l0.494,0.661l0.225,0.069l0.224-0.03l0.466-0.271l0.754-0.386l0.818-0.273l0.881,0.009l0.368-0.031l0.258-0.143l0.646-1.176l0.117-0.806l0.209-0.199l0.434-0.059l2.181-0.055l0.386-0.087l2.649-2.275l0.196-0.284l0.005-0.41l0.165-0.382l0.372-0.228l0.939-0.613l0.322-0.086l0.321,0.012l0.559,0.208l1.342,1.673l0.347,0.549l0.122,0.536l-0.416,1.472l0.01,0.664l0.158,0.211l0.802-0.019l0.272-0.001l0.207,0.126l0.252,0.493l0.223,0.225l0.797,0.447l0.799,0.235l0.351,0.196l0.223,0.267l-0.148,0.481l0.173,0.395l0.445,0.351l0.558,0.378l0.717,0.434l0.207,0.168l0.206,0.366l0.059,0.72l0.285,0.436l0.367,0.224l0.814,0.165l0.558,0.477l0.157,0.352l-0.083,0.679l0.031,0.07l-0.496,0.145l-0.962,0.344l-0.319-0.026l-0.287-0.167l-0.687-0.264l-1.15-0.361l-0.4,0.13l-0.082,0.551l-0.13,0.241l-0.256,0.058l-0.399-0.026l-0.862-0.207l-0.593,0.102l-0.93,0.373l-0.93,0.486l-0.271,0.016l-0.559-0.35l-0.383-0.153l-0.353,0.186l-0.677,1.36l-0.176,0.157l-0.591-0.067l-1.934-0.511l-1.422-0.189l-0.512-0.322l-0.159-0.239l-0.334-0.394l-0.75-0.518l-0.432-0.167l-0.479,0.06l-0.529,0.3l-0.353,0.341l-0.785,0.979l-0.097,0.297l0.096,0.452l-0.017,0.353l-0.063,0.594l-0.16,0.058l-0.751,0.287l-0.895-0.093l-0.624-0.138l-0.367-0.054l-0.975,0.175l-0.479,0.102l-0.255,0.228l-0.222,1.287l-0.158,0.523l-0.365,0.497l-0.303,0.312z"/> - <path id="SL" country:name="Sierra Leone" d="M371.324,180.419l1.088-1.235l0.643-0.866l0.238-0.157l0.594,0.039l1.137-0.148l0.466,0.04l0.42,0.224l0.456,0.421l0.475,0.619l0.252,0.761l0.165,1.369l0.26,0.656l-0.259,0.502l-1.184,1.151l-0.63,0.724l-0.285,0.256l-0.061,0.103l-0.631-0.523l-0.661-0.408l-0.483-0.196l-0.033-0.141l0.061-0.297l-0.05-0.184l-0.531-0.21l-0.792-0.549l-0.389-0.366l-0.375-0.465l0.494-0.241l0.174-0.227l-0.034-0.155l-0.484-0.211l-0.065-0.113l0.022-0.173z"/> - <path id="LK" country:name="Sri Lanka" d="M579.606,186.906l-0.493-0.083l-0.265-0.197l-0.21-0.353l-0.246-0.621l-0.361-1.256l-0.034-0.649l0.005-0.763l-0.02-0.904l-0.24-0.696l0.188-0.513l-0.298-0.35l0.068-0.28l0.423,0.023l0.349-0.43l0.053-0.367l0.226-0.369l-0.152-0.537l0.529,0.48l0.699,0.38l0.234,0.395l0.549,0.776l0.175,0.324l-0.099,0.339l0.024,0.141l0.592,0.338l0.266,0.733l0.798,1.368l0.136,0.508l-0.193,0.735l-0.397,0.679l-0.369,0.396l-0.514,0.425l-0.78,0.284l-0.642,0.043z"/> - <path id="PM" country:name="Panama" d="M217.111,178.792l0.52,0.307l0.195,0.512l0.02,0.374l0.363,0.155l0.628,0.024l0.244-0.205l0.398,0.43l0.726,0.082l0.458-0.083l1.348-0.751l0.514-0.046l1.387-0.921l0.373,0.144l0.742,0.069l0.071,0.156l0.789-0.017l0.767,0.21l0.666,0.38l0.644,0.563l0.406,0.666l0.084,0.327l0.228,0.149l0.509,1.038l-0.322,0.062l-0.094,0.43l-0.584,0.409l-0.085-0.307l-0.19-0.082l0.045,0.45l-0.228,0.082l-0.256,0.753l-0.378-0.825l-0.441-0.762l-0.137-0.452l0.179-0.24l0.22-0.085l0.786,0.125l-0.336-0.193l-0.125-0.164l-0.096-0.471l-0.309,0.307l-0.439,0.041l-0.244-0.378l-0.031-0.269l-0.193-0.282l-0.132,0.151l-0.226-0.287l-0.11,0.102l-0.132-0.266l-0.456-0.192l-0.562-0.013l-0.499,0.241l-0.382,0.108l-0.07,0.359l0.081,0.234l-0.529,0.318l-0.374,0.184l-0.335,0.029l-0.345,0.41l0.049,0.296l0.316,0.297l0.464,0.43l0.178,0.386l-0.011,0.146l-0.281,0.081l-0.243-0.042l-0.431,0.391l-0.568,0.105l-0.339-0.042l-0.189-0.146l0.108-0.164l-0.349-0.833l-0.244-0.353l-0.177,0.674l-0.812-0.409l-0.227-0.757l-0.207,0.041l-0.96-0.123l-0.434-0.266l-0.599,0l-0.314,0.113l-0.361,0.495l0.204-0.609l-0.243-0.184l0.374-0.369l-0.125-0.532l0.396-0.368l-0.507-0.307l0-0.58l0.014-0.321l0.219-0.205l0.478,0.184l0.074-0.123z"/> - <path id="GY" country:name="Guyana" d="M266.015,188.956l-0.503-0.647l-0.732-0.745l-0.324-0.521l0.071-0.212l0.395-0.539l-0.008-0.58l0.061-0.452l1.032-0.19l0.41-0.144l0.308-0.299l-0.141-0.282l-0.62-0.604l-0.074-0.212l0.101-0.255l1.655-1.239l0.061-0.41l-0.095-0.296l0.072,0.049l0.496,0.338l0.856,0.521l0.695,0.521l0.587,0.663l0.128,0.409l-0.036,0.734l0.148,0.945l0.298-0.593l0.22-0.099l0.6,0.182l0.101,0.127l0.507,0.295l0.708,0.549l0.401,0.493l0.374,0.649l-0.015,0.339l-0.142,0.496l-0.082,0.862l-0.183,0.27l-1.131,0.091l-0.169,0.17l0.078,0.777l-0.095,0.467l-0.328,0.694l0.571,0.831l0.532,0.675l0.561,0.067l0.185,0.295l0.246,0.832l0.49,1.127l0.332,0.563l-0.06,0.212l-0.943-0.022l-0.934,0.429l-1,0.331l-0.505,0.314l-0.694,0.513l-0.686,0.075l-0.613-0.392l-1.103-0.897l-0.15-0.296l-0.008-0.396l0.072-0.354l-0.167-0.31l-0.281-0.394l-0.156-0.465l0.213-0.962l0.547-1.416l0.179-0.368l-0.435-0.958l-0.533-0.138l-0.304,0.001l0.452-1.09l-0.04-0.212l-0.26-0.111l-0.516-0.124l-0.302,0.058l-0.375,0.257z"/> - <path id="LR" country:name="Liberia" d="M377.518,182.142l0.193-0.376l0.252-0.242l0.367-0.143l0.528-0.046l0.338,0.097l0.165,0.366l0.22,0.846l0.009,0.65l-0.044,0.283l0.277,0.323l0.404,0.322l0.321,0.026l0.756-0.922l0.143-0.086l0.337,0.097l0.339,0.224l-0.062,0.17l0.119,0.55l-0.059,0.438l-0.501,0.865l0.05,0.183l0.194,0.183l0.369,0.097l0.592-0.032l1.264,1.334l0.131,0.282l-0.059,0.452l-0.247,0.849l-0.105,0.565l-0.041,0.919l-1.513-0.643l-1.221-0.619l-1.012-0.562l-0.403-0.423l-1.129-1.113l-1.111-0.76l-0.723-0.337l-0.901-0.535l-0.66-0.548l0.061-0.103l0.285-0.256l0.63-0.724l1.184-1.151l0.259-0.502z"/> - <path id="CD" country:name="Democratic Republic of the Congo (formerly Zaire)" d="M429.505,210.684l0.484,0.336l0.177,0.013l0.443-0.271l0.327-0.581l1.495-0.532l0.054,0.424l0.042,0.664l0.147,0.211l0.57-0.328l0.554-0.399l0.931-0.811l0.364-0.229l1.025-0.938l0.086-0.706l-0.122-0.72l0.074-0.396l0.193-1.159l0.343-0.751l0.47-0.836l0.41-0.454l0.809-0.599l0.525-0.229l0.459-0.427l0.139-0.523l0.169-0.708l0.115-0.61l0.254-1.342l0.196-2.021l0.156-0.764l0.094-0.551l0.349-0.821l0.558-0.837l0.398-1.203l0.031-0.156l-0.128-0.197l0.16-0.058l0.063-0.594l0.017-0.353l-0.096-0.452l0.097-0.297l0.785-0.979l0.353-0.341l0.529-0.3l0.479-0.06l0.432,0.167l0.75,0.518l0.334,0.394l0.159,0.239l0.512,0.322l1.422,0.189l1.934,0.511l0.591,0.067l0.176-0.157l0.677-1.36l0.353-0.186l0.383,0.153l0.559,0.35l0.271-0.016l0.93-0.486l0.93-0.373l0.593-0.102l0.862,0.207l0.399,0.026l0.256-0.058l0.13-0.241l0.082-0.551l0.4-0.13l1.15,0.361l0.687,0.264l0.287,0.167l0.319,0.026l0.962-0.344l0.496-0.145l0.143,0.239l0.795,0.772l0.348,0.493l0.525,0.477l0.366,0.195l0.352-0.016l0.258-0.242l0.529-0.37l0.384,0.012l0.684,0.631l0.16-0.1l0.436-0.582l0.258-0.157l0.207,0.083l1.032,0.926l1.288,1.32l0.063,0.028l0.159,0.183l-0.018,0.424l-0.26,1.88l0.128,0.253l0.191,0.027l0.479,0.04l0.271,0.182l0.111,0.31l-0.191,0.453l-1.195,1.066l-1.241,0.996l-0.255,0.284l-0.395,0.681l-0.217,1.02l-0.107,0.507l0.021,0.593l-0.025,0.734l0.057,0.748l-0.076,0.27l-0.188,0.298l-0.426,0.412l-0.301,0.171l-0.269,0.256l-0.122,0.425l-0.49,1.358l0.197,0.338l0.689,0.999l0.087,0.381l-0.04,0.438l0.014,0.636l0.237,0.634l0.017,1.329l-0.064,0.762l0.425,1.439l-0.102,0.848l0.122,0.693l0.486,0.631l0.936,0.898l0.428,0.78l0.689,1.804l-0.563,0.068l-3.015,0.499l-0.347,0.214l-0.154,0.198l-0.797,1.276l-0.029,0.622l0.372,2.088l-0.377,1.175l-0.3,1.02l0.043,0.296l0.456,0.605l0.837,0.843l0.445,0.279l0.515,0.012l0.448-0.455l0.362-0.186l0.136,0.183l0.032,0.791l0.028,1.427l-0.041,0.551l-0.371-0.012l-1.355-0.091l-0.348-0.21l-0.381-0.647l-0.561-0.731l-0.416-0.351l-0.477-0.252l-0.895-0.263l-0.38-0.28l-0.728-1.423l-0.212,0.354l-0.522,0.682l-0.366,0.087l-0.325-0.111l-0.922-0.164l-0.925-0.249l-0.489-0.194l-0.58-1.014l-0.175,0.071l-1.146,0.289l-0.195-0.056l-0.172-0.352l-0.365-0.379l-0.678-0.096l-1.24-0.147l-0.991,0.146l-0.859,0.26l-0.61,0.004l-0.199-0.197l-0.007-0.254l0.198-0.905l0.003-0.466l-0.306-0.62l-0.844-0.998l-0.117-0.211l-0.021-0.212l0.296-1.033l0.07-1.06l-0.109-0.607l-0.303-0.605l0.057-0.354l0.177-0.693l-0.052-0.183l-0.322-0.098l-1.231,0.093l-0.88,0.019l-0.212-0.168l0.055-0.48l-0.181-0.225l-2.016,0.082l-0.112,0.001l-0.089,0.354l0.027,0.593l-0.286,0.892l-0.184,0.411l-0.993,0.006l-0.899-0.122l-1.021,0.246l-0.88,0.034l-0.292-0.168l-0.64-0.787l-0.597-1.07l-0.537-1.409l-0.059-0.579l-0.121-0.521l-0.082-0.127l-0.321-0.111l-0.385-0.012l-1.104-0.008l-0.88,0.034l-0.624,0.003l-1.312-0.048l-0.945-0.052l-0.783,0.02l-0.432,0.03l-0.318,0.101l-0.896,0.062l-0.699,0.314l-0.56,0.06l-0.112-0.013l-0.322-0.922l0.012-0.053l0.74-0.3l-0.017-0.085l0.1-0.89l0.094-0.143l0.317-0.199l0.583-0.568z"/> - <path id="TZ" country:name="Tanzania, United Republic of" country:shortname="Tanzania" d="M468.568,202.653l1.277-0.05h4.659l1.448-0.033l4.663,2.568l3.553,1.984l0.137,0.381l-0.116,0.552l0.07,0.239l2.427,1.752l1.067,0.807l-0.237,0.427l-0.419,1.329l-0.137,1.017l0.109,0.551l0.665,0.987l0.768,0.577l-0.024,0.282l-0.263,0.354l-0.371,1.046l0.037,0.17l0.306,0.041l0.118,0.226l-0.172,0.692l-0.019,0.946l0.411,1.793l0.18,0.564l0.401,0.465l0.823,0.55l0.396,0.268l0.177,0.228l-1.157,0.836l-0.515,0.342l-1.218,0.402l-1.243,0.559l-0.448,0.031l-0.646-0.42l-0.276-0.083l-0.21,0.326l-0.543,0.766l-0.396,0.144l-0.42-0.054l-0.964,0.006l-0.963,0.02l-0.512-0.294l-0.323-0.394l-0.229-0.083l-0.123,0.128l-0.643,0.356l-0.526,0.088l-1.019-0.149l-0.898-0.018l-0.196-0.559l-0.135-0.766l-0.053-0.584l-0.135-0.946l-0.448-0.841l-0.663-0.538l-1.014-0.107l-0.223,0.016l-0.385-0.407l-0.732-0.349l-1.574-0.57l-1.269-0.6l-0.729-0.265l-0.263-0.21l-0.703-0.641l-0.689-1.804l-0.428-0.78l-0.936-0.898l-0.486-0.631l-0.122-0.693l0.102-0.848l-0.425-1.439l0.064-0.762l1.252-0.348l0.388-0.539l0.645-1.204l0.687-0.853l0.346-0.271l0.044-0.212l-0.148-0.239l-0.273-0.125l-0.401-0.068l-0.211-0.211l0.158-0.976l0.304-0.016l0.396-0.158l0.142-0.17l0.104-0.481l-0.167-0.493l-0.364-0.888l-0.121-0.748z"/> - <path id="RW" country:name="Rwanda" d="M464.786,206.235l-0.197-0.338l0.49-1.358l0.122-0.425l0.269-0.256l0.301-0.171l0.426-0.412l0.064,0.042l0.546,0.223l0.431-0.045l0.458-0.427l0.554-0.398l0.319-0.017l0.121,0.748l0.364,0.888l0.167,0.493l-0.104,0.481l-0.142,0.17l-0.396,0.158l-0.304,0.016l-0.559,0.031l-0.508,0.159l-0.391,0.567l-0.158,0.085l-0.396,0.13l-0.789-0.32l-0.688-0.024z"/> - <path id="BI" country:name="Burundi" d="M465.79,210.652l-0.017-1.329l-0.237-0.634l-0.014-0.636l0.04-0.438l-0.087-0.381l-0.689-0.999l0.688,0.024l0.789,0.32l0.396-0.13l0.158-0.085l0.391-0.567l0.508-0.159l0.559-0.031l-0.158,0.976l0.211,0.211l0.401,0.068l0.273,0.125l0.148,0.239l-0.044,0.212l-0.346,0.271l-0.687,0.853l-0.645,1.204l-0.388,0.539l-1.252,0.348z"/> - <path id="AO" country:name="Angola" d="M427.243,211.207l0.536-0.414l0.68-0.513l0.351-0.13l0.695,0.533l-0.583,0.568l-0.317,0.199l-0.094,0.143l-0.1,0.89l0.017,0.085l-0.74,0.3l0.143-0.625l-0.082-0.24l-0.505-0.796z M427.998,213.843l0.112,0.013l0.56-0.06l0.699-0.314l0.896-0.062l0.318-0.101l0.432-0.03l0.783-0.02l0.945,0.052l1.312,0.048l0.624-0.003l0.88-0.034l1.104,0.008l0.385,0.012l0.321,0.111l0.082,0.127l0.121,0.521l0.059,0.579l0.537,1.409l0.597,1.07l0.64,0.787l0.292,0.168l0.88-0.034l1.021-0.246l0.899,0.122l0.993-0.006l0.184-0.411l0.286-0.892l-0.027-0.593l0.089-0.354l0.112-0.001l2.016-0.082l0.181,0.225l-0.055,0.48l0.212,0.168l0.88-0.019l1.231-0.093l0.322,0.098l0.052,0.183l-0.177,0.693l-0.057,0.354l0.303,0.605l0.109,0.607l-0.07,1.06l-0.296,1.033l0.021,0.212l0.117,0.211l0.844,0.998l0.306,0.62l-0.003,0.466l-0.198,0.905l0.007,0.254l0.199,0.197l0.61-0.004l0.859-0.26l0.991-0.146l1.24,0.147l-0.214,1.344l0.195,1.059l0.269,0.323l0.089,0.254l-0.132,0.368l-0.436,0.44l-0.124,0.594l-0.125,0.086l-0.517-0.04l-3.408,0.091l-0.051,0.877l0.015,1.342l-0.024,3.249l0.017,0.848l0.023,0.594l0.099,0.438l0.308,0.394l0.471,0.436l1.354,1.391l0.611,0.632l-0.93,0.218l-1.96,0.379l-1.044,0.203l-0.717-0.08l-1.164,0.063l-0.408-0.083l-0.349-0.21l-2.024,0.026l-0.697-0.024l-0.622-0.151l-0.401-0.322l-0.305-0.366l-0.408-0.096l-0.989-0.023l-2.59,0.016l-1.636-0.019l-0.631-0.011l-1.296-0.006l-2.201,0.013l-0.636-0.151l-0.463-0.309l-0.45-0.478l-0.294-0.083l-0.499,0.088l-0.591,0.286l-0.778,0.513l-0.758-0.462l-0.352,0.144l-0.248,0.197l0.048-1.809l-0.017-0.805l-0.029-0.649l0.397-0.34l0.221-0.269l0.26-0.707l0.163-0.734l0.184-1.398l0.239-0.976l0.321-0.918l0.584-0.665l0.183-0.565l0.268-0.354l0.64-0.228l0.268-0.325l0.423-0.679l0.364-1.201l0.053-0.664l-0.046-0.848l-0.191-0.959l-0.201-0.536l-0.492-0.705l-0.476-0.776l-0.268-0.775l0.139-0.495l0.476-0.382l0.158-0.156l0.107-0.424l-0.006-0.479l-0.199-0.579l-0.489-0.69l-0.441-0.733l-0.203-1.031l-0.181-0.423l-0.276-0.366l-0.666-0.974l-0.072-0.15z"/> - <path id="ZM" country:name="Zambia" d="M452.198,239.34l-0.611-0.632l-1.354-1.391l-0.471-0.436l-0.308-0.394l-0.099-0.438l-0.023-0.594l-0.017-0.848l0.024-3.249l-0.015-1.342l0.051-0.877l3.408-0.091l0.517,0.04l0.125-0.086l0.124-0.594l0.436-0.44l0.132-0.368l-0.089-0.254l-0.269-0.323l-0.195-1.059l0.214-1.344l0.678,0.096l0.365,0.379l0.172,0.352l0.195,0.056l1.146-0.289l0.175-0.071l0.58,1.014l0.489,0.194l0.925,0.249l0.922,0.164l0.325,0.111l0.366-0.087l0.522-0.682l0.212-0.354l0.728,1.423l0.38,0.28l0.895,0.263l0.477,0.252l0.416,0.351l0.561,0.731l0.381,0.647l0.348,0.21l1.355,0.091l0.371,0.012l0.041-0.551l-0.028-1.427l-0.032-0.791l-0.136-0.183l-0.362,0.186l-0.448,0.455l-0.515-0.012l-0.445-0.279l-0.837-0.843l-0.456-0.605l-0.043-0.296l0.3-1.02l0.377-1.175l-0.372-2.088l0.029-0.622l0.797-1.276l0.154-0.198l0.347-0.214l3.015-0.499l0.563-0.068l0.703,0.641l0.263,0.21l0.729,0.265l1.269,0.6l1.574,0.57l0.732,0.349l0.385,0.407l0.559,0.887l0.434,0.859l0.013,0.324l-0.183,0.27l-0.709,0.344l-0.011,0.127l0.04,0.594l-0.091,1.682l0.08,0.353l0.216,0.168l0.511,0.266l0.072,0.197l-0.197,0.241l-0.472,0.258l-0.792,0.259l-0.146,0.34l-0.094,0.764l-0.3,0.807l0.2,0.479l0.261,0.408l0.394,0.125l-1.264,0.53l-1.696,0.575l-0.932,0.4l-2.165,0.578l-0.187,0.128l-0.009,0.495l0.152,0.465l0.087,0.438l-0.505-0.096l-0.999,0.049l-0.794,0.259l-0.636,0.54l-0.312,0.539l-0.019,0.579l-0.168,0.199l-0.285,0.114l-0.999,0.062l-0.621,0.202l-0.306,0.341l-0.777,0.937l-0.562,0.738l-0.825,0.951l-0.354,0.045l-0.803-0.165l-0.421-0.309l-0.334,0.129l-0.521,0.286l-0.404,0.017l-0.594-0.209l-0.264-0.097l-0.154-0.169l-0.163-0.027l-0.187-0.154l-0.456-0.393l-0.294-0.055l-1.089-0.093l-0.086-0.099l-0.165-0.056l-1.845,0.364z"/> - <path id="MW" country:name="Malawi" d="M477.231,225.874l-0.224,1.184l-0.107,0.48l0.252,0.917l0.177,1.017l0.149,0.408l0.238,0.268l0.803,0.588l1.189,1.166l0.454,0.661l0.14,0.48l-0.155,2.346l-0.04,0.41l-0.214,0.213l-0.432,0.073l-0.322,0.017l-0.229,0.213l-0.076,0.622l0.08,0.509l0.029,0.479l-0.096,0.283l-0.185-0.111l-0.562-0.463l-0.763-1.112l-0.484-0.548l-0.234-0.423l0.036-0.212l0.499-0.61l0.116-0.227l0.025-0.693l-0.1-0.96l-0.22-0.479l-0.261-0.056l-0.674,0.061l-0.702,0.132l-0.27-0.211l-0.343-0.407l-0.382-0.549l-0.195-0.041l-0.394-0.125l-0.261-0.408l-0.2-0.479l0.3-0.807l0.094-0.764l0.146-0.34l0.792-0.259l0.472-0.258l0.197-0.241l-0.072-0.197l-0.511-0.266l-0.216-0.168l-0.08-0.353l0.091-1.682l-0.04-0.594l0.011-0.127l0.709-0.344l0.183-0.27l-0.013-0.324l-0.434-0.859l-0.559-0.887l0.223-0.016l1.014,0.107l0.663,0.538l0.448,0.841l0.135,0.946l0.053,0.584l0.135,0.766l0.196,0.559z"/> - <path id="BO" country:name="Bolivia" d="M245.934,224.314l0.939,0.136l1.122,0.304l0.355-0.03l0.946-0.824l0.336,0.026l0.48,0.025l0.415-0.243l1.471-1.109l0.874-0.485l0.36-0.158l0.934-0.076l1.283,0.021l0.045,0.748l-0.079,0.621l-0.064,0.622l0.036,0.818l0.141,0.635l0.335,0.591l0.813,0.928l1.1,0.939l0.316,0.097l0.787,0.023l0.355-0.03l0.676,0.25l0.688,0.307l0.75,0.603l0.3,0.098l0.882,0.037l0.096,0.014l0.385,0.774l0.398,0.308l0.22,0.084l1.148-0.077l0.636,0.123l0.537,0.166l0.403,0.237l0.085,0.169l-0.038,0.565l0.203,1.029l0.03,0.706l0.138,2.032l0.249,0.944l0.153,0.112l0.967,0.036l0.5,0.012l1.615,0.019l0.693,0.024l0.042,0.296l-0.261,0.835l0.067,0.563l0.436,0.407l0.73,0.362l0.316,0.479l0.307,0.774l0.022,0.494l-0.185,1.173l-0.238,0.834l-0.38,0.765l-0.421,0.666l-0.089-0.084l-1.952-0.991l-0.352-0.054l-0.928,0.02l-0.843-0.01l-0.126,0.128l-1.076,0.204l-1.104,0.162l-0.784,0.202l-0.33,0.044l-0.332,0.383l-0.698,1.105l-0.278,0.341l-0.133,0.509l0.016,0.635l-0.385,1.188l-0.395,1.104l-0.149,0.325l-0.592-0.109l-1.33-0.077l-0.686,0.004l-1.034,1.784l-0.416-1.084l-0.341-0.309l-0.37-0.195l-0.531-0.067l-0.527,0.045l-0.901,0.034l-0.615-0.194l-0.193-0.169l-0.322-0.181l-0.292,0.27l-2.026,2.087l-1.047,0.006l-0.272-0.182l-0.397-2.144l-0.278-0.973l-0.212-0.563l-0.769-1.11l-0.249-0.676l0.04-0.354l0.437-1.555l-0.017-0.282l-0.761-0.744l-0.25-0.521l-0.193-1.213l-0.304-0.647l-0.555-0.745l-0.152-0.253l-0.018-0.142l-0.132-0.295l-0.049-0.48l0.12-0.227l0.723-0.61l0.285-0.439l-0.015-0.522l-0.604-1.168l-0.022-0.48l0.159-0.34l0.21-0.368l-0.347-0.845l0.102-0.452l0.532-0.582l0.221-0.34l0.156-0.34l-0.236-0.902l-0.057-0.522l0.143-0.848l0.15-0.523l0.437-0.736l-0.08-0.24l-0.922-1.646l-1.109-1.843z"/> - <path id="MZ" country:name="Mozambique" d="M473.575,260.04l-1.331,0.011l-0.192,0.058l-0.068-0.382l-0.261-0.889l0.071-0.495l-0.075-0.296l-0.095-0.324l0.03-0.806l0.057-1.301l-0.072-0.763l-0.147-0.678l-0.33-0.944l-0.441-0.689l-0.181-0.946l-0.295-1.199l-0.159-0.183l0.448-0.384l0.396-0.412l1.68-1.706l0.114-0.227l-0.09-0.367l0.075-0.834l0.229-0.481l0.736-0.683l0.205-0.341l0.168-0.41l-0.594-0.845l-0.118-0.805l-0.113-0.494l0.128-0.283l0.448-0.596l0.201-0.411l-0.132-0.805l-0.086-1.144l-0.031-0.791l-0.178-0.818l-0.441-0.379l-0.515-0.224l-1.167-0.347l-1.042-0.445l-0.658-0.223l-1.438-0.006l-0.137-0.14l-0.025-0.495l-0.011-0.212l-0.087-0.438l-0.152-0.465l0.009-0.495l0.187-0.128l2.165-0.578l0.932-0.4l1.696-0.575l1.264-0.53l0.195,0.041l0.382,0.549l0.343,0.407l0.27,0.211l0.702-0.132l0.674-0.061l0.261,0.056l0.22,0.479l0.1,0.96l-0.025,0.693l-0.116,0.227l-0.499,0.61l-0.036,0.212l0.234,0.423l0.484,0.548l0.763,1.112l0.562,0.463l0.185,0.111l0.096-0.283l-0.029-0.479l-0.08-0.509l0.076-0.622l0.229-0.213l0.322-0.017l0.432-0.073l0.214-0.213l0.04-0.41l0.155-2.346l-0.14-0.48l-0.454-0.661l-1.189-1.166l-0.803-0.588l-0.238-0.268l-0.149-0.408l-0.177-1.017l-0.252-0.917l0.107-0.48l0.224-1.184l0.898,0.018l1.019,0.149l0.526-0.088l0.643-0.356l0.123-0.128l0.229,0.083l0.323,0.394l0.512,0.294l0.963-0.02l0.964-0.006l0.42,0.054l0.396-0.144l0.543-0.766l0.21-0.326l0.276,0.083l0.646,0.42l0.448-0.031l1.243-0.559l1.218-0.402l0.515-0.342l1.157-0.836l0.128,0.167l0.212,0.479l-0.185,0.579l-0.302,0.453l-0.198,0.255l0.181,0.451l0.129,0.72l-0.012,0.466l0.182,1.115l-0.101,0.58l-0.258,0.325l0.374,0.705l0.154,0.494l-0.006,1.115l-0.004,0.819l0.043,0.184l0.185,0.127l0.327,0.084l0.015,0.269l-0.165,0.494l-0.563,0.58l0.184,0.381l-0.08,0.283l-0.418,0.565l-0.802,0.906l-0.512,0.622l-0.72,0.651l-1.36,0.751l-1.48,0.653l-0.73,0.228l-1.308,0.582l-0.852,0.637l-1.286,1.443l-0.886,0.85l-1.193,0.878l-1.181,0.836l-0.268,0.128l-0.035,0.96l-0.083,0.495l0.058,0.127l0.719,0.535l0.188,0.381l-0.166,0.452l-0.085,0.184l0.461,1.511l0.071,0.564l0.06,0.155l0.246,0.014l0.171-0.128l0.141-0.085l0.043,0.607l-0.234,2.218l-0.284,0.82l0.325,0.196l0.152,0.057l-0.025,0.325l-0.157,0.311l-0.516,0.566l-0.699,0.538l-0.664,0.34l-1.266,0.412l-0.796,0.312l-0.688,0.228l-0.895,0.524l-0.652,0.665l-0.337,0.51l0.292,0.338l0.589,0.338l0.045,0.325l-0.149,1.022z"/> - <path id="MG" country:name="Madagascar" d="M499.85,236.166l0.544-0.071l0.622-0.369l0.18,0.028l0.346,0.098l0.269-0.085l0.396-0.368l0.911-0.143l0.311,0.281l0.305-0.028l0.101-0.185l-0.171-0.366l0.771-0.539l0.423-0.198l0.322,0.226l0.389-0.213l-0.308-0.494l0.207-0.282l0.505-0.425l0.229,0.296l0.229,0.056l0.558-0.594l-0.158-0.197l-0.253-0.409l0.094-0.297l0.243,0.014l0.27-0.071l0.172-0.34l-0.297-0.875l0.06-0.339l0.255-0.043l0.117,0.07l0.253,0.438l0.28,0.099l0.2-0.41l0.692-0.524l0.235-0.367l0.134-0.452l0.168-0.692l-0.133-0.354l0.003-0.226l0.537-0.468l0.356,0.324l0.455,0.648l0.612,0.281l0.141,0.198l0.213,0.847l0.294,1.821l0.093,0.663l0.231,0.791l0.391,0.733l0.163,0.466l-0.038,0.367l-0.069,0.155l-0.058,0.099l-0.537,0.807l-0.22-0.127l-0.189-0.366l-0.555-0.748l-0.297,0.143l-0.05,0.424l0.193,0.875l0.396,0.521l0.079,0.396l-0.307,0.636l-0.746,1.005l-0.045,0.452l0.041,0.89l-0.18,0.946l-0.709,2.12l-0.825,2.572l-1.254,3.788l-1.324,4.48l-0.518,1.568l-0.188,0.255l-0.508,0.637l-0.2,0.113l-1.369,0.102l-0.999,0.327l-0.474,0.468l-0.813,0.086l-0.363-0.465l-0.196-0.142l-0.546-0.182l-0.37,0.071l-0.269-0.057l-0.863-0.718l-0.104-0.24l-0.02-0.565l-0.104-0.239l-0.46-0.366l-0.124-0.282l0.001-0.721l0.345-1.088l-0.094-0.325l-0.287-0.479l-0.62-0.931l-0.189-0.494l0.075-0.664l0.391-1.37l0.228-0.213l0.474-0.185l0.768-1.371l0.686-1.174l0.104-0.325l0.151-1.103l-0.11-0.353l-0.278-0.226l-0.354-0.366l0.066-0.184l0.252-0.509l-0.521-0.861l-0.117-0.677l-0.069-0.494l-0.231-0.721l0.024-0.112l0.517-0.693l0.362-0.594l0.163-0.438l0.007-1.073l0.484-0.016z"/> - <path id="ZW" country:name="Zimbabwe" d="M468.138,234.908l0.011,0.212l0.025,0.495l0.137,0.14l1.438,0.006l0.658,0.223l1.042,0.445l1.167,0.347l0.515,0.224l0.441,0.379l0.178,0.818l0.031,0.791l0.086,1.144l0.132,0.805l-0.201,0.411l-0.448,0.596l-0.128,0.283l0.113,0.494l0.118,0.805l0.594,0.845l-0.168,0.41l-0.205,0.341l-0.736,0.683l-0.229,0.481l-0.075,0.834l0.09,0.367l-0.114,0.227l-1.68,1.706l-0.396,0.412l-0.448,0.384l-0.342-0.225l-0.547-0.124l-0.442-0.025l-0.529,0.145l-0.31,0.016l-0.99-0.403l-0.597-0.139l-0.72-0.023l-0.067-0.042l-0.186-0.098l-0.306-0.451l-0.479-0.35l-0.549-0.167l-0.938-0.136l-0.352-0.153l-0.524-0.873l-0.163-0.564l0.032-0.565l-0.127-0.239l-0.78,0.019l-0.201-0.098l-0.109-0.211l0.051-0.537l-0.106-0.169l-0.552-0.266l-0.533-0.223l-0.57-0.321l-0.563-0.491l-0.377-0.662l-0.246-0.96l-0.469-0.604l-0.43-0.478l-0.267-0.451l0.103-0.227l0.594,0.209l0.404-0.017l0.521-0.286l0.334-0.129l0.421,0.309l0.803,0.165l0.354-0.045l0.825-0.951l0.562-0.738l0.777-0.937l0.306-0.341l0.621-0.202l0.999-0.062l0.285-0.114l0.168-0.199l0.019-0.579l0.312-0.539l0.636-0.54l0.794-0.259l0.999-0.049l0.505,0.096z"/> - <path id="NA" country:name="Namibia" d="M444.673,255.519l-0.006,3.434l0.031,1.894l0.025,2.246l-0.057,0.205l-0.454,0.318l-0.545,0.302l-0.581,0.498l-0.427,0.034l-0.581-0.166l-0.745-0.042l-0.892,0.048l-0.517-0.039l-0.296-0.212l-0.055-0.528l-0.042-0.345l-0.193-0.222l-0.637-0.348l-0.329-0.127l-0.335,0.116l-0.109,0.217l-0.317,0.416l-0.584,0.27l-0.152,0.068l-0.458-0.491l-1.041-1.001l-0.458-0.606l-0.359-1.03l-0.345-0.72l-0.136-0.493l0.12-0.269l0.053-0.34l-0.458-0.719l-0.231-0.861l0.148-0.861l-0.002-0.48l-0.537-1.326l-0.496-2.244l0.772-0.02l0.04-0.678l-0.077-0.749l-0.456-0.006l0.016-0.06l-0.099-0.522l-0.26-0.508l-1.018-1.283l-0.343-0.55l-1.102-2.158l-0.841-1.623l-0.9-1.509l-0.988-1.269l-0.511-1.044l-0.122-0.396l-0.045-0.551l0.015-0.578l0.248-0.197l0.352-0.144l0.758,0.462l0.778-0.513l0.591-0.286l0.499-0.088l0.294,0.083l0.45,0.478l0.463,0.309l0.636,0.151l2.201-0.013l1.296,0.006l0.631,0.011l1.636,0.019l2.59-0.016l0.989,0.023l0.408,0.096l0.305,0.366l0.401,0.322l0.622,0.151l0.697,0.024l2.024-0.026l0.349,0.21l0.408,0.083l1.164-0.063l0.717,0.08l1.044-0.203l1.96-0.379l0.93-0.218l1.845-0.364l0.165,0.056l0.086,0.099l1.089,0.093l0.294,0.055l0.456,0.393l-0.811,0.315l-0.891,0.02l-0.284,0.143l-0.993,0.938l-0.209,0.029l-0.62-0.773l-1.048,0.134l-2.962,0.47l-1.183,0.021l0.005,1.215l-0.007,1.286l-0.025,0.876l-0.043,1.201l0.002,3.561l-0.586,0.046l-1.564,0.052l-0.146,0.028l-0.106,2.657l-0.009,1.201l0.013,1.624l0.007,0.806z"/> - <path id="CL" country:name="Chile" d="M248.453,316.576l-0.306,0.101l-0.892-0.087l-0.538-0.293l-0.236-0.015l-0.311,0.163l-0.418,0.398l-0.498,0.192l-1.156,0.091l-0.349,0.09l-0.358,0.207l-0.267,0.621l-0.114,0.341l0.06,0.532l-0.163,0.622l-0.104,0.148l-0.453,0.031l-0.534,0.104l-0.956-0.413l0.667-0.639l0.326-0.444l0.582-0.4l0.025-0.147l-0.372-0.177l-0.273-0.117l-1.353,0.534l-1.01-0.013l-0.545,0.163l-0.202-0.339l0.128-0.192l0.959-0.268l0.266,0.028l0.792-0.208l0.441-0.118l-0.605-0.162l-0.582,0.002l-0.77,0.001l-0.014-0.413l0.265-0.31l-0.007-0.191l-0.446-0.073l-0.356-0.44l-0.66,0.384l-0.669-0.175l0.292-0.53l0.041-0.177l-0.378,0.045l-0.361,0.147l-0.416-0.396l-0.215-0.117l0.413-0.279l0.114-0.177l-0.091-0.278l-0.053-0.073l-0.351,0.03l-0.773-0.424l-0.135-0.059l0.844-0.192l0.253-0.161l0.1-0.294l0.396-0.366l0.049-0.234l-0.641,0.06l-0.257,0.104l-0.312-0.073l-0.256-0.672l0.573-0.395l-0.565-0.378l-0.12-0.421l0.757-0.452l-0.14-0.421l-0.686,0.422l-0.091-1.523l0.399-0.596l-0.185-0.825l0.013-0.218l0.593,0.014l0.41,0.245l0.711,0.071l0.171-0.246l0.002-0.159l-0.896-0.447l-0.867,0.146l-0.317-0.173l-0.536,0.059l-0.017-0.231l0.339-0.333l0.025-0.246l-0.067-0.087l0.186-0.202l0.536,0.014l0.229-0.377l0.01-0.216l-0.722-0.389l-0.354-0.129l-0.886,0.045l-0.332-0.101l-0.024-0.49l-0.939,0.16l-0.115-0.101l0.122-0.145l1.032-0.521l0.251-0.116l0.4-0.404l0.266-0.389l0.833-0.06l0.268,0.201l0.059,0.346l-0.648,0.202l-0.323,0.274l0.11,0.505l0.117,0.058l0.191-0.102l0.268-0.39l0.183-0.087l0.242,0.101l-0.037,0.317l0.057,0.504l0.886-0.996l0.161-0.678l0.056-0.647l0.237-0.375l0.079-0.058l0.631-0.217l-0.201-0.071l-0.438-0.143l-0.056-0.158l0.101-0.273l0.246-0.072l0.571-0.245l0.599-0.431l0.271-0.459l-0.061-0.229l-0.394-0.157l-0.662-0.399l-0.053-0.372l0.139-0.243l0.105-0.458l-0.06-0.828l0.366-0.33l0.676-0.272l-0.431-0.585l-0.053-0.784l0.133-0.158l0.554-0.157l0.054-0.314l-0.116-0.285l-0.317-0.085l-0.272-0.198l0.233-0.329l0.087-0.313l-0.401-0.185l-0.274-0.014l-0.161,0.101l-0.476,0.414l-0.548,0.058l-0.087,0.001l-0.289-0.199l-0.16-0.484l-0.399-0.726l-0.133-0.697l0.188-0.911l0.137-0.413l0.722-0.739l0.535-0.767l-0.006-0.326l-0.544-1.757l0.001-0.608l0.088-0.567l-0.076-0.438l-0.528-0.891l-0.04-0.298l0.236-0.198l0.499,0.098l0.182-0.085l0.2-0.142l0.097-0.143l0.41-1.288l0.252-0.481l0.304-0.935l0.18-0.65l0.664-0.808l0.363-0.722l0.201-0.636l0.252-0.946l0.311-0.691l0.187-0.128l0.273-0.382l0.013-0.296l-0.312-0.847l0.082-0.184l0.455-0.452l0.206-0.339l0.028-0.24l-0.093-0.226l-0.166-0.805l-0.292-2.088l-0.098-0.86l0.031-0.565l0.412-0.565l0.37-0.537l0.207-0.564l0.007-0.734l-0.339-0.521l-0.098-0.409l0.295-0.96l0.218-0.941l0.127-0.556l0.461-0.594l0.171-0.918l0.243-0.975l0.126-0.805l0.082-0.565l-0.063-1.087l0.422-0.664l0.211-0.494l-0.221-0.932l-0.048-0.833l0.148-0.24l-0.022-0.917l0.229-0.607l-0.124-0.297l-0.365-0.084l0.06-0.324l-0.046-0.396l0.223-0.198l0.402-0.198l0.137-0.424l-0.008-0.819l0.093-0.593l0.182-0.918l-0.004-2.344l-0.172-2.074l-0.042-1.539l-0.194-0.974l-0.15-0.387l0.852-0.275l0.259-0.298l0.228-0.933l0.15-0.199l0.586-0.187l0.152,0.253l0.555,0.745l0.304,0.647l0.193,1.213l0.25,0.521l0.761,0.744l0.017,0.282l-0.437,1.555l-0.04,0.354l0.249,0.676l0.769,1.11l0.212,0.563l0.278,0.973l0.397,2.144l0.272,0.182l1.047-0.006l0.107,0.056l0.212,0.14l0.161,0.154l-0.093,0.636l-0.541,1.457l-0.36,0.256l-1.346,0.53l-0.819,0.372l-0.204,0.312l0.25,0.817l-0.421,0.722l-0.007,0.579l0.113,0.437l0.34,0.449l0.03,0.226l-0.273,0.369l-0.161,0.382l0.114,0.507l0.53,0.477l0.011,0.227l-0.152,0.311l-0.333,0.017l-0.791,0.089l-0.329,0.835l-0.464,0.835l-0.608,0.694l-0.282,0.439l-0.823,1.839l0.167,1.466l0.054,0.762l-0.124,0.185l-0.492,0.271l-0.292,0.34l-0.388,1.201l-0.156,0.961l0.285,0.633l0.408,1.154l0.784,2.816l0.055,0.69l-0.075,0.41l-1.083,1.854l-0.319,0.595l0.088,0.409l0.189,1.06l-0.078,0.325l-1.334,1.11l-0.231,0.312l-0.142,1.075l0.014,1.16l0.249,1.103l0.437,0.932l-0.202,0.143l-0.951,0.529l-0.126,0.17l-0.053,0.312l-0.511,2.427l-0.316,0.541l-0.1,0.37l0.123,1.835l0.231,0.867l0.012,0.427l-0.596,0.317l-0.172,0.172l-0.106,0.271l0.094,1.226l0.125,0.128l0.555,0.111l0.088,0.655l-0.191,1.458l0.252,0.585l0.26,0.185l0.789,0.11l0.302,0.17l-0.007,0.186l-0.245,0.202l-0.322,0.13l-0.726,0.033l-0.757,0.146l0.176,0.171l0.586,0.298l0.552,0.385l0.017,0.216l-0.767,0.794l-0.059,1.094l0.158,1.035l-0.216,0.896l-0.212,0.434l-0.226,0.262l-0.598,0.161l-0.28,0.219l-0.249,0.781l0.446,0.648l-0.069,0.188l-0.296,1.218l-0.307,0.263l-1.729,1.01l-0.271,0.292l-0.037,0.45l0.28,1.309l0.508,1.123l0.218,0.043l0.961-0.283l0.654-0.121l0.187,0.248l0.231,2.285l0.778,0.568l0.669,0.041l1.41-0.052l2.827,0.132l0.841,0.217l1.385,0.36l0.286,0.039z M236.642,296.773l-0.394-0.113l-0.43-0.028l-0.21-0.171l-0.133-0.229l0.21-0.457l0.15-0.657l-0.087-0.514l0.011-0.414l0.364-0.728l0.817-0.116l0.36,0.327l0.044,0.328l-0.688,0.443l-0.146,0.229l0.493,0.771l-0.194,1.058l-0.167,0.271z M238.177,317.937l-0.445-0.177l0.083-0.842l-0.849,0.075l-0.073-0.368l0.218-0.354l0.823,0.102l0.508-0.207l0.205,0.103l0.054,0.812l-0.267,0.34l-0.257,0.518z M247.801,322.062l-1.033,0.102l-0.467-0.118l-0.55-0.237l-0.42,0.001l-0.481,0.104l-0.935,0.226l-0.496,0.03l0.125-0.343l0.202-0.312l-0.104-0.312l0.906-0.15l1.434,0.058l0.433,0.323l0.706-0.007l-0.622-0.689l-0.307-0.163l-0.56-0.117l-0.178-0.089l-0.188,0.03l-0.338-0.341l-0.229-0.4l1.611-0.581l-0.044-0.296l-0.165-0.147l-1.819,0.285l-0.292-0.222l0.263-0.474l0.146-0.163l1.074-0.52l0.868-0.637l0.414,0.28l1.153,0.062l-0.008,1.144l-0.098,3.675z"/> - <path id="BW" country:name="Botswana" d="M456.133,239.67l0.187,0.154l0.163,0.027l0.154,0.169l0.264,0.097l-0.103,0.227l0.267,0.451l0.43,0.478l0.469,0.604l0.246,0.96l0.377,0.662l0.563,0.491l0.57,0.321l0.533,0.223l0.552,0.266l0.106,0.169l-0.051,0.537l0.109,0.211l0.201,0.098l0.78-0.019l0.127,0.239l-0.032,0.565l0.163,0.564l0.524,0.873l0.352,0.153l0.938,0.136l0.549,0.167l0.479,0.35l0.306,0.451l0.186,0.098l-0.317,0.411l-0.388,0.327l-0.507,0.243l-0.747,0.075l-0.304,0.115l-0.7,0.823l-0.586,0.583l-0.362,0.229l-0.747,0.357l-0.388,0.355l-0.107,0.636l-0.222,0.666l-0.247,0.241l-0.634,0.357l-0.98,0.33l-0.249,0.214l-0.217,0.708l-0.345,0.963l-0.288,0.354l-0.237,0.129l-0.584,0.116l-0.43-0.026l-0.473,0.06l-0.511-0.011l-0.819-0.193l-0.744-0.32l-0.979-0.645l-0.545-0.039l-0.333,0.186l-0.084,0.24l-0.585,1.134l-0.382,0.469l-0.651,0.625l-0.632,0.428l-0.8,0.372l-0.823,0.033l-0.854,0.047l-0.368-0.097l-0.11-0.183l0.003-0.48l0.243-0.609l0.166-0.538l-0.21-0.762l-0.547-0.943l-0.716-0.787l-0.528-0.067l-0.007-0.806l-0.013-1.624l0.009-1.201l0.106-2.657l0.146-0.028l1.564-0.052l0.586-0.046l-0.002-3.561l0.043-1.201l0.025-0.876l0.007-1.286l-0.005-1.215l1.183-0.021l2.962-0.47l1.048-0.134l0.62,0.773l0.209-0.029l0.993-0.938l0.284-0.143l0.891-0.02l0.811-0.315z"/> - <path id="PY" country:name="Paraguay" d="M279.288,257.295l0.02,0.239l-0.544,1.57l-0.375,0.468l-1.007,0.74l-0.301,0.27l-0.352,0.51l-0.609-0.363l-0.35-0.097l-0.235,0.029l-0.387,0.172l-0.745,0.131l-0.71,0.005l-0.564-0.096l-0.992-0.333l-0.607-0.025l-1.187,0.332l-0.19-0.056l0.064-0.212l0.425-0.426l0.486-0.398l0.11-0.198l-0.21-0.619l0.048-0.227l0.625-0.851l0.617-1.203l0.018-0.268l-0.939-0.503l-0.65-0.18l-1.448-0.697l-1.632-1.106l-0.671-0.307l-1.173-0.204l-0.498-0.237l-0.835-0.588l-0.576-0.562l-1.271-1.376l-0.782-0.913l-0.225-0.337l-0.19-0.056l0.149-0.325l0.395-1.104l0.385-1.188l-0.016-0.635l0.133-0.509l0.278-0.341l0.698-1.105l0.332-0.383l0.33-0.044l0.784-0.202l1.104-0.162l1.076-0.204l0.126-0.128l0.843,0.01l0.928-0.02l0.352,0.054l1.952,0.991l0.089,0.084l0.253,0.408l0.084,0.663l0.521,0.872l0.104,0.959l-0.132,0.862l-0.086,0.721l-0.006,0.72l0.372,0.04l0.818,0.15l0.925,0.221l0.346-0.03l0.709-0.413l0.115-0.001l0.724,0.278l0.843,0.404l0.121,0.437l0.487,2.524l0.254,0.563l0.224,0.055l1.29-0.445l0.234,0.112l0.491,0.336l0.019,0.141l-0.321,0.75l-0.298,0.835l-0.222,0.819l-0.027,0.777l0.063,0.423z"/> - <path id="ZA" country:name="South Africa" d="M444.673,255.519l0.528,0.067l0.716,0.787l0.547,0.943l0.21,0.762l-0.166,0.538l-0.243,0.609l-0.003,0.48l0.11,0.183l0.368,0.097l0.854-0.047l0.823-0.033l0.8-0.372l0.632-0.428l0.651-0.625l0.382-0.469l0.585-1.134l0.084-0.24l0.333-0.186l0.545,0.039l0.979,0.645l0.744,0.32l0.819,0.193l0.511,0.011l0.473-0.06l0.43,0.026l0.584-0.116l0.237-0.129l0.288-0.354l0.345-0.963l0.217-0.708l0.249-0.214l0.98-0.33l0.634-0.357l0.247-0.241l0.222-0.666l0.107-0.636l0.388-0.355l0.747-0.357l0.362-0.229l0.586-0.583l0.7-0.823l0.304-0.115l0.747-0.075l0.507-0.243l0.388-0.327l0.317-0.411l0.067,0.042l0.72,0.023l0.597,0.139l0.99,0.403l0.31-0.016l0.529-0.145l0.442,0.025l0.547,0.124l0.342,0.225l0.159,0.183l0.295,1.199l0.181,0.946l0.441,0.689l0.33,0.944l0.147,0.678l0.072,0.763l-0.057,1.301l-0.03,0.806l0.095,0.324l-1.449-0.585l-0.279,0.199l-0.657,0.979l-0.28,0.567l-0.005,0.325l0.39,0.676l0.307,0.465l0.458,0.322l0.671,0.109l0.595-0.004l0.076-0.594l0.064-0.198l0.312-0.186l0.131-0.015l0.192-0.058l1.331-0.011l-0.182,1.195l-0.352,0.849l-0.182,0.184l-0.404,0.1l-0.093,0.24l0.199,0.536l-0.104,0.467l-0.248,0.354l-0.569,0.453l-0.923,0.581l-0.591,0.75l-1.383,1.98l-0.631,0.834l-1.242,1.373l-1.193,1.062l-0.829,0.863l-1.434,1.034l-1.379,1.091l-0.552,0.382l-0.989,0.638l-0.676,0.298l-0.782,0.101l-0.98-0.012l-0.549,0.071l-0.132,0.354l0.013,0.127l-0.109,0.085l-0.449-0.098l-0.553-0.126l-0.303,0.015l-0.25,0.198l-0.272,0.312l-0.226,0.113l-0.36-0.056l-0.768-0.408l-0.759-0.168l-0.542-0.013l-0.31,0.113l-0.38,0.27l-0.482-0.099l-0.645-0.21l-0.295,0.1l-0.638,0.043l-0.589,0.214l-0.729,0.538l-0.72,0.086l-0.44-0.013l-0.667-0.084l-0.738,0.072l-0.575,0.199l-0.827,0.82l-1.251-0.576l-0.092-0.509l-0.218-0.183l-0.479-0.056l-0.28,0.085l-0.257-0.479l-0.343-0.056l-0.149,0.255l-0.035,0.197l-0.312-0.112l-0.119-0.226l0.267-0.495l0.103-0.424l-0.857-1.354l-0.323-0.282l-0.134-0.226l0.173-0.17l0.636-0.044l0.172-0.424l0.06-0.819l-0.163-0.663l-0.186-0.522l-0.61-1.143l-0.75-1.029l-0.472-0.903l-0.612-1.383l-0.646-1.467l-0.573-0.818l-0.436-0.467l0.152-0.068l0.584-0.27l0.317-0.416l0.109-0.217l0.335-0.116l0.329,0.127l0.637,0.348l0.193,0.222l0.042,0.345l0.055,0.528l0.296,0.212l0.517,0.039l0.892-0.048l0.745,0.042l0.581,0.166l0.427-0.034l0.581-0.498l0.545-0.302l0.454-0.318l0.057-0.205l-0.025-2.246l-0.031-1.894l0.006-3.434z M462.462,268.501l0.412-0.044l0.194-0.553l0.633-0.343l1.035-0.303l0.263-0.199l0.582-1.007l0.268-0.326l0.143-0.241l-0.104-0.226l-0.967-0.744l-0.33-0.337l-0.422-0.266l-0.308,0.086l-0.995,0.359l-0.65,0.329l-0.513,0.567l-0.275,0.44l-0.691,0.611l0.12,0.409l0.582,0.858l0.285,0.366l0.739,0.561z M432.955,250.661l0.456,0.006l0.077,0.749l-0.04,0.678l-0.772,0.02l-0.078-0.354l-0.028-0.396l0.285-0.297l0.101-0.406z"/> - <path id="SZ" country:name="Swaziland" d="M471.719,258.047l0.075,0.296l-0.071,0.495l0.261,0.889l0.068,0.382l-0.131,0.015l-0.312,0.186l-0.064,0.198l-0.076,0.594l-0.595,0.004l-0.671-0.109l-0.458-0.322l-0.307-0.465l-0.39-0.676l0.005-0.325l0.28-0.567l0.657-0.979l0.279-0.199l1.449,0.585z"/> - <path id="LS" country:name="Lesotho" d="M462.462,268.501l-0.739-0.561l-0.285-0.366l-0.582-0.858l-0.12-0.409l0.691-0.611l0.275-0.44l0.513-0.567l0.65-0.329l0.995-0.359l0.308-0.086l0.422,0.266l0.33,0.337l0.967,0.744l0.104,0.226l-0.143,0.241l-0.268,0.326l-0.582,1.007l-0.263,0.199l-1.035,0.303l-0.633,0.343l-0.194,0.553l-0.412,0.044z"/> - <path id="NZ" country:name="New Zealand" d="M790.15,283.022l0.738,0.197l0.008-0.227l-0.242-0.524l0.052-0.284l0.233,0.014l0.389,0.17l0.37,0.751l0.277,0.964l0.48,0.17l1.753,0.691l0.506,0.113l0.37-0.072l0.699-0.483l0.885-0.343l0.4,0.027l0.329,0.17l0.066,0.454l-0.022,0.198l-0.402,1.236l-0.283,0.072l-0.761,0.058l-0.035,0.683l-0.124,0.156l-0.424,0.029l-0.746,0.016l-0.432,0.2l-0.271,0.284l0.041,0.384l0.254,0.525l-0.002,0.213l-0.151,0.199l-0.646,0.515l-0.898,1.129l-0.847,1.058l-0.756,0.587l-0.68,0.316l-0.337-0.171l-0.47-0.313l-0.237-0.328l0.056-0.314l0.288-0.386l0.307-0.671l0.398-0.5l-0.031-0.343l-0.271-0.128l-0.761-0.582l-0.421-0.185l-0.593-0.184l-0.98-0.452l-0.306-0.256l-0.11-0.17l0.081-0.128l0.419-0.157l1.389-0.685l0.209-0.512l-0.078-0.695l0.087-0.312l0.396-0.441l0.032-0.383l-0.482-0.837l0.081-0.567l-0.156-0.311l-0.479-0.655l-0.574-0.678l0.102-0.164l-0.145-0.304l-0.291-0.351l-0.336-0.188l-0.29-0.163l0.117,0.233l0.497,0.515l0.049,0.141h-0.169l-0.211-0.281l-0.525-0.631l-0.622-0.771l-0.518-0.561l0.001-0.117l-0.268-0.257l0.04-0.141l0.013-0.14l-0.048-0.188l-0.197-0.396l-0.379-0.42l-0.347-0.257l0.163-0.046l0.205,0.093l0.358-0.047l0.131-0.093l0.084,0.28l-0.149,0.187l0.186,0.303l0.177,0.21l0.167,0.116l0.228,0.164l0.041-0.141l0.269,0.023l0.519,0.257l0.42,0.117l0.274,0.07l0.128,0.257l-0.011,0.141l0.185,0.023l0.146-0.188l0.185,0.023l-0.022,0.164l0.227,0.351l0.249,0.187l0.233,0.28l-0.18,0.023l-0.076,0.164l0.093,0.163l-0.242-0.023l-0.175-0.047l0.143,0.117l0.251,0.188l0.23,0.233l0.352,0.28l0.063,0.234l0.019,0.21l-0.261-0.047l0.096,0.164l0.239,0.351l0.256,0.188l-0.292,0.023h-0.226l-0.205-0.047l-0.006,0.141l0.306,0.14l0.324,0.164l-0.09,0.211l0.205,0.046l0.265-0.023h0.226l0.223,0.141l-0.114,0.07l-0.031,0.141l0.025,0.141l0.136,0.06zM782.939,297.694l-0.088,0.158l-0.558,0.13l-0.309,0.288l-0.322,0.101l-0.246,0.244l-0.692-0.242l-0.16,0.086l0.15,0.216l0.429,0.415l-0.141,0.173l0.02,0.259l-0.064,0.431l-0.218-0.071l-0.976-0.099l0.418,0.229l0.449,0.244l-0.278,0.49l-0.427,0.896l-0.212,0.549l-0.418,0.318l-0.673,0.349l-0.171,0.246l-0.259,0.145l-0.581,0.233l-0.593,0.406l-0.398,0.015l-1.156-0.258l-0.628,0.112l-0.585-0.442l-0.812-0.158l-0.373-0.066l-0.162-0.308l-0.467-0.098l-0.24,0.142l-0.062,0.168l-0.78,0.095l-0.214-0.166l-0.515-0.095l-0.146-0.286l0.432-0.089l-0.223-0.216l0.328-0.116l0.322-0.001l-0.452-0.482l0.82,0.266l-0.464-0.576l0.121-0.145l0.946,0.156l0.082-0.13l-0.141-0.173l-0.201-0.216l-0.06-0.288l0.283-0.303l0.569-0.246l0.328-0.374l0.561-0.375l0.102-0.302l0.998-0.575l1.106-0.275l0.713-0.331l0.544-0.36l0.377-0.101l0.685-0.575l0.066-0.272l0.48-0.302l0.373-0.015l0.787-0.331l0.664-0.402l0.126-0.215l-0.008-0.172l0.266-0.144l0.448-0.302l-0.109-0.501l0.076-0.214l0.166-0.44l0.306,0.048l0.066-0.152l0.58-0.259l0.444-0.272l0.137-0.285l0.131-1.187l0.512-0.647l0.372,0.047l0.365,0.165l0.032,0.259l0.337,0.06l0.187,0.186l0.231,0.799l0.312,0.242l0.973-0.645l0.426-0.029l0.367,0.113l0.222,0.5l-0.197,0.399l0.299,0.429l0.066,0.271l-0.611,0.659l-0.261,0.401l-0.476,0.358l-0.868,0.746l-0.578,0.359l-0.295,0.13l-0.236,0.258l-0.389,0.159l-0.271,0.258l0.416,0.407l0.428,0.047l0.421,0.289l-0.276,0.113l-0.484,0.07l-0.503-0.296l-0.488,0.131l-0.352,0.158z"/> - <path id="AR" country:name="Argentina" d="M247.899,318.387l0.008-1.144l0.821,0.289l0.06,0.206l-0.354,0.312l-0.534,0.337z M248.453,316.576l-0.286-0.039l-1.385-0.36l-0.841-0.217l-2.827-0.132l-1.41,0.052l-0.669-0.041l-0.778-0.568l-0.231-2.285l-0.187-0.248l-0.654,0.121l-0.961,0.283l-0.218-0.043l-0.508-1.123l-0.28-1.309l0.037-0.45l0.271-0.292l1.729-1.01l0.307-0.263l0.296-1.218l0.069-0.188l-0.446-0.648l0.249-0.781l0.28-0.219l0.598-0.161l0.226-0.262l0.212-0.434l0.216-0.896l-0.158-1.035l0.059-1.094l0.767-0.794l-0.017-0.216l-0.552-0.385l-0.586-0.298l-0.176-0.171l0.757-0.146l0.726-0.033l0.322-0.13l0.245-0.202l0.007-0.186l-0.302-0.17l-0.789-0.11l-0.26-0.185l-0.252-0.585l0.191-1.458l-0.088-0.655l-0.555-0.111l-0.125-0.128l-0.094-1.226l0.106-0.271l0.172-0.172l0.596-0.317l-0.012-0.427l-0.231-0.867l-0.123-1.835l0.1-0.37l0.316-0.541l0.511-2.427l0.053-0.312l0.126-0.17l0.951-0.529l0.202-0.143l-0.437-0.932l-0.249-1.103l-0.014-1.16l0.142-1.075l0.231-0.312l1.334-1.11l0.078-0.325l-0.189-1.06l-0.088-0.409l0.319-0.595l1.083-1.854l0.075-0.41l-0.055-0.69l-0.784-2.816l-0.408-1.154l-0.285-0.633l0.156-0.961l0.388-1.201l0.292-0.34l0.492-0.271l0.124-0.185l-0.054-0.762l-0.167-1.466l0.823-1.839l0.282-0.439l0.608-0.694l0.464-0.835l0.329-0.835l0.791-0.089l0.333-0.017l0.152-0.311l-0.011-0.227l-0.53-0.477l-0.114-0.507l0.161-0.382l0.273-0.369l-0.03-0.226l-0.34-0.449l-0.113-0.437l0.007-0.579l0.421-0.722l-0.25-0.817l0.204-0.312l0.819-0.372l1.346-0.53l0.36-0.256l0.541-1.457l0.093-0.636l-0.161-0.154l-0.212-0.14l-0.107-0.056l2.026-2.087l0.292-0.27l0.322,0.181l0.193,0.169l0.615,0.194l0.901-0.034l0.527-0.045l0.531,0.067l0.37,0.195l0.341,0.309l0.416,1.084l1.034-1.784l0.686-0.004l1.33,0.077l0.592,0.109l0.19,0.056l0.225,0.337l0.782,0.913l1.271,1.376l0.576,0.562l0.835,0.588l0.498,0.237l1.173,0.204l0.671,0.307l1.632,1.106l1.448,0.697l0.65,0.18l0.939,0.503l-0.018,0.268l-0.617,1.203l-0.625,0.851l-0.048,0.227l0.21,0.619l-0.11,0.198l-0.486,0.398l-0.425,0.426l-0.064,0.212l0.19,0.056l1.187-0.332l0.607,0.025l0.992,0.333l0.564,0.096l0.71-0.005l0.745-0.131l0.387-0.172l0.235-0.029l0.35,0.097l0.609,0.363l0.352-0.51l0.301-0.27l1.007-0.74l0.375-0.468l0.544-1.57l-0.02-0.239l0.957-0.161l0.462-0.017l0.206,0.196l0.517,1.154l-0.094,1.638l-0.161,0.467l-0.521,0.313l-1.754,0.744l-0.348,0.242l-1.633,1.448l-1.435,1.363l-1.805,1.816l-0.833,0.88l-0.214,0.27l-0.443,0.524l-0.065,0.452l-0.595,2.359l-0.103,0.522l0.049,0.847l0.168,0.986l-0.118,0.325l-0.48,0.524l-0.24,0.495l-0.011,0.522l0.194,0.577l-0.054,0.338l-0.162,0.273l-0.26,0.325l0.015,0.226l0.924,0.831l0.68,0.281l0.715,0.281l0.283,0.169l0.281,0.325l-0.025,0.325l-0.362,0.523l-0.043,0.396l0.105,0.339l0.174,0.269l0.466,0.325l0.522,0.168l0.109,0.113l0.226,0.892l-0.308,0.481l-0.75,0.937l-0.729,0.766l-0.313,0.737l-0.368,0.284l-0.832,0.342l-1.04,0.342l-1.92,0.401l-1.795,0.188l-1.361,0.116l-0.945,0.044l-1.175-0.11l-0.934-0.226l-0.128,0.199l0.036,0.808l0.322,0.312l0.308,0.184l-0.09,0.298l-0.381,0.624l-0.345,0.498l-0.069,0.385l0.392,0.682l0.066,0.285l-0.208,0.214l-0.105,0.057l-1.251,0.473l-1.137,0.116l-0.814-0.069l-0.967-0.34l-1.47-0.396l-0.246,0.057l-0.23,0.271l0.041,0.598l0.429,0.684l0.037,0.398l-0.242,0.643l0.092,0.385l0.773,0.54l0.796,0.084l0.369-0.2l-0.387-0.398l0.872-0.188l0.383-0.043l0.234,1.041l0.052,0.3l-0.144,0.157l-0.299,0.101l-0.448,0.072l-0.261-0.157l-0.104-0.299l-0.115-0.071l-1.046,0.073l-0.67,0.201l-0.212,0.101l0.151,0.214l0.591,0.07l0.47,0.113l0.452,0.113l0.06,0.028l-0.864,0.388l-0.776,0.287l-0.577,0.602l0.003,0.414l0.161,0.787l-0.081,0.258l-0.815,0.817l0.022,0.215l0.423,0.371l-0.491,0.116l-1.194,0.088l-0.48,0.087l-0.632,0.246l-0.619,0.389l-0.56,0.548l-0.549,0.821l-0.052,0.389l0.061,0.375l0.312,0.591l0.48,0.446l0.98,0.633l0.657,0.244l0.97,0.143l0.362,0.086l0.14,0.274l-0.151,0.796l-0.128,0.348l-0.342,0.464l-0.189,0.145l-1.08,0.524l-1.541,0.814l-0.712,0.698l-0.179,0.276l-0.093,0.45l0.111,0.523l-0.169,0.451l-0.239,0.32l-0.97,0.454l-0.969,0.25l-0.421,0.221l-0.323,0.396l-0.226,0.791l-0.054,0.514l0.2,0.777l0.547,0.896l0.699,0.779l0.235,0.339l-0.101,0.032z M247.899,318.387l0.18,0.182l0.148,0.073l0.607-0.075l0.344,0.133l0.648,0.725l0.908,0.665l0.993,0.756l0.525,0.222l0.73,0.37l0.246,0.074l0.42-0.001l0.483,0.163l1.283,0.027l0.142-0.016l-0.006,0.224l-0.19,0.209l-0.492,0.06l-1.198,0.092l-0.777,0.196h-0.364l-1.179-0.355l-0.753-0.088l-1.15-0.027l-0.814-0.014l-0.831,0.081l0.098-3.675z"/> - <path id="IS" country:name="Iceland" d="M346.758,54.457l0.127-0.162l0.42-0.179l0.894,0.015l0.674-0.098l-0.354-0.227l-0.405-0.34l0.317-0.342l0.277,0l0.956,0.42l0.67,0.048l0.3-0.163l-0.191-0.26l-0.625-0.373l0.366-0.245l1.037,0.226l0.957,0.08l0.746,0.275l0.446,0.551l-0.119,0.405l-0.441,0.292l0.922,0.806l0.553-0.356l0.352-0.13l0.63-0.114l0.49-0.179l0.061-0.21l-0.169-0.778l0.542-0.245l0.501,0.454l0.426,0.307l0.489,0.209l0.215,0.016l0.185-0.13l-0.264-0.454l0.243-0.163l0.27-0.033l0.817-0.164l0.683,0.438l0.536,0.242l0.542,0.063l0.05-0.178l-0.358-0.535l1.006,0.145l1.439,0.079l0.787-0.115l0.427-0.229l-0.021-0.716l1.167,0.08l0.635,0.471l1.118,0.323l0.683,0.015l0.273,0.243l-0.252,0.552l0.786,0.29l1.674,0.159l0.127,0.145l0.143,0.548l-0.07,0.387l-0.152,0.256l-0.152,0.256l-0.443,0.129l-0.815,0.018l-0.195,0.096l-0.04,0.431l-0.515,0.463l-0.497,0.16l-0.568-0.031l-0.422-0.159l-0.817,0.495l-0.539,0.144l-1.46,0.463l-0.853,0.113l-0.726,0.001l-0.771,0.097l-0.784,0.587l-0.473,0.127l-1.078,0.097l-0.709-0.03l-1.316-0.171l-0.608-0.142l-1.283-0.489l-1.058-0.093l-0.443,0.064l-1.041-0.014l-1.834-0.124l-0.297-0.206l0.434-0.191l1.127-0.352l0.701-0.59l-0.818-0.015l-0.51-0.126l-0.428-0.398l-0.253-0.095l-0.358,0.081l-1.564,0.115l-0.557,0.033l-0.37-0.223l0.141-0.192l0.388-0.129l0.669-0.097l0.794-0.017l0.729-0.114l1.049-0.098l0.376-0.194l0.178-0.322l-0.144-0.258l-0.358-0.177l-0.426-0.015l-0.478-0.145l-1.005-0.047l-0.821,0.099l-0.424,0.162l-0.676,0.082l-1.041-0.272l-0.16-0.21z"/> - <path id="EE" country:name="Estonia" country:shortname="Estonia" d="M462.829,67.958l0.145,0.053l0.16,0.131l-0.043,0.174l-0.175,0.044h-0.189h-0.116l-0.088,0.043l-0.058,0.131l-0.175,0.277l-0.219,0.204l-0.319,0.131l-0.204,0.131l-0.088,0.16l0.029,0.16l0.131,0.437l0.073,0.189l0.029,0.16l-0.175,0.131v0.175l0.175,0.233l0.203,0.087l0.088,0.073v0.073l0.015,0.087l0.043,0.146l0.175,0.043l0.059,0.059l-0.175,0.073l-0.262,0.043l-0.16,0.058l-0.059,0.102l-0.087,0.116h-0.131L461.402,72l-0.015,0.087l-0.116,0.058l0.081,0.106l-0.125,0.025l-0.087-0.015l-0.306-0.043l-0.16-0.058l-0.175-0.073l-0.204-0.044l-0.131,0.102l-0.204-0.029l-0.131,0.044l-0.16,0.087l-0.146,0.014l-0.146-0.087l-0.116-0.029h-0.175l-0.204-0.117l-0.116-0.174l-0.203-0.117l-0.146-0.043l-0.072-0.117h-0.189l-0.247-0.043l-0.204-0.117h-0.029l-0.276-0.014l-0.102-0.102l-0.248-0.043l-0.116-0.102l-0.189-0.087v0.073l-0.116,0.087l-0.131-0.058l-0.015-0.073l-0.087-0.029h-0.103l-0.276,0.117l-0.102,0.029l-0.131,0.015l-0.219,0.015l-0.146,0.043l-0.262,0.029l-0.276,0.087l-0.116,0.102h-0.087l0.156-0.19l-0.003-0.351l0.183-0.238l-0.368-0.21l-0.605,0.437l-0.334-0.251l-0.527-0.038l0.043-0.942l-0.396,0.188l-0.336-0.415l0.158-0.202l-0.209-0.254l0.265-0.074l-0.092-0.252l0.344-0.042l1.026-0.084l-0.006-0.132l0.561-0.108l0.133-0.188l0.436,0.101l0.074-0.113l0.317,0.05l0.083-0.215l1.104,0.193l0.446-0.294l0.091,0.165l0.514-0.089l1.383,0.029l1.152,0.167l0.305,0.12l0.592-0.045l0.971,0.09l0.426-0.108l0.271-0.24l-0.006-0.009z"/> - <path id="LV" country:name="Latvia" country:shortname="Latvia" d="M461.353,72.251l0.37-0.004l-0.015,0.116v0.117l0.232,0.073l0.204,0.087l0.087,0.073l0.204,0.058l-0.015,0.087l-0.029,0.116l-0.015,0.087l-0.102,0.073l-0.087,0.015l-0.103,0.029l0.131,0.087l-0.072,0.131l0.029,0.117l-0.073,0.087l-0.102,0.073l-0.044,0.102l0.204-0.059l0.146-0.015l0.131,0.073l0.087,0.014l0.073,0.044l-0.059,0.087l-0.043,0.073l0.116,0.102l0.131,0.058l0.029,0.16l0.146,0.102l0.16,0.043l-0.059,0.087l0.131,0.117l-0.015,0.189l0.088,0.233l-0.044,0.087l-0.015,0.117l-0.061,0.042l-0.241,0.044l-0.24,0.051l-0.12,0.12l-0.223,0.034l-0.137,0.154l-0.137,0.085l-0.069,0.103l-0.068,0.206l-0.188,0.035l-0.239-0.035l-0.24-0.034l-0.325-0.034h-0.359l-0.172,0.068l-0.103,0.137l-0.223,0.085h-0.154l-0.103-0.017l-0.086,0.052l-0.377-0.035l-0.273-0.068l-0.154-0.171l-0.138-0.154l-0.325-0.137l-0.497-0.223l-0.342-0.24l-0.377-0.034l-0.583-0.035l-0.325-0.12l-0.291-0.188l-0.086-0.257l-0.188,0.017l-0.171,0.068l-0.36,0.171l-0.394,0.017h-0.24l-0.273,0.085l-0.24-0.085l-0.309-0.103l-0.6-0.017l-0.291,0.069l-0.359-0.069l-0.291-0.051l-0.154,0.034l-0.274,0.069l-0.103-0.052l-0.12-0.137h-0.154l-0.257,0.068h-0.188l-0.754-0.017l-0.445-0.085l-0.754,0.171l-0.599,0.154l-0.429,0.103l-0.257,0.137l-0.052,0.188l-0.526,0.026l-0.065-0.059l0.073-0.837l0.035-0.302l0.127-0.167l0.672-0.379l0.034-0.717l0.267-0.162l0.267-0.273l0.217-0.203l0.296-0.026l1.056-0.199l0.166-0.046l0.162-0.066h0.29l0.049,0.237l0.657,0.388l0.422,0.162l0.23,0.473l0.091,0.15l0.441,0.196l0.785,0.059l0.868-0.244l0.24-0.122l0.178-0.288l-0.052-0.394l-0.193-0.869l0.198-0.243l0.045-0.055h0.087l0.116-0.102l0.276-0.087l0.262-0.029l0.146-0.043l0.219-0.015l0.131-0.015l0.102-0.029l0.276-0.117h0.103l0.087,0.029l0.015,0.073l0.131,0.058l0.116-0.087v-0.073l0.189,0.087l0.116,0.102l0.248,0.043l0.102,0.102l0.276,0.014h0.029l0.204,0.117l0.247,0.043h0.189l0.072,0.117l0.146,0.043l0.203,0.117l0.116,0.174l0.204,0.117h0.175l0.116,0.029l0.146,0.087l0.146-0.014l0.16-0.087l0.131-0.044l0.204,0.029l0.131-0.102l0.204,0.044l0.175,0.073l0.16,0.058l0.306,0.043l0.087,0.015l0.125-0.025z"/> - <path id="LT" country:name="Lithuania" country:shortname="Lithuania" d="M451.02,79.165l-0.029-0.038l-0.034-0.137l-0.018-0.171l0.068-0.206l0.068-0.154l0.224-0.12l-0.052-0.12l-0.018-0.137l-0.171-0.069l-0.188-0.034l-0.103-0.103l-0.086-0.137l-0.223,0.017h-0.257h-0.445l-0.223,0.051l-0.086-0.103l-0.514-0.068l-0.257-0.069l-0.223-0.12h-0.24l-0.086-0.052l-0.051-0.154l-0.12,0.034l-0.353,0.096l-0.043-0.077l0.128-0.012l0.034-0.183l-0.439-0.646l-0.008-0.14l-0.042-0.727l-0.112-0.102l0.526-0.026l0.052-0.188l0.257-0.137l0.429-0.103l0.599-0.154l0.754-0.171l0.445,0.085l0.754,0.017h0.188l0.257-0.068h0.154l0.12,0.137l0.103,0.052l0.274-0.069l0.154-0.034l0.291,0.051l0.359,0.069l0.291-0.069l0.6,0.017l0.309,0.103l0.24,0.085l0.273-0.085h0.24l0.394-0.017l0.36-0.171l0.171-0.068l0.188-0.017l0.086,0.257l0.291,0.188l0.325,0.12l0.583,0.035l0.377,0.034l0.342,0.24l0.497,0.223l0.325,0.137l0.138,0.154l0.154,0.171l0.273,0.068l0.377,0.035l-0.017,0.171l-0.086,0.154l-0.034,0.12l-0.12,0.137l-0.086,0.137l0.343,0.034l0.274,0.052l0.085,0.051l-0.119,0.051h-0.086l-0.103,0.154l-0.018,0.154l-0.171,0.017l-0.12-0.086l-0.12,0.051l-0.239-0.034l-0.154,0.034l-0.086,0.154l-0.103,0.154l-0.257,0.068h-0.429l-0.137,0.137l-0.12,0.12l-0.034,0.154l-0.086,0.171l0.103,0.171l-0.068,0.137l-0.239,0.154v0.137l-0.068,0.085l-0.069,0.137l0.172,0.034h0.205l0.138,0.206l-0.086,0.188l-0.274,0.017l-0.223-0.068v-0.154l-0.034-0.085l-0.086-0.069l-0.171,0.051l-0.12,0.086l-0.291-0.034l-0.068,0.137l-0.24,0.12h-0.154l-0.188-0.034l-0.273,0.103l0.086,0.171l-0.069,0.12l-0.171,0.034l-0.137-0.034l-0.206,0.051l-0.377,0.154h-0.291l-0.068-0.103l-0.12-0.051l-0.239,0.051l-0.377,0.017l-0.24,0.034l-0.291-0.034l-0.154,0.034l-0.093-0.035l-0.09-0.171l-0.016-0.029l-0.099-0.186l-0.284-0.487l-0.679-0.243l-0.04-0.014l-0.641,0.021z"/> - <path id="BY" country:name="Byelarus" country:shortname="Byelarus" d="M452.867,80.273l0.093,0.035l0.154-0.034l0.291,0.034l0.24-0.034l0.377-0.017l0.239-0.051l0.12,0.051l0.068,0.103h0.291l0.377-0.154l0.206-0.051l0.137,0.034l0.171-0.034l0.069-0.12l-0.086-0.171l0.273-0.103l0.188,0.034h0.154l0.24-0.12l0.068-0.137l0.291,0.034l0.12-0.086l0.171-0.051l0.086,0.069l0.034,0.085v0.154l0.223,0.068l0.274-0.017l0.086-0.188l-0.138-0.206h-0.205l-0.172-0.034l0.069-0.137l0.068-0.085v-0.137l0.239-0.154l0.068-0.137l-0.103-0.171l0.086-0.171l0.034-0.154l0.12-0.12l0.137-0.137h0.429l0.257-0.068l0.103-0.154l0.086-0.154l0.154-0.034l0.239,0.034l0.12-0.051l0.12,0.086l0.171-0.017l0.018-0.154l0.103-0.154h0.086l0.119-0.051l-0.085-0.051l-0.274-0.052l-0.343-0.034l0.086-0.137l0.12-0.137l0.034-0.12l0.086-0.154l0.017-0.171l0.086-0.052l0.103,0.017h0.154l0.223-0.085l0.103-0.137l0.172-0.068h0.359l0.325,0.034l0.24,0.034l0.239,0.035l0.188-0.035l0.068-0.206l0.069-0.103l0.137-0.085l0.137-0.154l0.223-0.034l0.12-0.12l0.24-0.051l0.241-0.044l0.165,0.147l0.229,0.066l0.197-0.131l0.181,0.016l0.312,0.033l0.132,0.148l0.082,0.148l0.197-0.033l0.214-0.065l0.361-0.049l0.312,0.049l0.296,0.065l0.147,0.017v0.115l-0.164,0.099l-0.017,0.099l0.065,0.148l0.164,0.148h0.197l0.214-0.197l0.279-0.016h0.165l0.147-0.099l0.23-0.083l0.131,0.049l0.099,0.049l0.247-0.049l0.542,0.115l0.132,0.131l0.279,0.099l0.099,0.099l0.147,0.099l0.165,0.033l0.147-0.033l0.049,0.115l-0.065,0.115v0.083l-0.033,0.164l-0.131,0.165l0.197,0.247l0.147,0.099l0.05,0.164l-0.066,0.131h-0.114v0.083l-0.115,0.082l-0.099,0.049l-0.033,0.165l-0.049,0.147l0.345,0.049l0.132,0.181l0.082,0.115l0.181-0.049l0.132,0.033l-0.099,0.115l-0.066,0.131l0.017,0.099l0.214,0.017l0.164,0.263l0.115,0.23l0.443,0.213l0.23,0.066l0.279,0.082l0.164,0.099l0.066,0.148l-0.099,0.197l-0.066,0.181l0.182,0.066l0.361-0.066l0.378,0.066l0.361,0.099l0.263,0.066l-0.032,0.065l-0.066,0.049l-0.082,0.017l0.099,0.181l0.296,0.148l0.279,0.066l0.033,0.131l-0.065,0.164h-0.296l-0.148,0.083l-0.049,0.065l-0.444,0.247l-0.525,0.099l-0.51-0.016l-0.197-0.132l-0.328-0.049l-0.362,0.017l-0.131,0.165l-0.099,0.131l0.017,0.164l0.279,0.263l0.296,0.164v0.165l-0.132,0.066l0.099,0.148l0.147,0.131l-0.082,0.099l0.033,0.164l0.033,0.23l-0.033,0.099l0.164,0.082l0.082,0.115l0.165,0.066l0.002,0.142l-0.519-0.005l-0.522,0.056l-0.112,0.131l-0.205-0.056l-0.187-0.037l-0.336,0.075l-0.057,0.13l-0.111,0.112l-0.317,0.187l-0.188,0.261l-0.261,0.224l-0.057,0.206l0.243,0.205l0.056,0.149l-0.131,0.206l-0.261-0.019l-0.149-0.056l-0.149-0.206l-0.112-0.056l-0.187-0.075l-0.224-0.037l-0.225,0.037l-0.242,0.075l-0.299,0.019l-0.149-0.131l-0.224,0.075l-0.188,0.093l-0.316,0.056l-0.188-0.056l-0.037-0.205l-0.112-0.131l-0.168-0.131l-0.13,0.038l-0.131,0.075h-0.168l-0.299,0.149l-0.131,0.149h-0.168l-0.094-0.187l-0.13-0.075h-0.206l-0.224,0.112l-0.131-0.187l-0.224-0.093l-0.131,0.112l-0.354,0.056l-0.262-0.112h-0.112l-0.019,0.205l-0.168,0.093l-0.093-0.056l0.056-0.224l-0.243-0.038l-0.187-0.056l-0.541,0.112v-0.149h-0.187l0.019-0.224l-0.28-0.037l-0.242,0.075l-0.523-0.112l-0.578-0.056l-0.075-0.056h-0.522l-0.205-0.168l-0.262,0.019l-0.522-0.093l-0.467,0.075h-0.485l-0.354-0.056l-0.355,0.056l-0.354,0.056l-0.485-0.038l-0.485,0.019l-0.205,0.187l-0.037,0.168l-0.374,0.168l-0.373,0.206l-0.112-0.112h-0.261l-0.374-0.019l-0.037,0.131v0.045l-0.126-0.137l0.315-0.752l-0.013-0.25l-0.218-0.146l-0.149-0.176l-0.421-0.146l-0.289-0.012l0.128-0.292l0.291-0.328l0.571-0.244l0.44-0.03l0.263-0.208l0.023-0.236l-0.172-0.502l-0.615-1.5l-0.16-0.302z"/> - <path id="UK" country:name="United Kingdom" country:shortname="UK" d="M400.125,81.146l0.633,0.305l0.208,0.207l0.208,0.37l-0.038,0.193l-0.545,0.563l0.714,0.176l0.396-0.311l0.527-0.119l0.602,0.028l0.807,0.176l0.467,0.354l0.235,0.752l-0.077,0.221l-0.322,0.414l-1.068,0.473l-0.767,0.561l-0.96,0.237l1.223,0.167l0.501,0.043l0.354-0.104l0.39,0.117l-0.066,0.516l-0.997,0.308l0.005,0.199l-0.479-0.084l-1.068,0.443l-0.879-0.142l-0.293-0.048l-1.119,0.211l-0.587-0.211l-0.598,0.112l-1.584,0.141l0.137,0.295l-0.907-0.168l-0.264,0.168l-0.911-0.337l-0.334,0.143l-0.913,0.089l-0.093,0.569l-0.337,0.316l-0.37,0.042l-0.272-0.252l-0.53-0.172l-0.135,0.151l-0.527-0.077l-0.948,0.324l-0.701,0.552l-0.326-0.231l-0.775-0.147l1.2-0.472l0.492-0.476l0.447-0.097l0.468-0.388l0.118-0.485l0.242,0.063l0.367-0.211l-0.008-0.274l1.013-0.105l0.76,0.119l0.927,0.007l0.073-0.338l0.308-0.142l0.321-0.556l-0.939,0.394l-0.725,0.016l-1.467-0.482l-1.866-0.055l-0.399-0.191l-0.156-0.162l0.417-0.325l0.983-0.194l0.721-0.237l0.38-0.384l0.066-0.827l-0.119-0.192l-0.713,0.046l-0.34-0.044l0.288-0.355l0.387-0.223l0.802-0.253l1.394-0.062l0.922-0.076l-0.316-0.548l0.172-0.683l0.253-0.461l-0.045-0.312l-0.834,0.061l-0.484-0.296l-0.2-0.312l0.309-0.507l0.617-0.433l-0.347-0.104l-0.596-0.088l-0.735,0.3l-0.476,0.061l-0.753-0.222l-0.088,0.194l-0.222,0.194l-0.672-0.103l-0.464-0.133l0.1-0.343l0.348-0.36l0.604-0.706l-0.293-0.134l-0.305-0.39l0.028-0.24l0.304-0.106l0.3-0.196l-0.194-0.496l-0.306,0.076l-0.636,0.453l-0.442,0.031l-0.526,0.287l-0.14-0.421l0.302-0.527l0.438-0.559l0.065-0.257l-0.417-0.195l-0.196-0.045l-0.218,0.302l-0.394,0.257l-0.493-0.165l0.299-0.575l0.54-0.455l0.09-0.136l-0.225-0.575l0.366-0.092l0.225-0.197l-0.672-0.515l0.432-0.351l0.752,0.151l0.387-0.092l-0.645-0.759l0.975-0.169l-0.457-0.502l0.416-0.382l0.924,0.365l0.824-0.093l0.686-0.139l0.867-0.047l0.612,0.014l0.303,0.259l-0.307,0.29l-1.726,0.704l-0.46,0.274l-0.218,0.441l0.222,0.182l0.784,0.029l0.877-0.078l0.685-0.001l0.53,0.075l1.563-0.064l0.458,0.378l-0.363,0.425l-0.212,0.323l0.098,0.112l-0.565,0.66l-0.226,0.111l-0.339,0.437l-0.696,0.261l-0.382,0.038l0.451,0.186l0.508,0.167l-0.116,0.015l-0.272,0.19l-0.61,0.052l-0.275,0.196l-1.337-0.025l0.404,0.223h0.302l0.492,0.093l0.432-0.006l0.519-0.223l0.413-0.025l0.449,0.161l0.656,0.164l0.673,0.566l0.496,0.228l0.118,0.165l-0.067,0.238l0.312,0.78l0.371,0.536l0.438,0.189l0.714,0.107l0.59,0.549l0.688,0.593l0.135,0.52l-0.188,0.49l0.257,0.124z M387.915,77.13l-0.128-0.325l0.149-0.335l0.38-0.089l0.079,0.501l-0.307,0.251l-0.173-0.003zM386.786,80.184l-0.178-0.272l-0.967,0.072l0.123-0.256l-0.364-0.15l-0.26-0.257l-0.335-0.107l-0.253,0.364l-0.751,0.257l-0.778-0.192l-0.401-0.278l-0.101-0.278l0.86-0.278l-0.483-0.257l0.817-0.107l0.385-0.484l-0.029-0.235l0.449-0.09l0.508-0.15l0.781-0.077l0.424,0.044l0.389,0.104l0.362-0.046l0.218,0.149l0.519,0.791l0.047,0.179l-0.081,0.298l0.308,0.446l-0.155,0.328l-0.402,0.328l-0.354,0.12l-0.299,0.038z"/> <!-- ISO code is GB but domain is UK --> - <path id="KZ" country:name="Kazakhstan" country:shortname="Kazakhstan" d="M578.943,106.217l-0.41-0.375l-0.466-0.098h-0.663l-0.196-0.27l-0.27-0.147l-0.147-0.344l-0.564,0.049l-0.981-0.246l-0.662,0.074l-1.35-0.024l-0.662-0.098l-0.712-0.221l-0.785,0.147h-0.761l-0.858,0.024l-0.441,0.27l-0.54-0.098l-0.908-0.196l-0.735-0.246l-0.761-0.27l-0.589-0.074l-0.688,0.123l-0.466,0.368l-0.245,0.736l0.024,0.442l-0.344-0.123l-0.81-0.123l-0.688-0.196l-0.883-0.245l-0.883-0.147l-0.663,0.098l-0.736,0.123l-0.318,0.368l-0.393,0.442l0.044,0.273l-0.322,0.031l-0.377,0.377l-0.283-0.126l-0.22,0.063l-0.346,0.283l-0.534,0.471l-0.755,0.189l-0.943,0.377l-0.282,0.188l-0.221,0.472l-0.439,0.188l-0.504,0.44l0.157,0.409l-0.125,0.188h-0.66l-0.44-0.346l0.062-0.283l-0.062-0.283l-0.44-0.314h-0.346l-1.006,0.094l-0.691,0.032l-0.503-0.063l-0.346-1.069l-0.221-0.817h-1.006l-0.031-0.754l0.188-0.409l0.031-1.038l-0.66,0.314l-0.66-1.006l-0.597-0.22l-0.724-0.723l-1.1,0.409l-2.767-0.188l-2.578,0.346l-2.012-1.666l-5.722-2.986l-5.658,1.289l-0.056,8.174l-0.158-0.014l-0.341,0.106l-0.489,0.043l-0.447-0.255l-0.638-0.703l-0.256-0.511l-0.617-0.383l-0.681-0.383l-0.512-0.234l-0.979,0.085l-1.277,0.298l-0.937,0.532l-0.529,0.453l0.092-0.399l-0.06-0.18l-0.12-0.12l0.14-0.26l0.2-0.2l0.14-0.32l0.04-0.3l0.18-0.2l-0.159-0.24l-0.4-0.16l-0.459,0.06l-0.18-0.16l-0.3,0.06l-0.2,0.04l-0.199-0.18l-0.221-0.32l-0.319-0.28h-0.34l-0.359,0.02v-0.2l0.08-0.28l-0.2-0.379l-0.239-0.12l-0.2-0.24l-0.399-0.799l-0.08-0.28l-0.56-0.12l-0.699-0.08l-0.14-0.16l0.02-0.439l0.16-0.12l0.3-0.06l0.399,0.02l0.34,0.02l0.479,0.14l0.539,0.18l0.18-0.08l0.36-0.08l-0.2-0.16l-0.26-0.12l-0.399-0.2l-0.2-0.24l0.26-0.36l0.28-0.04l0.08-0.26l0.18-0.299l0.12-0.14l0.26,0.04l0.319-0.08l0.16-0.1l0.339,0.12h0.24l1.119-0.04l0.999,0.14l0.499,0.02l-0.159-0.08l-0.34-0.2l-0.479-0.12l-0.021-0.3l0.2-0.2l0.279-0.22l0.221-0.28l0.119-0.52l0.12-0.28l-0.16-0.24l-0.14-0.16l0.1-0.2l0.26-0.2l-0.119-0.12l-0.101-0.3l-0.359-0.12l-0.359-0.04l-0.68-0.1l-0.2,0.16l-0.199,0.08l-0.52,0.08l-0.46-0.12l-0.319-0.26l-0.26-0.06l-0.68-0.12l-0.56,0.06l-0.659,0.319l-0.42,0.02l-0.799,0.5l-0.72,0.28l-0.499,0.06l-0.42-0.02l-0.279,0.24l-0.213,0.18l-0.616-0.19l-0.857-0.377l-0.068-0.308l0.343-0.103l0.309,0.103l0.445,0.103l0.138-0.103l-0.96-1.131l-0.343-0.514l-0.479-0.206l-0.515-0.445l-0.514-0.034l-0.343,0.034l-0.583-0.206l-0.103,0.343l-0.514-0.514l0.068-0.309l-0.138-0.377l-1.37-0.343l0.65-1.165l0.446-0.274l0.239-0.206l-0.239-0.274l-0.343-0.171l0.205-1.303l0.823-0.137l0.343-0.549l0.103-0.308l0.411-0.069l0.514,0.24l0.48,0.548l0.514,0.411h0.651l0.411-0.24l0.068-0.446l-0.171-0.411l-0.068-0.445l0.479-0.206l0.891-0.411l0.172-0.24l0.309-0.309l0.514-0.171l0.549-0.068l0.788-0.377l0.548-0.343l0.515-0.309l0.651,0.069h0.479l0.309,0.274l0.651-0.137l0.273-0.137l0.617-0.24l0.411,0.069l0.411,0.514l0.788,0.035l0.617-0.069l0.96,0.171v0.343l0.582,0.206l0.789,0.343l0.411,0.274l0.068,0.583l0.274,0.137l0.239-0.274l-0.205-0.48l-0.034-0.24l0.72,0.068l0.582,0.548l0.686,0.137l0.411,0.24l0.686-0.171l0.274-0.274l0.377-0.343l0.514-0.377l0.823,0.068l0.65,0.035l0.651,0.411l0.617-0.068l0.137-0.412l1.062-0.103l0.754,0.103l0.274,0.548l0.926,0.309l0.754,0.137l0.411,0.171l0.651-0.343l0.171-0.309h0.24l0.343,0.343l0.959,0.034l1.577-0.411l0.137-0.309l0.138-0.686l-0.24-0.24l-1.165-0.171l-0.274-0.308l-0.651-0.069l-0.377-0.137l0.068-0.171l-0.377-0.137h-0.239l-0.164-0.274l0.467-0.067l0.735-0.368l0.588-0.147l0.331-0.294l-0.441-0.478l-0.146-0.257l0.662-0.515l0.698-0.184l1.103,0.147l0.515-0.073l0.11-0.257l-0.956-0.294l-1.065-0.11v-0.331l0.294-0.074l-0.294-0.221l-0.074-0.441l0.185-0.515l0.33-0.074l1.066,0.147h0.515h0.772l0.368-0.184l1.396-0.405l1.029-0.037l0.735-0.11l1.545-0.11l0.588-0.073l0.331,0.073l0.221-0.331l0.625-0.331l1.177-0.037l2.021-0.405l1.876-0.073l0.625-0.074l0.367-0.368V77.39l0.515-0.037l0.589-0.184l0.11-0.221l0.735-0.037l0.919,0.147l0.515,0.11l0.772,0.257l0.625-0.11l0.882-0.037l0.368,0.404l-0.037,0.331l0.147,0.221l0.515,0.22l-0.11,0.331l-0.147,0.257l0.073,0.331l-0.33,0.037l0.184,0.257l0.478,0.074l0.295-0.147l0.44,0.11l0.368-0.147l0.367,0.074l0.331-0.221l0.294,0.11l0.295,0.368l0.367,0.221l0.147-0.147l0.184-0.147l0.478,0.037l0.405,0.294l0.478,0.11l0.441-0.221h0.367l-0.146,0.294l-0.441,0.184l-0.331,0.441l0.331,0.184l0.441-0.11l0.771-0.073l0.441,0.037l0.552,0.184l0.294-0.294l0.772-0.441l1.103-0.257l0.956-0.515l0.772-0.221l0.515-0.22l0.809-0.074v0.441l-0.515,0.11l-0.11,0.368l1.104,0.588l0.809,0.294l1.287,0.772l1.066,1.029l1.69,2.133l0.846,0.882l1.104,1.434l0.515-0.257l0.331-0.257l0.367-0.515h0.92l0.367,0.331v0.368h0.478l0.258,0.257l0.184,0.184h0.589h0.992l0.993-0.221l0.771-0.221l0.993-0.037l0.698,0.441l0.772,0.588l0.331,0.625l0.956,0.147l0.588,0.552l0.662,0.699l0.882,0.073l0.993,0.074l0.478-0.368l0.625-0.184l-0.073,0.331l0.441,0.331l0.294,0.478h0.589l0.064,0.145l-0.551,0.034l-0.542,0.148l-0.279,0.262l-0.011,0.275l-0.035,0.478l-0.306,0.219l-0.289,0.06l-1.199,0.093l-0.428,0.277l-0.34,0.581l0.097,0.75l0.213,0.707l-0.157,0.39l-0.444,0.392l-0.417,0.103l-0.718,0.062l-1.402-0.079l-0.594-0.141l-0.721-0.141l-1.096-0.254l-0.427,0.507l-0.516,1.141L584.2,97.43l-0.286,0.605l-0.137,0.418l0.622,0.514l0.126,0.286l-0.156,0.245l-0.231,0.145l-0.394,0.074l-1.133-0.238l-0.5-0.184l-0.35,0.06l-1.082,0.207l-1.799,0.254l-0.393,0.188l-0.215,0.302l-0.068,0.215l0.232,0.185l0.366-0.06l0.483,0.141l0.03,1.357l0.345,0.627l0.29,0.441l0.119,0.47l-0.222,0.33l-0.705,0.546l-0.32,0.401l-0.02,0.399l0.139,0.86z"/> - <path id="IE" country:name="Ireland" d="M386.786,80.184l-0.304,0.038l-0.223,0.09l0.241,0.252l0.361,0.771l0.287,1.213l-0.061,0.281l-0.359,0.341l-0.242,0.414l-0.145,0.473l-0.185,0.044l-0.284-0.058l-0.616,0.031l-0.15,0.212l-0.913,0.042l-0.84,0.132l-0.247,0.144l-0.661,0.286l-0.903,0.498l-0.628,0.035l-0.879,0.283l-1.28,0.084l0.053-0.378l-0.089-0.441l-0.848,0.1l-0.171-0.487l0.734-0.254l-1.186-0.021l0.062-0.233l1.286,0.027l0.198-0.104l0.039-0.222l0.107-0.31l0.515-0.134l0.692-0.031l0.13-0.281l-1.07,0.099l0.387-0.437l-0.187-0.159l0.481-0.468l0.694-0.011l0.163-0.089l-0.174-0.311l-0.348,0.177l-0.309-0.131l-0.319,0.03l-0.391-0.177l-0.414,0.001l-0.182,0.106L378,81.478l0.309-0.306l-0.29-0.142l0.759-0.126l-0.139-0.301l0.391-0.235l-0.481-0.214l-0.59,0.128L378,79.792l0.38-0.268l0.215-0.16l0.928,0.187l0.336-0.075l0.527,0.038l1.102,0.123l-0.214-0.358L382.132,79l0.198-0.321h-1.373l0.154-0.15l0.569-0.107l0.061-0.29l0.291-0.479l0.505-0.181l0.804-0.169l0.22,0.302l0.354,0.149l0.156-0.031l0.029,0.235l-0.385,0.484l-0.817,0.107l0.483,0.257l-0.86,0.278l0.101,0.278l0.401,0.278l0.778,0.192l0.751-0.257l0.253-0.364l0.335,0.107l0.26,0.257l0.364,0.15l-0.123,0.256l0.967-0.072l0.178,0.272z"/> - <path id="UI" country:name="Ukraine" country:shortname="Ukraine" d="M452.998,85.535V85.49l0.037-0.131l0.374,0.019h0.261l0.112,0.112l0.373-0.206l0.374-0.168l0.037-0.168l0.205-0.187l0.485-0.019l0.485,0.038l0.354-0.056l0.355-0.056l0.354,0.056h0.485l0.467-0.075l0.522,0.093l0.262-0.019l0.205,0.168h0.522l0.075,0.056l0.578,0.056l0.523,0.112l0.242-0.075l0.28,0.037l-0.019,0.224h0.187v0.149l0.541-0.112l0.187,0.056l0.243,0.038l-0.056,0.224l0.093,0.056l0.168-0.093l0.019-0.205h0.112l0.262,0.112l0.354-0.056l0.131-0.112l0.224,0.093l0.131,0.187l0.224-0.112h0.206l0.13,0.075l0.094,0.187h0.168l0.131-0.149l0.299-0.149h0.168l0.131-0.075l0.13-0.038l0.168,0.131l0.112,0.131l0.037,0.205l0.188,0.056l0.316-0.056l0.188-0.093l0.224-0.075l0.149,0.131l0.299-0.019l0.242-0.075l0.225-0.037l0.224,0.037l0.187,0.075l0.112,0.056l0.149,0.206l0.149,0.056l0.261,0.019l0.131-0.206l-0.056-0.149l-0.243-0.205l0.057-0.206l0.261-0.224l0.188-0.261l0.317-0.187l0.111-0.112l0.057-0.13l0.336-0.075l0.187,0.037l0.205,0.056l0.112-0.131l0.522-0.056l0.519,0.005l0.357,0.089l0.469,0.022l0.313-0.156l0.179-0.291l0.134-0.268l0.536,0.246l0.536-0.022l0.67-0.223l0.692,0.112l0.514-0.134l0.201,0.268l0.312,0.134l0.246,0.335l0.134,0.201l0.246,0.156l0.312,0.156v0.268l-0.312-0.022l-0.312,0.134l0.134,0.291l0.111,0.357l0.269,0.29h0.647l0.156,0.112l0.514-0.067l0.38,0.022v0.312h0.402v0.357l0.224,0.268l0.089,0.246l-0.089,0.179l0.089,0.224l0.179,0.089l0.291,0.29l0.268-0.179l0.47-0.067l0.268,0.067l0.469,0.291l0.201-0.067l0.179,0.022l0.179,0.156l0.425-0.112l0.312-0.112h0.269l0.536-0.134l0.357-0.067l0.111,0.156l0.268,0.179v0.134l0.201,0.179l0.022,0.134l0.402,0.044l0.179,0.179l0.224,0.112l0.29-0.134l0.045-0.157l0.224-0.067l0.29,0.268l0.425,0.067l0.469,0.112l0.268,0.112l0.357-0.067l0.201,0.179l0.291,0.089l0.469,0.022l0.111,0.224l0.357,0.156h0.269l0.134-0.044l0.201-0.089l0.156,0.089l-0.089,0.111l-0.022,0.179l0.111,0.089l0.09,0.179l-0.045,0.224l-0.201,0.089l-0.156,0.067l-0.357,0.201l-0.312,0.044l0.223,0.246l0.269,0.089l0.29,0.044l-0.134,0.156h-0.312h-0.246l-0.045,0.179l-0.044,0.224l0.156,0.067l0.179,0.067l0.044,0.134l0.045,0.179l0.09,0.201l0.066,0.067l-0.156,0.491l-0.156,0.291v0.156l-0.335,0.134l-0.805-0.157l-0.736,0.045h-0.269l-0.022,0.179l-0.223,0.179l-0.38,0.134l-0.357,0.022l-0.224,0.089l-0.09,0.514v0.224l-0.021,0.112l-0.012,0.126l-0.779,0.104l-0.971,0.06l-0.511,0.405l-0.729,0.189l-1.135,0.075l-1.119,0.248l-0.502,0.318l-0.463,0.059l-0.453-0.316l-0.369,0.621l-0.31,0.188l-0.477,0.044l-0.438-0.057l-0.959,0.031l-0.5,0.16l0.641,0.287l1.957,1.004l0.053,0.172l-0.093,0.188l0.163,0.244l0.562,0.042l0.511-0.13l0.675-0.146l1.052,0.013l0.439,0.114l-0.235,0.259l-0.106,0.245l-0.228,0.144l-0.578,0.116l-0.31,0.029l-0.591-0.157l-0.473,0.044l-0.71,0.489l-1.007,0.045l-0.538,0.188l-0.527,0.488l-0.269,0.101l-0.786-0.07l-0.588-0.171l0.364-0.746l-0.096-0.416l-0.264-0.287l-0.854-0.286l-0.193-0.014l-0.629,0.016l-0.151,0.043l-0.16-0.187l0.887-0.505l0.644-0.261l0.772-0.188l0.221-0.116l-0.246-0.46l-0.435-0.071l-0.799,0.044l-1.015,0.045l-0.698-0.1l-0.195-0.101l-0.418-0.432l0.584-0.405l-0.528-0.605l-0.378,0.361l-0.541,0.001l-1.001,0.146l-0.565,0.131l-0.694,0.722l-1.003,0.867l-0.754,0.203l-0.223,0.044l-0.287,0.504l0.079,0.158l0.178,0.093l-0.706-0.131l-0.665,0.261h-0.457l-0.033,0.189l-0.609-0.047l-0.398-0.166l-0.119-0.249l-0.15,0.02l0.055-0.077l0.102-0.025l0.126,0.013l0.113,0.013h0.189l0.088-0.114v-0.088l-0.063-0.113l0.025-0.113l0.126-0.063l0.051-0.063l0.075-0.013l0.089-0.025l0.088-0.063l0.089-0.088l0.024-0.126l-0.013-0.114l0.14-0.013l0.29-0.063l0.075-0.076l-0.025-0.088l-0.062-0.088l0.126-0.114l0.037-0.063l-0.012-0.088l-0.114-0.113l0.051-0.101l-0.088-0.151l-0.063-0.101l0.202-0.151l0.239-0.025l0.126-0.088l0.113,0.025l0.013,0.088l-0.013,0.214l0.063,0.013h0.113V96.92l-0.013-0.063l0.101,0.038l0.063,0.051l0.025-0.076l0.075-0.038l0.139-0.012v0.075l0.089,0.063h0.075l0.126,0.164l0.076-0.076l0.075-0.076l0.013-0.05l0.101-0.025h0.177l-0.037,0.189l0.176,0.025l0.038-0.038l0.038-0.038l0.139,0.013h0.227l0.038-0.025l0.075-0.076l-0.126-0.013l-0.164-0.126l-0.101-0.051l-0.075-0.05l0.013-0.038l0.101-0.063l-0.025-0.113l0.038-0.101l-0.013-0.126l-0.051-0.139l-0.101-0.063l-0.177-0.076h-0.075l-0.151-0.126l-0.151-0.063l-0.151-0.038l0.051-0.151l0.037-0.088l-0.037-0.051l-0.127,0.038l-0.062-0.114l0.113-0.038l-0.013-0.189l0.089-0.075l-0.025-0.101l-0.038-0.088h-0.113l-0.102,0.05l-0.088,0.051l-0.113-0.088l-0.089-0.101l-0.188-0.101l-0.139-0.025l-0.102-0.139l-0.05-0.139l0.177-0.139v-0.189l0.024-0.114l0.051-0.05l-0.126-0.063l0.164-0.151l-0.113-0.025l-0.076-0.063l-0.062-0.126l-0.14-0.013l-0.062,0.101l-0.126-0.025l-0.215-0.025l-0.126-0.189l-0.05-0.189l-0.417-0.075l-0.277,0.012l-0.062,0.051l-0.076,0.101l-0.062-0.05v-0.076l-0.089-0.025l-0.101,0.038l0.038-0.05l0.088-0.101l-0.025-0.063h-0.113l-0.177,0.038l-0.126-0.025l-0.101,0.013l-0.076-0.076l-0.05-0.063l-0.101-0.063l-0.151-0.013l-0.139-0.05l-0.14-0.126l-0.214-0.088l-0.038-0.013l-0.126,0.025l-0.05,0.025l-0.114-0.051l-0.088-0.025l-0.139,0.025l-0.177,0.051l-0.177-0.025l-0.062,0.038l-0.126,0.114h-0.202l-0.265-0.038l-0.126,0.051l-0.315-0.114l-0.088,0.101l0.012,0.113h-0.126l-0.075-0.063l-0.126,0.114l-0.06,0.052l-0.634,0.08l-0.151,0.311l-0.278,0.178l-1.992,0.191l-0.186,0.215l-0.243,0.119l-0.339,0.06l-0.188-0.227l-0.327,0.004l-0.025-0.231l-0.363,0.045l-1.115-0.066l-0.958-0.193l-0.241,0.107l-0.787-0.121l-0.136,0.085l-0.678-0.387l-0.554-0.2l-0.668-0.301l-0.166,0.015l1.047-1.471l0.653,0.018l-0.349-0.383l-0.044-0.552l0.082-0.306l1.509-1.218l0.599-0.398l0.286-0.181l0.429-0.013l0.255-0.24l0.009-0.314l-0.328-0.302l0.085-0.133l0.298-0.048l-0.316-0.193l-0.816-0.835l0.074-0.242l-0.161-0.175z"/> - <path id="MN" country:name="Mongolia" d="M660.044,89.132l-0.295,0.31l-0.687,1.207l-1.224,1.959l-0.381,0.58l0.269,0.836l0.051,0.029l0.342-0.045l0.929-0.395l0.754-0.062l0.576-0.018l0.317,0.085l0.431,0.416l0.292,0.07l1.191-0.786l0.438-0.002l0.928,0.212l0.538,0.199l0.797,0.5l0.879,0.99l0.599,0.501l0.048,0.273l-0.107,0.217l-0.414,0.218l-0.464-0.127l-1.074-0.008l-0.432-0.099l-0.854,0.033l-0.937,0.221l-0.539,0.146l-0.831,0.278l-0.353,0.189l-0.483-0.127l-0.464,0.045l-0.47,0.204l-0.363,0.333l-0.312,0.82l-0.241,0.216l-0.347,0.188l-0.638,0.248l-0.896,0.134l-0.624-0.054l-0.438-0.012l-0.224-0.013l-1.192,0.91l-0.742,0.433l-0.744,0.047l-0.982,0.005l-0.592-0.125l-0.668-0.382l-0.718-0.154l-0.316,0.073l-0.457,0.231l-0.539,0.589l-0.214,0.401l0.003,0.343l0.389,0.569l0.599,0.411l0.188,0.228l-0.123,0.271l-0.326,0.259l-1.265,0.292l-0.67,0.389l-1.111,1.046l-0.265,0.172l-1.941,0.737l-0.651,0.061l-0.987-0.08l-1.514,0.065l-1.339,0.007l-1.204,0.349l-0.816,0.289l-0.736,0.274l-0.303,0.101l-1.44,0.534l-0.686,0.289l-0.481,0.017l-0.433-0.197l-0.253-0.297l-0.61-0.067l-0.663,0.061l-0.929-0.123l-1.599-0.433l-1.006-0.365l-0.815-0.551l-0.521-0.168l-1.69-0.119l-1.164-0.022l-0.937-0.023l-2.861,0.059l-1.165-0.022l-0.802-0.109l-1.241-0.207l-1.979-0.018l-0.444-0.254l-0.467-0.439l-1.571-2.161l-0.105-0.542l-0.744-0.096l-0.839-0.31l-1.645-0.806l-0.632-0.268l-0.998-0.224l-0.668-0.083l-0.995-0.038l-1.505-0.021l-1.062-0.181l-0.724-0.312l-0.233-0.229l-0.105-0.43l0.035-0.129l0.369-0.347l0.214-0.389l0.237-0.75l0.215-0.447l-0.401-0.66l-1.07-1.451l-0.568-0.618l-0.354-0.143l-0.633-0.144l-0.731-0.167l-0.614-0.069l-0.834-0.415l-1.301-0.745l-0.371-0.433l-0.24-0.563l-0.131-0.405l-0.062-0.145l0.154-0.044l0.799-0.425l0.599-0.207l1.387-0.08l0.603-0.148l0.727-0.381l0.017-0.012l0.971-0.692l0.787-0.398l1.143-0.341l1.512-0.476l0.84-0.18l0.953,0.097l0.932,0.156l1.842,0.122l0.831,0.083l0.694,0.755l0.393,0.406l0.699,0.113l1.458-0.008l0.719,0.083l0.85-0.004l0.875,0.068l0.312,0.114l0.576,0.186l0.562-0.018l0.755-0.28l0.31-0.162l0.744-0.572l0.163-0.526l-0.116-0.204l-0.396-0.304l-0.409-0.86l0.098-0.293l0.905-0.839l1.269-0.96l0.84,0.201l1.028,0.098l1.036,0.185l1.748,0.328l0.702,0.231l0.989,0.317l0.767,0.143l0.145,0.204l0.004,0.541l0.182,0.481l0.408,0.451l0.421,0.333l1.643,0.531l0.673,0.113l2.48-0.538l0.796-0.077l1.172,0.037l1.423,0.022l0.769,0.229l1.333,0.75l0.623,0.331l1.132,0.313l0.812,0.373l1.318,0.254l0.905,0.241l0.984,0.082l0.739,0.039l1.602-0.11l1.018-0.063l0.532-0.075l0.867-0.106l1.147-0.136l0.526-0.163l0.604-0.264l0.447-0.394l0.755-0.498l1.165-0.487l0.333-0.002l0.609-0.047l0.74,0.156l0.751,0.506l0.34,0.129l0.86,0.169l1.228-0.297l0.622-0.018l0.431,0.168z"/> - <path id="BE" country:name="Belgium" d="M406.183,86.551l1.051-0.494l0.485-0.089l0.574,0.087l0.465-0.016l0.209-0.147l0.477,0.098l0.407,0.042l0.52-0.034l-0.025-0.157l0.307,0.012h0.307l0.267-0.182l0.313,0.242l0.173-0.121l0.228,0.061l0.292,0.375l0.535-0.109l0.754,0.375l-0.11,0.423l-0.172,0.097l0.001,0.338l0.672-0.024l0.344,0.177l0.282,0.365l0.038,0.468l-0.422,0.376l-0.225-0.072l-0.142,0.08l-0.245,0.147l-0.213,0.322l0.017,0.327l0.31,0.204l-0.136,0.348l-0.079-0.114l-0.694,0.174l-0.127-0.228l-0.371-0.204l-0.341-0.192l-0.529-0.048l0.039-0.228l-0.146-0.18l0.119-0.373l-0.245,0.072l-0.193,0.313l-0.446,0.035l-0.406,0.075l-0.285-0.122l0.072-0.198l-0.091-0.175l0.159-0.241l-0.375-0.168l-0.576-0.048l-0.259,0.012l-0.159-0.301l-0.518,0.012l-0.194-0.133l-0.202-0.458l-0.153-0.17l-0.41,0.208l-0.141,0.071l-0.266-0.127l-0.311-0.335l-0.208-0.447z"/> - <path id="SK" country:name="Slovakia" country:shortname="Slovakia" d="M438.22,91.952l0.039-0.044l0.065-0.105l0.014-0.131l0.092-0.066l0.146-0.119l0.026-0.04l0.171-0.053l0.093-0.026l0.092,0.053l0.132,0.053h0.158l0.065-0.026h0.093l0.065,0.026l0.065,0.026l0.093-0.026l0.145-0.04h0.132l0.118-0.053l0.079-0.053l0.066-0.026l0.105-0.026h0.039l0.053-0.079l0.04-0.092l0.079-0.079l0.092,0.026l0.105-0.04l0.145-0.066l0.053-0.105l0.053-0.079l0.026-0.132l0.026-0.092l0.053-0.092l0.118-0.013l0.105-0.013l0.132-0.079l0.119-0.053l0.118-0.092l0.053-0.079l0.132-0.066l0.065-0.04L442,89.998l0.145,0.013l0.105,0.026l0.066-0.04l0.065-0.066l0.071,0.012l0.285,0.041l0.03,0.228l0.43-0.048l0.183-0.24l0.193,0.016l0.062-0.112l0.261-0.024l0.194,0.24l0.073,0.169l0.331-0.025l0.066,0.18l-0.026,0.083l0.003,0.204l0.389-0.083l0.18,0.12l0.149-0.135l0.104-0.177l0.558-0.204l0.168,0.056l0.483-0.046l0.46,0.254l0.373-0.18l0.073-0.137l0.508,0.041l0.561-0.076l0.129,0.13l0.703,0.186l0.104,0.216l0.424,0.101l0.831,0.33l-1.047,1.471l-0.629,0.076l-0.437-0.143l-0.534-0.359l-1.062,0.035l-0.717,0.047l-1.024,0.759L444.857,93l-0.59-0.072l-0.499,0.061l-0.761,0.134l-0.255,0.001l-0.334,0.568l-1.651-0.036l-0.414-0.027l-0.617-0.17l-0.399-0.172l-0.245,0.146l-0.761-0.547l-0.155-0.26l0.097-0.581l-0.053-0.093z"/> - <path id="HU" country:name="Hungary" d="M442.391,98.111l-0.589,0.203l-0.433,0.031l-0.668,0.047l-0.58-0.098l-1.116-0.671l-1.412-0.612l-0.215-0.197l-0.364-0.333l-0.304-0.59l0.346-0.299l0.154-0.294l-0.204-0.188l0.04-0.375l0.409-0.062l0.157-0.206l-0.136-0.196l-0.452-0.063l0.223-0.197h0.325l0.164,0.134l0.701-0.054l0.019-0.367l0.636-0.291l0.245-0.146l0.399,0.172l0.617,0.17l0.414,0.027l1.651,0.036l0.334-0.568l0.255-0.001l0.761-0.134l0.499-0.061l0.59,0.072l0.427-0.063l1.024-0.759l0.717-0.047l1.062-0.035l0.534,0.359l0.437,0.143l0.629-0.076l0.166-0.015l0.668,0.301l0.554,0.2l0.678,0.387l-0.45,0.338l-1.125,0.267l-0.581,0.408l-0.968,1.451l-0.63,0.84l-0.753,0.567l-0.361,0.16l-0.724,0.047l-0.264,0.103l-0.176-0.002l-0.907-0.067l-0.889,0.077l-1.535,0.529z"/> - <path id="MD" country:name="Moldova" country:shortname="Moldova" d="M459.717,92.836l0.06-0.052l0.126-0.114l0.075,0.063h0.126l-0.012-0.113l0.088-0.101l0.315,0.114l0.126-0.051l0.265,0.038h0.202l0.126-0.114l0.062-0.038l0.177,0.025l0.177-0.051l0.139-0.025l0.088,0.025l0.114,0.051l0.05-0.025l0.126-0.025l0.038,0.013l0.214,0.088l0.14,0.126l0.139,0.05l0.151,0.013l0.101,0.063l0.05,0.063l0.076,0.076l0.101-0.013l0.126,0.025l0.177-0.038h0.113l0.025,0.063l-0.088,0.101l-0.038,0.05l0.101-0.038l0.089,0.025v0.076l0.062,0.05l0.076-0.101l0.062-0.051l0.277-0.012l0.417,0.075l0.05,0.189l0.126,0.189l0.215,0.025l0.126,0.025l0.062-0.101l0.14,0.013l0.062,0.126l0.076,0.063l0.113,0.025l-0.164,0.151l0.126,0.063l-0.051,0.05l-0.024,0.114v0.189l-0.177,0.139l0.05,0.139l0.102,0.139l0.139,0.025l0.188,0.101l0.089,0.101l0.113,0.088l0.088-0.051l0.102-0.05h0.113l0.038,0.088l0.025,0.101l-0.089,0.075l0.013,0.189l-0.113,0.038l0.062,0.114l0.127-0.038l0.037,0.051l-0.037,0.088l-0.051,0.151l0.151,0.038l0.151,0.063l0.151,0.126h0.075l0.177,0.076l0.101,0.063l0.051,0.139l0.013,0.126l-0.038,0.101l0.025,0.113l-0.101,0.063l-0.013,0.038l0.075,0.05l0.101,0.051l0.164,0.126l0.126,0.013l-0.075,0.076l-0.038,0.025h-0.227l-0.139-0.013l-0.038,0.038l-0.038,0.038l-0.176-0.025l0.037-0.189h-0.177l-0.101,0.025l-0.013,0.05l-0.075,0.076l-0.076,0.076l-0.126-0.164h-0.075l-0.089-0.063v-0.075l-0.139,0.012l-0.075,0.038l-0.025,0.076l-0.063-0.051l-0.101-0.038l0.013,0.063v0.088h-0.113l-0.063-0.013l0.013-0.214l-0.013-0.088l-0.113-0.025l-0.126,0.088l-0.239,0.025l-0.202,0.151l0.063,0.101l0.088,0.151l-0.051,0.101l0.114,0.113l0.012,0.088l-0.037,0.063l-0.126,0.114l0.062,0.088l0.025,0.088l-0.075,0.076l-0.29,0.063l-0.14,0.013l0.013,0.114l-0.024,0.126l-0.089,0.088l-0.088,0.063l-0.089,0.025l-0.075,0.013l-0.051,0.063l-0.126,0.063l-0.025,0.113l0.063,0.113v0.088l-0.088,0.114h-0.189l-0.113-0.013l-0.126-0.013l-0.102,0.025l-0.055,0.077l-0.03,0.004l-0.062-0.237l-0.218-0.106l0.16-0.071l-0.021-0.267l-0.104-0.561l0.323-0.978l0.027-0.404l-0.353-0.856l-0.604-0.286l-1.037-1.119L460.567,93l-0.626-0.191l-0.225,0.028z"/> - <path id="RO" country:name="Romania" d="M445.722,97.573l0.176,0.002l0.264-0.103l0.724-0.047l0.361-0.16l0.753-0.567l0.63-0.84l0.968-1.451l0.581-0.408l1.125-0.267l0.45-0.338l0.136-0.085l0.787,0.121l0.241-0.107l0.958,0.193l1.115,0.066l0.363-0.045l0.025,0.231l0.327-0.004l0.188,0.227l0.339-0.06l0.243-0.119l0.186-0.215l1.992-0.191l0.278-0.178l0.151-0.311l0.634-0.08l0.225-0.028L460.567,93l0.767,1.17l1.037,1.119l0.604,0.286l0.353,0.856l-0.027,0.404l-0.323,0.978l0.104,0.561l0.021,0.267l-0.16,0.071l0.218,0.106l0.062,0.237l0.03-0.004l0.15-0.02l0.119,0.249l0.398,0.166l0.609,0.047l0.033-0.189h0.457l0.665-0.261l0.706,0.131l0.149,0.079l0.062,0.259l-0.293,0.446l-0.27,0.316l-0.436,0.044l-0.382,0.043l-0.382,0.245l-0.515,0.617l-0.252,0.645l-0.096,0.787l-0.044,0.223l-0.671-0.12l-1.346-0.336l-0.514-0.226l-0.295-0.042l-0.671-0.369l-0.562-0.04l-0.618,0.218l-1.904,0.771l-0.38,0.059l-1.385-0.35l-0.3-0.013l-0.69,0.261l-0.34,0.031l-1.151-0.395l-0.506-0.002l-0.771,0.189l-0.266,0.023l-0.048-0.189l0.234-0.318l-0.352-0.106l-0.392-0.204l-0.418-0.186l-0.146-0.33l0.32-0.201l0.351,0.012l-0.114-0.13l-0.625-0.248l-0.253,0.13l-0.215,0.283l-0.147,0.118l-0.414-0.239l-0.194-0.139l-0.594-0.059l-0.02-0.189h-0.234l-0.245-0.036l-0.052-0.165l0.178-0.094l0.271-0.071l-0.239-0.083l-0.183-0.059l0.124-0.146l0.19-0.127l-0.069-0.142l-0.306-0.118l-0.555-0.141l-0.712-0.471l0.058-0.088l-0.104-0.119l0.075-0.356l-0.202-0.036l-0.19-0.237l-0.569-0.178l-0.054-0.309z"/> - <path id="IT" country:name="Italy" d="M420.177,113.472l-0.274-0.042l-0.253-0.155l-0.367-0.325l-0.096-0.213l0.202-0.738l0.097-0.681l-0.046-0.583l-0.133-0.569l-0.503-0.44l-0.094-0.271l0.181-0.157l0.366-0.015l0.801-0.001l0.339-0.172l0.861-0.543l0.633,0.625l0.451,0.754l-0.014,0.271l-0.204,0.285l-0.145,0.484l0.149,0.894l-0.11,0.525l-0.377,0.695l-0.405-0.198l-0.52,0.03l-0.143,0.1l-0.149,0.27l-0.248,0.17z M433.783,118.446l-0.712-0.084l-0.902-0.607l-0.772-0.239l-1.904-0.817l-0.833-0.126l-0.232-0.127l-0.173-0.283l0.139-0.34l0.328-0.34l0.264-0.1l0.629,0.112l0.569-0.341l0.68,0.424l0.403,0.141l0.722-0.016l1.403-0.187l1.38-0.329l0.148,0.085l0.043,0.127l-0.112,0.127l-0.536,0.823l-0.153,0.497l0.009,0.382l0.411,0.509l-0.179,0.128l-0.43,0.567l-0.188,0.015zM431.244,98.829l-0.281-0.329l-0.242-0.027l-0.281,0.196l-0.156-0.125l-0.47-0.071l-0.114,0.32l-0.458,0.054l-1.001,0.364l0.078-0.151l-0.452,0.133l-0.063,0.249l-0.157,0.044l-0.01,0.125l0.303,0.08l0.021,0.302l0.193,0.119l0.253,0.236l-0.104,0.213l-0.449,0.254l0.016,0.272l0.143,0.554l0.783,0.814l2.008,0.889l0.29,0.357l0.134,0.558l0.274,0.557l0.395,0.585l0.694,0.57l0.254,0.274l0.446,0.195l0.041,0.21l0.408,0.167l1.17,0.255l1.254-0.105l0.388,0.141l0.024,0.212l-0.465,0.247l-0.258,0.294l0.262,0.213l0.954,0.283l1.168,0.411l0.829,0.366l1.589,0.739l0.058,0.185l0.719,0.458l0.31,0.475l-0.198,0.435l-0.152,0.337l-0.455-0.281l-0.318-0.167l-0.109-0.486l-0.263-0.17l-0.512-0.099l-0.483-0.009l-0.439-0.236l0.086-0.217l-0.353-0.065l-0.301,0.098l-0.232,0.262l-0.259,0.399l-0.273,0.208l0.043,0.271l-0.197,0.303l-0.007,0.298l0.76,0.342l0.611,0.271l-0.093,0.314l0.03,0.432l0.133,0.142l-0.191,0.238l-0.659-0.024l-0.41,0.219l-0.202,0.228l0.11,0.595l-0.536,0.303l-0.617,0.866l-0.595,0.048l-0.167-0.071l-0.184-0.14l-0.002-0.508l0.364-0.141l0.317-0.542l-0.236-0.184l0.361-0.249l0.361,0.074l0.133-0.17l-0.077-0.34l-0.211-0.181l-0.206-0.924l-0.367-0.516l-0.15-0.607l-0.201-0.352l-0.334,0.058l-0.187,0.171l-0.899-0.496l-0.286-0.065l0.208-0.291l-0.092-0.398l-0.461-0.34l-0.909,0.247l0.034-0.109l0.322-0.194l-0.276-0.27l-0.29-0.003l-0.42,0.19l-0.242-0.512l-0.198-0.207l-0.124-0.228l-0.663-0.241l-0.505-0.027l-0.654-0.127l-0.745-0.355l-0.548-0.441l-0.959-0.612l-1.036-0.826l-0.872-0.384l-0.805-0.67l-0.566-0.856l-0.434-1.043l-0.347-0.443l-0.505-0.457l-0.483-0.243l-1.188-0.341l-0.579-0.142l-0.5,0.044l-1.078,0.647l-0.46,0.359l-0.646,0.173l-0.303,0.043l0.146-0.469l-0.062-0.281l-0.849,0.07l-0.754-0.391l-0.193-0.442l0.315-0.371l0.175-0.01l-0.135-0.331l-0.616-0.191l-0.352-0.358l0.437-0.186l0.183,0.111l0.541-0.353l0.199-0.272l-0.43-0.192l-0.025-0.292l-0.532-0.344l0.624-0.301l0.599,0.062l0.627-0.204l0.629,0.168l0.275-0.16l0.349-0.432l-0.103-0.212l0.777-0.404l0.016,0.415l0.534,0.363l0.311,0.071l-0.098,0.182l0.385,0.312l0.285-0.151l0.018-0.535l0.425-0.384l-0.019-0.333l0.371-0.081l0.143,0.354l0.23,0.142l0.216-0.03l0.071-0.122l0.469-0.05l0.244,0.333l0.228-0.415l-0.244-0.131l0.081-0.273l0.283-0.091l0.176,0.162l0.315,0.051l0.038-0.192l-0.112-0.212l0.126-0.309l0.631,0.171l0.597,0.034l0.329-0.411l0.366-0.096l0.183,0.083l0.445-0.11l0.301,0.103l0.856-0.227l0.023,0.363l0.318,0.096l0.32,0.391l1.311,0.247l0.894,0.082l0.478,0.112l0.116,0.199l-0.614,0.303l0.098,0.151l0.297,0.002l0.187,0.185l-0.367,0.285l0.336,0.089l-0.127,0.361l0.36,0.11l0.284,0.198l-0.056,0.214z"/> - <path id="SI" country:name="Slovenia" country:shortname="Slovenia" d="M430.73,96.731l1.04,0.065l0.179,0.107l0.612-0.009l0.287,0.152l0.646-0.5l0.566-0.107l0.85,0.08l0.298-0.196l0.89,0.116l-0.082-0.393l0.693-0.157l0.304,0.59l0.364,0.333l-0.035-0.009l-0.1-0.073l-0.145-0.036h-0.172l-0.145,0.009l-0.055,0.063v0.072l0.019,0.09l0.009,0.082l-0.063,0.009l-0.136-0.009l-0.108-0.036l-0.091,0.063l-0.045,0.082l-0.081,0.063l-0.082,0.045l-0.081,0.009l-0.163,0.036l-0.117,0.036l-0.108,0.036l-0.055,0.045l-0.153-0.009l-0.127,0.072l-0.063,0.054l-0.018,0.082l0.036,0.072l0.081,0.054l0.063,0.055l0.045,0.045l0.019,0.063l0.018,0.09l-0.036,0.108l-0.018,0.063l-0.046,0.1h-0.108l-0.081-0.009l-0.091,0.027l-0.108,0.009l-0.117,0.054l-0.091,0.018l-0.081,0.027l-0.1,0.045l-0.055,0.063l-0.036,0.027l0.055,0.018l0.063,0.009l0.026,0.027l0.037,0.072l-0.046,0.063l-0.027,0.009l-0.081,0.027l-0.009,0.045l0.045,0.081v0.072l0.045,0.1l-0.054,0.072l-0.063-0.018l-0.1,0.045l-0.117,0.018l-0.127-0.036l-0.063-0.027l-0.1-0.063h-0.099l-0.063-0.027l-0.118-0.045l-0.018,0.045l-0.027,0.045l-0.1,0.027h-0.136l-0.054-0.045l-0.072-0.063l-0.127-0.018l-0.019-0.09l-0.026-0.018l-0.063-0.054l-0.055-0.027l-0.018-0.054l-0.01-0.054l-0.036-0.009l-0.063,0.018l-0.036,0.054l-0.009,0.027l-0.054,0.063l-0.019,0.018l-0.018,0.081l-0.063,0.045l-0.046,0.018l-0.062,0.054l-0.036,0.009h-0.254l-0.108-0.027l-0.108,0.027l-0.145,0.009l-0.1-0.009l-0.1-0.036l-0.045-0.019h-0.055v0.037v0.036l-0.045,0.027l-0.045,0.018l-0.136-0.009l-0.027-0.036l-0.108,0.018l-0.019,0.018l-0.136,0.018l-0.063,0.018l-0.126,0.018l-0.272-0.063l0.428-0.077l0.113-0.16l0.056-0.214l-0.284-0.198l-0.36-0.11l0.127-0.361l-0.336-0.089l0.367-0.285l-0.187-0.185l-0.297-0.002l-0.098-0.151l0.614-0.303l-0.116-0.199z"/> - <path id="HR" country:name="Croatia" country:shortname="Croatia" d="M439.573,104.709l-1.051-0.672l-0.185-0.222l-0.783-0.149l-0.203-0.159l-0.403-0.115l-0.683,0.177l-0.326-0.486l-1.112-0.627l-0.584-0.678l0.277,0.007l0.608,0.016l-0.583-0.221l-0.659-0.469l-0.183-0.407l0.086-0.452l-0.289-0.336l-0.646-0.418l-0.378-0.126l-0.258,0.579l-0.142,0.116l0.03,0.15l-0.284,0.106l-0.154,0.248l-0.213,0.053l-0.496-0.647l-0.063-0.286l-0.259-0.612l0.065-0.012l0.272,0.063l0.126-0.018l0.063-0.018l0.136-0.018l0.019-0.018l0.108-0.018l0.027,0.036l0.136,0.009l0.045-0.018l0.045-0.027v-0.036v-0.037h0.055l0.045,0.019l0.1,0.036l0.1,0.009l0.145-0.009l0.108-0.027l0.108,0.027h0.254l0.036-0.009l0.062-0.054l0.046-0.018l0.063-0.045l0.018-0.081l0.019-0.018l0.054-0.063l0.009-0.027l0.036-0.054l0.063-0.018l0.036,0.009l0.01,0.054l0.018,0.054l0.055,0.027l0.063,0.054l0.026,0.018l0.019,0.09l0.127,0.018l0.072,0.063l0.054,0.045h0.136l0.1-0.027l0.027-0.045l0.018-0.045l0.118,0.045l0.063,0.027h0.099l0.1,0.063l0.063,0.027l0.127,0.036l0.117-0.018l0.1-0.045l0.063,0.018l0.054-0.072l-0.045-0.1v-0.072l-0.045-0.081l0.009-0.045l0.081-0.027l0.027-0.009l0.046-0.063l-0.037-0.072l-0.026-0.027l-0.063-0.009l-0.055-0.018l0.036-0.027l0.055-0.063l0.1-0.045l0.081-0.027l0.091-0.018l0.117-0.054l0.108-0.009l0.091-0.027l0.081,0.009h0.108l0.046-0.1l0.018-0.063l0.036-0.108l-0.018-0.09l-0.019-0.063l-0.045-0.045l-0.063-0.055l-0.081-0.054l-0.036-0.072l0.018-0.082l0.063-0.054l0.127-0.072l0.153,0.009l0.055-0.045l0.108-0.036l0.117-0.036l0.163-0.036l0.081-0.009l0.082-0.045l0.081-0.063l0.045-0.082l0.091-0.063l0.108,0.036l0.136,0.009l0.063-0.009l-0.009-0.082l-0.019-0.09v-0.072l0.055-0.063l0.145-0.009h0.172l0.145,0.036l0.1,0.073l0.035,0.009l0.215,0.197l1.412,0.612l1.116,0.671l0.58,0.098l0.668-0.047l0.433-0.031l0.589-0.203l0.201,0.142l0.056,0.089l0.022,0.112l-0.022,0.078l0.045,0.044l0.011,0.067l-0.078,0.056l-0.011,0.146l0.078,0.067l0.145-0.034l0.101,0.034l0.045,0.089l-0.078,0.011l-0.056-0.022l-0.022,0.078l0.033,0.1l-0.045,0.034l-0.044,0.022l0.066,0.111l0.168-0.022l0.033,0.078l0.123,0.1h0.122h0.101l0.09,0.078l0.122,0.011h0.134l0.012,0.078l-0.033,0.056l-0.135-0.011l-0.089-0.034l-0.067,0.022l-0.078-0.011l-0.066-0.045l-0.056-0.011l-0.045,0.011l0.033,0.067l-0.101,0.089h-0.078v0.156l0.045,0.067l-0.033,0.078l0.022,0.078l0.011,0.078l-0.089,0.033l-0.09-0.033l-0.056,0.067l0.078,0.089l-0.078,0.011l-0.189,0.022l-0.201-0.022l-0.145-0.123l0.056-0.101l-0.045-0.089l-0.123-0.011l-0.022-0.112l-0.145-0.056l-0.146-0.045l-0.101,0.089l-0.1-0.011l-0.156-0.078l-0.067-0.022h-0.146l-0.156-0.045l-0.111,0.067l-0.134,0.045l-0.134-0.045l-0.111-0.067h-0.112l-0.122,0.089l-0.168,0.078l-0.156-0.067l-0.268-0.089l-0.179,0.011l-0.156,0.011l-0.189-0.056l-0.168-0.011l-0.156-0.089l-0.089,0.078l-0.111,0.022l-0.057-0.056l-0.234-0.078l-0.156-0.056l-0.134-0.045l-0.089-0.011l-0.134,0.123l-0.112-0.011l-0.223-0.022l-0.168-0.033l-0.212,0.022l-0.101,0.111l-0.145,0.145l-0.123,0.201l-0.201-0.022l-0.256-0.134l-0.156-0.19l-0.101-0.111l-0.312-0.034l-0.123,0.044l-0.089,0.179l-0.045,0.167l0.045,0.134v0.078l0.033,0.212l-0.123,0.067l0.022,0.089l0.134,0.078l0.09,0.089l0.122,0.034l0.101,0.033l0.179,0.179l0.146,0.234l0.089,0.134l0.022,0.123l0.156,0.111l-0.078,0.056l-0.012,0.1l0.022,0.146l0.168-0.011l0.089,0.111l0.056,0.123l0.112,0.111l0.167,0.045l0.167,0.033l0.369,0.357l0.021,0.167l0.078,0.044l0.213,0.078l0.379,0.357l0.224,0.123l0.223,0.067l0.101,0.056v0.112l0.078,0.279l0.201,0.078l0.189,0.167l0.146,0.112l0.245,0.123l0.067,0.212l-0.284,0.083z M439.792,104.833l0.132-0.118l0.134,0.011l0.123,0.034l0.045,0.078l0.066,0.089l0.146,0.089l0.179,0.078l0.212,0.011l0.312,0.257l0.045,0.067l0.134-0.033l0.123,0.022l0.089,0.034l0.062,0.063l0.005,0.004l-0.022,0.089l0.033,0.078l0.082,0.072l0.029,0.092l-0.002,0.1l-0.589-0.367l-0.549-0.371l-0.789-0.378z"/> - <path id="SR" country:name="Serbia" country:shortname="Serbia" d="M451.009,101.725l-0.328,0.346l-0.383,0.374l-0.18,0.302l0.056,0.271l1.326,1.122l0.028,0.2l-0.302,0.302l-0.762,0.333l-0.246,0.301l-0.008,0.514l-0.013,0.208l-0.058-0.017l-0.072,0.029l-0.16,0.022l-0.145,0.021l-0.116,0.022l-0.058,0.015l-0.102-0.051l-0.087,0.043l-0.088,0.021l-0.102-0.043l-0.064-0.021l-0.131,0.116l-0.087,0.08l-0.152-0.015l-0.196-0.007l-0.064,0.007l-0.175-0.043l-0.152,0.087l-0.151,0.102l-0.109,0.058l0.059,0.072l-0.029,0.058h-0.116l-0.094-0.109l-0.131-0.058l-0.087-0.073l-0.08,0.065l-0.116,0.058l-0.246,0.058l-0.225,0.058l-0.088,0.058l-0.058,0.167l0.029,0.13l-0.029,0.072l-0.072,0.087h-0.188l-0.14-0.049l-0.018-0.109l-0.733-0.866l-0.382-0.369l-0.058-0.004l0.109-0.286v-0.067l-0.078-0.067h-0.101l-0.056-0.056l0.022-0.089l0.111-0.033l0.146,0.011l0.167,0.033l0.057-0.033l0.021-0.067l0.09-0.044l0.134-0.022l0.089-0.011l-0.011-0.089l-0.101-0.101l-0.167-0.067l-0.134-0.045l-0.057-0.044l-0.111,0.022l-0.078-0.045l-0.033-0.067l-0.123-0.101l-0.078-0.1l-0.066-0.022l-0.067,0.044l-0.078-0.011l-0.101-0.056l-0.279-0.078l-0.078-0.022l-0.056-0.033l-0.167-0.134l-0.101-0.146l-0.111-0.111l-0.168-0.078l-0.156-0.101l-0.223-0.056v-0.101l0.179-0.101l0.089-0.111l0.078-0.011l0.067,0.034l0.078,0.044l0.1,0.022l0.045-0.022l0.012-0.134l0.011-0.19l-0.134-0.145l-0.179-0.19l-0.212-0.134l-0.101-0.145l0.101,0.022l0.101,0.011l0.145,0.056l0.224,0.044l0.134-0.078l0.089-0.056l0.067-0.078l-0.089-0.044l-0.135-0.022l-0.089-0.089l-0.123-0.078l-0.156-0.089l-0.033-0.101l-0.045-0.1l-0.212,0.011l-0.167-0.056l-0.078-0.1l-0.022-0.134l0.078-0.067v-0.089l-0.033-0.1l0.056-0.056l0.066-0.078l0.156-0.156l0.156-0.223l0.034-0.167l0.056-0.1l-0.022-0.067l-0.123-0.022l-0.179-0.011h-0.156l-0.212,0.112l-0.078-0.089l0.056-0.067l0.09,0.033l0.089-0.033l-0.011-0.078l-0.022-0.078l0.033-0.078l-0.045-0.067v-0.156h0.078l0.101-0.089l-0.033-0.067l0.045-0.011l0.056,0.011l0.066,0.045l0.078,0.011l0.067-0.022l0.089,0.034l0.135,0.011l0.033-0.056l-0.012-0.078h-0.134l-0.122-0.011l-0.09-0.078h-0.101h-0.122l-0.123-0.1l-0.033-0.078l-0.168,0.022l-0.066-0.111l0.044-0.022l0.045-0.034l-0.033-0.1l0.022-0.078l0.056,0.022l0.078-0.011l-0.045-0.089l-0.101-0.034l-0.145,0.034l-0.078-0.067l0.011-0.146l0.078-0.056l-0.011-0.067l-0.045-0.044l0.022-0.078l-0.022-0.112l-0.056-0.089l-0.201-0.142l1.535-0.529l0.889-0.077l0.907,0.067l0.054,0.309l0.569,0.178l0.19,0.237l0.202,0.036l-0.075,0.356l0.104,0.119l-0.058,0.088l0.712,0.471l0.555,0.141l0.306,0.118l0.069,0.142l-0.19,0.127l-0.124,0.146l0.183,0.059l0.239,0.083l-0.271,0.071l-0.178,0.094l0.052,0.165l0.245,0.036h0.234l0.02,0.189l0.594,0.059l0.194,0.139l0.414,0.239l0.147-0.118l0.215-0.283l0.253-0.13l0.625,0.248l0.114,0.13l-0.351-0.012l-0.32,0.201l0.146,0.33l0.418,0.186z"/> - <path id="UZ" country:name="Uzbekistan" country:shortname="Uzbekistan" d="M551.198,117.997l-0.351-0.48l-0.236-0.126l-1.217-0.05l-0.646-0.011l-0.096-0.016l0.091-0.726l-0.062-0.503l0.157-0.251l0.062-0.22l-0.503-0.094l-0.534-0.283l-0.566-0.189l-0.471,0.063l-0.378-0.251l-1.132-0.597l-0.565-0.22l-0.943-0.597l-0.314,0.063l-1.006-0.503l-0.377-0.44l-1.194-0.597l-1.384-0.975v-0.283l-0.188-0.44l-0.283-0.188l-0.408-0.597l-0.126-0.566l-0.22-0.377l-0.881-0.251l-0.188,0.157l-0.439,0.063l-0.535-0.126l-0.439,0.032l-0.503,0.094l-0.314-0.157l-0.691-0.314l0.094-0.22l0.157-0.188l-0.188-0.22l0.031-0.188l0.188-0.157l-0.439-0.283v-0.22l-0.032-0.22l-0.251-0.22l-0.534-0.094l-0.692-0.095l-0.22-0.314l-0.346-0.032l-0.629-0.377l-0.472-0.095l-0.188,0.063l-0.565,0.157l0.251,0.251l0.188,0.377l-0.597-0.283h-0.283l-0.126,0.126l-0.22,0.346l-0.283,0.126h-0.629l-0.503,0.251l-0.503,0.409l-0.062,0.628l0.314,0.409l-0.126,0.314l-1.383,0.032l-1.03-0.063l0.056-8.174l5.658-1.289l5.722,2.986l2.012,1.666l2.578-0.346l2.767,0.188l1.1-0.409l0.724,0.723l0.597,0.22l0.66,1.006l0.66-0.314l-0.031,1.038l-0.188,0.409l0.031,0.754h1.006l0.221,0.817l0.346,1.069l0.503,0.063l0.691-0.032l1.006-0.094h0.346l0.44,0.314l0.062,0.283l-0.062,0.283l0.44,0.346h0.66l0.125-0.188l-0.157-0.409l0.504-0.44l0.439-0.188l0.221-0.472l0.282-0.188l0.943-0.377l0.755-0.189l0.534-0.471l0.346-0.283l0.22-0.063l0.283,0.126l0.377-0.377l0.322-0.031l0.349-0.126l0.441,0.246l-0.368,0.172l-0.368,0.171l-0.221,0.049l-0.073,0.196l-0.295,0.049l-0.294,0.172l-0.196,0.147l-0.441,0.295l-0.172,0.098l-0.024,0.123l0.294,0.049l0.295,0.074l0.146,0.123l0.418-0.147l0.098,0.221l0.172,0.221l0.368,0.27h0.589h0.393l0.049-0.393l0.221,0.049l0.196-0.196l0.024-0.245l0.196,0.098l0.196,0.172l0.172,0.294l0.049,0.147l0.393,0.024l0.147-0.024l0.073,0.246l0.025,0.098l0.343-0.025l0.319,0.147l0.245,0.196l0.516,0.074l0.466,0.024l0.172,0.123l-0.49,0.221l-0.197,0.147l-0.221,0.147l-0.49-0.024l-0.245-0.049l0.049,0.171v0.147h-0.319l-0.172,0.049l-0.343,0.196l-0.221,0.196l-0.271,0.049l-0.221,0.196l-0.245-0.147l-0.319-0.098l-0.294-0.098l-0.221,0.025l-0.246,0.073l-0.318-0.073l-0.042,0.098l-0.345-0.005l-0.409,0.031l-0.188-0.283l-0.251-0.063l-0.126-0.188l0.251-0.126l0.409-0.346l0.188-0.22l-0.252-0.251l-0.439-0.377l-0.221,0.251l-0.471,0.346l-0.692,0.188l-0.22,0.157l-0.252-0.22l-0.22-0.157h-0.346l0.031,0.22l-0.283,0.314l0.189,0.314l-0.032,0.346l-0.062,0.126l-0.472-0.095l-0.565,0.095l-0.503,0.094l0.251,0.125l0.534-0.031l0.126,0.094l-0.251,0.063l-0.188,0.063l-0.032,0.346h-0.188l-0.251,0.157l-0.063,0.409l-0.282,0.188l-1.069-0.094l-0.629-0.126l-0.472,0.283l-0.125,0.471l0.251,0.283l0.346,0.188l0.157,0.157l0.44,0.032h0.346l0.126,0.22l-0.126,0.22l-0.031,0.472l0.126,0.409l0.471,0.314l0.126,0.283l-0.157,0.22l-0.503,0.346l-0.283,0.503l-0.377,0.377l0.063,0.377l-0.375,0.843z"/> - <path id="BA" country:name="Bosnia and Herzegovina" country:shortname="Bosnia/Herz" d="M439.792,104.833l-0.113-0.054l-0.105-0.07l0.284-0.083l-0.067-0.212l-0.245-0.123l-0.146-0.112l-0.189-0.167l-0.201-0.078l-0.078-0.279v-0.112l-0.101-0.056l-0.223-0.067l-0.224-0.123l-0.379-0.357l-0.213-0.078l-0.078-0.044l-0.021-0.167l-0.369-0.357l-0.167-0.033l-0.167-0.045l-0.112-0.111l-0.056-0.123l-0.089-0.111l-0.168,0.011l-0.022-0.146l0.012-0.1l0.078-0.056l-0.156-0.111l-0.022-0.123l-0.089-0.134l-0.146-0.234l-0.179-0.179l-0.101-0.033l-0.122-0.034l-0.09-0.089l-0.134-0.078l-0.022-0.089l0.123-0.067l-0.033-0.212v-0.078l-0.045-0.134l0.045-0.167l0.089-0.179l0.123-0.044l0.312,0.034l0.101,0.111l0.156,0.19l0.256,0.134l0.201,0.022l0.123-0.201l0.145-0.145l0.101-0.111l0.212-0.022l0.168,0.033l0.223,0.022l0.112,0.011l0.134-0.123l0.089,0.011l0.134,0.045l0.156,0.056l0.234,0.078l0.057,0.056l0.111-0.022l0.089-0.078l0.156,0.089l0.168,0.011l0.189,0.056l0.156-0.011l0.179-0.011l0.268,0.089l0.156,0.067l0.168-0.078l0.122-0.089h0.112l0.111,0.067l0.134,0.045l0.134-0.045l0.111-0.067l0.156,0.045h0.146l0.067,0.022l0.156,0.078l0.1,0.011l0.101-0.089l0.146,0.045l0.145,0.056l0.022,0.112l0.123,0.011l0.045,0.089l-0.056,0.101l0.145,0.123l0.201,0.022l0.189-0.022l0.078-0.011l0.212-0.112h0.156l0.179,0.011l0.123,0.022l0.022,0.067l-0.056,0.1l-0.034,0.167l-0.156,0.223l-0.156,0.156l-0.066,0.078l-0.056,0.056l0.033,0.1v0.089l-0.078,0.067l0.022,0.134l0.078,0.1l0.167,0.056l0.212-0.011l0.045,0.1l0.033,0.101l0.156,0.089l0.123,0.078l0.089,0.089l0.135,0.022l0.089,0.044l-0.067,0.078l-0.089,0.056l-0.134,0.078l-0.224-0.044l-0.145-0.056l-0.101-0.011l-0.101-0.022l0.101,0.145l0.212,0.134l0.179,0.19l0.134,0.145l-0.011,0.19l-0.012,0.134l-0.045,0.022l-0.1-0.022l-0.078-0.044l-0.067-0.034l-0.078,0.011l-0.089,0.111l-0.179,0.101l-0.056-0.033l-0.156,0.056l-0.112-0.022l-0.066-0.044l-0.112,0.033l-0.078,0.056l0.012,0.078l0.089,0.1l0.123,0.167l0.056,0.101l-0.056,0.101h-0.111l-0.09-0.056l-0.056-0.089l-0.056-0.044l-0.123-0.011l-0.122,0.056l-0.168,0.078l-0.045,0.101l-0.044,0.089l-0.112,0.101l0.034,0.089l0.011,0.1L442,104.458l-0.134,0.011l-0.111,0.022l-0.101,0.089l-0.012,0.134l0.012,0.112l0.011,0.145l0.012,0.044l0.066,0.112l0.078,0.089l0.045,0.101l-0.09,0.089l-0.183,0.108l-0.062-0.063l-0.089-0.034l-0.123-0.022l-0.134,0.033l-0.045-0.067l-0.312-0.257l-0.212-0.011l-0.179-0.078l-0.146-0.089l-0.066-0.089l-0.045-0.078l-0.123-0.034l-0.134-0.011l-0.132,0.118z"/> - <path id="BG" country:name="Bulgaria" d="M450.198,105.998l0.013-0.208l0.008-0.514l0.246-0.301l0.762-0.333l0.302-0.302l-0.028-0.2l-1.326-1.122l-0.056-0.271l0.18-0.302l0.383-0.374l0.328-0.346l0.392,0.204l0.352,0.106l-0.234,0.318l0.048,0.189l0.266-0.023l0.771-0.189l0.506,0.002l1.151,0.395l0.34-0.031l0.69-0.261l0.3,0.013l1.385,0.35l0.38-0.059l1.904-0.771l0.618-0.218l0.562,0.04l0.671,0.369l0.295,0.042l0.514,0.226l1.346,0.336l0.671,0.12l-0.066,0.335l-0.077,0.258l-0.261,0.086l-0.313-0.028l-0.339,0.129l-0.327,0.73l-0.039,0.586l-0.075,0.143l-0.404,0.115l-0.338,0.372l-0.017,0.257l0.252-0.036l0.255,0.224l0.033,0.154l0.391,0.375l0.01,0.223l-1.333-0.005l-0.527-0.111l-0.497,0.045l-0.629,0.374l-0.498,0.445l-0.363-0.026l-0.344,0.216l0.097,0.327l-0.086,0.257l-1.117,0.277l-0.388,0.031l-0.619-0.21l-1.473-0.505l-0.584,0.06l-0.799,0.261l-1.855,0.195l-0.09,0.029l-0.047-0.199l0.104-0.3l0.006-0.499l-0.225-0.469l-0.358-0.383l-0.666-0.296l-0.134-0.213l0.007-0.106z"/> - <path id="ES" country:name="Spain" d="M381.009,107l-0.121-0.278l0.138-0.4l0.343-0.5l-0.358-0.471l-0.304-0.428l-0.514-0.07l-0.164-0.1l-0.053-0.329l0.163-0.243l0.409-0.272l0.365-0.101l0.563-0.03l0.634-0.03l0.133-0.172l0.068-0.415l0.535-0.273l0.763,0.042l1.078,0.37l0.763,0.07l0.756-0.087l0.577-0.173l0.508-0.144l0.354-0.001l0.629,0.285l0.694,0.156l0.939,0.084l1.538,0.04l0.583,0.027l0.957,0.141l0.491-0.158l0.419-0.229l0.531,0.027l0.891,0.47l0.67-0.016l0.335,0.062l0.472,0.243l0.469-0.03l0.058,0.122l-0.205,0.243l0.094,0.106l0.15,0.03l0.112-0.106l1.088,0.334l0.15-0.061l0.507,0.395l0.056-0.076l0.262,0.03l0.131-0.076l0.431,0.152l0.028,0.038l0.084,0.114l0.767-0.03l0.037,0.122l0.337-0.061l0.542,0.015l-0.017-0.319h0.355l1.252,0.304l0.091,0.213l0.035,0.289l0.187,0.076l0.374-0.076l0.206-0.03l0.335,0.091l0.036,0.152l0.261,0.015l0.395-0.167l0.427,0.197l0.485,0.015l0.039-0.136l0.75-0.137l0.334,0.091l-0.001,0.088l-0.001,0.463l0.156,0.1l-0.062,0.485l-1.112,0.528l-0.95,0.385l-0.267,0.328l-1.046,0.198l-0.664,0.116l-0.96,0.301l-0.323,0.326l-0.053,0.2l0.261,0.128l-0.088,0.157l-0.628,0.143l-0.594,0.783l-0.886,0.787l-0.096,0.192l-0.18,0.361l-0.245,0.45l0.353,0.827l0.072,0.111l0.084,0.13l0.648,0.295l0.103,0.185l-0.621,0.327l-0.215,0.105l-0.515,0.252l-0.286,0.479l-0.224,0.085l-0.461,0.926l0.155,0.322l-0.257,0.099l-0.992,0.049l-0.581,0.242l-0.425,0.327l-0.274,0.757l-0.663,0.496l-0.258-0.213l-0.599,0.028l-0.305,0.27h-0.342l-0.121-0.113l-3.282,0.042l-0.69,0.524l-1.021,0.17l-0.35,0.382l-0.028,0.283l-0.083,0.085l-0.073-0.212l-0.068-0.014l0.005,0.241l-0.389,0.127l-0.421-0.142l-0.788-0.467l-0.224-0.382l0.036-0.262l-0.345-0.113l-0.125-0.213l0.175-0.163l-0.468-0.51l-0.702-0.284L385,117.498l-0.484-0.135l-0.586,0.039l0.008-0.018l0.304-0.951l0.242-0.37l0.884-0.643l-0.408-0.31l-0.812-0.123l0.17-0.455l0.506-0.655l0.347-0.371l-0.163-0.198l-0.455-0.551l-0.488-0.494l0.288-0.129l0.482-0.045l0.458-0.229l0.043-0.199l-0.057-0.938l0.132-0.983l-0.072-0.456l0.051-0.442l0.084-0.072l1.234-0.506l0.288-0.216l-0.062-0.242l-0.842-0.495l-0.15-0.242l-0.272-0.227l-0.335-0.055l-0.531,0.26L382.981,107l-0.531-0.439l-0.55,0.188L381.009,107z"/> - <path id="GE" country:name="Georgia" country:shortname="Georgia" d="M489.685,103.693l0.112-0.309l0.26-0.166l0.284,0.047l0.07,0.047l0.402,0.023l0.449,0.023l0.283,0.095l0.284,0.142l0.188,0.094l0.189,0.047h0.331h0.213l0.212,0.166l0.261,0.095l0.307,0.071l0.355,0.047h0.307l0.426-0.095h0.544l0.401,0.166h0.189l0.283-0.047l0.354,0.166l0.095,0.142l0.284,0.213l0.52,0.118l0.354,0.071l0.236,0.118l0.308,0.119l-0.142,0.118l-0.048,0.118l0.261,0.118l0.212,0.071l0.261-0.118h0.283l0.166-0.166l0.094-0.095l0.213-0.071h0.354l0.261,0.071l0.188,0.142l0.142-0.166l0.095-0.071h0.118l0.236,0.118l0.143,0.094h0.212l0.189,0.118l0.213,0.166h0.378l0.354,0.024l0.118,0.142l-0.118,0.189l-0.118,0.307l0.354,0.284l0.284,0.166l0.26,0.094l0.284,0.047l0.236-0.023l0.236,0.071l0.126,0.189l-0.268,0.189l-0.143,0.142l-0.095,0.071l0.143,0.26l0.213,0.307l0.614,0.166l0.118,0.213l-0.095,0.331l-0.236,0.095l-0.236,0.047l-0.26-0.189l-0.143-0.071l-0.188-0.023l-0.284,0.047l-0.638-0.189l-0.189-0.213l-0.331-0.189l-0.473-0.024h-0.236l-0.418,0.308l-0.291,0.094l-0.378,0.047l-0.591,0.095l-0.592-0.047l-0.401,0.118l-0.426,0.023l-0.308,0.095l-0.307-0.024l-0.377,0.108l-0.031-0.028l-1.326-1.018l-0.41-0.041l-0.761,0.36l-0.226,0.072l-0.491-0.068l-1.212-0.082l0.083-0.065l0.322-0.585l0.032-0.143l-0.064-0.728l-0.331-1.084l-0.206-0.399l-0.639-0.513l-0.341-0.128l-0.916-0.155l-0.679-0.271l-0.341-0.243z"/> - <path id="MW" country:name="Montenegro" country:shortname="Montenegro" d="M443.617,107.095l-0.065-0.035l-0.435-0.156l-0.017-0.15l-0.501-0.485l-0.848-0.3l-0.033-0.021l0.002-0.1l-0.029-0.092l-0.082-0.072l-0.033-0.078l0.022-0.089l-0.005-0.004l0.183-0.108l0.09-0.089l-0.045-0.101l-0.078-0.089l-0.066-0.112l-0.012-0.044l-0.011-0.145l-0.012-0.112l0.012-0.134l0.101-0.089l0.111-0.022l0.134-0.011l0.056-0.056l-0.011-0.1l-0.034-0.089l0.112-0.101l0.044-0.089l0.045-0.101l0.168-0.078l0.122-0.056l0.123,0.011l0.056,0.044l0.056,0.089l0.09,0.056h0.111l0.056-0.101l-0.056-0.101l-0.123-0.167l-0.089-0.1l-0.012-0.078l0.078-0.056l0.112-0.033l0.066,0.044l0.112,0.022l0.156-0.056l0.056,0.033v0.101l0.223,0.056l0.156,0.101l0.168,0.078l0.111,0.111l0.101,0.146l0.167,0.134l0.056,0.033l0.078,0.022l0.279,0.078l0.101,0.056l0.078,0.011l0.067-0.044l0.066,0.022l0.078,0.1l0.123,0.101l0.033,0.067l0.078,0.045l0.111-0.022l0.057,0.044l0.134,0.045l0.167,0.067l0.101,0.101l0.011,0.089l-0.089,0.011l-0.134,0.022l-0.09,0.044l-0.021,0.067l-0.057,0.033l-0.167-0.033l-0.146-0.011l-0.111,0.033l-0.022,0.089l0.056,0.056h0.101l0.078,0.067v0.067l-0.109,0.286l-0.361-0.022l-0.727-0.11l-0.273,0.273l-0.279,0.515l0.133,0.427l-0.002,0.342z"/> - <path id="KG" country:name="Kyrgyzstan" country:shortname="Kyrgyzstan" d="M558.52,110.652l0.042-0.098l0.318,0.073l0.246-0.073l0.221-0.025l0.294,0.098l0.319,0.098l0.245,0.147l0.221-0.196l0.271-0.049l0.221-0.196l0.343-0.196l0.172-0.049h0.319v-0.147l-0.049-0.171l0.245,0.049l0.49,0.024l0.221-0.147l0.197-0.147l0.49-0.221l-0.172-0.123l-0.466-0.024l-0.516-0.074l-0.245-0.196l-0.319-0.147l-0.343,0.025l-0.025-0.098l-0.073-0.246l-0.147,0.024l-0.393-0.024l-0.049-0.147l-0.172-0.294l-0.196-0.172l-0.196-0.098l-0.024,0.245l-0.196,0.196l-0.221-0.049l-0.049,0.393h-0.393h-0.589l-0.368-0.27l-0.172-0.221l-0.098-0.221l-0.418,0.147l-0.146-0.123l-0.295-0.074l-0.294-0.049l0.024-0.123l0.172-0.098l0.441-0.295l0.196-0.147l0.294-0.172l0.295-0.049l0.073-0.196l0.221-0.049l0.368-0.171l0.368-0.172l-0.441-0.246l-0.349,0.126l-0.044-0.273l0.393-0.442l0.318-0.368l0.736-0.123l0.663-0.098l0.883,0.147l0.883,0.245l0.688,0.196l0.81,0.123l0.344,0.123l-0.024-0.442l0.245-0.736l0.466-0.368l0.688-0.123l0.589,0.074l0.761,0.27l0.735,0.246l0.908,0.196l0.54,0.098l0.441-0.27l0.858-0.024h0.761l0.785-0.147l0.712,0.221l0.662,0.098l1.35,0.024l0.662-0.074l0.981,0.246l0.564-0.049l0.147,0.344l0.27,0.147l0.196,0.27h0.663l0.466,0.098l0.41,0.375l0.031,0.194l-0.051,0.157l-0.325,0.187l-0.97,0.219l-1.338,0.349l-0.445,0.145l-0.405,0.301l-0.638,0.701l-0.646,0.345l-0.478,0.102l-0.459,0.017l-1.248-0.235l-0.238,0.03l-0.467,0.472l-0.463,0.784l-0.268,0.243l-0.885,0.132l-0.507,0.145l-0.344-0.055l-0.183-0.567l-0.06-0.071l-0.359,0.03l-1.737,0.734l-1.422,0.704l-0.274,0.186l-0.129,0.213l-0.139,0.739l-0.196-0.073l-0.344,0.098l-0.344,0.171h-0.539l-0.663-0.073l-0.834,0.221l-0.172,0.147h-0.196l-0.172-0.319l-0.368,0.024l-0.318,0.172l-0.074-0.221l-0.049-0.172l-0.122,0.024l-0.319-0.123l-0.049-0.147l-0.221-0.024l-0.442,0.123l-0.343,0.049l0.024,0.221l-0.295,0.049l-0.393-0.074l-0.073-0.196l-0.147-0.123l-0.368-0.098l-0.49,0.147l-0.196-0.073l-0.688,0.024h-0.564l-0.589,0.024l-0.122-0.098l-0.049-0.147l-0.099-0.27l0.099-0.245l0.196-0.196l0.098,0.221l0.196-0.074l-0.049-0.196l0.098-0.27h0.123l0.981-0.196l0.515,0.147l0.516,0.196l0.099,0.172h0.196l0.024-0.246l0.441-0.196l0.302-0.147z"/> - <path id="KP" country:name="Korea, Democratic People's Republic of" country:shortname="Korea D P Rp" d="M685.343,114.455l-0.571,0.678l-0.309,0.115l-0.511-0.096l-0.579-0.068l-0.595-0.011l-0.315,0.157l-0.633,0.738l-0.283,0.256l-0.235,0.171l-0.268-0.206l-0.35,0.34l-0.319,0.199l-0.373-0.608l-0.398-0.112l-0.649,0.78l-0.195-0.382l-0.232-0.254l-0.683-0.367l-0.169-0.453l0.095-0.312l0.429-0.411l0.754-0.229l0.056-0.269l-0.591-0.282l0.407-0.879l0.189-0.34l-0.199-0.269l-0.632-0.296l-0.139,0l-0.381,0.029l-0.312,0.143l-0.234-0.07l-0.52-0.368l-0.167-0.233l0.379-0.528l0.415-0.442l0.52-0.329l1.533-0.604l1.032-0.545l0.636-0.543l0.686-1.027l0.386-0.13l0.448-0.017l0.273,0.396l0.493,0.253l0.508,0.153l0.975-0.048l0.527-0.159l-0.046-0.113l-0.508-0.765l0.025-0.342l0.273-0.243l0.392-0.059l0.333,0.126l0.452,0.054l0.538-0.017l0.62-0.259l0.955-0.532l0.23-0.713l0.383-0.358l0.253-0.129l0.247-0.001l0.579,0.68l0.298,0.439l0.167,0.393l-1.356,0.923l-0.408,0.457l-0.112,0.414l0.09,0.427l-0.154,0.456l-0.187,0.868l-0.668,0.115l-0.36,0.229l-0.497,0.385l-0.766,0.641l-0.468,0.214l-0.678,0.03l-0.577,0.199l-0.265,0.228l-0.248,0.312l-0.364,0.893l0.284,0.326l1.225,0.847l0.419,0.354z"/> - <path id="TM" country:name="Turkmenistan" country:shortname="Turkmenistan" d="M536.625,121.017l-0.078-0.028l-0.15-0.692l-0.01-0.565l-0.038-0.848l-0.185-0.211l-0.787,0.075l-0.696-0.01l-0.655-0.506l-1.803-1.362l-0.597-0.336l-0.66-0.167l-0.5-0.054l-0.788-0.066l-0.822-0.335l-0.708-0.251l-0.402-0.437l-1.055-0.107l-0.519-0.054l-0.343,0.129l-0.517,0.343l-0.333,0.03l-0.78-0.038l-0.609,0.032l-0.413,0.144l-0.476,0.328l-0.621,0.654l-0.466,0.3l-0.562,0.13l-0.441-0.025l-0.066-0.376l-0.128-0.681l-0.106-0.447l0.128-0.298v-0.383v-0.532l0.106-0.191l0.106-0.298l0.085-0.234l-0.085-0.212l-0.256-0.128l-0.319-0.191l-0.213-0.255l-0.042-0.149h-0.171l-0.191-0.042l-0.361-0.106l-0.191,0.192l-0.086-0.234l0.086-0.106l0.148-0.255l0.128,0.106l0.383-0.042l0.426,0.085l0.128,0.021l0.043-0.128l-0.319-0.213l-0.256-0.021l-0.085-0.277l0.17-0.255l0.213-0.191l-0.404-0.042l-0.319,0.085h-0.383l-0.319-0.085l-0.128,0.149l-0.17-0.255l-0.149-0.298v-0.34l-0.042-0.298l0.17-0.213l0.106-0.319l0.043-0.255l0.105-0.277l0.086-0.234l0.213,0.34l0.063,0.128l0.17,0.17l0.405-0.085l0.383,0.128l0.106-0.149l-0.021-0.149h0.106l0.148,0.021l0.064,0.319l0.106,0.191l0.298-0.021l0.298-0.063l0.256-0.106l0.233,0.085l0.192,0.064l0.085-0.128l-0.149-0.191l-0.042-0.213l0.191-0.042l0.106,0.149l0.233,0.085l0.256-0.085l0.213-0.064l0.021-0.234l-0.171-0.341l-0.34-0.234l-0.532-0.319l-0.426-0.213l-0.063-0.319l-0.043-0.34l-0.213-0.17v-0.213v-0.213l-0.085-0.127l-0.554-0.064l-0.617,0.085l-0.426,0.021l-0.446,0.127l-0.192,0.277l-0.085,0.298l0.128,0.192l-0.063,0.276l-0.086,0.405l0.064,0.234l0.021,0.298l-0.256-0.553l-0.361-0.319l0.042-0.17l-0.063-0.191l-0.274-0.143l0.529-0.453l0.937-0.532l1.277-0.298l0.979-0.085l0.512,0.234l0.681,0.383l0.617,0.383l0.256,0.511l0.638,0.703l0.447,0.255l0.489-0.043l0.341-0.106l0.158,0.014l1.03,0.063l1.383-0.032l0.126-0.314l-0.314-0.409l0.062-0.628l0.503-0.409l0.503-0.251h0.629l0.283-0.126l0.22-0.346l0.126-0.126h0.283l0.597,0.283l-0.188-0.377l-0.251-0.251l0.565-0.157l0.188-0.063l0.472,0.095l0.629,0.377l0.346,0.032l0.22,0.314l0.692,0.095l0.534,0.094l0.251,0.22l0.032,0.22v0.22l0.439,0.283l-0.188,0.157l-0.031,0.188l0.188,0.22l-0.157,0.188l-0.094,0.22l0.691,0.314l0.314,0.157l0.503-0.094l0.439-0.032l0.535,0.126l0.439-0.063l0.188-0.157l0.881,0.251l0.22,0.377l0.126,0.566l0.408,0.597l0.283,0.188l0.188,0.44v0.283l1.384,0.975l1.194,0.597l0.377,0.44l1.006,0.503l0.314-0.063l0.943,0.597l0.565,0.22l1.132,0.597l0.378,0.251l0.471-0.063l0.566,0.189l0.534,0.283l0.503,0.094l-0.062,0.22l-0.157,0.251l0.062,0.503l-0.091,0.726l-1.454-0.244l-0.565-0.294l-0.445,0.356l-0.417,0.2l-1.135,0.205l-0.432,0.809l-0.203,0.991l-0.103,0.128l-0.508,0.243l-1.985,0.689l-0.568,0.159l-0.119,0.199l-0.001,0.466l-0.22,0.199l-0.636,0.3l-0.534,0.031l-0.573-0.082l-0.999-0.348l-0.937-0.193l-0.193-0.112z"/> - <path id="AL" country:name="Albania" d="M445.294,112.196l-0.07-0.115l-0.138-0.469l-0.5-0.452l-0.966-0.541l0.024-0.141l0.23,0.062l0.023-0.237l-0.345-0.414l0.418-0.616l-0.182-0.22l0.188-0.563l-0.251-0.282l0.182-0.396l0.268-0.079l-0.027-0.45l-0.331-0.081l-0.2-0.107l0.002-0.342l-0.133-0.427l0.279-0.515l0.273-0.273l0.727,0.11l0.361,0.022l0.058,0.004l0.382,0.369l0.733,0.866l0.018,0.109l0.035,0.218l-0.132,0.429l0.074,0.641l0.298,0.668l0.722,0.608l-0.09,0.029l-0.449,0.842l-0.402,0.386l-0.496,0.472l-0.583,0.884z"/> - <path id="MK" country:name="Macedonia" country:shortname="Macedonia" d="M451.512,108.463l-0.507,0.16l-0.532,0.245l-0.622-0.054l-0.361-0.041l-0.365,0.159l-0.395,0.429l-0.606,0.146l-0.809,0.076l-0.722-0.608l-0.298-0.668l-0.074-0.641l0.132-0.429l-0.035-0.218l0.14,0.049h0.188l0.072-0.087l0.029-0.072l-0.029-0.13l0.058-0.167l0.088-0.058l0.225-0.058l0.246-0.058l0.116-0.058l0.08-0.065l0.087,0.073l0.131,0.058l0.094,0.109h0.116l0.029-0.058l-0.059-0.072l0.109-0.058l0.151-0.102l0.152-0.087l0.175,0.043l0.064-0.007l0.196,0.007l0.152,0.015l0.087-0.08l0.131-0.116l0.064,0.021l0.102,0.043l0.088-0.021l0.087-0.043l0.102,0.051l0.058-0.015l0.116-0.022l0.145-0.021l0.16-0.022l0.072-0.029l0.058,0.017l-0.007,0.106l0.134,0.213l0.666,0.296l0.358,0.383l0.225,0.469l-0.006,0.499l-0.104,0.3l0.047,0.199z"/> - <path id="PT" country:name="Portugal" d="M383.93,117.402l-0.249,0.101l-0.517,0.291l-0.439,0.052l-0.548-0.178h-0.58l-0.28-0.073l-0.719,0.292l-0.058-0.177l0.389-1.012l-0.021-0.856l-0.182-0.115l0.244-0.542l-0.054-0.397l0.13-0.114l-0.144-0.141l-0.375,0.085l-0.476,0.097l-0.108-0.449l0.48-0.052l0.283-0.22l-0.042-0.17l-0.178-0.226l-0.3,0.417l-0.413,0.136l-0.357-0.042l-0.059-0.188l0.198-0.397l0.138-0.616l-0.039-0.303l0.258-0.114l0.403-0.503l0.45-1.098l-0.12-0.115l0.612-1.783l-0.35-0.924l-0.007-0.42l-0.146-0.378l0.255-0.271l0.891-0.251l0.55-0.188l0.531,0.439l1.822,0.047l0.531-0.26l0.335,0.055l0.272,0.227l0.15,0.242l0.842,0.495l0.062,0.242l-0.288,0.216l-1.234,0.506l-0.084,0.072l-0.051,0.442l0.072,0.456l-0.132,0.983l0.057,0.938l-0.043,0.199l-0.458,0.229l-0.482,0.045l-0.288,0.129l0.488,0.494l0.455,0.551l0.163,0.198l-0.347,0.371l-0.506,0.655l-0.17,0.455l0.812,0.123l0.408,0.31l-0.884,0.643l-0.242,0.37l-0.304,0.951l-0.008,0.018z"/> - <path id="TR" country:name="Turkey" d="M500.121,117.572l-0.407-0.016l-0.433,0.388l-0.164,0.126l-0.318-0.105l-0.102-0.269l0.03-0.259l-0.274-0.151l-0.366-0.082l-0.244,0.234l-0.343-0.023l-0.811-0.153l-0.364,0.032l-0.304-0.16l-0.437,0.094l-0.266,0.143l-0.23,0.043l-0.064-0.245l-0.207-0.023l-0.24,0.292l-0.693,0.304l-1.185,0.224l-0.711-0.039l-0.747-0.123l-0.439,0.073l-1.498,0.673l-0.567,0.13l-1.104,0.176l-0.556-0.153l-1.532-0.444l-0.278,0.03l-0.929,0.373l-0.746,0.075l-0.575-0.025l-0.777-0.166l-0.222,0.001l-0.142-0.035l-0.055,0.319l0.102,0.452l0.243,0.423l-0.627,0.127l-0.156,0.374l-0.2,0.169l-0.171-0.041l-0.114,0.127l-0.39-0.125l-0.311,0.001l-0.245-0.459l-0.119-0.093l0.097-0.175l0.242-0.197l0.617-0.403l0.021-0.175l-0.049-0.134l-0.279-0.28l-0.146-0.053l-0.487,0.368l-0.23,0.041l-0.137,0.064l0.092,0.041l-0.118,0.216l-0.172,0.023l-0.063-0.047l-0.076,0.088l-0.297,0.058l-0.332-0.222l-0.447-0.198l-0.461-0.157l-0.395,0.046l-0.849,0.548l-0.337,0.286l0.006,0.204l-0.141,0.046l-0.122,0.07l-0.005,0.082l-0.179-0.169l-0.604,0.206l-0.689,0.185l-0.594-0.013l-0.587-0.07l-0.678-0.267l-0.963-0.819l-1.181-0.479l-1.034-0.182l-0.692,0.072l-0.119,0.255l-0.097,0.609l-0.053,0.411l-0.173,0.156l-0.256,0l-0.253-0.155l-1.12,0.243l-0.423-0.027l-0.386-0.183l-0.657-1.159l-0.42,0.354l-0.764-0.451l-0.451,0.057l-0.562,0.412l-0.227-0.382l0.066-0.127l0.242-0.17l-0.116-0.17l-0.989-0.012l-0.545-0.013l-0.088-0.269l0.571-0.199l-0.074-0.241l-0.284-0.198l-0.454-0.07l-0.084-0.297l0.041-0.34l0.087-0.284l-0.089-0.255l-0.396-0.126l-0.627-0.353l-0.371,0.086l-0.265-0.084l-0.004-0.255l0.171-0.501l0.131,0.059l0.478,0.311l0.567-0.271l-0.396-0.283l0.021-0.124l-0.296-0.128l0.03-0.128l0.571-0.159l0.152-0.113l-0.068-0.142l-0.149-0.088l-0.337-0.035l0.01-0.187l0.18-0.07l-0.163-0.164l-0.198-0.117l-0.009-0.152l-0.227-0.012l0.263-0.181l0.296-0.275l0.161-0.035l0.07-0.16l-0.341-0.042l-0.573,0.12l-0.905,0.164l-0.166-0.035l0.046-0.33l0.127-0.125l-0.003-0.199l-0.029-0.286l0.13-0.264l0.299,0.012l0.184-0.41l0.175-0.023l0.63-0.422l0.514,0.012l0.133-0.129l0.479-0.047l0.128,0.211l0.268,0.102l0.169,0.028l0.529,0.022l0.147-0.129l-0.067-0.129l-0.269-0.129l0.286-0.094l0.324,0.036l0.117,0.082l-0.219,0.223l0.213-0.026l1.053-0.073l0.619,0.042l0.379,0.046l0.279,0.047l0.155-0.176l-0.086-0.094l-0.468-0.035l-0.212-0.118l0.275-0.212l1.386-0.151l0.417-0.012l0.377-0.117l-0.442-0.012l-0.592,0.023h-0.215l-0.068-0.146l-0.611-0.382l0.325-0.528l0.926,0.14l1.244,0.048l0.264-0.117l1.086,0.321l1.051-0.031l0.414-0.243l-0.041-0.27l0.624-0.244l0.455-0.214l1.218-0.573l0.598-0.215l1.039-0.23l0.889-0.073l0.758,0.07l0.905,0.126l0.798,0.041l0.753-0.372l0.216,0.527l0.416,0.298l0.278,0.099l0.592,0.013l0.622-0.144l0.453,0.74l0.492,0.255l0.574-0.172l0.391,0.056l0.968,0.582l1.265,0.04l1.094,0.197l0.749-0.001l1.084-0.272l0.514-0.044l0.651,0.141l0.764,0.098l0.787-0.016l0.554-0.144l1.518-0.573l0.424-0.335l1.212,0.082l0.491,0.068l0.226-0.072l0.761-0.36l0.41,0.041l1.326,1.018l0.031,0.028l0.795,0.722l0.026,0.199l-0.421,0.813l0.033,0.412l0.284,0.211l1.413,0.12l0.492,0.451l-0.072,0.211l-0.409-0.023l-0.231,0.141l-0.009,0.433l-0.584,0.267l-0.039,0.27l0.264,0.67l-0.122,0.375l0.224,0.492l0.09,0.117l0.106-0.105l0.288,0.203l0.039,0.207l-0.229,0.281l-0.287,0.535l-0.06,0.128l0.213,0.14l0.424,0.111l-0.145,0.245l0.099,0.421l0.42,0.374l0.275,0.035l0.023,0.308z M462.617,106.804l0.241,0.211l-0.019,0.287l0.115,0.285l0.077,0.071l0.593,0.355l0.819,0.241l0.605,0.155l0.152,0.121L464.943,109l-0.304,0.166l-0.515-0.072l-0.94-0.246l-0.326,0.07l-0.209,0.152l-1.019-0.012l-0.357,0.384l-0.109,0.273l-0.833,0.316l-0.612,0.282l-0.222,0.258l-0.307,0.152l-0.268,0.293l-0.255,0.082l0.164-0.258l0.019-0.141l-0.062-0.176l0.584-0.293l0.22-0.141l-0.226-0.191l-0.082,0.015l-0.653-0.056l-0.229-0.148l0.326-0.546l0.387-0.558l0.678-0.631l-0.127-0.227l-0.427-0.197l-0.105,0l0.498-0.445l0.629-0.374l0.497-0.045l0.527,0.111l1.333,0.005z"/> - <path id="AZ" country:name="Azerbaijan" country:shortname="Azerbaijan" d="M509.077,114.955l-0.72-0.317l-0.268,0.016l-0.356-0.433l-0.374-0.105l-0.13-0.363l0.532-0.27l0.095-0.222l-0.43-0.176l-0.027-0.188l0.63-0.129l0.094-0.155l-0.061-0.113l-0.487-0.21l-0.351-0.281l-0.306-0.166l-0.456,0.234l-1.058,0.492l-0.374,0.445l-0.642,0.188l-0.254,0.255l-0.014-0.027l0.094-0.118l-0.094-0.213l-0.189-0.071l0.26-0.095l0.166-0.047l-0.261-0.189l-0.236-0.236l0.236-0.118l0.095-0.189l-0.283-0.047l-0.354-0.024l-0.284-0.118l-0.213-0.212l-0.236-0.024l-0.26-0.354l-0.283-0.142l-0.048-0.094h0.166h0.378l0.165-0.236v-0.236l-0.213-0.024l-0.188-0.142l-0.544-0.331l-0.283-0.354l0.047-0.284l0.402-0.142l-0.119-0.236l-0.212-0.166l-0.426-0.071l-0.284-0.095l0.071-0.094l0.071-0.118l-0.284-0.095l-0.087-0.212l0.418-0.308h0.236l0.473,0.024l0.331,0.189l0.189,0.213l0.638,0.189l0.284-0.047l0.188,0.023l0.143,0.071l0.26,0.189l0.236-0.047l0.236-0.095l0.095-0.331l-0.118-0.213l-0.614-0.166l-0.213-0.307l-0.143-0.26l0.095-0.071l0.143-0.142l0.268-0.189l0.229-0.023l0.023,0.166l0.213-0.047h0.189l0.142,0.189l0.473,0.284l0.095,0.118h0.118l0.283,0.284v0.308l0.591,0.094l0.449,0.142l0.379-0.047l0.165-0.213l0.308-0.331l0.283-0.094l0.496-0.284l0.292-0.449l0.465,0.331l0.236,0.378l0.26,0.189l0.284,0.307l0.095,0.52l0.142,0.236l0.283,0.26l0.284,0.165v0.166l0.449,0.236l0.473-0.047l0.378,0.071l0.284,0.166l0.236,0.189l0.095,0.189v0.142l-0.355-0.142l-0.401-0.047h-0.213l-0.26,0.047l-0.142,0.118l-0.402,0.071l-0.213,0.142l-0.047,0.189l-0.023,0.473l-0.118,0.26l-0.095,0.236l-0.095,0.378l0.213,0.236l-0.023,0.189l-0.237-0.071l-0.094,0.095l-0.071,0.331l-0.071,0.26l-0.118-0.047l-0.094-0.236l-0.143-0.095l-0.165,0.095l-0.047,0.307l0.07,0.166l-0.118,0.118l-0.118,0.095l0.095,0.26l-0.363,0.91z M499.844,111.738l0.709,0.061l0.142-0.047l0.26-0.071l0.236,0.236l0.071,0.166l0.378,0.142l0.213,0.071l0.308-0.118h0.52l-0.071,0.213l0.024,0.236l0.118,0.023l0.331,0.166l-0.071,0.236l0.421,0.763l-0.009,0.001l-0.253-0.133l-0.416,0.038l-0.512-0.025l-0.421-0.125l-0.335-0.211l-0.294-0.402l-0.551-0.223l-0.281-0.417l-0.265-0.381l-0.252-0.197z"/> - <path id="GR" country:name="Greece" d="M455.452,122.442l0.049-0.209l-0.057-0.128l-0.812-0.256l-0.691-0.006l-0.506-0.116l-0.484,0.017l-0.121-0.046l-0.103-0.093l0.139-0.56l0.315-0.005l-0.005-0.088l-0.009-0.122l0.069-0.07l0.083,0.157l0.021,0.146l0.303,0.021l0.172,0.055l0.184-0.076l-0.014-0.082l0.108-0.029l0.157,0.105l-0.037,0.093l-0.099,0.006l-0.04,0.053l0.088,0.023l0.144,0.035l0.094,0.046l0.021,0.128l0.353,0.041l0.846-0.122l0.509,0.016l0.035,0.13l0.192,0.035l0.608,0.064l0.307,0.051l0.358-0.121l0.09,0.05l-0.101,0.312l0.163,0.11h0.105l0.325-0.169l0.286-0.058l0.078,0.052l0.154-0.07l0.232-0.146l-0.083,0.187l0.015,0.186l-0.183,0.268l-0.582-0.046l-0.349,0.081l-0.335-0.017l-1.994,0.169z M445.294,112.196l0.583-0.884l0.496-0.472l0.402-0.386l0.449-0.842l0.09-0.029l0.809-0.076l0.606-0.146l0.395-0.429l0.365-0.159l0.361,0.041l0.622,0.054l0.532-0.245l0.507-0.16l0.09-0.029l1.855-0.195l0.799-0.261l0.584-0.06l1.473,0.505l0.619,0.21l0.388-0.031l1.117-0.277l0.086-0.257l-0.097-0.327l0.344-0.216l0.363,0.026l0.105,0l0.427,0.197l0.127,0.227l-0.678,0.631l-0.387,0.558l-0.326,0.546l-0.062-0.407l-0.794-0.056l-0.743-0.041l-0.566-0.125l-0.062-0.144l-0.459,0.186l-0.248,0.123l-0.403,0.012l-0.031-0.247l-0.335,0.029l-0.301,0.314l-0.431,0.186l-0.31,0.03l-0.306-0.159l-0.252,0.07l-0.004,0.133l0.169,0.185l0.169,0.34l0.308,0.059l0.826,0.609l-0.166,0.07l-0.369-0.258l-0.015-0.105l-0.276-0.082l-0.331-0.105l-0.116,0.099l-0.211,0.007l0.069,0.129l-0.016,0.129l0.338,0.164l0.145-0.012l0.114,0.234l-0.03,0.129l-0.245,0.023l-0.445-0.457l-0.341-0.141l-0.207-0.059l-0.128-0.012l0.003,0.094l-0.075,0.035l0.138,0.164l0.102,0.105l0.154,0.141l0.193,0.059l0.153,0.035l0.103,0.094l-0.093,0.058l-0.494-0.046l-0.253-0.035l0.035-0.176l-0.137-0.293l-0.164-0.188l-0.401-0.108l-0.472-0.373l0.258-0.118l0.025-0.136l-0.053-0.122l-0.182-0.035l-0.153,0.199l-0.465,0.176l0.245,0.224l-0.25,0.371l-0.05,0.249l0.13,0.121l0.065,0.172l0.311,0.338l0.133,0.036l0.131,0.479l0.579,0.421l0.359,0.467l-0.172,0.14l-0.237,0.082l0.106-0.187l-0.121-0.187l-0.142-0.128l-0.139-0.035l-0.151-0.047l-0.29,0.175l0.102,0.188l0.153,0.081l0.08,0.316l-0.193,0.187l-0.652,0.141l0.248,0.046l0.27,0.14l0.391,0.058l0.188,0.222l0.257-0.012l0.155,0.012l0.048,0.126l0.367,0.269l0.306,0.014l0.138,0.292l0.282,0.012h0.27l0.348,0.303l0.015,0.128l-0.193,0.082l0.238,0.782l-0.153,0.175h-0.185l-0.226-0.385l-0.222-0.047l-0.207-0.278l-0.101-0.142h-0.17l-0.496,0.14l-0.479,0.105l-0.184,0.128l0.315,0.093l0.013,0.188l0.007,0.291l0.229,0.117l0.153-0.026l0.225-0.079l-0.021,0.198l0.235,0.175l-0.519,0.093l0.002,0.117l-0.169,0.062l-0.309-0.086l0.121-0.21l-0.186-0.086l-0.508-0.056l-0.158-0.092l-0.008,0.206l0.194,0.453l0.193,0.17l-0.045,0.163l0.209,0.204l0.213,0.96l-0.688-0.31l-0.331,0.071l-0.298,0.439l-0.442-0.735l-0.46-0.367l-0.452,0.44l-0.428-0.353l-0.127-0.297l0.212-0.425l-0.028-0.241l-0.215-0.269l-0.491-0.424l-0.167-0.226l0.017-0.17l0.471-0.61l0.609,0.098l0.425-0.298l0.202,0.042l1.668,0.663l0.337-0.1l0.483-0.355l-0.266-0.049l-0.27-0.056l-1.204-0.493l-1.127-0.083l-0.367,0.058l-0.66,0.058l-0.427,0.143l-0.89-1.118l0.269-0.1l0.253,0.056l0.218-0.114l0.122-0.185l-0.339-0.24l-0.235,0.114l-0.496-0.042l-1.035-0.721l-0.199-0.325z"/> - <path id="AM" country:name="Armenia" country:shortname="Armenia" d="M504.136,113.458l-0.327,0.328l-0.377,0.03l-0.421-0.763l0.071-0.236l-0.331-0.166l-0.118-0.023l-0.024-0.236l0.071-0.213h-0.52l-0.308,0.118l-0.213-0.071l-0.378-0.142l-0.071-0.166l-0.236-0.236l-0.26,0.071l-0.142,0.047l-0.709-0.061l-0.492-0.451l-1.413-0.12l-0.284-0.211l-0.033-0.412l0.421-0.813l-0.026-0.199l-0.795-0.722l0.377-0.108l0.307,0.024l0.308-0.095l0.426-0.023l0.401-0.118l0.592,0.047l0.591-0.095l0.378-0.047l0.291-0.094l0.087,0.212l0.284,0.095l-0.071,0.118l-0.071,0.094l0.284,0.095l0.426,0.071l0.212,0.166l0.119,0.236l-0.402,0.142l-0.047,0.284l0.283,0.354l0.544,0.331l0.188,0.142l0.213,0.024v0.236l-0.165,0.236h-0.378h-0.166l0.048,0.094l0.283,0.142l0.26,0.354l0.236,0.024l0.213,0.212l0.284,0.118l0.354,0.024l0.283,0.047l-0.095,0.189l-0.236,0.118l0.236,0.236l0.261,0.189l-0.166,0.047l-0.26,0.095l0.189,0.071l0.094,0.213l-0.094,0.118l0.014,0.027z"/> - <path id="TJ" country:name="Tajikistan" country:shortname="Tajikistan" d="M566.651,117.4l-0.565-0.153l-0.496-0.054l-0.264-0.151l-0.564,0.227l-0.974,0.147l-0.137-0.059l0.129-0.176l-0.198-0.077l-0.678,0.03l-0.739,0.315l-0.592,0.486l-0.589,0.064l-0.745,0.495l-0.351,0.03l-0.368-0.026l-0.128-0.084l-0.164-0.409l-0.199-0.521l0.185-0.444l0.099-0.775l0.029-0.255l-0.17-0.187l-0.484,0.093l0.156-0.597l-0.576-0.45l-0.153-0.056l-0.384,0.016l-0.286,0.162l-0.134,0.363l-0.435,0.428l-0.049,0.425l0.006,0.255l-0.208,0.228l-0.442,0.158l-0.133-0.013l-0.587-0.152l-0.292,0.058l-0.073,0.185l0.007,0.311l-0.3,0.313l-0.21,0.128l-0.381,0.016l-0.63-0.237l-0.325,0.001l-0.581,0.286l-0.58,0.343l-0.485,0.144l-0.245-0.041l-0.129-0.141l-0.04-0.055l0.375-0.843l-0.063-0.377l0.377-0.377l0.283-0.503l0.503-0.346l0.157-0.22l-0.126-0.283l-0.471-0.314l-0.126-0.409l0.031-0.472l0.126-0.22l-0.126-0.22h-0.346l-0.44-0.032l-0.157-0.157l-0.346-0.188l-0.251-0.283l0.125-0.471l0.472-0.283l0.629,0.126l1.069,0.094l0.282-0.188l0.063-0.409l0.251-0.157h0.188l0.032-0.346l0.188-0.063l0.251-0.063l-0.126-0.094l-0.534,0.031l-0.251-0.125l0.503-0.094l0.565-0.095l0.472,0.095l0.062-0.126l0.032-0.346l-0.189-0.314l0.283-0.314l-0.031-0.22h0.346l0.22,0.157l0.252,0.22l0.22-0.157l0.692-0.188l0.471-0.346l0.221-0.251l0.439,0.377l0.252,0.251l-0.188,0.22l-0.409,0.346l-0.251,0.126l0.126,0.188l0.251,0.063l0.188,0.283l0.409-0.031l0.345,0.005l-0.302,0.147l-0.441,0.196l-0.024,0.246h-0.196l-0.099-0.172l-0.516-0.196l-0.515-0.147l-0.981,0.196h-0.123l-0.098,0.27l0.049,0.196l-0.196,0.074l-0.098-0.221l-0.196,0.196l-0.099,0.245l0.099,0.27l0.049,0.147l0.122,0.098l0.589-0.024h0.564l0.688-0.024l0.196,0.073l0.49-0.147l0.368,0.098l0.147,0.123l0.073,0.196l0.393,0.074l0.295-0.049l-0.024-0.221l0.343-0.049l0.442-0.123l0.221,0.024l0.049,0.147l0.319,0.123l0.122-0.024l0.049,0.172l0.074,0.221l0.318-0.172l0.368-0.024l0.172,0.319h0.196l0.172-0.147l0.834-0.221l0.663,0.073h0.539l0.344-0.171l0.344-0.098l0.196,0.073l-0.011,0.069l0.023,1.031l-0.207,0.223l0.077,0.305l0.325,0.394l0.463-0.045l0.229-0.162l0.22,0.06l0.692,0.039l0.273,0.154l0.295,0.494l-0.009,0.284l0.028,0.246l0.152,0.012l0.049,0.123l-0.126,0.428l0.245,0.237l-0.152,0.36l0.2,0.163l-0.181,0.185l-0.08,0.249l-0.354,0.136z"/> - <path id="IR" country:name="Iran" d="M500.121,117.572l-0.023-0.308l-0.275-0.035l-0.42-0.374l-0.099-0.421l0.145-0.245l-0.424-0.111l-0.213-0.14l0.06-0.128l0.287-0.535l0.229-0.281l-0.039-0.207l-0.288-0.203l-0.106,0.105l-0.09-0.117l-0.224-0.492l0.122-0.375l-0.264-0.67l0.039-0.27l0.584-0.267l0.009-0.433l0.231-0.141l0.409,0.023l0.072-0.211l0.252,0.197l0.265,0.381l0.281,0.417l0.551,0.223l0.294,0.402l0.335,0.211l0.421,0.125l0.512,0.025l0.416-0.038l0.253,0.133l0.009-0.001l0.377-0.03l0.327-0.328l0.254-0.255l0.642-0.188l0.374-0.445l1.058-0.492l0.456-0.234l0.306,0.166l0.351,0.281l0.487,0.21l0.061,0.113l-0.094,0.155l-0.63,0.129l0.027,0.188l0.43,0.176l-0.095,0.222l-0.532,0.27l0.13,0.363l0.374,0.105l0.356,0.433l0.268-0.016l0.72,0.317l0.015,0.007l-0.05,0.707l-0.143,0.581l0.205,0.48l0.494,0.252l0.925,0.235l0.827,0.052l0.424,0.097l0.162,0.282l0.312,0.451l0.687,0.463l1.902,0.513l0.841,0.052l0.438-0.059l1.354-0.262l1.192-0.148l1.469-0.079l0.41-0.229l0.185-0.354l-0.131-0.905l0.015,0l0.441,0.025l0.562-0.13l0.466-0.3l0.621-0.654l0.476-0.328l0.413-0.144l0.609-0.032l0.78,0.038l0.333-0.03l0.517-0.343l0.343-0.129l0.519,0.054l1.055,0.107l0.402,0.437l0.708,0.251l0.822,0.335l0.788,0.066l0.5,0.054l0.66,0.167l0.597,0.336l1.803,1.362l0.655,0.506l0.696,0.01l0.787-0.075l0.185,0.211l0.038,0.848l0.01,0.565l0.15,0.692l0.078,0.028l-0.145,0.241l-0.084,0.339l-0.246,0.807l-0.49,1.272l-0.222,0.297l-0.596,0.384l-0.016,0.141l0.119,0.663l0.096,0.098l0.738,0.235l0.026,0.183l-0.661,0.935l-0.034,0.155l0.254,1.085l0.167,1.283l0.143,0.775l0.191,0.21l0.209,0.041l1.198,0.275l0.401,0.167l0.144,0.366l0.046,0.437l-0.425,0.553l-0.853,0.795l-0.853,1.034l0.802,1.083l0.71,1.068l0.353,0.464l0.695,0.391l1.144,0.388l0.409,0.224l0.168,0.38l0.111,1.34l0.185,0.394l0.652,0.053l0.186,0.281l-0.036,0.974l-0.188,0.255l-0.209,0.072l-1,0.077l-0.697,0.258l-0.794,0.47l-0.285,0.383l-0.31,0.792l-0.049,0.354l-0.182,0.954l-0.502,0.028l-1.079-0.153l-0.236-0.197l-0.605-0.253l-0.403-0.056l-1.43,0.003l-0.783-0.041l-0.602,0.072l-0.475-0.38l-0.163-0.126l-0.835-0.026l-0.576,0.001l-0.465,0.014l-0.212-0.239l-0.756-0.125l-0.305-0.183l-0.162-0.014l-0.021-0.5l-0.295-0.128l-0.103-0.514l-0.292-0.349l-0.013-0.639l-0.309-0.493l-0.237,0.012l-0.035-0.181l-0.526-0.126l-0.807-0.013l-0.374,0.017l-0.209,0.222l-0.329,0.018l-0.517,0.075l-0.188,0.364l-0.538,0.138l-0.383,0.443l-0.368,0.283l-0.253,0.043l-1.292-0.689l-0.958-0.104l-0.562-0.359l-1.088-0.317l-0.247-0.301l-0.324-0.282l-0.497-0.592l-0.997-0.436l-0.584-0.083l-0.194-0.028l-0.58-0.465l-0.596-1.058l-0.635-1.114l-0.209-0.268l0.005-0.593l-0.767-0.761l-0.506-0.719l-0.921,0.143l-0.46-0.042l-0.13-0.126l-0.291-0.056l-0.191-0.268l-0.029-0.565l-0.448,0.1l-0.166,0.099l-0.32,0.678l-0.195,0.184l-0.355,0.012l-0.014-0.12l-0.351-0.224l-0.686-0.546l0.064-0.212l-0.007-0.395l-0.164-0.465l-0.215-0.013l-0.551,0.003l-0.034-0.325l0.055-0.579l0.197-0.622l0.014-0.508l-0.112-0.239l-0.29-0.28l-0.774-0.603l-0.436-0.209l-1.242-0.925l-0.533-0.025l-0.321,0.115L503,127.106l0.033-0.819l-1.02-0.954l-0.312-0.351l-0.002-0.184l0.133-0.875l0.235-0.763l1.142-0.98l-0.422-0.761l0.013-0.254l0.468-0.596l-1.067-0.107l-0.761-0.208l-0.065-0.198l-0.563-1.086l-0.69-1.397z"/> - <path id="AF" country:name="Afghanistan" d="M535.734,133.791l0.853-1.034l0.853-0.795l0.425-0.553l-0.046-0.437l-0.144-0.366l-0.401-0.167l-1.198-0.275l-0.209-0.041l-0.191-0.21l-0.143-0.775l-0.167-1.283l-0.254-1.085l0.034-0.155l0.661-0.935l-0.026-0.183l-0.738-0.235l-0.096-0.098l-0.119-0.663l0.016-0.141l0.596-0.384l0.222-0.297l0.49-1.272l0.246-0.807l0.084-0.339l0.145-0.241l0.193,0.112l0.937,0.193l0.999,0.348l0.573,0.082l0.534-0.031l0.636-0.3l0.22-0.199l0.001-0.466l0.119-0.199l0.568-0.159l1.985-0.689l0.508-0.243l0.103-0.128l0.203-0.991l0.432-0.809l1.135-0.205l0.417-0.2l0.445-0.356l0.565,0.294l1.454,0.244l0.096,0.016l0.646,0.011l1.217,0.05l0.236,0.126l0.351,0.48l0.04,0.055l0.129,0.141l0.245,0.041l0.485-0.144l0.58-0.343l0.581-0.286l0.325-0.001l0.63,0.237l0.381-0.016l0.21-0.128l0.3-0.313l-0.007-0.311l0.073-0.185l0.292-0.058l0.587,0.152l0.133,0.013l0.442-0.158l0.208-0.228l-0.006-0.255l0.049-0.425l0.435-0.428l0.134-0.363l0.286-0.162l0.384-0.016l0.153,0.056l0.576,0.45l-0.156,0.597l0.484-0.093l0.17,0.187l-0.029,0.255l-0.099,0.775l-0.185,0.444l0.199,0.521l0.164,0.409l0.128,0.084l0.368,0.026l0.351-0.03l0.745-0.495l0.589-0.064l0.592-0.486l0.739-0.315l0.678-0.03l0.198,0.077l-0.129,0.176l0.137,0.059l0.974-0.147l0.564-0.227l0.264,0.151l0.496,0.054l0.565,0.153l-0.192,0.145l-0.574-0.059l0.01,0.269l0.236,0.012l0.048,0.088l-0.148,0.142l-0.358,0.004l-0.455,0.297l-0.332-0.005l-0.338,0.179l-0.647-0.144l-1.345,0.012l-1.148,0.152l-0.53,0.292l-0.272,0.19l-0.559,0.395l-0.246-0.023l-0.258,0.214l-0.464,0.413l0.01,0.32l0.411,0.271l0.01,0.336l0.232,0.171l-0.119,0.483l0.198,0.477l-0.324,0.426l-0.524,0.355l-0.4,0.341l-0.13,0.283l0.223,0.478l0.033,0.31l-0.289,0.255l-0.513,0.215l-0.698-0.039l-0.997-0.122l-0.355,0.129l0.35,0.336l0.365,0.407l0.129,0.281l0.088,0.437l-0.199,0.255l-0.315,0.115l-0.513,0.031l-0.416,0.115l-0.292,0.228l-0.224,0.424l-0.288,0.834l-0.139,1.214l-0.021,0.084l-0.34,0.383l-0.237,0.086l-1.001-0.375l-0.562-0.025l-0.559,0.243l-0.362,0.271l-0.321,0.693l-0.254,0.086l-0.516-0.082l-0.644-0.039l-0.283,0.072l-0.597,0.441l-0.412,0.369l-0.188,0.34l-0.232,0.876l-0.099,0.903l-0.069,0.184l-0.247,0.156l-1.066,0.274l-1.183,0.19l-0.964,0.175l-1.234,0.12l-1.005-0.135l-0.349,0.002l-1.187,0.218l-0.742-0.024l-0.541-0.039l-0.854-0.235l-1.069-0.248l-0.63-0.194l-0.887-0.32z"/> - <path id="IQ" country:name="Iraq" d="M486.696,126.295l5.257-2.711l0.589-2.701l-0.024-0.467l-0.187-0.508l0.009-0.255l0.23-0.355l0.31-0.214l0.866-0.174l0.457-0.371l0.944-0.883l-0.059-0.24l0.23-0.043l0.266-0.143l0.437-0.094l0.304,0.16l0.364-0.032l0.811,0.153l0.343,0.023l0.244-0.234l0.366,0.082l0.274,0.151l-0.03,0.259l0.102,0.269l0.318,0.105l0.164-0.126l0.433-0.388l0.407,0.016l0.69,1.397l0.563,1.086l0.065,0.198l0.761,0.208l1.067,0.107l-0.468,0.596l-0.013,0.254l0.422,0.761l-1.142,0.98l-0.235,0.763l-0.133,0.875l0.002,0.184l0.312,0.351l1.02,0.954L503,127.106l0.075,0.155l0.321-0.115l0.533,0.025l1.242,0.925l0.436,0.209l0.774,0.603l0.29,0.28l0.112,0.239l-0.014,0.508l-0.197,0.622l-0.055,0.579l0.034,0.325l0.551-0.003l0.215,0.013l0.164,0.465l0.007,0.395l-0.064,0.212l0.686,0.546l0.351,0.224l0.014,0.12l-0.096,0.003l-0.664,0.101l-0.408-0.056l-0.157,0.057l-0.103,0.127l-1.271,0.044l-0.518,0.13l-0.343,0.693l-0.463,0.609l-0.521,0.568l-4.048-0.132l-1.557-0.697l-0.812-0.277l-0.118-0.253l-0.047-0.818l0.118-0.396l-0.135-0.366l-0.973,0.048l-0.141-0.07l-0.399-0.633l-0.258-0.196l-2.44-1.101l-1.14-0.473l-2.034-0.934l-0.757-0.222l-1.129-0.459l-0.093-0.056l-0.093-0.056l-0.311-0.69l-0.87-1.632z"/> - <path id="SY" country:name="Syria" d="M479.916,127.377l-0.082-0.085l0.047-0.122l-0.021-0.183l-0.201-0.128l-0.183-0.346l0.398-0.209l0.041-0.099l0.526-0.396l-0.048-0.058l-0.223-0.099l0.077-0.151l0.298-0.25l0.599-0.006l-0.14-0.146l-0.035-0.046l0.078-0.111l0.177-0.163l0.169-0.116l0.299-0.239l-0.068-0.058l0.023-0.163l-0.09-0.047l-0.031-0.221l-0.241-0.157l-0.222-0.058l0.204-0.204l-0.125-0.052l-0.053-0.116l-0.12,0.058l-0.335,0.052l-0.388-0.023l-0.225-0.564l0.129-0.593l0.072-0.064l-0.1-0.507l-0.42-0.326l0.126-0.093l0.036-0.152l0.117-0.128l-0.093-0.222l0.107-0.012l0.259-0.32l-0.061-0.112l0.311-0.001l0.39,0.125l0.114-0.127l0.171,0.041l0.2-0.169l0.156-0.374l0.627-0.127l-0.243-0.423l-0.102-0.452l0.055-0.319l0.142,0.035l0.222-0.001l0.777,0.166l0.575,0.025l0.746-0.075l0.929-0.373l0.278-0.03l1.532,0.444l0.556,0.153l1.104-0.176l0.567-0.13l1.498-0.673l0.439-0.073l0.747,0.123l0.711,0.039l1.185-0.224l0.693-0.304l0.24-0.292l0.207,0.023l0.064,0.245l0.059,0.24l-0.944,0.883l-0.457,0.371l-0.866,0.174l-0.31,0.214l-0.23,0.355l-0.009,0.255l0.187,0.508l0.024,0.467l-0.589,2.701l-5.257,2.711l-0.161,0.071l-2.96,1.541l-1.139,0.656l-0.253,0.016l-0.365-0.167l-1.902-1.034z"/> - <path id="TN" country:name="Tunisia" d="M426.068,126.434l-0.093,0.981l0.064,0.564l-0.093,0.269l-0.802,0.428l-0.579,0.314l-1.473,1.138l-0.126,0.354l0.274,0.973l-0.147,0.537l-0.155,0.227l-0.864,0.598l-0.22,0.143l-0.564-1.536l-0.699-2.242l-0.323-0.464l-0.363-0.252l-0.432-0.181l-0.484-0.831l-0.225-0.465l-0.363-0.28l-0.452-0.097l-0.336-0.774l-0.301-0.888l0.112-0.509l1-0.853l0.414-0.355l0.163-0.411l0.048-0.537l-0.052-0.594l-0.026-0.892l-0.012-1.429l0.114-0.439l0.685-0.627l0.012-0.184l0.508-0.185l0.633-0.455l0.591-0.228l0.703-0.016l0.643,0.183l0.247,0.212l0.059,0.241l0.25,0.538l0.27,0.084l0.417-0.171l0.584-0.44l0.401-0.17l0.034,0.354l-0.265,0.567l-0.638,0.511l-0.275,0.468l0.005,0.283l0.202,0.438l0.508,0.466l0.351,0.127l0.303,0.848l-0.094,0.212l-0.541,0.764l-0.59,0.34l-1.017,0.92l-0.216,0.339l0.287,0.451l0.587,0.55l0.528,0.295l0.284,0.056l0.396-0.227l0.316,0.084l0.244,0.635l0.582,0.239z"/> - <path id="DZ" country:name="Algeria" d="M381.402,139.704l-0.027-0.876l0.069-2.006l0.037-0.382l0.686-0.314l1.512-0.998l0.963-0.542l1.265,0.078l0.397-0.059l0.181-0.693l0.864-0.033l0.777-0.174l0.527-0.229l0.524-0.356l0.484-0.652l1.109-0.332l1.52-0.701l0.129-0.227l-0.296-0.62l-0.025-0.396l0.079-0.227l0.265-0.114l1.186-0.12l0.381-0.186l0.309-0.553l1.022,0.022l0.67-0.018l1.826,0.004l0.34-1.033l-0.07-0.211l-0.507-0.322L397,126.646l-0.158-0.465l0.016-1.271l0.022-0.833l-0.165-0.889l-0.189-0.211l-0.563-0.279l-0.259-0.508l0.351,0l0.66-0.143l0.541-0.256l0.369-0.566l0.405-0.312l0.509-0.086l0.407-0.157l0.679-0.27l0.324,0.226l0.176,0.017l0.249,0.024l0.238-0.142l0.407-0.51l0.613-0.426l0.682-0.355l0.614-0.171l1.16-0.116l1.587-0.06l0.513-0.072l0.634-0.312l0.578,0.211l0.564-0.072l0.585-0.313l0.343-0.1l0.939,0.012l0.513-0.015l0.307,0.056l0.221,0.042l0.322,0.113l0.816,0.168l0.529-0.015l0.772-0.171l0.705-0.2l0.612-0.554l0.994,0.508l0.339,0.099l0.312-0.143l0.314-0.241l0.228-0.156l0.528,0.042l0.388,0.197l0.162,0.269l0.269,0.126l0.516-0.086l1.093-0.158l-0.012,0.184l-0.685,0.627l-0.114,0.439l0.012,1.429l0.026,0.892l0.052,0.594l-0.048,0.537l-0.163,0.411l-0.414,0.355l-1,0.853l-0.112,0.509l0.301,0.888l0.336,0.774l0.452,0.097l0.363,0.28l0.225,0.465l0.484,0.831l0.432,0.181l0.363,0.252l0.323,0.464l0.699,2.242l0.564,1.536l-0.204,0.156l-0.241,0.383l0.88,1.605l0.147,0.833l0.052,0.691l-0.1,0.862l0.101,0.748l-0.16,0.622l-0.158,0.495l0.457,1.156l-0.061,0.664l-0.086,0.17l-0.666,0.47l-0.249,0.128l-0.152,0.283l1.272,1.702l0.249,0.917l0.562,0.873l0.244,0.154l0.544-0.201l0.702,0.165l1.028,0.347l0.178,0.168l0.86,1.506l0.098,0.07l-0.265,0.186l-1.632,0.843l-4.012,2.241l-1.607,0.956l-2.308,1.454l-0.834,0.655l-3.084,2.617l-1.82,0.364l-1.672,0.321l-2.176,0.408l-0.146-0.564l0.161-0.679l-0.099-0.522l-0.277-0.352l-0.309-0.111l-0.748-0.024l-0.375-0.167l-0.588-0.562l-0.47,0.314l-0.229-0.027l-1.111-1.039l-0.393-0.28l-0.082-0.183l0.096-0.396l-0.181-0.253l-2.472-1.469l-0.397-0.253l-1.292-0.824l-1.924-1.26l-3.283-2.241l-0.811-0.575l-2.054-1.344l-0.895-0.531l-0.1-0.084l-1.414-0.91l-4.12-2.42l-2.829-1.509z"/> - <path id="MA" country:name="Morocco" d="M395.704,122.189l0.259,0.508l0.563,0.279l0.189,0.211l0.165,0.889l-0.022,0.833l-0.016,1.271l0.158,0.465l0.598,0.788l0.507,0.322l0.07,0.211l-0.34,1.033l-1.826-0.004l-0.67,0.018l-1.022-0.022l-0.309,0.553l-0.381,0.186l-1.186,0.12l-0.265,0.114l-0.079,0.227l0.025,0.396l0.296,0.62l-0.129,0.227l-1.52,0.701l-1.109,0.332l-0.484,0.652l-0.524,0.356l-0.527,0.229l-0.777,0.174l-0.864,0.033l-0.181,0.693l-0.397,0.059l-1.265-0.078l-0.963,0.542l-1.512,0.998l-0.686,0.314l-0.037,0.382l-0.069,2.006l-1.42,0.008l-1.718-0.004l-2.677,0.001l-2.511,0l-1.635,0.04l0.141-0.28l0.431-0.411l0.427-0.085l1.296-0.285l1.143-0.455l0.453-0.312l1.147-0.85l1.149-0.878l1.043-1.104l0.46-0.693l0.133-0.509l-0.05-0.494l-0.427-0.776l-0.09-0.678l0.099-0.508l0.396-0.636l0.706-0.863l0.211-0.65l-0.063-0.367l0.071-0.353l1.285-1.203l0.724-0.481l0.916-0.327l1.266-0.469l0.73-0.397l0.558-0.552l0.537-0.736l0.466-0.905l0.829-1.925l0.269-0.128l0.54-0.171l0.19,0.127l0.684,0.848l0.138,0.099l1.148,0.507l0.661-0.001l0.595,0.042l1.304-0.074l0.522-0.228l0.437-0.27l0.398,0.551l0.256,0.099l0.798,0.097l0.361,0z"/> - <path id="LB" country:name="Lebanon" d="M480.248,123.437l0.388,0.023l0.335-0.052l0.12-0.058l0.053,0.116l0.125,0.052l-0.204,0.204l0.222,0.058l0.241,0.157l0.031,0.221l0.09,0.047l-0.023,0.163l0.068,0.058l-0.299,0.239l-0.169,0.116l-0.177,0.163l-0.078,0.111l0.035,0.046l0.14,0.146l-0.599,0.006l-0.298,0.25l-0.077,0.151l0.223,0.099l0.048,0.058l-0.526,0.396l-0.041,0.099l-0.398,0.209l-0.07-0.023l-0.088,0.041l-0.067,0.193l-0.009,0.167l-0.355,0.07l-0.07-0.099l-0.151-0.022l-0.372,0.051l0.26-0.291l0.097-0.361l0.169-0.227l0.328-0.681l-0.017-0.232h0.181l0.138-0.192l0.072-0.32l0.018-0.32l0.409-0.431l0.232-0.07l0.116-0.174l-0.048-0.157z"/> - <path id="MX" country:name="Mexico" d="M184.444,142.729l-0.367,0.82l-0.518,0.821l-0.186,0.763l-0.179,1.159l0.017,1.851l-0.133,1.187l-0.016,1.13l0.564,1.737l0.275,0.805l0.624,0.945l0.76,0.903l0.191,0.452l0.481,0.521l0.529,0.974l0.729,1.228l0.375,0.296l0.677,0.069l0.436-0.015l0.577,0.154l0.593,0.451l0.503,0.508l0.773,0.069l1.016-0.242l1.55-0.456l1.396-0.3l0.803-0.157l-0.02,0.542l0.838,0.223l0.264-0.286l0.293-0.199l-0.104-0.247l-0.393-0.175l1.073-0.62l0.633-0.62l0.086-0.827l0.498-0.429l-0.094-0.477l0.092-1.145l0.254-0.699l0.625-0.334l0.164-0.043l0.757-0.198l0.701-0.1l1.088-0.229l1.016-0.37l0.594-0.058l0.499,0.056l1.139,0.181l0.502-0.194l0.378,0.093l0.62,0.507l0.047,0.297l-0.079,0.424l-0.298,0.382l-0.541,0.496l-0.433,0.425l-0.317,0.445l-0.02,0.7l-0.254,0.297l-0.188,0.354l0.155,0.155l0.337-0.138l-0.101,0.652l-0.262,1.196L205.356,159l-0.062,0.24l-0.34-0.534l-0.167-0.452l-0.072-0.155l-0.386,0.34l-0.02,0.549l-0.437,0.016l-0.178,0.447l-0.599,0.857l-0.386-0.27l-0.278,0.095l0.025,0.329l-2.332-0.006l-1.792-0.005l-0.04,1.24l-0.999,0.032l0.396,0.223l0.495,0.541l0.624,0.231l0.359,0.69l0.532,0.223l-0.211,0.683l-1.762-0.007l-1.06,0.007l-1.076,1.812l0.305,0.397l-0.207,0.238l0.054,0.553l0.044,0.454l-0.704-0.555l-0.952-0.888l-0.956-0.761l-1.069-0.859l-0.534-0.352l-0.053-0.071l-0.639-0.252l-1.048-0.21l-0.657,0.044l-0.817,0.397l-1.1,0.567l-0.756,0.256l-0.931-0.069l-0.724-0.21l-0.48-0.197l-1.305-0.195l-0.588-0.267l-0.644-0.422l-0.935-0.521l-0.785-0.267l-1.711-0.392l-0.963-0.365l-0.722-0.366l-1.074-0.436l-0.592-0.352l-1.123-1l-0.207-0.07l-0.606,0.058l-0.689-0.14l-1.835-0.575l-0.565-0.536l-0.503-0.634l-0.495-0.395l-1.049-0.577l-0.619-0.267l-0.5-0.494l-0.742-0.987l-0.363-0.55l-0.038-0.113l0.15-0.155l0.504-0.086l0.18-0.17l0.047-0.184l-0.331-0.367l0.457-0.679l0.041-0.381l-0.172-0.466l-0.744-0.959l0.121-0.297l0.146-0.17l-0.07-0.268l-0.665-0.62l-1.495-1.777l-0.546-0.493l-0.963-1.058l-0.474-0.522l-0.815-0.578l-0.322-0.197l-0.158-0.268l-0.058-0.48l-0.144-0.183l-0.329-0.197l-0.609-0.197l-0.408-0.31l-0.366-0.522l-0.271-0.028l-0.414,0.114l-0.238-0.155l-0.163-0.367l-0.005-0.325l0.459-0.736l-0.126-0.339l-0.751-0.62l-0.439,0.255l-0.375-0.621l-0.118-0.353l-0.359-0.211l-0.61-0.168l-0.319-0.296l-0.125-0.254l0.05-0.381l0.084-0.269l-0.185-0.226l-0.561-0.21l-0.46-0.098l-0.46-0.253l-0.935-0.86l-0.478-0.706l-0.281-0.551l-0.646-0.832l-0.736-1.073l-0.184-0.423l-0.38-0.678l-0.242-0.338l-0.152-0.452l0.042-0.509l0.032-0.311l-0.56-0.239l-0.795-0.196l-0.06-0.452l-0.128-0.155l-0.458-0.183l-0.289,0.326l-0.251,0.043l-1.43-0.647l-0.285,1.004l-0.045,0.438l0.033,0.084l0.265,0.339l0.264,0.296l0.028,1.046l0.088,0.509l0.51,0.677l0.143,0.169l0.643,0.267l0.601,0.536l0.525,0.663l0.602,1.214l0.44,0.282l0.328,0.042l0.237,0.169l0.325,1.398l0.102,0.169l0.246,0.155l0.497,0.056l0.133,0.056l0.215,0.438l0.161,0.65l0.445,0.79l0.49-0.071l0.223-0.142l0.245,0.452l0.344,1.469l0.531,1.059l0.649,1.2l0.069,0.593l-0.014,0.522l0.26,0.353l0.378,0.154l0.389-0.17l0.234-0.198l0.588,0.804l0.258,0.579l0.464,0.253l0.281,0.014l0.133,0.311l-0.196,0.537l-0.136,0.127l-0.691,0.595l-0.254-0.042l-0.251-0.409l-0.24-0.734l-0.617-0.578l-0.625-0.309l-0.516-0.479l-0.834-0.507l-1.143-0.986l-0.416-0.451l-0.162-0.269l0.216-0.989l-0.035-0.254l-0.488-1.002l-0.238-0.381l-0.327-0.282l-0.44-0.098l-0.5-0.31l-0.675-0.677l-0.305,0.142l-0.363-0.056l-1.262-0.746l-0.722-0.31l-0.896-0.973l-0.139-0.127l-0.246-0.254l0.679,0.15l0.599,0.013l0.588-0.284l0.244-0.326l0.093-0.636l-0.01-0.184l-0.458-0.635l-0.466-0.452l-1.1-0.888l-0.986-0.493l-0.402-0.338l-0.203-0.522l-0.272-0.649l-0.091-0.155l-0.447-0.126l-0.15-0.353l-0.026-0.594l-0.203-0.395l-0.623-0.734l-0.434-0.706l-0.003-0.254l0.212-0.382l-0.777-0.62l-0.254-0.325l-0.22-0.485l0.34-0.017l2.367-0.155l2.381-0.084l0.316,0.31l0.267,0.154l1.186,0.39l2.811,0.933l3.516,1.112l0.338,0.055l1.662,0.019l1.544,0.02l0.966,0.037l1.867-0.011l0.213-0.101l0.096-0.892l1.858,0.003l1.892,0.046l0.209,0.112l0.631,0.662l0.766,0.632l0.837,0.519l0.708,0.491l0.179,0.226l0.284,0.678l0.318,0.847l0.445,0.549l1.092,0.659l1.104,0.503l0.337,0.069l0.501,0.011l0.416-0.158l0.283-0.37l0.418-0.413l0.576-0.541l0.468-0.201l0.643-0.018l0.475,0.082l0.783,0.321l0.412,0.252l0.363,0.366l0.663,1.029l0.744,1.227l0.845,1.042l0.657,0.576l0.268,0.253l0.078,0.467l0.332,0.932l0.336,0.592l0.375,0.365l0.921,0.32l1.029,0.56l0.264,0.069l0.416-0.116l0.296-0.001l0.816,0.377l0.347,0.119z"/> - <path id="KW" country:name="Kuwait" d="M507.047,133.665l0.055,0.197l0.134,0.691l-0.336-0.028l-0.513,0.513l0.421,0.194l0.418-0.206l0.306,0.021l0.698,1.84l-0.644,0.044l-1.07-0.05l-0.185-0.239l-0.334-0.619l-0.408-0.054l-1.657-0.259l0.521-0.568l0.463-0.609l0.343-0.693l0.518-0.13l1.271-0.044z"/> - <path id="MM" country:name="Burma" d="M606.155,150.953l0.595,0.152l0.255,0.14l0.25-0.129l0.273-0.368l0.015-0.678l-0.152-0.93l0.228-0.185l0.401-0.144l0.191-0.354l-0.146-1.594l0.133-0.283l0.811,0.32l0.391,0.11l0.309,0.013l0.17-0.128l1.148-2.25v-0.324l-0.192-0.408l0.045-0.212l0.938-1.134l0.136-0.382l-0.057-0.761l0.197-0.354l1.446-0.883l0.719-0.512l0.312-0.129l0.558,0.082l0.853,0.221l0.295-0.058l-0.184-0.718l0.072-0.283l0.596-0.582l0.112-0.24l0.018-0.508l0.001-0.127l0.306-0.34l0.277-0.044l0.504,0.279l0.397,0.435l0.243,0.901l0.217,0.309l0.287,0.041l0.504-0.031l0.146,0.14l0.195,1.649l0.02,0.875l-0.353,0.862l-0.429,0.722l-0.611,0.525l-0.487,0.271l-0.191,0.198l-0.617,0.85l0.075,0.465l0.163,0.705l-0.224,0.58v0.268l0.216,0.069l0.312-0.086l0.819-0.442l0.771-0.089l0.479-0.017l0.156,0.126l0.277,1.762l0.202,0.324l0.554-0.074l0.521,0.096l0.033,0.268l-0.729,1.584l0.117,0.352l0.228,0.098l0.507-0.003l0.481-0.045l0.291,0.379l0.341,0.746l0.378,0.266l0.246,0.083l0.647-0.159l0.628-0.413l0.111,0.38l0.153,0.239l-0.502,0.355l-0.53,0.61l-0.442,0.581l-0.582,0.455l-0.193,0.185l-0.08,0.085l-0.158,0.071l-0.645,0.06l-0.436,0.172l-0.528,0.342l-0.394,0.595l-1.078,0.316l-0.62,0.018l-0.474-0.082l-0.362,0.411l-0.143,0.368l-0.036,0.819l-0.114,0.509l0.064,0.409l-0.086,0.24l-0.163,0.001l-0.588,0.131l0.739,0.884l0.069,0.183l0.112,0.875l0.254,0.14l1.091,0.953l0.148,0.324l0.646,1.041l0.163,0.338l-0.194,0.241l-0.451,0.229l-0.128,0.226l0.231,1.185l-0.171,0.198l-0.812,0.428l0.178,0.38l0.6,1.436l0.54,0.477l0.606,0.604l0.203,0.479l0.088,0.663l-0.086,0.636l0.006,0.254l0.488,1.183l0.586,1.225l-0.077,0.297l-1.011,1.559l-1.01,1.7l-0.098,0.374l-0.359-0.181l-0.075-0.805l0.461-0.665l0.174-0.495l0.122-0.777l0.287-0.466l-0.512-0.027l-0.104-0.084l-0.004-0.282l0.195-0.509l-0.177-1.524l-0.246-0.832l-0.639-1.185l-0.488-1.312l-0.347-0.846l-0.179-0.875l-0.174-1.736l-0.117-0.677l-0.034-0.564l-0.051-0.212l-0.344-0.084l-0.148-0.098l-0.304-0.917l-0.516-0.677l-0.226-0.225l-0.247,0.029l-0.081,0.988l-0.158,0.424l-0.43,0.41l-0.59,0.284l-1.089,0.511l-0.359,0.622l-0.298,0.297l-0.196,0.142l-0.237-0.282l-0.007-0.438l-0.212,0.015l-0.338,0.354l-0.321-0.013l-0.166-0.211l0.147-0.495l-0.001-0.113l-0.621,0.171l-0.276,0.127l-0.247,0.283l-0.355-0.126l-0.002-0.466l0.553-1.54l0.162-0.791l0.001-0.889l-0.101-1.059l-0.384-0.973l-0.431-1.072l-0.196-0.296l-0.281,0.537l-0.32-0.126l-0.526-0.366l0.482-0.17l0.312-0.015l-0.149-0.479l-0.054-0.268l-0.684-0.775l-0.182-0.183l-0.19-0.028l-0.407,0.1l-0.38-0.267l0.086-0.438l-0.026-0.141l-0.209-0.112l-0.365,0.043l-0.577-0.465l-0.504-0.606l-0.117-0.244l0.252-0.341l0.801-0.527l-0.194-1.607z"/> - <path id="BD" country:name="Bangladesh" d="M605.297,153.429l-0.126-0.264l-0.269-0.55l-0.223-1.213l-0.611-1.41l-0.357-0.395l-0.73,0.354l-0.393,0l-0.034-0.084l-0.242-0.211l-0.356-0.592l-0.124-0.042l-0.152,0.127l-0.026,0.537l0.374,0.79l-0.006,0.424l-0.143,0.169l-0.455,0.086l-0.235,0.537l-0.261,0.1l-0.255-0.437l-0.311-0.395l-0.073-0.057l-0.163,0.669l-0.28,0.249l-0.203,0.043l-0.271-0.536l-0.495,0.636l-0.359-0.265l-0.147-0.532l-0.402-1.775l-0.325-1.409l-0.352-0.45l-0.04-0.254l0.505-0.765l0.029-0.269l-0.193-0.21l-1.042-0.431l-0.339-0.323l0.548-0.61l0.4-0.299l0.502-0.13l0.382-0.101l0.047-0.155l-0.126-0.112l-1.224-0.938l-0.494-0.237l-0.083-0.155l0.124-0.283l0.555-0.525l0.234-0.171l1.252,0.303l0.339,0.266l0.372,0.266l0.489-0.06l0.417,0.054l0.129,0.324l0.053,0.479l0.079,0.719l0.095,0.099l0.537,0.109l0.547,0.053l0.916-0.062l0.559-0.003l2.473,0.198l0.111,0.098l0.057,0.127l-0.012,0.79l-0.159,0.34l-0.938,0.767l-0.498,0.13l-0.651,0.356l-0.131,0.283l0.009,0.522l0.001,0.381l0.23,0.281l0.249,0.267l0.529,0.448l0.224-0.354l0.395-1.159l0.281-0.115l0.4-0.044l0.064,0.578l0.627,2.479l0.037,0.466l0.194,1.607l-0.801,0.527l-0.252,0.341z"/> - <path id="TH" country:name="Thailand" d="M627.408,186.411l-0.086,0.337l-0.495,0.35l-0.11,0.575l-0.644,0.089l-0.05-0.478l-0.309-0.163l-0.279,0.28l-0.244,0.394l-0.204-0.083l-0.118-0.239l0.213-0.398l-0.041-0.21l-0.055-0.226l-0.261-0.238l-0.447-0.119l-0.106-0.466l-0.571,0.013l-0.448,0.17l0.013-0.104l0.128-0.297l-0.15-0.183l-0.411,0.212l-0.301-0.07l-0.38-0.38l-0.116-0.508l0.064-0.282l-0.151-0.438l-0.229-0.169l-0.388,0.043l-0.39-0.719l-0.209-0.508l-0.3-0.324l-0.311-0.155l-0.456-0.395l-0.343,0.1l-0.218,0.142l-0.216-0.381l-0.04-0.607l0.163-0.749l0.559-1.738l0.29-0.848l-0.087-0.044l0.098-0.374l1.01-1.7l1.011-1.559l0.077-0.297l-0.586-1.225l-0.488-1.183l-0.006-0.254l0.086-0.636l-0.088-0.663l-0.203-0.479l-0.606-0.604l-0.54-0.477l-0.6-1.436l-0.178-0.38l0.812-0.428l0.171-0.198l-0.231-1.185l0.128-0.226l0.451-0.229l0.194-0.241l-0.163-0.338l-0.646-1.041l-0.148-0.324l-1.091-0.953l-0.254-0.14l-0.112-0.875l-0.069-0.183l-0.739-0.884l0.588-0.131l0.163-0.001l0.086-0.24l-0.064-0.409l0.114-0.509l0.036-0.819l0.143-0.368l0.362-0.411l0.474,0.082l0.62-0.018l1.078-0.316l0.394-0.595l0.528-0.342l0.436-0.172l0.645-0.06l0.158-0.071l0.08-0.085l0.541,0.166l0.295,0.182l0.118,0.168l0.01,0.423l-0.106,0.805l0.066,0.367l0.186,0.154l0.423-0.003l0.489-0.2l0.414-0.045l0.045,0.113l0.249,1.311l-0.085,0.41l-0.528,1.569l-0.117,0.438l-0.027,0.494l0.145,0.324l0.481,0.138l0.37-0.411l1.173-1.178l0.346-0.03l0.835,0.348l0.59,0.265l0.223-0.072l0.543-0.257l0.2-0.538l0.286-0.453l0.403,0.012l0.893,0.192l0.266,0.153l0.052,0.282l0.285,0.535l0.688,0.659l0.435,0.632l0.058,1.524l0.107,0.366l0.255,0.464l0.979,1.279l0.419,0.703l0.157,0.507l0.002,0.945l-0.121,0.438l-0.808,0.64l-0.301-0.167l-0.599-0.109l-0.575-0.039l-0.558,0.074l-0.798-0.066l-1.172,0.091l-0.383,0.101l-0.521,0.441l-0.92,1.233l-0.146,0.297l-0.076,0.382l0.026,0.635l0.219,0.648l0.487,0.717l0.16,0.479l-0.146,0.176l-0.026-0.063l-0.286-0.183l-0.458-0.084l-0.9-0.887l-0.434-0.154l-0.304-0.014l-0.572,0.227l-0.391-0.112l-0.29-0.141l-0.337-0.014v-0.282l0.19-1.243l-0.107-0.184l-0.719-0.055l-0.248-0.084l-0.521,0.043l-0.443,0.212l-0.244,0.297l0.207,0.593l-0.103,0.339l-0.318,0.707l0.083,0.579l0.054,0.41l-0.293,0.664l-0.583,1.187l-0.7,1.682l-0.255,1.314l0.104,1.171l0.172,0.296l0.229,0.169l0.55-0.072l0.396-0.142l0.252,0.07l0.135,0.353l0.009,0.325l-0.08,0.466l0.141,0.282l0.178,0.211l0.271-0.094l0.17,0.46l0.209,0.974l-0.032,0.254l0.127,0.737l0.434,0.871l0.167,0.155l0.801,0.281l0.539,0.112l0.467-0.058l0.294,0.197l0.266,0.612l0.664,0.544l0.212,0.145z"/> - <path id="BZ" country:name="Belize" d="M204.31,158.989l-0.175,0.412l0.612-0.173l0.026,0.429l-0.419,1.241l0.178,0.269l-0.237,0.795l0.189,0.318l-0.092,0.397l-0.358,0.875l-0.3,0.35l-0.36,0.032l-0.054,0.286l-0.388,0.238l0,0.286l-0.69,0.016l0.215-4.297l-0.025-0.329l0.278-0.095l0.386,0.27l0.599-0.857l0.178-0.447l0.437-0.016z"/> - <path id="GT" country:name="Guatemala" d="M200.276,169.481l-0.151-0.056l-0.928-0.342l-0.614,0.032l-0.766-0.032l-0.608-0.239l-0.909-0.656l-0.513-0.419l-0.044-0.454l-0.054-0.553l0.207-0.238l-0.305-0.397l1.076-1.812l1.06-0.007l1.762,0.007l0.211-0.683l-0.532-0.223l-0.359-0.69l-0.624-0.231l-0.495-0.541l-0.396-0.223l0.999-0.032l0.04-1.24l1.792,0.005l2.332,0.006l-0.215,4.297l0.69-0.016l0.303,0.095l0.311,0.302l0.14-0.191l-0.066-0.381l0.336,0.157l0.458,0.367l-1.507,1.208l-0.499,0.238l-0.177,0.493l0.162,0.604l-0.438,0.302l-0.467,0.048l-0.043,0.254l0.164,0.159l-0.351,0.111l-0.184,0.302l-0.22-0.016l-0.565,0.461l-0.012,0.223z"/> - <path id="HN" country:name="Honduras" d="M204.413,165.093l0.312-0.03l0.612-0.27l0.639-0.058l0.743,0.126l0.478,0.069l1.443,0.04l0.699-0.228l0.379-0.199l0.567,0.267l0.788-0.03l0.763-0.101l0.63-0.001l0.5,0.126l0.564,0.253l-0.038,0.353l-0.102,0.226l0.228,0.282l0.787,0.238l0.557,0.069l0.244,0.524l-1.425,0.486l-0.424,0.229l-0.248,0.086l-0.463-0.097l-0.328-0.182l-0.259-0.013l-0.294,0.242l-0.503,0.794l-1.207,0.997l-0.725-0.42l-0.513,0.583l-0.882,0.034l-0.005,0.961l-0.293,0.412l-0.29,0.143l-1.001,0.125l-0.311-0.661l-0.025-0.085l-0.478-0.3l0.085-0.731l-0.128-0.175h-0.272l-0.541-0.276l-0.433,0.34l-0.365-0.016l-0.066-0.271l-0.565-0.35l-0.409-0.08l-0.208-0.418l-0.677-0.17l0.438-0.302l-0.162-0.604l0.177-0.493l0.499-0.238l1.507-1.208z"/> - <path id="SV" country:name="El Salvador" d="M205.532,170.085l0.035,0.076l-0.203,0.057l0.01,0.265l-0.237,0.334l-0.68-0.046l-0.853-0.139l-1.697-0.505l-1.305-0.435l-0.325-0.21l0.012-0.223l0.565-0.461l0.22,0.016l0.184-0.302l0.351-0.111l-0.164-0.159l0.043-0.254l0.467-0.048l0.677,0.17l0.208,0.418l0.409,0.08l0.565,0.35l0.066,0.271l0.365,0.016l0.433-0.34l0.541,0.276h0.272l0.128,0.175l-0.085,0.731z"/> - <path id="CO" country:name="Colombia" d="M242.38,173.617l-0.128-0.105l-0.84,0.171l-0.534,0.156l-0.414,0.2l-0.056,0.288l0.048,0.497l-0.129,0.396l-0.227-0.027l-0.381,0.059l-0.99,1.758l-0.172,0.722l-0.241,0.722l-0.709,1.191l0.402,0.025l0.234-0.1l0.384-0.017l0.31,0.606l0.855,1.45l0.103,0.395l-0.226,1.132l0.099,0.353l0.401,0.309l0.429,0.548l0.397,0.252l0.496-0.017l1.163-0.12l1.167-0.05l0.521,0.181l0.64,0.321l0.188,0.253l0.847,0.998l0.554,0.576l0.144,0l0.522-0.13l0.76-0.174l1.99-0.224l0.644,0.081l-0.409,0.525l-0.085,1.004l-0.379,0.511l-0.147,0.326l0.026,0.254l0.035,0.438l0.048,0.367l0.162,0.804l0.447,0.789l0.256,0.437l0.486,0.647l0.121,0.282l-0.731,0.612l-0.479,0.526l0.51,0.491l0.797,1.182l-0.52,0.286l-0.834,0.57l-0.412,0.158l-0.463,0.017l-2.812-0.082l-0.64-0.024l-0.042,0.325l-0.013,1.031l0.178,0.154l0.896,0.122l0.177,0.084l0.293,0.408l0.052,0.367l-0.384-0.04l-0.417-0.11l-0.687,0.032l-0.493,0.187l-0.111,0.085l-0.001,1.071l0,0.554l0.192,0.197l0.688,0.363l0.192,0.183l-0.031,0.777l0.399,0.562l0.031,0.212l-0.326,1.428l-0.706,4.411l-0.073,0.382l-0.133,0.198l-0.156-0.14l-0.575-0.703l-0.237-0.126l-0.161,0.058l-0.448,0.031l1.155-1.956l0.035-0.198l-0.127-0.069l-1.299-0.84l-0.509-0.209l-0.708,0.442l-0.397-0.182l-0.523-0.421l-0.452,0.427l-0.337,0.157l-0.496,0.031l-1.038-0.008l-0.573-0.152l-0.092-0.281l0.004-0.396l-0.173-0.296l-0.479-0.039l-0.366-0.14l-0.078-0.282l-0.251-0.761l-0.988-0.672l-0.526-0.364l-0.208-0.62l-0.208-0.324l-0.513-0.435l-0.897-0.418l-0.927-0.107l-0.081-0.112l-0.269-0.162l-0.197-0.118l-0.709-0.631l-0.128-0.056l-0.89,0.401l-0.67,0.061l-0.977-0.277l-0.355-0.309l-0.166-0.493l-0.227-0.225l-1.432-0.656l-1.496-0.803l0.033-0.068l-0.117-0.311l-0.181-0.282l0.108-0.212l0.509-0.114l0.465,0.112l0.186-0.325l-0.348-0.564l0.086-0.424l0.314-0.227l0.878-0.058l0.193,0.042l0.41-0.227l0.445-0.679l0.45-0.961l0.651-1.061l-0.122-0.268l-0.56-0.408l-0.071-0.184l0.306-0.721l0.089-0.523l-0.149-0.861l-0.371-0.86l0.085-0.254l0.49-0.143l0.135-0.212l-0.088-0.198l-0.565-0.479l-0.042-0.226l0.103-0.198l0.242-0.326l0.036-0.254l-0.173-0.282l-0.739-0.719l-0.364-0.396l0.256-0.753l0.228-0.082l-0.045-0.45l0.19,0.082l0.085,0.307l0.584-0.409l0.094-0.43l0.322-0.062l-0.509-1.038l-0.228-0.149l-0.084-0.327l0.142,0.075l0.42,0.338l0.397,0.507l0.22,0.508l0.235,0.197l0.199-0.17l0.147-0.241l-0.332-0.776l0.02-0.212l0.176-0.297l0.445-0.34l0.399-0.297l0.501-0.736l0.327-0.156l0.684-0.101l0.217-0.382l-0.104-0.381l0.174-0.777l0.067-0.65l0.207-0.48l0.498-0.439l0.429-0.283l0.592-0.242h0.113l0.374,0.206l0.22,0.443l0.281-0.34l0.031-0.438l0.199-0.551l0.22-0.071l0.267,0.126l0.855,0.041l0.562-0.001l0.623-0.27l0.237-0.254l0.476-0.298l0.848-0.256l0.435-0.396l0.278-0.551l0.333-0.255l0.469-0.17l0.58,0.013l0.526,0.338l0.155,0.126l0.155,0.339l-0.285,0.332z"/> - <path id="BJ" country:name="Benin" d="M408.6,174.04l-0.062,0.777l0.164,0.762l0.388,0.718l-0.316,0.962l-0.19,0.566l-0.223,0.298l-0.656,0.414l-0.095,0.34l0.116,0.592l-0.078,0.368l-0.433,0.13l-0.257,0.03l-0.237,0.397l0.002,0.381l0.003,0.48l-0.012,0.876l-0.09,0.989l0.217,1.439l-0.121,1.188l0.006,0.234l-0.333,0.015l-1.232,0.144l-0.669,0.052l-0.106-0.205l-0.295-1.072l0.188-0.708l0.026-0.833l-0.036-0.537l-0.135-0.974l-0.006-0.862l-0.035-0.522l0.013-0.579l-0.442-1.311l-0.164-0.691l-0.403-0.323l-0.468-0.294l-0.18-0.395l0.141-0.594l0.046-0.424l0.062-0.142l0.24-0.157l0.366-0.553l0.415-0.271l0.418-0.045l0.739,0.095l0.337-0.158l0.415-0.468l0.237-0.764l-0.131-0.367l0.577-0.3l0.321-0.073l0.339,0.28l0.727,0.589l0.902,0.503z"/> - <path id="GH" country:name="Ghana" d="M394.266,178.814l0.191-0.17l-0.02-0.41l-0.261-1.934l0.125-0.34l0.271-0.157l2.119-0.041l0.867,0.037l1.429,0.006l0.976-0.458l0.161,0.032l0.595,0.119l-0.25,0.849l0.05,0.254l0.633,0.915l0.244,0.451l-0.188,0.721l0.02,0.396l0.265,1.114l0.181,0.592l0.503,0.788l0.032,0.155l-0.286,0.242l-0.174,0.382l0.01,1.314l-0.011,0.72l0.021,0.551l0.18,0.479l0.468,0.577l0.752,0.608l-0.503,0.682l-0.304,0.099l-0.593-0.013l-0.992,0.144l-0.463,0.185l-0.188,0.098l-0.898,0.469l-1.263,0.398l-0.942,0.412l-0.958,0.567l-0.578-0.324l-0.945-0.436l-0.074-0.124l-0.066-0.741l-0.554-1.155l-0.263-0.747l-0.103-0.706l0.327-1.005l0.437-1.274l0.521-0.851l0.203-0.595l-0.334-1.438l-0.189-1.285l-0.178-0.154z"/> - <path id="TG" country:name="Togo" d="M400.72,175.499l1.013,0.163l0.611,0.166l0.29,0.041l-0.046,0.424l-0.141,0.594l0.18,0.395l0.468,0.294l0.403,0.323l0.164,0.691l0.442,1.311l-0.013,0.579l0.035,0.522l0.006,0.862l0.135,0.974l0.036,0.537l-0.026,0.833l-0.188,0.708l0.295,1.072l0.106,0.205l-0.452,0.035l-0.479,0.128l-0.368,0.212l-0.023,0.04l-0.752-0.608l-0.468-0.577l-0.18-0.479l-0.021-0.551l0.011-0.72l-0.01-1.314l0.174-0.382l0.286-0.242l-0.032-0.155l-0.503-0.788l-0.181-0.592l-0.265-1.114l-0.02-0.396l0.188-0.721l-0.244-0.451l-0.633-0.915l-0.05-0.254l0.25-0.849z"/> - <path id="CI" country:name="Ivory Coast" d="M383.772,190.418l0.041-0.919l0.105-0.565l0.247-0.849l0.059-0.452l-0.131-0.282l-1.264-1.334l-0.592,0.032l-0.369-0.097l-0.194-0.183l-0.05-0.183l0.501-0.865l0.059-0.438l-0.119-0.55l0.062-0.17l0.047-0.099l0.602-0.554l0.188-0.354l-0.179-0.21l-0.296-0.549l0.03-0.127l0.158-0.199l0.304-0.03l0.548,0.223l0.304,0.012l0.19-0.143l-0.051-0.226l-0.648-0.561l-0.309-0.351l0.332-0.37l0.125-0.283l-0.197-0.31l-0.695-0.405l-0.214-0.409l0.264-0.623l0.379-0.397l0.522-0.54l0.352-0.059l0.566,0.321l0.455,0.436l0.35-0.228l0.362-0.469l0.571-0.483l0.239-0.114l0.257,0.041l0.147,0.211l0.004,0.297l0.117,0.381l0.148,0.239l0.352-0.059l0.604-0.399l0.159-0.1l0.259,0.168l0.545-0.003l0.308,0.252l0.15,0.465l0.52,0.562l0.452,0.223l0.354,0.083l0.368-0.115l0.446-0.257l0.608-0.159l0.769-0.075l0.644,0.166l0.63,0.434l0.178,0.154l0.189,1.285l0.334,1.438l-0.203,0.595l-0.521,0.851l-0.437,1.274l-0.327,1.005l0.103,0.706l0.263,0.747l0.554,1.155l0.066,0.741l-0.119-0.201l-0.289-0.197l-0.208,0.015l-0.143,0.24l-0.096,0.042l-0.48-0.027l-0.705-0.167l-0.608-0.083l-2.352,0.062l-1.279,0.243l-0.575,0.199l-1.07,0.369l-1.739,0.781l-0.701,0.425l-0.256-0.013l-0.075-0.032z"/> - <path id="MY" country:name="Malaysia" d="M627.408,186.411l0.035,0.024l0.523,0.098l1.061,1.198l0.693,0.916l0.506,0.762l0.081,0.579l-0.023,0.805l-0.134,0.862l0.07,1.073l-0.07,0.636l0.097,0.494l0.196,0.381l0.53,0.493l0.338,0.536l0.705,1.608l0.062,0.127l-0.366-0.069l-0.895-0.055l-0.401,0.142l-0.175-0.07l-0.521-0.437l-0.885-0.605l-0.6-0.337l-1.231-0.675l-1.02-0.732l-0.217-0.254l-0.16-0.988l-0.438-0.691l-0.895-0.817l-0.195-0.663l0.039-0.494l0.03-0.283l-0.107-0.409l-0.399-0.634l-0.347-1.849l-0.188-0.72l0.043-0.362l0.448-0.17l0.571-0.013l0.106,0.466l0.447,0.119l0.261,0.238l0.055,0.226l0.041,0.21l-0.213,0.398l0.118,0.239l0.204,0.083l0.244-0.394l0.279-0.28l0.309,0.163l0.05,0.478l0.644-0.089l0.11-0.575l0.495-0.35l0.086-0.337z M643.95,196.042l0.081,0.044l0.375,0.408l0.397,0.141l0.861,0.083l0.413,0.168l0.761,0.436l0.335,0.042l0.337-0.1l-0.503-0.535l0.169-0.551l0.365-0.608l0.528-1.258l0.584-0.27l1.481-0.342l1.018-0.299l0.428-0.326l0.524-1.021l0.523-0.323l0.87-1.117l0.22-0.212l0.244-0.147l0.112-0.068l0.084,0.126l0.062,0.37l0.234-0.012l0.111,0.259l0.309,0.271l0.383-0.271l1.234-0.42l-0.025-0.086l-0.197-0.197l0.013-0.247l0.024-0.111l-0.148-0.444l-0.11-0.174l0.167-0.042l0.188,0.143l0.085-0.016l0.449-0.084l0.161-0.283l-0.036-0.24l-0.478-0.366l0.197-0.396l0.436-0.071l0.511,0.041l0.154-0.605l0.408-0.313l0.284-0.48l0.531-0.58l0.498-1.032l0.075-0.17l0.322,0.465l0.33,0.098l0.315-0.424l0.305,0.494l0.351,0.282l0.402,0.211l0.075,0.338l-0.182,0.354l-0.234,0.452l0.037,0.198l0.631-0.128l0.472-0.128l0.115,0.226l-0.349,0.495l0.742-0.1l0.357-0.085l0.269,0.056l1.035,0.662l0.345,0.14l0.1,0.24l-0.158,0.269l-0.201,0.155l-0.44,0.143l-0.594,0.029l-0.683-0.083l-0.355,0.311l0.096,0.254l0.888,0.69l-0.161,0.311l-0.458,0.199l-0.646,0.1l-0.518,0.114l-0.067,0.15l-0.182-0.09l-0.753-0.292l-0.446-0.04l-0.624,0.018l-0.651-0.081l-0.748-0.081l-0.464,0.017l-0.247,0.157l-0.381,0.638l-0.119,0.565l0.106,0.988l-0.22,0.383l-0.646,0.244l-0.218,0.34l0.076,0.748l-0.928,1.785l-0.387,0.299l-0.864,0.175l-0.465,0.172l-0.467,0.356l-0.287,0.03l-0.559-0.152l-0.524-0.223l-0.557-0.251l-0.431-0.11l-0.479,0.074l-0.531,0.441l-0.403,0.525l-0.528,0.342l-0.399,0.172l-0.543-0.11l-0.526-0.223l-0.255,0.001l-0.928,0.416l-0.446-0.28l-0.304-0.083l-1-0.983l-0.253-0.295l-0.288-0.792z"/> - <path id="SR" country:name="Suriname" d="M274.556,195.884l0.06-0.212l-0.332-0.563l-0.49-1.127l-0.246-0.832l-0.185-0.295l-0.561-0.067l-0.532-0.675l-0.571-0.831l0.328-0.694l0.095-0.467l-0.078-0.777l0.169-0.17l1.131-0.091l0.183-0.27l0.082-0.862l0.142-0.496l0.015-0.339l0.326-0.312l0.382-0.057l1.392,0.463l0.465,0.042l0.083-0.41l0.141-0.085l0.337,0.027l0.833,0.012l0.863-0.03l0.723,0.069l0.63,0.182l0.999,0.427l-0.647,0.876l-0.391,0.751l-0.137,0.594l0.094,0.381l0.134,0.635l0.086,0.664l0.521,0.844l0.029,0.438l-0.424,1.472l-0.489,0.963l-1.05-0.488l-0.319,0.001l-0.534,0.385l-0.398,0.059l-0.418-0.139l-0.642-0.124l-0.172,0.156l-0.2,0.326l0.611,1.014l-0.528-0.054l-1.108-0.276l-0.4-0.04z"/> - <path id="GF" country:name="French Guiana" country:shortname="Fr Guiana" d="M285.859,190.719l0.015,0.422l-1.102,1.646l-0.427,0.765l-0.439,0.992l-0.464,0.681l-0.299,0.214l-0.56-0.025l-1.11-0.389l-0.882,0.613l-0.225-0.069l-0.649-0.505l0.489-0.963l0.424-1.472l-0.029-0.438l-0.521-0.844l-0.086-0.664l-0.134-0.635l-0.094-0.381l0.137-0.594l0.391-0.751l0.647-0.876l0.218,0.093l1.033,0.294l0.55,0.196l0.799,0.549l1.264,1.084l0.545,0.564l0.317,0.465l0.193,0.028z"/> - <path id="CF" country:name="Congo" d="M429.505,210.684l-0.695-0.533l-0.351,0.13l-0.68,0.513l-0.536,0.414l-0.112-0.177l-0.392-0.86l-1.381-1.344l0.184-0.295l0.413-0.229l0.803,0.307l0.343-0.681l-0.052-0.296l-0.274-0.253l-0.39-0.521l-0.116-0.366l0.058-0.495l0.127-0.1l0.909-0.146l0.604-0.243l0.125-0.213l0.167-0.807l0.174-0.185l0.239-0.029l0.193,0.14l0.341,0.479l0.405,0.521l0.386,0.195l0.287-0.016l0.188-0.228l0.362-0.482l0.29,0.253l0.167,0.578l0.146,0.112l0.304,0.068l0.255-0.114l0.184-0.68l0.243-1.089l0.131-1.229l0.229-1.047l-0.114-0.338l-0.161-0.127l-0.384-0.082l-0.528-0.208l-0.242-0.31l-0.132-0.437l0.008-0.109l0.021-0.3l0.157-0.284l0.492-0.398l0.556-0.441l0.094-0.354l-0.389-0.902l-0.369-0.322l-0.592-0.067l-0.939,0.5l-0.463-0.025l-0.146-0.253l-0.068-0.734l0.077-0.679l0.396-0.468l0.56,0.109l0.863,0.023l0.878-0.076l0.271,0.055l0.479,0.04l0.56,0.124l0.576,0.194l0.864,0.334l0.863,0.292l0.271-0.086l-0.1-0.861l0.159-0.185l0.303-0.312l0.365-0.497l0.158-0.523l0.222-1.287l0.255-0.228l0.479-0.102l0.975-0.175l0.367,0.054l0.624,0.138l0.895,0.093l0.751-0.287l0.128,0.197l-0.031,0.156l-0.398,1.203l-0.558,0.837l-0.349,0.821l-0.094,0.551l-0.156,0.764l-0.196,2.021l-0.254,1.342l-0.115,0.61l-0.169,0.708l-0.139,0.523l-0.459,0.427l-0.525,0.229l-0.809,0.599l-0.41,0.454l-0.47,0.836l-0.343,0.751l-0.193,1.159l-0.074,0.396l0.122,0.72l-0.086,0.706l-1.025,0.938l-0.364,0.229l-0.931,0.811l-0.554,0.399l-0.57,0.328l-0.147-0.211l-0.042-0.664l-0.054-0.424l-1.495,0.532l-0.327,0.581l-0.443,0.271l-0.177-0.013l-0.484-0.336z"/> - <path id="GA" country:name="Gabon" d="M425.506,195.522l0.045-0.495l0.88,0.093l1.773,0.088l0.831,0.038l1.022,0.149l-0.396,0.468l-0.077,0.679l0.068,0.734l0.146,0.253l0.463,0.025l0.939-0.5l0.592,0.067l0.369,0.322l0.389,0.902l-0.094,0.354l-0.556,0.441l-0.492,0.398l-0.157,0.284l-0.021,0.3l-0.008,0.109l0.132,0.437l0.242,0.31l0.528,0.208l0.384,0.082l0.161,0.127l0.114,0.338l-0.229,1.047l-0.131,1.229l-0.243,1.089l-0.184,0.68l-0.255,0.114l-0.304-0.068l-0.146-0.112l-0.167-0.578l-0.29-0.253l-0.362,0.482l-0.188,0.228l-0.287,0.016l-0.386-0.195l-0.405-0.521l-0.341-0.479l-0.193-0.14l-0.239,0.029l-0.174,0.185l-0.167,0.807l-0.125,0.213l-0.604,0.243l-0.909,0.146l-0.127,0.1l-0.058,0.495l0.116,0.366l0.39,0.521l0.274,0.253l0.052,0.296l-0.343,0.681l-0.803-0.307l-0.413,0.229l-0.184,0.295l-0.038-0.037l-0.563-0.493l-0.532-0.55l-0.259-0.466l-1.318-1.169l0.286-0.312l-0.369-0.281l-0.528-0.056l-0.918-1.438l0.382-0.297l0.111-0.1l-0.321-0.395l-0.464-0.14l-0.29-0.564l-0.369-0.451l0.319-0.17l0.541-0.411l0.223-0.396l0.291-0.976l0.089-0.295l0.415,0.07l0.495,0.013l-0.064-0.211l-0.56-0.352l-0.561-0.451l0.208-0.042l0.271-0.128l0.142-0.617l0.83-0.043l0.927,0.008l1.245,0.021l0.575-0.032l-0.001-0.155l-0.02-0.551l-0.026-1.836z"/> - <path id="GQ" country:name="Equatorial Guinea" country:shortname="Eq Guinea" d="M422.536,195.513l1.005-0.007l1.965,0.017l0.026,1.836l0.02,0.551l0.001,0.155l-0.575,0.032l-1.245-0.021l-0.927-0.008l-0.83,0.043l0.033-0.146l-0.049-0.297l-0.144-0.084l-0.416-0.098l0.287-0.467l0.447-0.523l0.335-0.58l0.066-0.403zM419.636,193.273l-0.484-0.049l-0.049-0.218l0.049-0.291l0.242-0.097l0.024-0.146v-0.291l0.17-0.097l0.169-0.121l0.219,0.048l0.218,0.048l0.097,0.194l-0.193,0.169l-0.146,0.243l-0.17,0.339l-0.146,0.267z"/> - <path id="EC" country:name="Ecuador" d="M222.291,207.801l0.188-0.126l0.264-0.312l0.585-1.061l0.038-0.269l-0.209-0.733l0.058-0.391l-0.478,0.617l-0.732,0.623l-0.333-0.098l-0.601-0.324l-0.408-0.408l0.389-0.283l0.1-0.24l-0.167-0.579l0.005-0.438l0.133-0.466l-0.109-0.282l-0.362-0.649l0.193-0.17l0.48-0.198l0.721-0.454l-0.319-0.395l0-0.226l0.175-0.354l0.497-0.462l0.157-0.146l0.14-0.848l-0.116-0.452l-0.082-0.184l0.11-0.226l0.686-0.101l0.891-0.341l0.396-0.241l0.474-0.382l0.09-0.186l1.496,0.803l1.432,0.656l0.227,0.225l0.166,0.493l0.355,0.309l0.977,0.277l0.67-0.061l0.89-0.401l0.128,0.056l0.709,0.631l0.197,0.118l0.269,0.162l0.081,0.112l0.387,0.76l0.321,0.789l-0.08,0.255l-0.352,0.384l-0.547,1.147l-0.533,0.779l-0.71,0.725l-1.001,0.755l-0.336,0.087l-1.028,0.303l-0.901,0.358l-0.809,0.499l-0.59,0.653l-0.284,0.51l-0.987,2.506l-0.267,0.312l-0.242,0.072l-0.398-0.068l-0.398-0.491l-0.191-0.479l-0.312-0.252l-0.815,0.005l-0.444-0.11l-0.105-0.197l-0.097-0.494l0.233-0.34l0.029-0.495l0.005-0.569z"/> - <path id="PE" country:name="Peru" d="M245.934,224.314l1.109,1.843l0.922,1.646l0.08,0.24l-0.437,0.736l-0.15,0.523l-0.143,0.848l0.057,0.522l0.236,0.902l-0.156,0.34l-0.221,0.34l-0.532,0.582l-0.102,0.452l0.347,0.845l-0.21,0.368l-0.159,0.34l0.022,0.48l0.604,1.168l0.015,0.522l-0.285,0.439l-0.723,0.61l-0.12,0.227l0.049,0.48l0.132,0.295l0.018,0.142l-0.586,0.187l-0.15,0.199l-0.228,0.933l-0.259,0.298l-0.852,0.275l-0.201-0.517l-0.289-0.31l-1.422-0.618l-0.313-0.239l-0.233-0.678l-0.315-0.38l-0.559-0.225l-0.504-0.281l-0.489-0.254l-0.616-0.309l-0.873-0.464l-0.673-0.366l-0.866-0.379l-0.838-0.337l-1.271-0.845l-1.354-0.985l-1.232-1.099l-0.594-0.705l-0.42-0.677l0.008-0.438l0-0.903l-0.269-0.606l-0.781-1.043l-1.389-2.778l-0.285-0.268l-0.467-0.211l-0.074-0.085l0.055-0.536l-0.02-0.396l-0.149-0.396l-1.208-2.199l-0.997-1.961l-0.688-1.27l-1.365-1.917l-0.272-0.353l-0.598-0.973l-0.462-0.423l-0.75-0.437l-0.914-0.365l-0.61-0.365l0.119-0.17l0.181-0.113l0.609-0.029l0.144-0.41l-0.118-0.282l-0.592-0.874l-0.353-0.437l-0.258-0.72l0.01-0.24l0.244-0.523l0.582-0.622l1.02-0.878l0.47-0.198l0.317-0.214l-0.005,0.569l-0.029,0.495l-0.233,0.34l0.097,0.494l0.105,0.197l0.444,0.11l0.815-0.005l0.312,0.252l0.191,0.479l0.398,0.491l0.398,0.068l0.242-0.072l0.267-0.312l0.987-2.506l0.284-0.51l0.59-0.653l0.809-0.499l0.901-0.358l1.028-0.303l0.336-0.087l1.001-0.755l0.71-0.725l0.533-0.779l0.547-1.147l0.352-0.384l0.08-0.255l-0.321-0.789l-0.387-0.76l0.927,0.107l0.897,0.418l0.513,0.435l0.208,0.324l0.208,0.62l0.526,0.364l0.988,0.672l0.251,0.761l0.078,0.282l0.366,0.14l0.479,0.039l0.173,0.296l-0.004,0.396l0.092,0.281l0.573,0.152l1.038,0.008l0.496-0.031l0.337-0.157l0.452-0.427l0.523,0.421l0.397,0.182l0.708-0.442l0.509,0.209l1.299,0.84l0.127,0.069l-0.035,0.198l-1.155,1.956l0.448-0.031l0.161-0.058l0.237,0.126l0.575,0.703l0.156,0.14l0.136,0.324l-0.341,0.186l-0.793-0.235l-0.493-0.096l-0.322,0.072l-0.604,0.441l-0.371,0.115l-0.669-0.066l-1.895,0.773l-0.701,0.442l-0.372,0.172l-0.599,1.415l-0.319,0.511l-0.021,0.155l0.277,0.86l0.012,0.112l-0.625,0.498l-0.62,0.328l-0.349,0.342l-0.247,0.622l0.106,0.564l0.619,0.957l1.333,2.166l0.106,0.127l-0.247,0.495l-0.208,0.312l1.085,0.12l0.415,0.04l0.312,0.182l0.241,0.323l0.096,0.663l1.843,0.032l0.762-0.499l0.648-0.484l0.326-0.114l-0.059,1.511l-0.098,1.173l0.108,0.353l0.317,0.337l0.285,0.068l0.358-0.072l0.786-0.259l0.42-0.045z"/> - <path id="BR" country:name="Brazil" d="M279.288,257.295l-0.063-0.423l0.027-0.777l0.222-0.819l0.298-0.835l0.321-0.75l-0.019-0.141l-0.491-0.336l-0.234-0.112l-1.29,0.445l-0.224-0.055l-0.254-0.563l-0.487-2.524l-0.121-0.437l-0.843-0.404l-0.724-0.278l-0.115,0.001l-0.709,0.413l-0.346,0.03l-0.925-0.221l-0.818-0.15l-0.372-0.04l0.006-0.72l0.086-0.721l0.132-0.862l-0.104-0.959l-0.521-0.872l-0.084-0.663l-0.253-0.408l0.421-0.666l0.38-0.765l0.238-0.834l0.185-1.173l-0.022-0.494l-0.307-0.774l-0.316-0.479l-0.73-0.362l-0.436-0.407l-0.067-0.563l0.261-0.835l-0.042-0.296l-0.693-0.024l-1.615-0.019l-0.5-0.012l-0.967-0.036l-0.153-0.112l-0.249-0.944l-0.138-2.032l-0.03-0.706l-0.203-1.029l0.038-0.565l-0.085-0.169l-0.403-0.237l-0.537-0.166l-0.636-0.123l-1.148,0.077l-0.22-0.084l-0.398-0.308l-0.385-0.774l-0.096-0.014l-0.882-0.037l-0.3-0.098l-0.75-0.603l-0.688-0.307l-0.676-0.25l-0.355,0.03l-0.787-0.023l-0.316-0.097l-1.1-0.939l-0.813-0.928l-0.335-0.591l-0.141-0.635l-0.036-0.818l0.064-0.622l0.079-0.621l-0.045-0.748l-1.283-0.021l-0.934,0.076l-0.36,0.158l-0.874,0.485l-1.471,1.109l-0.415,0.243l-0.48-0.025l-0.336-0.026l-0.946,0.824l-0.355,0.03l-1.122-0.304l-0.939-0.136l-0.42,0.045l-0.786,0.259l-0.358,0.072l-0.285-0.068l-0.317-0.337l-0.108-0.353l0.098-1.173l0.059-1.511l-0.326,0.114l-0.648,0.484l-0.762,0.499l-1.843-0.032l-0.096-0.663l-0.241-0.323l-0.312-0.182l-0.415-0.04l-1.085-0.12l0.208-0.312l0.247-0.495l-0.106-0.127l-1.333-2.166l-0.619-0.957l-0.106-0.564l0.247-0.622l0.349-0.342l0.62-0.328l0.625-0.498l-0.012-0.112l-0.277-0.86l0.021-0.155l0.319-0.511l0.599-1.415l0.372-0.172l0.701-0.442l1.895-0.773l0.669,0.066l0.371-0.115l0.604-0.441l0.322-0.072l0.493,0.096l0.793,0.235l0.341-0.186l-0.136-0.324l0.133-0.198l0.073-0.382l0.706-4.411l0.326-1.428l-0.031-0.212l-0.399-0.562l0.031-0.777l-0.192-0.183l-0.688-0.363l-0.192-0.197l0-0.554l0.001-1.071l0.111-0.085l0.493-0.187l0.687-0.032l0.417,0.11l0.384,0.04l-0.052-0.367l-0.293-0.408l-0.177-0.084l-0.896-0.122l-0.178-0.154l0.013-1.031l0.042-0.325l0.64,0.024l2.812,0.082l0.463-0.017l0.412-0.158l0.834-0.57l0.52-0.286l0.148,0.168l0.138,0.437l0.161,0.861l0.088,0.452l0.199,0.437l0.432,0.054l0.694,0.546l0.482,0.223l0.414-0.073l0.757-0.697l0.083,0.183l0.186,0.776l0.271-0.016l0.645-0.739l0.74-0.654l0.554-0.286l0.652-0.173l0.235-0.213l0.259-0.666l0.203-0.199l0.652-0.131l0.569-0.272l0.265-0.27l-0.15-0.253l-0.434-0.125l-0.96-0.051l-0.166-0.239l-0.079-0.55l-0.302-1.524l-0.391-0.69l-0.616-0.688l0.041-0.184l0.159-0.029l0.309,0.125l0.896,0.461l0.385,0.04l1.149-0.035l0.344,0.224l0.628,0.618l0.348-0.115l0.232-1.117l0.284-0.115l0.465,0.054l0.557-0.074l0.807-0.23l1.74-0.9l0.592-0.385l0.163-0.326l-0.103-0.169l0.375-0.257l0.302-0.058l0.516,0.124l0.26,0.111l0.04,0.212l-0.452,1.09l0.304-0.001l0.533,0.138l0.435,0.958l-0.179,0.368l-0.547,1.416l-0.213,0.962l0.156,0.465l0.281,0.394l0.167,0.31l-0.072,0.354l0.008,0.396l0.15,0.296l1.103,0.897l0.613,0.392l0.686-0.075l0.694-0.513l0.505-0.314l1-0.331l0.934-0.429l0.943,0.022l0.4,0.04l1.108,0.276l0.528,0.054l-0.611-1.014l0.2-0.326l0.172-0.156l0.642,0.124l0.418,0.139l0.398-0.059l0.534-0.385l0.319-0.001l1.05,0.488l0.649,0.505l0.225,0.069l0.882-0.613l1.11,0.389l0.56,0.025l0.299-0.214l0.464-0.681l0.439-0.992l0.427-0.765l1.102-1.646l-0.015-0.422l0.409-0.241l0.276,0.141l0.235,0.423l0.164,0.791l0.414,1.34l0.108,0.607l0.472,1.383l0.296,0.55l0.324,0.324l0.978,0.21l0.196,0.338l0.038,0.551l-0.045,0.254l-0.524,0.354l-0.933,1.414l-0.238,0.325l-0.51,0.411l-0.41,0.231l-0.244,0.138l-0.798,0.778l-0.544,0.947l-0.419,1.018l-0.402,0.453l0.271,0.112l0.512-0.072l0.497-0.198l1.202-0.709l0.112-0.028l0.299,0.889l0.442,0.818l0.255,0.112l0.287,0.07l1.135-0.031l0.592-0.058l0.737-0.298l-0.277,0.679l-0.017,0.584l0.448-0.557l1.254-1.006l0.289-0.156l0.306-0.382l0.499-0.933l0.272-0.396l0.256-0.099l1.006-0.003l0.352-0.198h0.175l0.687,0.549l0.654,0.267l0.32-0.028l0.814,0.28l1.069,0.45l0.334,0.281l0.269,0.593l0.08,0.028l0.176-0.015l0.402-0.354l0.319,0.042l0.302,0.254l0.538,0.789l0.205,0.396l-0.13,0.254l-0.308,0.41l-0.116,0.424l0.091,0.466l0.171,0.396l0.825-0.821l0.369-0.156l0.609-0.156l0.995-0.454l0.224-0.028l0.367,0.069l0.764,0.38l0.907,0.436l0.462,0.098l1.117,0.167l1.118,0.083l0.464-0.058l0.48-0.029l0.577-0.171l0.416-0.016l1.131,0.351l0.731,0.408l0.762,0.479l0.586,0.437l1.595,1.395l0.742,0.662l0.821,0.605l0.41,0.338l0.477,0.196l0.734,0.168l1.247,0.097l0.912,0.04l0.445,0.197l0.265,0.465l0.087,0.607l0.592,2.004l0.268,1.143l0.062,0.988l-0.076,0.579l-0.179,0.904l-0.243,0.848l-0.559,1.301l-0.518,0.849l-1.347,1.175l-1.388,1.288l-0.44,0.198l-0.354,0.043l-0.39,0.637l-0.094,0.396l-0.012,0.353l-0.504,1.074l-0.6,0.976l-0.8,1.104l-0.266,0.212l-0.194,0.015l-0.079-0.423l-0.278-0.296l-0.367-0.084l-0.064,0.79l-0.538,1.64l-0.049,0.734l-0.077,0.607l0.318,2.738l0.078,0.988l-0.577,2.543l-0.039,0.663l0.14,0.649l0.043,0.085l-0.759,0.495l-0.404,0.51l-0.261,0.791l-0.04,0.367l0.245,1.468l-0.106,0.367l-0.214,0.283l-0.676,0.608l-0.752,1.498l-1.01,1.4l-0.201,0.537l-0.055,0.311l0.144,0.945l-1.203,0.37l-0.544,0.283l-0.355,0.368l-0.084,0.466l0.021,0.367l-0.401,0.114l-0.864-0.041l-0.979,0.172l-0.654,0.001l-0.764-0.055l-0.465-0.112l-0.922,0.072l-0.736,0.002l-0.214,0.607l-0.295,0.198l-0.795,0.312l-0.481,0.453l-0.21,0.354l-0.747-0.267l-0.35,0.071l-0.563,0.255l-1.864,1.232l-0.528,0.396l-0.725,0.383l-0.616,0.438l-0.532,0.679l-0.486,0.241l-0.567,0.072l-0.278-0.014l0.006,0.24l0.336,0.225l0.12,0.536l-0.111,0.537l-0.099,0.282l-0.282,0.156l-0.084,0.155l0.384,0.648l0.036,1.186l0.05,1.045l-0.057,0.311l-0.11,0.594l-0.198,0.621l-0.464,0.735l-0.566,0.495l-0.788,0.524l-0.866,1.046l-0.208,0.396l-0.476,1.145l-0.499,0.933l-0.75,1.004l-0.69,0.623l-0.801,0.78l0.321-0.808l0.436-0.594l0.629-0.566l0.605-1.158l-0.06-0.254l-0.356,0.142l-0.397-0.014l-0.633-0.21l-0.075,0.155l0.002,0.297l-0.401,1.215l-0.349,0.48l-0.661,0.438l-0.317,0.283l-0.225,0.424l-0.013,0.354l-0.448,1.709l-0.481,0.763l-0.787,0.934l-1.076,0.979l-0.101-0.313l-0.258-0.746l0.103-0.269l0.634-0.766l0.017-0.269l-0.333-0.379l-0.163-0.027l-0.131-0.197l-0.853-1.109l-0.474-0.435l-0.999-0.587l-0.55-0.194l-0.617-0.194l-0.432-0.576l-0.365-0.393l-0.693,0.427l-0.27,0.016l-0.232-0.38l-0.59-0.814l-0.379-0.407l-0.47-0.364l-0.266-0.098l-0.25,0.101l-1.042,0.246l-0.55,0.003l0.214-0.27l0.833-0.88l1.805-1.816l1.435-1.363l1.633-1.448l0.348-0.242l1.754-0.744l0.521-0.313l0.161-0.467l0.094-1.638l-0.517-1.154l-0.206-0.196l-0.462,0.017l-0.957,0.161z M288.966,203.943l-0.558-0.125l-0.301-0.536l-0.078-0.382l0.16-0.197l-0.094-0.636l0.048-0.381l0.208-1.018l0.176-0.099l0.479-0.058l0.879,0.097l1.007,0.11l0.479-0.199l0.368,0.028l0.479,0.168l0.479,0.083l0.319,0.155l-0.335,0.538l-0.193,0.946l-0.257,0.494l-0.289,0.312l-0.561,0.326l-0.464,0.171l-0.527,0.015l-0.783,0.016l-0.641,0.171z"/> - <path id="PG" country:name="Papua New Guinea" country:shortname="Papua N Guin" d="M732.92,214.323l-0.164-0.24l-0.225-0.197l-0.379-0.126l-0.416,0.198l-0.399-0.38l-0.287-0.184l-0.659-0.238l-0.243-0.239l0.156-0.255l0.29,0.027l0.731-0.058l0.538,0.126l0.743,0.083l0.523-0.058l0.258-0.185l0.232-0.509l0.056,0.099l0.351,0.395l0.286,0.184l0.241,0.014l0.961-0.2l0.366-0.227l0.361-0.722l0.241-0.212l0.653-0.029l0.263-0.128l0.04-0.282l-0.064-0.565l-0.043-0.536l0.495,0.196l0.404,0.056l0.324-0.354l0.318,0.578l0.077,0.353l-0.196,0.495l-0.099,0.184l-0.509,0.044l-0.159,0.226l0.061,0.17l0.437,0.479l-0.308,0.354l-0.264,0.113l-0.742-0.083l-0.416,0.001l-0.091,0.269l-0.408,0.495l-0.275,0.156l-0.973,0.426l-0.484,0.143l-0.798,0.029l-0.807,0.115z M713.795,220.696l0.031-3.438l-0.046-0.805l-0.431-1.368l0.44-0.822l-0.169-7.966l2.581,0.802l0.85,0.337l1.04,0.295l1.254,0.378l0.848,0.507l0.613,0.323l0.597,0.084l0.38-0.058l0.26,0.508l0.274,0.254l0.635,0.352l0.687,0.395l0.779,0.718l-0.3,0.947l0.033,0.226l0.305,0.226l0.665,0.111l1.887,0.787l0.354,0.027l0.72,0.183l0.181,0.254l0.413,0.535l0.211,0.579l-0.166,0.113l-1.114,0.073l-0.563,0.156l-0.098,0.155l0.047,0.339l0.589,0.987l0.5,0.521l1.464,1l0.218,0.847l0.725,1.044l0.288,0.141l0.304-0.015l0.712-0.086l0.338,0.013l0.087,0.198l-0.354,0.551l0.218,0.212l0.401,0.141l0.423,0.041l0.63,0.168l0.096,0.127l-0.031,0.142l-0.648,0.213l0.287,0.24l1.064,0.28l0.538,0.295l0.235,0.763l-0.064,0.226l-1.094-0.012l-0.215-0.154l-0.146-0.466l-0.126-0.099l-1.011-0.111l-1.063-0.266l-0.644-0.126l-0.752,0.016l-0.774-0.026l-0.573-0.211l-0.494-0.352l-0.223-0.522l-0.24-0.268l-0.726-0.31l-0.472-0.338l-0.135-0.197l-1.089-1.608l-0.613-0.817l-0.454-0.056l-1.524-0.336l-0.671-0.31l-0.55-0.055l-0.415,0.185l-0.394,0.071l-0.78-0.45l0.282,0.762l-0.027,0.212l-0.249,0.071l-0.382-0.126l-0.311,0.1l0.296,0.395l-0.116,0.113l-1.037,0.045l-1.125-0.182l-0.478,0.029l0.237,0.127l0.24,0.154l0.642,0.169l0.662,0.352l0.404,0.338l0.219,0.395l-0.411,0.199l-0.739,0.425l-0.458,0.213l-0.668-0.097l-1.801-0.039l-1.219-0.092z"/> - <path id="AU" country:name="Australia" d="M726.605,297.247l-0.479-0.229l-1.179-0.471l-0.543-0.371l-0.508-0.715l-0.477-0.558l-0.216-0.414l0.264-0.044l0.169,0.1l0.421,0.171l0.129-0.143l-0.209-0.387l-0.703-0.699l-0.617-0.713l-0.149-0.257l-0.375-0.956l-0.008-0.67l0.177-0.044l1.004,0.312l1.476,0.354l1.089,0.369l0.797-0.03l0.463-0.144l0.382-0.115l0.373-0.058l0.684,0.027l0.306-0.301l0.716-0.244l0.475,0.385l-0.009,0.1l0.128,0.8l-0.009,0.686l-0.751,1.503l-0.124,0.758l-0.245,0.315l-0.943,0.26l-0.553,0.388l-0.49,0.689l-0.189,0.272l-0.274,0.072z M716.883,224.344l0.682,0.394l0.233,0.509l0.047,0.649l0.118,0.678l0.256,0.197l0.42,0.013l0.102,0.24l-0.45,0.919l0.715,0.338l0.175,0.282l0.147,0.593l0.08,1.3l0.144,0.621l0.456,1.157l0.293,0.268l0.422,0.014l0.328-0.312l0.384-0.185l0.32,0.663l0.363,0.127l0.563,0.408l0.385,0.154l0.144,0.155l0.002,0.41l0.083,0.96l0.275,0.776l-0.046,1.06l0.279,0.24l0.93,1.325l0.276,0.706l0.055,0.777l-0.209,0.876l0.403,0.649l0.275,0.833l0.204,0.353l1.395,0.803l0.285,0.154l0.744,0.111l0.402,0.649l0.843,0.535l0.483,0.169l1.141,0.068l0.117,0.197L731,245.42l-0.273,0.565l0.309,0.424l0.879,0.479l0.22,0.564l0.469,1.342l0.211,0.748l0.112,0.396l0.252,0.311l0.771,0.352l-0.021-0.127l-0.141-0.777l0.913,0.507l0.567,0.154l0.184,0.127l0.136,0.296l0.106,1.752l0.884,0.762l0.573,0.323l0.604,0.154l0.287,0.296l0.244,0.579l0.229,0.424l0.545,0.168l0.176,0.297l0.007,0.269l0.19,0.536l0.106,0.113l0.506,0.126l0.156,0.112l0.162,0.354l0.366,1.327l0.026,0.876l0.013,0.862l-0.132,0.41l-0.181,0.325l0.778,1.271l0.223,0.48l0.181,0.833l0.034,0.749l-0.293,0.708l-0.353,1.668l-0.585,1.755l0.137,0.791l-0.065,0.806l-0.306,0.778l-0.661,0.977l-0.203,0.665l-0.598,0.821l-0.45,0.185l-0.465,0.1l-0.423,0.468l-0.466,0.68l-0.328,1.527l-0.477,0.638l-0.34,0.495l0.014,0.65l-0.208,0.539l-0.331,0.312l-0.601,0.341l-0.27,0.326l-0.3,1.021l-0.169,1.049l-0.079,0.937l0.021,0.666l-0.283,0.64l-0.322,0.354l-0.463,0.3l-0.754,0.101l-1.158,0.087l-0.82,0.03l-0.527,0.157l-0.516,0.299l-1.529,0.94l-0.443,0.129l-0.214,0.284l-0.346,0.071l-0.528,0.059l-0.286-0.014l0.295,0.368l0.209,0.27l-1.315-0.665l-0.885-0.353l0.003-0.469l-0.073-0.156l-0.56-0.467l-0.628-0.368l-0.421-0.014l-0.485,0.172l-0.335,0.242l0.748,0.467l-0.97,0.243l-0.929,0.428l-0.953,0.442l-0.222,0.028l-0.604-0.226l-0.886-0.438l-0.67-0.226l-1.086-0.311l-0.51-0.041l-0.239,0.156l-0.044,0.113l-0.716-0.169l-0.751-0.353l-0.522-0.298l-0.896-0.82l-0.526-0.34l-0.422-0.879l0.09-1.035l-0.082-0.411l-0.184-0.495l-0.664-0.736l-0.141-0.523l-0.029-0.425l-0.534-0.014l-0.786,0.398l-0.597,0.114l-0.34,0.058l-0.178-0.07l-0.167-0.17l0.517-0.454l0.233-0.567l0.073-0.821l-0.253-0.324l-0.536-0.593l-0.247-0.353l-0.485,0.735l-0.443,1.431l-0.19,0.113l-0.796,0.002l-0.199,0.156l-0.196,0.015l-0.255,0.028l0.198-0.396l0.081-0.396l0.079-0.1l0.634,0.041l0.242-0.142l0.126-0.255l-0.105-1.004l0.454-0.835l0.328-0.453l0.091-0.396l0.018-0.409l0.151-0.128l0.245-0.015l0.218-0.354l-0.052-0.227l-0.323-0.494l-0.338-0.494l-0.107,0.707l-0.288,0.255l-0.518,0.299l-0.311,0.467l-0.086,0.155l-0.189,0.467l-0.281,0.326l-0.747,0.242l-0.735,0.481l-0.653,0.567l-0.36,0.693l-0.514,0.808l-0.41-0.339l-0.38-1.328l-0.263-0.579l-0.19-0.325l-0.688-0.79l-0.297-0.734l-0.176-0.212l-0.704,0.072l-0.235-0.099l-0.139-0.24l-0.085-0.269l0.334-0.34l-0.047-0.297l-0.346-0.395l-0.543-0.494l-0.266-0.098l-0.83,0.157l-0.486-0.07l-0.95-0.549l-0.274-0.014l-0.438,0.17l-0.433-0.027l-0.421-0.183l-0.662-0.521l-0.921-0.437l-0.218,0.001l-0.723,0.213l-1.282,0.088l-0.669,0.001l-1.764,0.061l-0.611,0.129l-0.656,0.213l-0.989,0.44l-0.972,0.256l-1.039,0.257l-1.503,0.088l-0.794-0.013l-0.383,0.044l-0.927,0.284l-0.993,0.469l-0.773,0.397l-0.538,0.143l-0.431,0.085l-0.361,0.199l-0.615,0.693l-0.774,1.02l-0.588,0.284l-0.766-0.013l-0.547-0.013l-0.927,0.143l-0.4,0.185l-0.663-0.395l-0.294-0.084l-0.734,0.016l-1.572,0.173l-0.938,0.157l-0.459-0.041l-0.672,0.044l-0.398,0.227l-0.583,0.793l-0.344,0.128l-0.958-0.125l-0.158,0.057l-0.57,0.708l-0.465,0.368l-0.919,0.271l-0.586,0.086l-1.516-0.082l-0.638-0.055l-0.688-0.197l-0.633-0.366l-0.778-0.677l-0.74-0.353l-0.374-0.041l-0.151-0.07l-0.19-1.229l0.055-0.255l0.489,0.112l0.45-0.086l0.332-0.425l0.197-0.467l0.267-1.357l-0.043-1.215l-0.156-0.622l-0.258-0.593l-1.117-1.906l-0.208-0.635l-0.144-0.834l0.027-0.989l-0.16-0.692l-0.467-1.072l-0.663-0.945l-0.603-0.734l-0.214-0.254l0.128-0.904l-0.215-0.536l-0.733-1.115l-0.972-1.018l-0.273-0.583l0.126-0.233l0.188,0.187l0.152,0.443l0.183,0.163l0.235,0.35l0.327,0.188l0.354,0.023l-0.348-1.144l-0.437-0.396l-0.226-0.326l0.08-0.304l0.748,0.84l0.495,0.979l0.477,0.065l-0.099-0.555l0.289-0.039l0.004-0.564l-0.282-0.48l-1.03-1.368l-0.354-0.691l-0.119-0.579l-0.038-0.734l0.355-0.595l0.323-0.523l0.21-0.664l-0.083-1.031l-0.254-0.635l0.033-0.368l0.438-0.692l0.109-0.325l0.064-0.156l0.271,0.649l0.011,0.424l0.105,0.184l0.35,0.027l0.171-0.113l0.187-0.565l0.141-0.48l0.765-0.468l1.22-0.624l0.484-0.326l0.676-0.581l0.585-0.467l0.632-0.327l0.79-0.114l0.697-0.016l0.7-0.002l0.431-0.043l0.352-0.185l0.474-0.453l0.494-0.128l0.929-0.072l0.279-0.143l0.291-0.551l0.158-0.1l0.444,0.027l0.877,0.224l0.626-0.043l0.911-0.299l1.084-0.469l0.359-0.213l0.716-0.665l0.427-0.58l0.29-0.622l0.132-0.297l0.41-0.369l0.968-0.651l0.079-0.17l-0.067-0.409l-0.242-0.805l-0.016-0.495l1.063-1.118l0.387-0.692l0.291,0.169l0.341,0.437l0.619,1.355l0.262,0.253l0.177-0.579l0.021-0.466l0.436,0.238l0.272,0.07l0.189-0.607l-0.06-0.142l-0.563-0.238l-0.175-0.24l0.007-0.565l0.044-0.112l0.897,0.04l0.661,0.253l0.642-0.029l0.334-0.029l0.289,0.074l-0.699-0.455l-0.431-0.141l0.128-0.537l-0.07-0.296l0.135-0.509l0.422-0.354l0.165-0.07l0.732,0.394l0.202-0.043l-0.112-0.452l0.11-0.48l0.146-0.367l-0.041-0.522l0.358-0.171l0.4-0.113l0.813,0.04l0.529-1.088l0.371-0.298l0.35,0.169l0.268,0.451l0.265-0.552l0.222-0.227l0.197-0.48l0.695,0.62l0.513,0.084l0.293,0.211l0.331,0.536l0.632,0.592l0.122,0.706l-0.072,0.594l0.181,0.197l0.256-0.283l0.462-0.679l0.155-0.128l1.16,0.082l0.479,0.155l0.637,0.492l0.332,0.141l0.156-0.48l0.302-0.297l0.022-0.24l-0.266-0.324l-0.601-0.395l-0.079-0.184l0.008-0.24l0.145-0.099l0.604-0.538l0.007-0.452l0.191-0.213l0.518-0.283l0.268-0.241l0.151-0.269l-0.094-0.184l0.003-0.296l0.512-0.863l0.121-0.057l0.317-0.029l0.397-0.029l0.248-0.17l-0.205-0.409l0.377-0.396l0.344-0.071l0.793,0.366l0.616-0.072l1.291-0.088l0.512-0.128l0.232-0.17l0.04-0.057l-0.077-0.197l-0.2-0.734l-0.248-0.282l-0.471-0.268l-0.374,0.086l-0.244-0.141l0.035-0.212l0.367-0.143l0.396-0.043l0.617,0.521l0.255,0.099l0.34-0.1l0.364,0.31l0.676,0.465l0.36,0.154l1.297,0.294l0.591,0.084l0.413-0.143l0.372,0.014l0.396,0.606l0.419,0.112l0.141-0.029l0.562-0.438l0.454,0.027l0.652,0.38l0.331,0.479l0.46-0.143l0.122-0.791l0.181-0.085l0.455,0.465l0.337,0.099l0.152,0.154l-0.436,0.411l-0.126,0.424l-0.176,0.212l-0.011,0.438l-0.12,0.255l-0.513,0.015l-0.51,0.228l-0.396,0.34l-0.004,0.551l0.301,0.353l-0.187,0.692l-0.381,0.58l-0.559,0.481l-0.155,0.48l0.063,0.17l0.469,0.437l1.038,0.619l0.81,0.677l0.508,0.606l0.246,0.099l0.349-0.114l0.264,0.027l0.782,0.352l0.742,0.465l0.434,0.451l0.679,0.535l0.335,0.127l0.442,0.027l0.784,0.182l0.25,0.184l0.218,0.621l0.167,0.169l0.507,0.31l0.76,0.423l0.537,0.154l0.422-0.072l0.414-0.17l0.603-0.199l0.208-0.156l0.736-1.344l0.403-1.131l0.194-1.314l0.259-0.721l0.43-0.679l-0.131-0.424l-0.409-0.621l0.022-0.311l0.236-0.637l0.187-0.48l-0.164-0.282l-0.183-0.395l0.088-0.692l0.104-1.004l0.225-0.297l0.329-0.156l0.158-0.311l-0.534-0.521l0.033-0.198l0.576-0.947l0.312-0.934l0.072-0.833l0.191-0.241l0.279-0.297z"/> - <path id="UY" country:name="Uruguay" d="M270.934,276.123l0.054-0.338l-0.194-0.577l0.011-0.522l0.24-0.495l0.48-0.524l0.118-0.325l-0.168-0.986l-0.049-0.847l0.103-0.522l0.595-2.359l0.065-0.452l0.443-0.524l0.55-0.003l1.042-0.246l0.25-0.101l0.266,0.098l0.47,0.364l0.379,0.407l0.59,0.814l0.232,0.38l0.27-0.016l0.693-0.427l0.365,0.393l0.432,0.576l0.617,0.194l0.55,0.194l0.999,0.587l0.474,0.435l0.853,1.109l0.131,0.197l0.163,0.027l0.333,0.379l-0.017,0.269l-0.634,0.766l-0.103,0.269l0.258,0.746l0.101,0.313l-0.059,0.053l-0.803,1.103l-0.625,0.552l-0.775,0.454l-0.441,0.156l-0.818,0.1l-0.874-0.337l-0.551,0.044l-0.551,0.114l-0.64,0.283l-0.38-0.042l-0.846-0.676l-0.637-0.252l-0.76-0.154l-0.469,0.128l-0.507,0.072l-0.327-0.127l-0.548-0.563l-0.354-0.159z"/> - <path id="DK" country:name="Denmark" d="M418.763,73.869l0.391-0.499l0.389-0.262l0.283,0.081l0.663-0.062l0.762-0.075l0.324-0.137l0.891-0.787l0.979-0.2l0.224,0.025l0.198-0.219l0.175,0.032l-0.349,0.531l0.11,0.106l0.026,0.481l-0.288,0.156l-0.17,0.368l-1.675,0.069l-0.376-0.106l-0.428,0.031l-0.14-0.062l-0.239,0.081l-0.275,0.031l-0.153,0.417l-0.249,0.218l-0.353,0.118l-0.08,0.112l-0.229-0.155l-0.411-0.292z M421.68,78.002l-1.839,0.129l-0.116-0.016l0.064-0.404l-0.19-0.638l-0.174,0.015l-0.36-0.293l-0.233,0.184l-0.398-0.172l0.2-0.355l0.434-0.293l-0.007-0.181l-0.445-0.541l0.018-0.256l0.131-0.498l0.279-0.106l0.318,0.15l0.495,0.12l0.43-0.574l0.299-0.091l0.296,0.437l0.391-0.046l0.022-0.528l0.107-0.363l1.032-0.017l0.848,0.089l0.03,0.544l0.187,0.301l1.138,0.058l0.14,0.166l-0.307,0.604l-0.565,0.142l-0.119-0.261l-0.331,0.031l-0.263,0.136l0.121,0.278l-0.184,0.414l-0.312,0.077l-0.069,0.244l-0.635,0.035l0.157,0.229l-0.291,0.094l-0.191,0.24l-0.061,0.285l0.003,0.21l-0.215,0.338l0.166,0.084z M427.177,77.967l-0.139-0.149l-0.312-0.344l-0.405,0.031l-0.665-0.059l-0.123-0.329l-0.285-0.66l0.433-0.091l0.603-0.467l0.356,0.495l0.521,0.179l0.2-0.271l0.078-0.586l0.333-0.046l0.459,0.044l0.056,0.571l-0.134,0.36l-0.144,0.09l-0.413,0.286l0.603,0.299l-0.285,0.166l-0.499,0.39l-0.238,0.09z"/> - <path id="DE" country:name="Germany" country:shortname="Germany" d="M417.259,94.301l-0.135-0.233l0.216-0.701l-0.091-0.076l0.075-0.295l0.321-0.372l0.054-0.358l0.054-0.213l0.954-0.806l-0.605-0.193l-0.479,0.014l-0.456-0.09l-0.095-0.186l-0.233-0.007l-0.072,0.048l-0.689,0.062l-0.045-0.145l-0.395,0.055l-0.337-0.277l-0.428-0.319l-0.074-0.353l0.248-0.144l0.044-0.288l-0.466-0.096l-0.41-0.312l-0.062-0.301l0.422-0.376l-0.038-0.468l-0.282-0.365l-0.344-0.177l0.165-0.278l-0.143-0.217l-0.182-0.037l0.08-0.097l0.235-0.133l0.236-0.133l-0.193-0.121l0.201-0.275l0.095-0.148l-0.152-0.292l-0.082-0.265l-0.376-0.182l0.07-0.182l0.341-0.078l0.175-0.092l0.378,0.134l0.664-0.151l0.32-0.152l0.128-0.376l0.412-0.207l0.003-0.328l-0.16-0.17l-0.188,0.061l-0.44-0.134l0.029-0.184l0.113-0.181l0.571,0.036l0.084-0.401l0.345-0.361l-0.151-0.438l0.066-0.147l-0.465-0.192l0.126-0.43l0.285-0.181l0.371-0.028l1.12-0.062l0.293-0.012l0.095,0.16l0.195,0.271l-0.155,0.158l0.324,0.113l0.148-0.068l0.042-0.192l-0.159-0.204l0.259,0.012l0.437,0.169l-0.163-0.362l0.247-0.419l0.687,0.113l0.614-0.091l-0.596-0.17l-0.084-0.227l0.282-0.102l-0.252-0.114l-0.12-0.147l0.166-0.08l0.068-0.136l-0.675,0.08l-0.06-0.182l0.664-0.125l0.218-0.193l-0.464-0.42l-0.324-0.341l0.045-0.28l0.116,0.016l1.839-0.129l0.254,0.13l0.565,0.341l0.271,0.297l-0.02,0.228l-0.252,0.175l0.445-0.05l0.171,0.216l0.157-0.078l0.283,0.021l0.235,0.156l0.45,0.073l0.866-0.121l0.077,0.208l-0.07,0.149l-0.057,0.125l-0.665,0.295l0.316,0.193l0.649-0.136l0.113,0.182l0.457-0.006l0.349-0.391l1.059-0.136l0.602-0.234l0.757-0.266l0.249,0.113l0.396-0.17l0.184,0.182l0.085,0.159l0.634,0.29l0.182,0.074l0.526-0.12l0.156,0.12l0.059,0.34l0.036,0.227l0.154,0.102l0.354,0.125l0.372-0.022l0.028,0.13l0.201,0.025l0.319,0.835l-0.219,0.52l-0.391,0.147l-0.051,0.328l0.391,0.102l0.683,0.429l-0.217,0.395l0.094,0.18l0.312,0.146l-0.021,0.304l0.131,0.102l-0.118,0.292l-0.214,0.124l-0.007,0.191l0.325,0.27l-0.114,0.258l0.468,0.188l0.281,0.485l-0.435,0.698l-0.142,0.115l-0.344-0.072l-0.031-0.278l-0.308-0.121l-0.436,0.072l0.282,0.218l-0.254,0.084l-0.284,0.097l-0.524,0.048l-0.124,0.169l-0.735,0.024l-0.112,0.217l-0.176-0.072l-0.358,0.061l-0.097,0.229l-0.382,0.012l-0.078,0.181h-0.442l-0.422,0.201l-0.293-0.033l-0.26,0.181l-0.243,0.168l0.037,0.056l0.258,0.378l0.413,0.098l-0.155,0.25l-0.08,0.406l0.159,0.085l0.036,0.233l0.244,0.173l0.478,0.265l0.188-0.072l0.573,0.515l0.431,0.17l0.184,0.201l0.219-0.084l0.165,0.18l0.207,0.036l0.447,0.633l-0.682,0.26l-0.437-0.151l-0.132,0.027l-0.039,0.337l-0.162,0.172l-0.968,0.295l-0.364,0.227l0.538,0.571l-0.197,0.295l0.334,0.014l0.056,0.158l-0.098,0.343l-0.082,0.055l-0.441-0.178l0.049-0.165l-0.146-0.117l-0.564,0.062l-0.195-0.138l-0.433,0.035l-0.092,0.178l-1.25,0.035l-0.125,0.171l-0.319,0.014l-0.044,0.13L425.4,94.7l-0.594,0.021l-0.059-0.144l-0.093-0.145l-0.493-0.089l-0.262,0.055l-0.237-0.041l0.032,0.274l-0.452,0.343h-0.215l0.078-0.195l-0.26-0.039l0.011-0.165l-0.194-0.048l-0.104-0.137l-0.249-0.007l-0.096-0.11l-0.164,0.137l-0.368-0.014l-0.664-0.261l-0.852-0.007l-0.149-0.089l-0.199,0.014l-0.017-0.151l-0.709,0.199l0.179,0.199l-0.354,0.021l-0.278-0.11l-0.567,0.158l-0.271-0.096l-0.272,0.117l-0.271-0.089z M432.012,80.473l-0.171-0.038l-0.088-0.049l-0.447,0.08l-0.111-0.264l0.002-0.213l0.647,0.281l0.168,0.203z"/> - <path id="PL" country:name="Poland" d="M450.734,91.05l-0.831-0.33l-0.424-0.101l-0.104-0.216l-0.703-0.186l-0.129-0.13l-0.561,0.076l-0.508-0.041l-0.073,0.137l-0.373,0.18l-0.46-0.254l-0.483,0.046l-0.168-0.056l-0.558,0.204l-0.104,0.177l-0.149,0.135l-0.18-0.12l-0.389,0.083l-0.003-0.204l0.026-0.083l-0.066-0.18l-0.331,0.025l-0.073-0.169l-0.194-0.24l-0.261,0.024l-0.062,0.112l-0.193-0.016l-0.183,0.24l-0.43,0.048l-0.03-0.228l-0.285-0.041l-0.105-0.331l-0.382-0.096l-0.188-0.208l0.02-0.249l-0.802-0.132l-0.311-0.181l-0.368,0.161l-0.293-0.013l-0.013-0.221l0.001-0.253l-0.329,0.084l0.181-0.283l-0.709,0.005l-0.258-0.121l-0.509-0.193l-0.286-0.024l-0.003,0.145l0.282,0.302l-0.41,0.12l-0.22,0.187l-0.318-0.072l-0.296-0.38l-0.55-0.247l0.224-0.211l0.208-0.024l0.099-0.121l-0.199-0.181l-0.257-0.024l-0.061,0.066l-0.466,0.066l0.005-0.169l-0.278,0.037l-0.132-0.181l-0.568-0.054l-0.201-0.025l-0.363-0.163l-0.093-0.26l-0.211-0.091l-0.361,0.018l-0.063,0.084l0.062,0.073l-0.024,0.151h-0.375l0.435-0.698l-0.281-0.485l-0.468-0.188l0.114-0.258l-0.325-0.27l0.007-0.191l0.214-0.124l0.118-0.292l-0.131-0.102l0.021-0.304l-0.312-0.146l-0.094-0.18l0.217-0.395l-0.683-0.429l-0.391-0.102l0.051-0.328l0.391-0.147l0.219-0.52l-0.319-0.835l0.34,0.043l0.23,0.125l-0.093-0.193l0.156-0.153l-0.019-0.147l-0.166-0.13l-0.021-0.129l-0.012-0.075l0.93-0.154l0.431-0.051l0.516-0.152l1.304-0.128l0.48-0.158l0.797-0.479l1.117-0.298l1.515-0.303l1.382-0.086l1.067,0.417l-0.882-0.294l-0.054,0.147l0.256,0.172l0.132,0.466l0.355,0.135l0.648,0.061l0.645-0.11l1.063-0.409l0.054,0.004l-0.978,0.417l-0.19,0.11l-0.004,0.123l0.218,0.012l0.286-0.123l0.613-0.208l0.543-0.253l0.842,0.006l2.246,0.115l2.96-0.101l0.641-0.021l0.04,0.014l0.679,0.243l0.284,0.487l0.099,0.186l0.016,0.029l0.09,0.171l0.16,0.302l0.615,1.5l0.172,0.502l-0.023,0.236l-0.263,0.208l-0.44,0.03l-0.571,0.244l-0.291,0.328l-0.128,0.292l0.289,0.012l0.421,0.146l0.149,0.176l0.218,0.146l0.013,0.25l-0.315,0.752l0.126,0.137l0.161,0.175l-0.074,0.242l0.816,0.835l0.316,0.193l-0.298,0.048l-0.085,0.133l0.328,0.302l-0.009,0.314l-0.255,0.24l-0.429,0.013l-0.286,0.181l-0.599,0.398l-1.509,1.218l-0.082,0.306l0.044,0.552l0.349,0.383l-0.653-0.018z M431.844,80.27l0.232,0.024l0.069,0.208l-0.134-0.029l-0.168-0.203z M432.739,80.361l-0.03,0.129l-0.278-0.024l-0.191,0.03l-0.046-0.208l0.174-0.012h0.266l0.106,0.085z"/> - <path id="NL" country:name="Netherlands" d="M416.488,81.945l0.151,0.438l-0.345,0.361l-0.084,0.401l-0.571-0.036l-0.113,0.181l-0.029,0.184l0.44,0.134l0.188-0.061l0.16,0.17l-0.003,0.328l-0.412,0.207l-0.128,0.376l-0.32,0.152l-0.664,0.151l-0.378-0.134l-0.175,0.092l-0.341,0.078l-0.07,0.182l0.376,0.182l0.082,0.265l0.152,0.292l-0.095,0.148l-0.201,0.275l0.193,0.121l-0.236,0.133l-0.235,0.133l-0.08,0.097l0.182,0.037l0.143,0.217l-0.165,0.278l-0.672,0.024l-0.001-0.338l0.172-0.097l0.11-0.423l-0.754-0.375l-0.535,0.109l-0.292-0.375l-0.228-0.061l-0.173,0.121l-0.313-0.242l-0.267,0.182h-0.307l-0.307-0.012l0.025,0.157l-0.52,0.034l-0.407-0.042l-0.477-0.098l-0.07-0.162l-0.496-0.264l0.795-0.472l0.858-0.621l0.273-0.354l0.563-1.167l0.173-0.104l0.644-0.12l0.367,0.251l0.136,0.268l-0.28,0.203l-0.228-0.056l0.066,0.496l-0.191,0.124l1.163,0.225l0.225-0.236l0.406-0.113l0.134-0.417l-0.458-0.022l-0.123-0.124l-0.02-0.203l0.236-0.158l-0.171-0.023l-0.558-0.067l0.072-0.328l-0.034-0.13l-0.023-0.034l0.128-0.283l0.572-0.198l0.709-0.238l0.654,0.03l1.089-0.151l0.245,0.275l0.329,0.045l0.076,0.181l0.259,0z"/> - <path id="CZ" country:name="Czech Republic" country:shortname="Czech Repub" d="M431.57,91.965l-0.447-0.633l-0.207-0.036l-0.165-0.18l-0.219,0.084L430.349,91l-0.431-0.17l-0.573-0.515l-0.188,0.072l-0.478-0.265l-0.244-0.173l-0.036-0.233l-0.159-0.085l0.08-0.406l0.155-0.25l-0.413-0.098l-0.258-0.378l-0.037-0.056l0.243-0.168l0.26-0.181l0.293,0.033l0.422-0.201h0.442l0.078-0.181l0.382-0.012l0.097-0.229l0.358-0.061l0.176,0.072l0.112-0.217l0.735-0.024l0.124-0.169l0.524-0.048l0.284-0.097l0.254-0.084l-0.282-0.218l0.436-0.072l0.308,0.121l0.031,0.278l0.344,0.072l0.142-0.115h0.375l0.024-0.151l-0.062-0.073l0.063-0.084l0.361-0.018l0.211,0.091l0.093,0.26l0.363,0.163l0.201,0.025l0.568,0.054l0.132,0.181l0.278-0.037l-0.005,0.169l0.466-0.066l0.061-0.066l0.257,0.024l0.199,0.181l-0.099,0.121l-0.208,0.024l-0.224,0.211l0.55,0.247l0.296,0.38l0.318,0.072l0.22-0.187l0.41-0.12l-0.282-0.302l0.003-0.145l0.286,0.024l0.509,0.193l0.258,0.121l0.709-0.005l-0.181,0.283l0.329-0.084l-0.001,0.253l0.013,0.221l0.293,0.013l0.368-0.161l0.311,0.181l0.802,0.132l-0.02,0.249l0.188,0.208l0.382,0.096l0.105,0.331l-0.071-0.012l-0.065,0.066l-0.066,0.04l-0.105-0.026L442,89.998l-0.119,0.013l-0.065,0.04l-0.132,0.066l-0.053,0.079l-0.118,0.092l-0.119,0.053l-0.132,0.079l-0.105,0.013l-0.118,0.013l-0.053,0.092l-0.026,0.092l-0.026,0.132l-0.053,0.079l-0.053,0.105l-0.145,0.066l-0.105,0.04l-0.092-0.026l-0.079,0.079l-0.04,0.092l-0.053,0.079h-0.039l-0.105,0.026l-0.066,0.026l-0.079,0.053l-0.118,0.053h-0.132l-0.145,0.04l-0.093,0.026l-0.065-0.026l-0.065-0.026h-0.093l-0.065,0.026h-0.158l-0.132-0.053l-0.092-0.053l-0.093,0.026l-0.171,0.053l-0.026,0.04l-0.146,0.119l-0.092,0.066l-0.014,0.131l-0.065,0.105l-0.039,0.044l-0.055-0.095l-0.545-0.2l-1.332,0.181l-1.019-0.227l-1.374-0.341l-0.746,0.773l-0.598,0.163l-0.483-0.099l-0.354-0.129l-0.145-0.014z"/> - <path id="AT" country:name="Austria" d="M421.683,94.397l0.368,0.014l0.164-0.137l0.096,0.11l0.249,0.007l0.104,0.137l0.194,0.048l-0.011,0.165l0.26,0.039l-0.078,0.195h0.215l0.452-0.343l-0.032-0.274l0.237,0.041l0.262-0.055l0.493,0.089l0.093,0.145l0.059,0.144L425.4,94.7l0.377-0.103l0.044-0.13l0.319-0.014l0.125-0.171l1.25-0.035l0.092-0.178l0.433-0.035l0.195,0.138l0.564-0.062l0.146,0.117l-0.049,0.165l0.441,0.178l0.082-0.055l0.098-0.343l-0.056-0.158l-0.334-0.014l0.197-0.295l-0.538-0.571l0.364-0.227l0.968-0.295l0.162-0.172l0.039-0.337l0.132-0.027l0.437,0.151l0.682-0.26l0.145,0.014l0.354,0.129l0.483,0.099l0.598-0.163l0.746-0.773l1.374,0.341l1.019,0.227l1.332-0.181l0.545,0.2l0.055,0.095l0.053,0.093l-0.097,0.581l0.155,0.26l0.761,0.547l-0.636,0.291l-0.019,0.367l-0.701,0.054l-0.164-0.134h-0.325l-0.223,0.197l0.452,0.063l0.136,0.196l-0.157,0.206l-0.409,0.062l-0.04,0.375l0.204,0.188l-0.154,0.294l-0.346,0.299l-0.693,0.157l0.082,0.393l-0.89-0.116l-0.298,0.196l-0.85-0.08l-0.566,0.107l-0.646,0.5l-0.287-0.152l-0.612,0.009l-0.179-0.107l-1.04-0.065l-0.478-0.112l-0.894-0.082l-1.311-0.247l-0.32-0.391l-0.318-0.096l-0.023-0.363l-0.856,0.227l-0.301-0.103l-0.445,0.11l-0.183-0.083l-0.366,0.096l-0.329,0.411l-0.597-0.034l-0.631-0.171l0.029-0.171l-0.215-0.117l-0.579,0.332l-0.55-0.242l-0.008-0.144l-0.622-0.062l0.09-0.192l-0.214-0.288l0.266-0.274l-0.193-0.336z"/> - <path id="NG" country:name="Nigeria" d="M431.763,171.063l-0.067,0.354l0.091,0.72l0.108,0.508l0.225,0.168l0.562,0.11l0.144,0.183l0.077,0.353l-0.089,1.116l-0.146,0.227l-0.274,0.171l-0.885,0.217l-0.291,0.256l-0.664,1.275l-0.503,1.203l-0.243,1.004l-0.354,0.129l-0.369,0.03l-0.129,0.354l-0.146,1.229l-0.192,0.312l-0.385,0.045l-0.257,0.284l-0.417,0.836l-0.944,2.223l-0.304,0.624l-0.352,0.496l-0.368,0.355l-0.239,0.114l-0.145-0.056l-0.722-0.97l-0.145-0.14l-1.104-0.05l-0.272,0.03l-1.31,1.265l-0.941,0.839l-0.495,0.526l0.02,0.974l-0.189,0.552l-0.376,0.686l-0.188-0.119l-0.224-0.042l-0.176-0.127l-0.145,0.212l0.144,0.296l-0.063,0.127l-0.353,0.198l-0.56,0.03l-0.977,0.101l-0.607-0.267l-0.288,0.043l-0.271,0.368l-0.177,0.113l-0.432-0.07l-1.247-0.011l-0.528-0.225l-0.543-0.451l-0.416-0.72l-0.192-0.649l0.048-0.254l0.208-0.254l-0.144-0.296l-0.513-0.069l-0.128-0.254l-0.464-0.55l-0.561-0.465l-0.608-0.253l-0.641-0.253l-0.272-0.31l-0.513,0.072l-0.24,0.297l-0.336,0.071l-0.881,0.044l-0.659,0.03l-0.006-0.234l0.121-1.188l-0.217-1.439l0.09-0.989l0.012-0.876l-0.003-0.48l-0.002-0.381l0.237-0.397l0.257-0.03l0.433-0.13l0.078-0.368l-0.116-0.592l0.095-0.34l0.656-0.414l0.223-0.298l0.19-0.566l0.316-0.962l-0.388-0.718l-0.164-0.762l0.062-0.777l0.092-0.961l0.158-0.849l0.353-0.482l0.687-1.614l0.676-0.4l1.064-0.188l1.174-0.108l1.111,0.121l0.821,0.277l1.095,1.223l0.209,0.098l0.37-0.002l1.337-0.544l0.467-0.116l0.354,0.083l1.173,0.742l0.965,0.277l0.934-0.005l0.273-0.059l0.629-0.399l0.403-0.327l0.774-0.287l0.628-0.103l0.709-0.047l0.531,0.04l0.884,0.221l0.724,0.193l0.609,0.208l0.259-0.058l0.761-0.697l0.453-0.299l0.437-0.2l0.951-0.034l0.173,0.394l0.575,0.52l0.351,0.407z"/> - <path id="CM" country:name="Cameroon" d="M425.506,195.522l-1.965-0.017l-1.005,0.007l0.029-0.176l-0.208-0.536l0.271-0.989l-0.159-0.72l-0.191-0.522l-0.399-0.649l0.433-0.396l-0.287-0.367l-0.24-0.056l-0.576,0.058l-0.559-0.268l-0.176-0.324l-0.063-0.537l-0.111-0.211l-0.527-0.14l-0.101-0.064l0.376-0.686l0.189-0.552l-0.02-0.974l0.495-0.526l0.941-0.839l1.31-1.265l0.272-0.03l1.104,0.05l0.145,0.14l0.722,0.97l0.145,0.056l0.239-0.114l0.368-0.355l0.352-0.496l0.304-0.624l0.944-2.223l0.417-0.836l0.257-0.284l0.385-0.045l0.192-0.312l0.146-1.229l0.129-0.354l0.369-0.03l0.354-0.129l0.243-1.004l0.503-1.203l0.664-1.275l0.291-0.256l0.885-0.217l0.274-0.171l0.146-0.227l0.089-1.116l-0.077-0.353l-0.144-0.183l-0.562-0.11l-0.225-0.168l-0.108-0.508l-0.091-0.72l0.067-0.354l0.627,0.109l0.208,0.083l0.923,1.238l0.395,0.887l0.119,1.2l-0.134,0.651l0.169,1.228l0.205,0.578l0.381,0.633l0.208,0.21l0.047,0.127l-0.225,0.143l-0.674,0.032l-1.187-0.191l-0.481-0.082l-0.24,0.1l-0.29,0.312l-0.323,0.539l1.088,1.067l1.343,1.179l0.638,1.07l0.382,1.057l0.208,0.183l-0.208,0.114l-0.354,0.327l-0.866,1.743l-0.4,0.511l-0.528,0.399l-0.144,0.198l-0.064,0.424l0.112,0.776l0.273,1.185l0.207,0.592l0.4,0.661l0.432,0.605l0.064,0.791l0.112,0.324l1.217,1.236l0.498,0.802l0.194,0.804l0.209,0.451l-0.159,0.185l0.1,0.861l-0.271,0.086l-0.863-0.292l-0.864-0.334l-0.576-0.194l-0.56-0.124l-0.479-0.04l-0.271-0.055l-0.878,0.076l-0.863-0.023l-0.56-0.109l-1.022-0.149l-0.831-0.038l-1.773-0.088l-0.88-0.093l-0.045,0.495z"/> - <path id="PK" country:name="Pakistan" d="M551.793,147.278l-0.788-0.111l-0.458-0.253l-0.379-0.367l-0.248-1.101l-0.112-0.141l-0.342-0.141l-0.662-0.083l-0.105-0.07l-0.014-0.268l0.116-0.466l-0.178-0.451l-0.418-0.38l-0.294-0.013l-1.181,0.412l-1.229,0.087l-0.81,0.143l-0.947,0.073l-0.415-0.083l-0.263-0.226l-0.135-0.197l-0.909,0.143l-0.548,0.382l-0.856,0.016l-1.264-0.011l-0.691,0.128l-0.723,0.115l-0.541,0.03l0.182-0.954l0.049-0.354l0.31-0.792l0.285-0.383l0.794-0.47l0.697-0.258l1-0.077l0.209-0.072l0.188-0.255l0.036-0.974l-0.186-0.281l-0.652-0.053l-0.185-0.394l-0.111-1.34l-0.168-0.38l-0.409-0.224l-1.144-0.388l-0.695-0.391l-0.353-0.464l-0.71-1.068l-0.802-1.083l0.887,0.32l0.63,0.194l1.069,0.248l0.854,0.235l0.541,0.039l0.742,0.024l1.187-0.218l0.349-0.002l1.005,0.135l1.234-0.12l0.964-0.175l1.183-0.19l1.066-0.274l0.247-0.156l0.069-0.184l0.099-0.903l0.232-0.876l0.188-0.34l0.412-0.369l0.597-0.441l0.283-0.072l0.644,0.039l0.516,0.082l0.254-0.086l0.321-0.693l0.362-0.271l0.559-0.243l0.562,0.025l1.001,0.375l0.237-0.086l0.34-0.383l0.021-0.084l0.139-1.214l0.288-0.834l0.224-0.424l0.292-0.228l0.416-0.115l0.513-0.031l0.315-0.115l0.199-0.255l-0.088-0.437l-0.129-0.281L556.193,125l-0.35-0.336l0.355-0.129l0.997,0.122l0.698,0.039l0.513-0.215l0.289-0.255l-0.033-0.31l-0.223-0.478l0.13-0.283l0.4-0.341l0.524-0.355l0.324-0.426l-0.198-0.477l0.119-0.483l-0.232-0.171l-0.01-0.336l-0.411-0.271l-0.01-0.32l0.464-0.413l0.258-0.214l0.246,0.023l0.559-0.395l0.272-0.19l0.53-0.292l1.148-0.152l1.345-0.012l0.647,0.144l0.338-0.179l0.332,0.005l0.455-0.297l0.358-0.004l0.148-0.142l0.313,0.14l0.105,0.112l0.281-0.21l0.296,0.047l0.554,0.117l0.004,0.456l0.282-0.128l0.625-0.009l0.373,0.323l0.213,0.247l0.007,0.501l-0.312,0.516l0.301,0.07l0.198,0.218l0.252,0.281l0.52-0.196h0.239l0.104,0.199l0.178,0.09l0.565,0.436l1.337,0.104l0.305,0.111l0.147,0.126l-0.207,0.084l-0.688,0.37l-0.411,0.232l-0.155,0.43l-0.071,0.479l-0.234,0.116l-0.125-0.179l-0.621-0.102l-0.438,0.132l-0.271,0.298l-0.262-0.116l-0.557,0.265l-0.928-0.149l-0.568-0.138l-1.708-0.325l-0.894,0.265l-0.38,0.611l0.09,0.166h0.336l0.047,0.314l-0.202,0.149l0.101,0.199l0.598-0.017l-0.002,0.347l-0.384,0.099l-0.139,0.413l0.389,0.232l-0.116,0.479l-0.215,0.132l0.089,0.248l0.606,0.298l-0.003,0.532l0.782-0.003l-0.039,0.43l0.188,0.248l0.702-0.05l0.668,0.377l0.012,0.211l-0.2,0.255l-0.504,0.2l-0.643,0.196l-0.517,0.248l0.032,0.366l0.188,0.377l-0.237,0.977l-1.512,1.503l0.261,0.38l-0.358,0.281l-0.609,0.133l-0.353,0.467l-0.509,1.216l-0.478,0.547l-1.193,0.496l-0.177,0.364l-0.277,0.481l-0.563,0.61l-0.076,0.38l-0.71,0.259l-0.734-0.011l-0.895,0.314l-0.361-0.094l-0.158-0.518l-0.207-0.132l-0.404,0.083l-0.535,0.463l-0.144,0.446l-0.979,0.893l-0.186,0.543l-0.079,0.269l0.116,0.38l0.541,0.163l0.504,0.085l0.425,0.014l-0.114,0.689l-0.154,0.735l0.412,0.411l0.33,0.099l0.537-0.099l0.112,0.441l0.216,0.507l0.654,1.333l-0.232,0.149l0.241,0.463l-0.317,0.066l-0.15,0.248l-0.55,0.083l-0.145-0.335l-0.183-0.062l-0.78,0.215l-0.2,0.331l-0.735-0.099l-0.229-0.149l-0.835-0.021l-0.835-0.009l-0.259-0.052l0.015,0.728l-0.866,0.017l-0.296,0.431l-0.37,0.036z"/> - <path id="IN" country:name="India" d="M606.155,150.953l-0.037-0.466l-0.627-2.479l-0.064-0.578l-0.4,0.044l-0.281,0.115l-0.395,1.159l-0.224,0.354l-0.529-0.448l-0.249-0.267l-0.23-0.281l-0.001-0.381l-0.009-0.522l0.131-0.283l0.651-0.356l0.498-0.13l0.938-0.767l0.159-0.34l0.012-0.79l-0.057-0.127l-0.111-0.098l-2.473-0.198l-0.559,0.003l-0.916,0.062l-0.547-0.053l-0.537-0.109l-0.095-0.099l-0.079-0.719l-0.053-0.479l-0.129-0.324l-0.417-0.054l-0.489,0.06l-0.372-0.266l-0.339-0.266l-1.252-0.303l-0.234,0.171l-0.555,0.525l-0.124,0.283l0.083,0.155l0.494,0.237l1.224,0.938l0.126,0.112l-0.047,0.155l-0.382,0.101l-0.502,0.13l-0.4,0.299l-0.548,0.61l0.339,0.323l1.042,0.431l0.193,0.21l-0.029,0.269l-0.505,0.765l0.04,0.254l0.352,0.45l0.325,1.409l0.402,1.775l0.147,0.532l-0.172,0.322l0.068,0.183l-0.321,0.071l-0.35-0.056l-0.148-0.706l-0.198-0.084l-0.253,0.354l-0.171,0.354l-0.172,0.057l-0.115-0.099l-0.28-0.592l-0.152-0.169l-0.412,0.537l-0.504,0.298l-0.992,0.397l-0.571,0.213l-0.264,0.226l-0.05,0.113l0.106,0.579l0.183,0.409l-0.336,0.495l-0.305,0.332l-0.013,0.257l-0.548,0.415l-0.593,0.467l-0.467,0.185l-0.432,0.057l-0.746,0.206l-0.591,0.362l-0.459,0.58l-0.551,0.552l-0.88,1.061l-0.611,0.552l-0.673,0.276l-0.675,0.829l-0.676,0.467l-0.728,0.368l-0.452,0.241l-0.427,0.312l-0.192,0.509l-0.073,0.466l-0.341,0.41l-0.649,0.298l-0.428,0.058l-0.506-0.098l-0.258,0.269l-0.366,0.887l-0.277,0.23l-0.505-0.253l-0.614,0.142l-0.354,0.283l-0.304,0.565l-0.165,0.48l-0.005,0.508l0.166,1.539l0.018,0.805l-0.208,0.495l0.227,0.324l0.315,0.423l-0.015,0.508l-0.199,0.607l-0.669,1.611l-0.341,0.834l-0.13,0.636l0.047,0.649l0.21,1.764l-0.081,0.24l-0.643,0.001l-0.433-0.013l-0.186,0.142l-0.334,0.961l-0.324,0.594l0.025,0.127l0.493,0.352l-0.805,0.327l-0.306,0.015l-0.77,0.284l-0.295,0.41l-0.101,0.692l-0.157,0.255l-0.367,0.283l-0.526,0.255l-0.099,0.057l-0.066,0.042l-0.231,0.156h-0.145l-0.174-0.056l-1.417-1.451l-0.092-0.395l-0.276-0.522l-0.34-1.397l-0.689-1.792l-0.94-1.933l-0.979-1.508l-0.554-1.722l-0.507-1.792l-0.738-1.636l-0.82-1.42l-0.424-0.737l-0.598-1.439l-0.363-1.157l-0.767-3.274l-0.469-2.695l-0.157-1.566l-0.051-0.24l0.232-0.565l0.546-0.834l0.007-0.311l-0.404-0.281l-0.367-0.437l-0.113-0.635l-0.108-0.917l0.065-0.622l-0.837,0.03l-0.19,0.212l-0.235,0.424l0.009,0.183l0.276,0.254l0.074,0.183l-0.073,0.438l-0.301,0.438l-0.503,0.368l-0.812,0.369l-0.504,0.114l-0.617,0.255l-0.377,0.015l-0.861-0.281l-0.572-0.38l-1.018-1l-1.391-1.268l-0.516-0.705l0.267-0.043l1.062,0.125l0.615-0.086l0.443-0.142l0.461-0.283l0.521-0.608l-0.067-0.24l-0.156,0.071l-0.587,0.114l-0.847-0.026l-0.607-0.112l-0.632-0.132l-0.5-0.218l-0.203-0.07l-0.929-0.661l-0.668-0.775l-0.057-0.197l0.37-0.036l0.296-0.431l0.866-0.017l-0.015-0.728l0.259,0.052l0.835,0.009l0.835,0.021l0.229,0.149l0.735,0.099l0.2-0.331l0.78-0.215l0.183,0.062l0.145,0.335l0.55-0.083l0.15-0.248l0.317-0.066l-0.241-0.463l0.232-0.149l-0.654-1.333l-0.216-0.507l-0.112-0.441L557,143.058l-0.33-0.099l-0.412-0.411l0.154-0.735l0.114-0.689l-0.425-0.014l-0.504-0.085l-0.541-0.163l-0.116-0.38l0.079-0.269l0.186-0.543l0.979-0.893l0.144-0.446l0.535-0.463l0.404-0.083l0.207,0.132l0.158,0.518l0.361,0.094l0.895-0.314l0.734,0.011l0.71-0.259l0.076-0.38l0.563-0.61l0.277-0.481l0.177-0.364l1.193-0.496l0.478-0.547l0.509-1.216l0.353-0.467l0.609-0.133l0.358-0.281l-0.261-0.38l1.512-1.503l0.237-0.977l-0.188-0.377l-0.032-0.366l0.517-0.248l0.643-0.196l0.504-0.2l0.2-0.255l-0.012-0.211l-0.668-0.377l-0.702,0.05l-0.188-0.248l0.039-0.43l-0.782,0.003l0.003-0.532l-0.606-0.298l-0.089-0.248l0.215-0.132l0.116-0.479l-0.389-0.232l0.139-0.413l0.384-0.099l0.002-0.347l-0.598,0.017l-0.101-0.199l0.202-0.149l-0.047-0.314h-0.336l-0.09-0.166l0.38-0.611l0.894-0.265l1.708,0.325l0.568,0.138l0.928,0.149l0.557-0.265l0.262,0.116l0.271-0.298l0.438-0.132l0.621,0.102l0.125,0.179l0.234-0.116l0.071-0.479l0.155-0.43l0.411-0.232l0.688-0.37l0.207-0.084l0.502-0.152v0.515l0.441,1.03l0.221,0.515l0.81,0.11l0.441,0.405l0.221,0.258l-0.331,0.221l-0.184,0.184l0.073,0.589l0.037,0.552l0.294,0.221l0.718,0.096l0.092,0.078l0.044,0.182l0.68,0.099l-0.104,0.414l0.367,0.694l-0.578,0.364l-0.376,0.281l-0.368,0.049l-0.337-0.264l-0.033-0.364l-0.785,0.198l0.157,0.694l0.579,0.595l-0.104,0.446l0.272,0.364l-0.215,0.215l0.099,0.43l0.198,0.066l0.477-0.314l0.383,0.248l0.772,0.843l0.363-0.116l1.078,0.579l-0.116,0.364l0.756,0.248l0.154-0.066l0.859,0.596l-1.07,0.909l-0.281,0.116l0.008,0.364l-0.221,0.265l0.04,0.396l-0.309,0.397l-0.218,0.43l0.039,0.248l0.63,0.38l0.466-0.083l0.665,0.479l0.704,0.149l0.305,0.529l1.242,0.678l0.231-0.166l1.027,0.595l0.538-0.066l0.182,0.397l0.835,0.166l0.304,0.198l0.15-0.066l0.087-0.215h0.503l0.482,0.265l0.582-0.347l0.494,0.298l0.643,0.066l0.142,0.231l-0.101,0.446l0.663,0.149l0.286,0.281l0.618,0.265l0.584-0.281l0.313,0.066l-0.034,0.331l0.312,0.248l0.379-0.231l0.721,0.148l0.847,0.364l0.606-0.297l0.268,0.364l0.399,0.116l0.357-0.132l0.271,0.083l0.687-0.132l0.336,0.05l0.311-0.694l-0.429-0.827l0.07-0.876l0.318-0.761l-0.037-0.022l0.345-0.129l0.471-0.102l0.231,0.069l0.139,0.183l-0.052,0.861l0.212,0.662l-0.092,0.113l0.235,0.493l0.637,0.18l0.559,0.081l0.869,0.214l0.085,0.021l0.544-0.074l0.531-0.313l0.301,0.055l0.335,0.125l1.238,0.063l1.036-0.062l0.624-0.06l0.217-0.58l-0.017-0.282l-0.258-0.238l-0.313-0.069l-0.326-0.294l-0.042-0.24l0.07-0.156l0.189-0.1l0.784-0.033l0.714-0.216l0.397-0.27l1.123-1.107l0.543-0.37l0.829-0.258l1.105-0.726l0.546-0.299l0.355-0.087l0.286,0.167l0.975,0.319l0.377-0.044l1.377-0.84l0.455,0.392l0.716,0.715l0.046,0.38l-0.354,0.454l-0.138,0.269l0.102,0.056l0.3,0.055l0.657,0.081l0.73,0.179l0.624,0.081l-0.018,0.508l-0.112,0.24l-0.596,0.582l-0.072,0.283l0.184,0.718l-0.295,0.058l-0.853-0.221l-0.558-0.082l-0.312,0.129l-0.719,0.512l-1.446,0.883l-0.197,0.354l0.057,0.761l-0.136,0.382l-0.938,1.134l-0.045,0.212l0.192,0.408v0.324l-1.148,2.25l-0.17,0.128l-0.309-0.013l-0.391-0.11l-0.811-0.32l-0.133,0.283l0.146,1.594l-0.191,0.354l-0.401,0.144l-0.228,0.185l0.152,0.93l-0.015,0.678l-0.273,0.368l-0.25,0.129l-0.255-0.14l-0.595-0.152z"/> - <path id="JO" country:name="Jordan" d="M478.516,135.173l0.052-0.292l-0.049-0.169l-0.197-0.107l0.107-0.175l0.292-0.919l-0.015-0.818l0.517-1.09l0.3-0.891l-0.004-0.409l0.133-0.283l0.07-0.749l0.033-0.847l0.062-0.174l0.026-0.278l-0.065-0.411l0.037-0.119l0.102-0.063l1.902,1.034l0.365,0.167l0.253-0.016l1.139-0.656l2.96-1.541l0.161-0.071l0.87,1.632l0.311,0.69l0.093,0.056l-0.46,0.44l-0.257,0.171l-0.97,0.26l-2.586,0.622l-0.646,0.229l1.146,1.32l0.698,0.885l-0.765,0.724l-0.456,0.37l-0.24,0.072l-1.249,0.332l-0.462,0.61l-0.975,0.782l-2.079-0.299l-0.154-0.017z"/> - <path id="LY" country:name="Libya" d="M456.028,151.46l-0.021,1.003l0.033,3.078l-0.088,0.17l-1.561-0.019l-0.52-0.011l-0.073,1.13l-1.981-0.963l-5.577-2.792l-4.941-2.372l-5.231-2.554l-0.41,0.059l-1.818,0.858l-1.519,0.729l-0.231,0.157l-1.192-0.911l-0.258-0.182l-1.008-0.333l-1.646-0.442l-0.832-0.137l-0.098-0.07l-0.86-1.506l-0.178-0.168l-1.028-0.347l-0.702-0.165l-0.544,0.201l-0.244-0.154l-0.562-0.873l-0.249-0.917l-1.272-1.702l0.152-0.283l0.249-0.128l0.666-0.47l0.086-0.17l0.061-0.664l-0.457-1.156l0.158-0.495l0.16-0.622l-0.101-0.748l0.1-0.862l-0.052-0.691l-0.147-0.833l-0.88-1.605l0.241-0.383l0.204-0.156l0.22-0.143l0.864-0.598l0.155-0.227l0.147-0.537l-0.274-0.973l0.126-0.354l1.473-1.138l0.579-0.314l0.802-0.428l0.093-0.269l-0.064-0.564l0.093-0.981l1.436,0.59l0.995,0.309l0.521,0.013l0.863-0.129l0.604,0.027l1.552,0.223l0.614,0.479l0.794,0.224l0.486-0.001l0.342,0.197l0.173,0.226l0.26,0.819l0.39,0.564l0.688,0.591l0.378,0.126l0.678,0.14l1.031,0.083l0.447,0.07l0.973,0.224l0.639,0.224l0.552,0.281l1.289,0.788l0.84,0.464l0.465,0.013l0.441-0.128l0.758-0.411l0.706-0.623l0.3-0.523v-0.254l-0.276-0.621l-0.112-0.579l0.044-0.41l0.237-0.537l0.661-0.58l0.333-0.198l0.554-0.241l0.644-0.298l1.376-0.413l1.205,0.054l0.728,0.154l0.844,0.365l0.188,0.169l0.043,0.508l0.281,0.253l0.301,0.014l0.945,0.125l0.712,0.309l0.45,0.027l1.286,0.04l0.302,0.197l0.068,0.381l0.276,0.296l-0.099,0.208l-0.369,0.228l-0.21,0.34l0.354,1.283l-0.231,0.425l-0.322,0.553l-0.056,0.311l0.185,0.945l0.388,0.916l0.042,0.367l-0.015,0.988l-0.019,3.869l-0.016,1.468l-0.008,2.048l-0.001,0.692l0.045,2.81l-0.021,1.342l0.011,2.612z"/> - <path id="IL" country:name="Israel" d="M478.212,134.714l-0.834-1.746l-0.796-1.944l-0.124-0.289l0.109-0.066l0.679-0.851l0.219-0.438l0.183-0.507l0.171-0.566l0.188-0.822l0.116,0.018l0.137-0.093l0.006-0.204l0.028-0.315l0.372-0.051l0.151,0.022l0.07,0.099l0.355-0.07l0.009-0.167l0.067-0.193l0.088-0.041l0.07,0.023l0.183,0.346l0.201,0.128l0.021,0.183l-0.047,0.122l0.082,0.085l-0.102,0.063l-0.037,0.119l0.065,0.411l-0.026,0.278l-0.062,0.174l-0.033,0.847l-0.07,0.749l-0.133,0.283l0.004,0.409l-0.3,0.891l-0.517,1.09l0.015,0.818l-0.292,0.919l-0.107,0.175l-0.067,0.068l-0.042,0.042z"/> - <path id="SA" country:name="Saudi Arabia" d="M495.751,163.817l-0.03-0.184l-0.112-0.537l-0.508-0.945l-0.73-0.987l-0.438-0.493l-0.846-0.69l-0.51-0.875l-0.814-1.876l-0.474-0.889l-0.28-0.409l-0.794-0.507l-1.271-0.689l-0.527-0.634l-0.8-1.17l-0.081-0.96l-0.061-0.776l-0.002-0.89l-0.104-0.381l-0.312-0.663l-0.944-1.65l-0.357-0.494l-0.758-0.62l-0.459-0.225l-0.499-0.126l-0.308-0.282l-0.483-0.578l0.149-0.692l-0.111-0.437l-0.474-0.818l-0.747-1.072l-0.793-0.902l-1.069-1.494l-0.525-0.931l-0.352-0.479l-0.722-0.761l-0.524-0.056l-0.248,0l0.077-0.296l0.193-0.283l0.311-1.314l0.104-0.583l0.154,0.017l2.079,0.299l0.975-0.782l0.462-0.61l1.249-0.332l0.24-0.072l0.456-0.37l0.765-0.724l-0.698-0.885l-1.146-1.32l0.646-0.229l2.586-0.622l0.97-0.26l0.257-0.171l0.46-0.44l0.093,0.056l1.129,0.459l0.757,0.222l2.034,0.934l1.14,0.473l2.44,1.101l0.258,0.196l0.399,0.633l0.141,0.07l0.973-0.048l0.135,0.366l-0.118,0.396l0.047,0.818l0.118,0.253l0.812,0.277l1.557,0.697l4.048,0.132l1.657,0.259l0.408,0.054l0.334,0.619l0.185,0.239l1.07,0.05l0.644-0.044l0.043,0.121l0.277,0.648l0.365,0.494l0.178,0.663l0.052,0.113l0.615-0.029l0.248,0.126l-0.204,0.237l0.194,0.187l0.184,0.282l0.234,0.067l0.234,0.27l0.886,0.168l0.423,0.437l-0.07,0.28l-0.235,0.035l-0.111,0.25l0.316,0.381l-0.188,0.593l-0.122,0.198l0.165,0.268l0.302,0.666l0.149-0.117l0.372,0.282l0.105,0.616l0.422,0.696l-0.028,0.423l0.222,0.268l0.16,0.197l0.287,0.084l0.136-0.007l0.336,0.083l1.043,2.198l0.548,1.154l0.261,0.902l3.362,0.375l3.387,0.446l0.839,0.108l0.584-0.469l0.152-0.057l0.581,0.914l0.155,1.453l-5.346,2.982l-2.35,1.213l-1.691,0.815l-0.169,0.085l-1.148,0.346l-3.097,1.035l-4.618,1.566l-0.484,0.229l-0.041,0.127l-0.383,0.397l-1.907,2.271l-2.042,2.667l-1.302-2.703l-1.211-2.45l-0.452-0.012l-0.715,0.047l-0.446-0.125l-0.671-0.151l-0.216,0.1l-0.174,0.185l-0.11,0.495l0.041,0.678l-0.113,0.565l-0.692,0.563z"/> - <path id="EG" country:name="Egypt" d="M476.458,130.735l0.124,0.289l0.796,1.944l0.834,1.746l-0.38,0.381l-0.479,1.145l-0.334,1.413l-0.171,0.593l-0.18,0.156l-0.407-0.07l-0.448-0.521l-0.782-0.676l-0.386-0.494l-0.338-0.988l-0.521-0.45l-0.289-0.621l-0.17-0.479l-0.198-0.353l-0.466,0.17l-0.267,0.523l0.604,1.34l0.131,0.381l0.634,0.86l0.933,1.042l0.473,1.199l0.526,0.973l0.277,0.818l0.391,0.465l0.912,1.735l1.072,1.904l0.428,0.705l0.586,0.549l0.451,0.352l0.151,0.183l-0.241,0.17l-0.285,0.1l-0.043,0.155l0.238,1.087l0.252,0.467l0.127,0.238l0.812,0.591l0.397,0.168l0.406,0.521l0.416,0.38l0.311,0.56l-10.382-0.006l-2.138-0.001l-2.774,0.002l-2.513,0.015l-2.268-0.029l-1.664,0.01l-1.241,0.007l-1.614-0.019l-0.914,0.005l-0.819,0.089l-0.011-2.612l0.021-1.342l-0.045-2.81l0.001-0.692l0.008-2.048l0.016-1.468l0.019-3.869l0.015-0.988l-0.042-0.367l-0.388-0.916l-0.185-0.945l0.056-0.311l0.322-0.553l0.231-0.425l-0.354-1.283l0.21-0.34l0.369-0.228l0.099-0.208l0.337,0.168l0.553-0.015l0.628-0.1l0.786-0.001l1.513,0.293l0.587,0.115l0.779,0.122l0.721,0.154l0.348,0.409l0.4,0l0.928,0.083l0.998,0.394l0.628,0.069l0.245-0.127l0.72-0.538l0.925-0.397l0.837-0.186l0.78-0.27l0.375-0.072l0.346,0.056l0.535-0.001l0.723,0.126l0.202,0.465l0.596,0.366l0.518-0.156l0.64,0.267l0.382,0.027l0.561-0.401l0.241,0.179l0.277,0.056l0.674,0.13l0.338-0.062l0.46-0.165l0.51-0.308z"/> - <path id="NP" country:name="Nepal" d="M580.625,132.873l0.24,0.43l0.299,0.05l0.276-0.314l0.134-0.513l0.275,0.066l0.186-0.182l1.079,0.199l0.132,0.612l0.867,0.264l0.726,0.595l0.472,0.215l0.15-0.132l0.454,0.281l0.657,0.794l0.158-0.166l0.71-0.116l0.289,0.166l0.178,0.38l-0.069,0.281l1.451,0.893l0.333-0.248l0.326,0.017l-0.175,0.396l0.014,0.265l0.935,0.066l0.365-0.066l0.54,0.496l0.141,0.463l0.237-0.099l-0.01-0.364l0.685,0.38l0.271-0.083l0.08-0.331h0.407l0.63,0.281l0.319,0.364l0.849-0.066l0.341,0.116l0.339-0.281l0.655,0.159l0.037,0.022l-0.318,0.761l-0.07,0.876l0.429,0.827l-0.311,0.694l-0.336-0.05l-0.687,0.132l-0.271-0.083l-0.357,0.132l-0.399-0.116l-0.268-0.364l-0.606,0.297l-0.847-0.364l-0.721-0.148l-0.379,0.231l-0.312-0.248l0.034-0.331l-0.313-0.066l-0.584,0.281l-0.618-0.265l-0.286-0.281l-0.663-0.149l0.101-0.446l-0.142-0.231l-0.643-0.066l-0.494-0.298l-0.582,0.347l-0.482-0.265h-0.503l-0.087,0.215l-0.15,0.066l-0.304-0.198l-0.835-0.166l-0.182-0.397l-0.538,0.066l-1.027-0.595l-0.231,0.166l-1.242-0.678l-0.305-0.529l-0.704-0.149l-0.665-0.479l-0.466,0.083l-0.63-0.38l-0.039-0.248l0.218-0.43l0.309-0.397l-0.04-0.396l0.221-0.265l-0.008-0.364l0.281-0.116l1.07-0.909z"/> - <path id="MR" country:name="Mauritania" d="M374.125,167.166l-1.41-0.924l-0.661-0.604l-0.537-0.788l-0.292-0.662l-0.15-0.183l-0.312-0.154l-0.567-0.053l-0.655-0.307l-0.695-0.561l-0.604-0.194l-0.567-0.025l-1.209,0.12l-1.821,0.194l-0.523,0.417l0.06-0.502l0.563-1.301l0.188-0.819l0.13-1.13l-0.162-1.101l-0.3-0.791l-0.624-0.747l0.267-0.283l0.182-0.424l0.067-0.975l-0.065-0.537l-0.174-0.353l-0.808-0.817l-0.297-0.112l-0.393,0.438l-0.055-0.197l-0.013-0.381l0.08-0.689l0.474,0.013l5.055,0.056l2.396,0.014l0.732-0.033l0.212,0.027l-0.051-1.102l-0.164-1.539l0.01-0.707l0.249-0.383l0.575-0.427l0.726-0.315l0.809-0.287l0.144-0.128l0.099-2.6l0.07-2.261l0.047-0.509l0.557-0.074l6.005,0.022l0.56,0.011l0.104-0.396l-0.002-0.65l0.03-1.752l2.829,1.509l4.12,2.42l1.414,0.91l-0.523,0.13l-3.231,0.089l0.049,0.776l0.908,7.962l0.19,1.468l0.178,1.736l0.325,2.753l0.202,2.386l0.186,1.468l0.724,0.787l-0.379,1.613l-6.457,0.01l-1.953,0.026l-0.945,0.344l-0.387,0.031l-0.485-0.054l-0.713-0.137l-0.535-0.124l-0.06,0.212l0.055,0.296l-0.107,0.269l-0.454-0.082l-0.214-0.168l-0.568-0.83l-0.261-0.111l-0.402,0.073l-0.252,0.256l-0.181,0.552l-0.018,0.607l-0.332,0.284z"/> - <path id="SD" country:name="Sudan" d="M476.114,191.139l-0.563,0.54l-0.626,0.314l-0.367,0.016l-0.303-0.196l-0.303-0.097l-0.88,0.132l-0.881,0.33l-0.911,0.048l-0.942-0.234l-0.495-0.011l-0.464,0.087l-0.496,0.229l-1.288-1.32l-1.032-0.926l-0.207-0.083l-0.258,0.157l-0.436,0.582l-0.16,0.1l-0.684-0.631l-0.384-0.012l-0.529,0.37l-0.258,0.242l-0.352,0.016l-0.366-0.195l-0.525-0.477l-0.348-0.493l-0.795-0.772l-0.143-0.239l-0.031-0.07l0.083-0.679l-0.157-0.352l-0.558-0.477l-0.814-0.165l-0.367-0.224l-0.285-0.436l-0.059-0.72l-0.206-0.366l-0.207-0.168l-0.717-0.434l-0.558-0.378l-0.445-0.351l-0.173-0.395l0.148-0.481l-0.223-0.267l-0.351-0.196l-0.799-0.235l-0.797-0.447l-0.223-0.225l-0.252-0.493l-0.207-0.126l-0.272,0.001l-0.802,0.019l-0.158-0.211l-0.01-0.664l0.416-1.472l-0.122-0.536l-0.347-0.549l-1.342-1.673l0.15-0.425l-0.026-0.367l-0.266-0.465l-0.444-0.407l-0.155-0.295l-0.137-0.522l-0.221-1.228l-0.141-0.225l-0.338-0.012l-0.517,0.088l-0.219-0.352l0.316-0.609l0.542-0.596l0.087-0.34l-0.342-0.662l0.053-0.24l0.718-0.428l0.149-0.212l-0.131-0.677l0.122-0.438l0.583-0.809l0.417-1.245l0.229-0.143l1.245-0.05l0.839,0.009l0.04-0.283l-0.031-1.229l-0.036-1.002l0.038-0.749l-0.085-2.5l0.036-0.636l0.016-0.946l0.02-1.045l0.073-1.13l0.52,0.011l1.561,0.019l0.088-0.17l-0.033-3.078l0.021-1.003l0.819-0.089l0.914-0.005l1.614,0.019l1.241-0.007l1.664-0.01l2.268,0.029l2.513-0.015l2.774-0.002l2.138,0.001l10.382,0.006l0.229,0.414l0.499,1.115l0.281,3.501l0.319,1.637l0.182,0.211l0.625,0.394l0.595,0.366l0.617,0.507l0.491,0.197l0.254,0.223l-0.238,0.199l-0.277,0.327l-0.306,0.566l-0.369,0.242l-0.511,0.172l-0.427,0.116l-0.153,0.142l-0.235,0.496l-0.348,0.171l-0.73,0.033l-0.204,0.552l-0.038,0.452l-0.202,0.862l-0.242,0.722l-0.541,1.302l-0.068,0.495l0.092,0.903l-0.013,0.679l-0.001,0.083l-0.148,0.947l-0.398,1.231l-0.214,1.061l-1.04,0.331l-0.414,0.37l-0.693,1.134l-0.154,0.34l-0.191,1.088l-0.141,1.074l-0.197,0.185l-0.274,0.044l-0.431-0.096l-0.259,0.072l-0.163,0.114l-0.187,1.103l-0.115,0.933l-0.2,1.272l0.039,0.522l-0.229,1.159l-0.469,0.299l-0.288-0.012l-0.928-0.122l-0.321,0.03l-0.188,0.806l-0.054,0.466l0.094,0.141l0.479,0.11l0.734,0.123l0.334,0.167l0.805,0.913l1.06,1.067l0.751,1.464l0.345,0.732l0.348,0.421l0.462,0.28l0.415,0.097l0.269,0.309l0.117,0.988l-0.034,0.17l-0.018,0.141l-0.079-0.028l-0.464,0.017l-1.009,0.133l-0.832,0.005l-0.671-0.052l-0.291,0.327l-0.678,0.795z"/> - <path id="YE" country:name="Yemen" d="M518.402,163.079l-0.282,0.097l-0.538,0.27l-0.656,0.566l-0.265,0.297l-0.166,0.508l-0.062,0.41l-0.41,0.326l-1.418,0.652l-2.27,0.641l-1.285,0.412l-0.843,0.312l-0.356,0.297l-0.473,0.622l-0.436,0.269l-0.506,0.114l-0.593-0.069l-0.521,0.072l-0.83,0.439l-0.65,0.396l-0.956,0.397l-0.752,0.199l-1.16,0.003l-0.562-0.013l-0.297,0.128l-0.386,0.312l-0.272,0.297l-0.45,0.312l-0.511,0.241l-0.389,0.043l-0.239-0.042l-0.535,0.411l-0.839,0.058l-0.494-0.112l-0.623-0.437l-0.17-0.155l-0.317-0.437l-0.084-0.254l0.18-0.721l-0.081-0.635l-0.312-0.507l-0.341-1.171l-0.572-1.919l-0.072-0.438l0.268-0.707l-0.124-0.748l0.692-0.563l0.113-0.565l-0.041-0.678l0.11-0.495l0.174-0.185l0.216-0.1l0.671,0.151l0.446,0.125l0.715-0.047l0.452,0.012l1.211,2.45l1.302,2.703l2.042-2.667l1.907-2.271l0.383-0.397l0.041-0.127l0.484-0.229l4.618-1.566l3.097-1.035l1.148-0.346l0.169-0.085l0.092,0.663l0.226,0.634l0.604,0.971l0.933,1.364l0.127,0.253l-0.006,0.296l0.483,0.689l0.241,0.306z"/> - <path id="ER" country:name="Eritrea" country:shortname="Eritrea" d="M494.64,172.627l-0.261-0.166l-0.476-0.633l-0.475-0.159l-0.437-0.911l-1.267-0.792l-0.277-0.594l-0.673-0.673l-0.594-0.119l-0.871-0.554l-0.555,0.079l-0.158-0.158l-0.237,0.04l-0.277-0.198l-0.356,0.159l-0.476,0.079l-0.277-0.436l-0.158,0.237l-0.436,0.198l-0.792,0.079l-0.554-0.594h-0.238l-0.396-0.317l-0.832,1.663l-0.436-0.871l-0.475,0.079l-0.277,0.356l-0.396-0.08l-0.349,0.041l0.013-0.679l-0.092-0.903l0.068-0.495l0.541-1.302l0.242-0.722l0.202-0.862l0.038-0.452l0.204-0.552l0.73-0.033l0.348-0.171l0.235-0.496l0.153-0.142l0.427-0.116l0.511-0.172l0.369-0.242l0.306-0.566l0.277-0.327l0.238-0.199l0.098,0.129l0.718,2.102l0.442,1.623l0.689,1.919l0.618,0.832l0.205-0.212l-0.072-0.479l0.093-0.226l0.31,0.253l0.4,0.677l0.384,0.395l0.534-0.043l0.242,0.014l1.338,1.282l0.809,0.916l0.124,0.099l0.706,0.055l0.618,0.874l0.021,0.24l-0.025,0.198l0.118,0.212l0.507,0.182l0.915,0.869l-0.075,0.094l-0.529,0.78l-0.331-0.182l-0.396-0.125l-0.214,0.114l-0.055,0.085z"/> - <path id="SG" country:name="Senegal" d="M370.147,172.035l-2.301-0.043l-1.045,0.006l-0.505,0.384l-0.51,0.187l-0.74-0.024l-0.819,0.047l-0.463,0.139l-0.009-0.003l-0.278-0.226l-0.169-0.409l0.104-0.424l-0.095-0.55l-0.018-0.198l0.001-0.046l1.695,0.014v-0.434h0.155l0.341-0.016l0.186-0.077l0.248,0.062l0.294-0.046l0.124-0.093l0.016-0.263l0.077-0.078l0.14-0.016l0.155,0.155l0.232,0.124l0.356,0.108l0.046,0.108l0.139,0.047l0.217-0.031l0.263,0.108l0.186,0.17h0.434l0.186-0.108l0.263-0.108h0.279l0.108-0.124l0.016-0.124l-0.155-0.217l-0.202-0.077l-0.201,0.031l-0.294,0.093l-0.108,0.093l-0.248,0.062l-0.279-0.186l-0.031-0.186l-0.186-0.108l-0.17-0.015l-0.186,0.124l-0.139-0.108l-0.108-0.217l-0.155-0.108l-0.201,0.031l-0.17-0.062l-0.387,0.17l-0.108-0.108l-0.155,0.046l-0.202,0.124l-0.093,0.294h-1.664l-0.007-0.067l-0.028-0.269l-0.377-0.268l-0.068-0.155l-0.057-0.367l-0.386-0.635l-0.399-0.494l-0.379-0.31l-0.472-0.183l0.54-0.34l0.723-0.75l0.588-1.004l0.334-0.82l0.099-0.826l0.523-0.417l1.821-0.194l1.209-0.12l0.567,0.025l0.604,0.194l0.695,0.561l0.655,0.307l0.567,0.053l0.312,0.154l0.15,0.183l0.292,0.662l0.537,0.788l0.661,0.604l1.41,0.924l-0.506,0.399l-0.057,0.339l0.251,1.1l0.144,0.663l0.22,0.479l0.181,0.197l0.554,0.322l0.265,0.337l0.082,0.833l-0.004,0.565l-0.062,0.142l-0.146-0.042l-0.963,0.091l-0.658,0.074l-0.725-0.081l-0.503-0.209l-0.795-0.32l-1.255-0.021z"/> - <path id="ET" country:name="Ethiopia" d="M495.973,175.881l-0.363,0.807l0.083,0.409l0.428,0.732l0.587,0.844l0.732,0.801l0.596,0.547l0.634,0.321l0.54,0.209l4.26,1.443l1.447,0.472l1.875-0.04l0.236,0.154l-4.087,4.205l-1.562,1.69l-0.813,0.909l-0.8,0.004l-1.693-0.046l-0.626,0.088l-0.562,0.215l-0.388,0.214l-0.502,0.497l-0.294,0.426l-0.337,0.115l-1.216,0.078l-0.305,0.101l-0.453,0.511l-1.103-0.106l-0.461-0.181l-0.46-0.336l-0.271-0.098l-0.852,0.358l-0.675,0.343l-0.258,0.199l-0.71,0.753l-0.16,0.114l-0.847-0.094l-0.67-0.193l-1.373-0.133l-0.335-0.041l-2.353-1.525l-0.604-0.293l-0.749-0.193l-1.054-0.149l-0.319-0.069l0.018-0.141l0.034-0.17l-0.117-0.988l-0.269-0.309l-0.415-0.097l-0.462-0.28l-0.348-0.421l-0.345-0.732l-0.751-1.464l-1.06-1.067l-0.805-0.913l-0.334-0.167l-0.734-0.123l-0.479-0.11l-0.094-0.141l0.054-0.466l0.188-0.806l0.321-0.03l0.928,0.122l0.288,0.012l0.469-0.299l0.229-1.159l-0.039-0.522l0.2-1.272l0.115-0.933l0.187-1.103l0.163-0.114l0.259-0.072l0.431,0.096l0.274-0.044l0.197-0.185l0.141-1.074l0.191-1.088l0.154-0.34l0.693-1.134l0.414-0.37l1.04-0.331l0.214-1.061l0.398-1.231l0.148-0.947l0.001-0.083l0.349-0.041l0.396,0.08l0.277-0.356l0.475-0.079l0.436,0.871l0.832-1.663l0.396,0.317h0.238l0.554,0.594l0.792-0.079l0.436-0.198l0.158-0.237l0.277,0.436l0.476-0.079l0.356-0.159l0.277,0.198l0.237-0.04l0.158,0.158l0.555-0.079l0.871,0.554l0.594,0.119l0.673,0.673l0.277,0.594l1.267,0.792l0.437,0.911l0.475,0.159l0.476,0.633l0.261,0.166l-0.594,0.921l-0.488,0.61l-0.105,0.254l-0.029,0.396l0.202,1.157l0.5-0.074l0.892-0.246l0.4,0.04l0.556,0.195z"/> - <path id="GM" country:name="Gambia, The" d="M364.011,169.929h1.664l0.093-0.294l0.202-0.124l0.155-0.046l0.108,0.108l0.387-0.17l0.17,0.062l0.201-0.031l0.155,0.108l0.108,0.217l0.139,0.108l0.186-0.124l0.17,0.015l0.186,0.108l0.031,0.186l0.279,0.186l0.248-0.062l0.108-0.093l0.294-0.093l0.201-0.031l0.202,0.077l0.155,0.217l-0.016,0.124l-0.108,0.124h-0.279l-0.263,0.108l-0.186,0.108h-0.434l-0.186-0.17l-0.263-0.108l-0.217,0.031l-0.139-0.047l-0.046-0.108l-0.356-0.108l-0.232-0.124l-0.155-0.155l-0.14,0.016l-0.077,0.078l-0.016,0.263l-0.124,0.093l-0.294,0.046l-0.248-0.062l-0.186,0.077l-0.341,0.016h-0.155v0.434l-1.695-0.014l0.019-0.477l0.173-0.198l0.434-0.058l0.093-0.155l-0.006-0.059z"/> - <path id="DJ" country:name="Djibouti" d="M495.973,175.881l-0.556-0.195l-0.4-0.04l-0.892,0.246l-0.5,0.074l-0.202-1.157l0.029-0.396l0.105-0.254l0.488-0.61l0.594-0.921l0.055-0.085l0.214-0.114l0.396,0.125l0.331,0.182l0.529-0.78l0.075-0.094l0.627,0.596l0.285,0.465l0.036,0.282l-0.118,0.113l-0.361,0.185l-0.438,0.1l-0.56,0.312l-0.566,0.467l0.253,0.127l0.645-0.058l0.321,0.013l0.434,0.124l-0.114,0.26l-0.37,0.468l-0.34,0.567z"/> - <path id="GW" country:name="Guinea-Bissau" country:shortname="GuineaBissau" d="M363.763,172.732l0.463-0.139l0.819-0.047l0.74,0.024l0.51-0.187l0.505-0.384l1.045-0.006l2.301,0.043l-0.111,0.792l0.115,0.847l-0.186,0.312l-0.333,0.186l-0.513,0.031l-0.401,0.017l-0.381,0.186l-0.789,0.64l-0.321,0.372l-0.047-0.126l-0.192,0l-0.501-0.14l-0.165-0.254l0.121-0.41l0.33-0.438l0.253-0.212l-0.131-0.141l-0.372-0.112l-0.498,0.015l-0.415,0.17h-0.161l-0.616-0.281l-0.36-0.296l-0.069-0.24l-0.323-0.084l-0.316-0.137z"/> - <path id="GN" country:name="Guinea" d="M383.005,177.596l-0.379,0.397l-0.264,0.623l0.214,0.409l0.695,0.405l0.197,0.31l-0.125,0.283l-0.332,0.37l0.309,0.351l0.648,0.561l0.051,0.226l-0.19,0.143l-0.304-0.012l-0.548-0.223l-0.304,0.03l-0.158,0.199l-0.03,0.127l0.296,0.549l0.179,0.21l-0.188,0.354l-0.602,0.554l-0.047,0.099l-0.339-0.224l-0.337-0.097l-0.143,0.086l-0.756,0.922l-0.321-0.026l-0.404-0.322l-0.277-0.323l0.044-0.283l-0.009-0.65l-0.22-0.846l-0.165-0.366l-0.338-0.097l-0.528,0.046l-0.367,0.143l-0.252,0.242l-0.193,0.376l-0.26-0.656l-0.165-1.369l-0.252-0.761l-0.475-0.619l-0.456-0.421l-0.42-0.224l-0.466-0.04l-1.137,0.148l-0.594-0.039l-0.238,0.157l-0.643,0.866l-1.088,1.235l0.051-0.392l-0.312-0.55l-0.764-0.775l-0.122-0.649l-0.84-0.366l-0.908-0.563l-0.277-0.296l0.09-0.396l-0.053-0.311l-0.547-0.041l-0.323-0.098l-0.115-0.155l0.059-0.311l-0.038-0.1l0.321-0.372l0.789-0.64l0.381-0.186l0.401-0.017l0.513-0.031l0.333-0.186l0.186-0.312l-0.115-0.847l0.111-0.792l1.255,0.021l0.795,0.32l0.503,0.209l0.725,0.081l0.658-0.074l0.963-0.091l0.146,0.042l0.113,0.028l0.18,0.183l0.882,0.715l0.536,0.265l0.252-0.256l0.475-0.413l0.338,0.026l0.356,0.153l0.565,0.152l0.43-0.243l0.3-0.327l0.684-0.428l0.323,0.055l0.246,0.281l0.022,0.339l0.271,0.832l0.265,0.451l0.474,0.478l0.349,0.718l0.194,1.143l0.559,0.901z"/> - <path id="VE" country:name="Venezuela" d="M266.015,188.956l0.103,0.169l-0.163,0.326l-0.592,0.385l-1.74,0.9l-0.807,0.23l-0.557,0.074l-0.465-0.054l-0.284,0.115l-0.232,1.117l-0.348,0.115l-0.628-0.618l-0.344-0.224l-1.149,0.035l-0.385-0.04l-0.896-0.461l-0.309-0.125l-0.159,0.029l-0.041,0.184l0.616,0.688l0.391,0.69l0.302,1.524l0.079,0.55l0.166,0.239l0.96,0.051l0.434,0.125l0.15,0.253l-0.265,0.27l-0.569,0.272l-0.652,0.131l-0.203,0.199l-0.259,0.666l-0.235,0.213l-0.652,0.173l-0.554,0.286l-0.74,0.654l-0.645,0.739l-0.271,0.016l-0.186-0.776l-0.083-0.183l-0.757,0.697l-0.414,0.073l-0.482-0.223l-0.694-0.546l-0.432-0.054l-0.199-0.437l-0.088-0.452l-0.161-0.861l-0.138-0.437l-0.148-0.168l-0.797-1.182l-0.51-0.491l0.479-0.526l0.731-0.612l-0.121-0.282l-0.486-0.647l-0.256-0.437l-0.447-0.789l-0.162-0.804l-0.048-0.367l-0.035-0.438l-0.026-0.254l0.147-0.326l0.379-0.511l0.085-1.004l0.409-0.525l-0.644-0.081l-1.99,0.224l-0.76,0.174l-0.522,0.13l-0.144,0l-0.554-0.576l-0.847-0.998l-0.188-0.253l-0.64-0.321l-0.521-0.181l-1.167,0.05l-1.163,0.12l-0.496,0.017l-0.397-0.252l-0.429-0.548l-0.401-0.309l-0.099-0.353l0.226-1.132l-0.103-0.395l-0.855-1.45l-0.31-0.606l-0.384,0.017l-0.234,0.1l-0.402-0.025l0.709-1.191l0.241-0.722l0.172-0.722l0.99-1.758l0.381-0.059l0.227,0.027l0.129-0.396l-0.048-0.497l0.056-0.288l0.414-0.2l0.534-0.156l0.84-0.171l0.128,0.105l-0.9,0.151l-0.731,0.312l-0.145,0.212l0.19,0.607l0.142,0.407l0.224,0.126l-0.043,0.145l0.153,0.579l-0.135,0.367l-0.327,0.364l-0.348,0.824l-0.137,0.368l0.253,0.479l0.288,0.253l0.25,0.72l0.341,0.353l0.523-0.114l0.184-0.156l0.419-0.255l0.12-0.142l0.066-0.523l-0.167-0.649l-0.21-0.282l-0.438-0.804l-0.136-0.135l-0.118-0.395l-0.247-0.18l0.239-0.099l0.095-0.251l-0.204-0.144l1-0.379l1.085-0.327l0.998-0.272l0.086-0.225l0.69-0.086l0.143-0.008l-0.042-0.157l-0.055-0.198l-0.125-0.036l-0.039-0.108l-0.128-0.072l-0.226,0.071l-0.156,0.027l-0.229-0.012l-0.315-0.55l0.109-0.254l0.337-0.213l0.367-0.043l0.09,0.112l0.14,0.368l0.186,0.162l-0.001,0.148l0.026,0.193l0.068,0.09l0.004,0.198l0.253,0.258l0.329-0.02l0.699,0.111l0.455,0.07l0.593,0.196l0.323,0.254l0.393,0.564l0.156,0.635l0.358,0.324l0.359,0.084l1.02-0.129l0.928-0.059l0.59-0.058l0.799-0.059l0.714,0.125l0.4,0.479l0.267,0.169l0.578,0.253l0.49,0.14l1.094,0.04l0.382-0.057l0.388-0.227l1.042-0.807l0.47-0.185l0.453,0.042l0.959-0.073l1.152-0.073l0.919,0.055l0.248,0.112l-0.056,0.141l-0.294,0.185l-0.854-0.041l-0.433,0.015l-0.083,0.212l0.059,0.184l0.593,0.253l0.609,0.535l0.195,0.649l0.246-0.523l0.185-0.142l0.415,0.253l0.483,0.027l0.374,0.098l0.258,0.338l0.918,0.394l0.464,0.295l-0.729,0.496l-0.161,0.65l-0.214,0.226l-1.055,0.417l0.5,0.064l0.598,0.098l0.368-0.029l0.33-0.142l0.929-0.03l0.725,0.083l0.84,0.274l0.095,0.296l-0.061,0.41l-1.655,1.239l-0.101,0.255l0.074,0.212l0.62,0.604l0.141,0.282l-0.308,0.299l-0.41,0.144l-1.032,0.19l-0.061,0.452l0.008,0.58l-0.395,0.539l-0.071,0.212l0.324,0.521l0.732,0.745l0.503,0.647z"/> - <path id="SO" country:name="Somalia" d="M493.044,204.258l-1.223-1.771l-0.027-0.932l-0.03-1.43l-0.042-2.045l-0.003-1.017v-0.438l0.016-0.848l0.004-1.215l0.002-0.508l1.649-2.467l0.453-0.511l0.305-0.101l1.216-0.078l0.337-0.115l0.294-0.426l0.502-0.497l0.388-0.214l0.562-0.215l0.626-0.088l1.693,0.046l0.8-0.004l0.813-0.909l1.562-1.69l4.087-4.205l-0.236-0.154l-1.875,0.04l-1.447-0.472l-4.26-1.443l-0.54-0.209l-0.634-0.321l-0.596-0.547l-0.732-0.801l-0.587-0.844l-0.428-0.732l-0.083-0.409l0.363-0.807l0.34-0.567l0.37-0.468l0.114-0.26l0.154,0.044l0.935,1.142l0.586,0.62l0.243,0.381l0.265,0.211l0.372-0.071l0.417-0.001l0.465,0.027l0.372-0.071l0.572-0.27l0.836-0.425l0.585-0.157l0.397,0.098l0.76,0.267l0.549-0.072l0.56-0.326l0.779-0.566l0.247-0.127l0.447,0.041l0.479,0.098l0.419-0.043l1.195-0.482l0.288,0.027l0.682,0.196l0.74-0.03l0.764-0.185l0.964-0.327l0.9-0.666l0.47-0.382l0.604,0.154l0.391,0.211l0.08,0.014l0.147,0.268l-0.414,0.919l0.021,0.564l0.132,0.621l-0.165,0.452l-0.375,0.509l-0.028,0.678l-0.047,0.833l-0.163,0.509l-1.264,2.262l-0.842,0.792l-0.122,0.311l0.102,0.353l-0.893,1.569l-0.834,1.272l-0.214,0.947l-0.351,0.636l-0.712,1.117l-0.874,1.188l-1.159,1.498l-0.384,0.439l-2.274,2.504l-1.82,1.557l-2.164,1.121l-0.593,0.382l-1.28,1.09l-1.74,1.755l-0.06,0.061l-1.055,1.1l-1.235,1.569l-0.615,0.835l0.1,0.353l-0.094,0.276z"/> - <path id="TT" country:name="Trinidad" d="M264.768,176.039l-0.128,0.225l-0.115,0.067l-0.029,0.135l0.039,0.25l-0.058,0.086l0.125,0.376l-0.039,0.424l-0.453,0.154l-0.135-0.01l-0.144,0.039l-0.482-0.039l-0.192,0.039l-0.087-0.048h-0.356l-0.02-0.058l0.039-0.067l0.202-0.029l0.222-0.135l0.019-0.087l0.106,0.02l0.154,0.01l0.135-0.145l-0.096-0.279l0.048-0.125l0.029-0.183l-0.067-0.125l-0.097-0.135l-0.279-0.048l0.116-0.096l0.164-0.019l0.231-0.029l0.115-0.087l0.385,0.02l0.106-0.039l0.299-0.067l0.244,0.006z"/> - <path id="BN" country:name="Brunei" d="M654.075,190.187l0.206-0.125l0.63-0.114l0.656-0.938l0.241-0.07l-0.069,0.268l0.122,0.087l0.187-0.046l0.11,0.174l0.148,0.444l-0.024,0.111l-0.013,0.247l0.197,0.197l0.025,0.086l-1.234,0.42l-0.383,0.271l-0.309-0.271l-0.111-0.259l-0.234,0.012l-0.062-0.37l-0.084-0.126z"/> - <path id="KE" country:name="Kenya" d="M493.044,204.258l-0.602,0.389l-0.557,0.171l-0.385-0.112l-0.086,0.777l-0.282,0.367l-0.67,0.115l-0.394,0.382l-0.088,0.48l0.006,0.353l-0.356,0.622l-0.964,1.358l0.092,0.536l-0.337,0.65l-0.25,0.255l-0.334,0.1l-0.084,0.152l-1.067-0.807l-2.427-1.752l-0.07-0.239l0.116-0.552l-0.137-0.381l-3.553-1.984l-4.663-2.568l-1.448,0.033l1.144-2.479l0.105-0.229l0.656-0.835l0.985-0.938l0.477-0.525l0.43-0.695l0.143-0.566l-0.048-0.664l-0.223-0.606l-0.224-0.352l-0.732-1.069l-0.174-0.465l-0.027-0.861l-0.126-0.226l-0.477-0.463l-0.3-0.493l0.678-0.795l0.291-0.327l0.671,0.052l0.832-0.005l1.009-0.133l0.464-0.017l0.079,0.028l0.319,0.069l1.054,0.149l0.749,0.193l0.604,0.293l2.353,1.525l0.335,0.041l1.373,0.133l0.67,0.193l0.847,0.094l0.16-0.114l0.71-0.753l0.258-0.199l0.675-0.343l0.852-0.358l0.271,0.098l0.46,0.336l0.461,0.181l1.103,0.106l-1.649,2.467l-0.002,0.508l-0.004,1.215l-0.016,0.848v0.438l0.003,1.017l0.042,2.045l0.03,1.43l0.027,0.932l1.223,1.771z"/> - <path id="UG" country:name="Uganda" d="M466.196,203.275l0.188-0.298l0.076-0.27l-0.057-0.748l0.025-0.734l-0.021-0.593l0.107-0.507l0.217-1.02l0.395-0.681l0.255-0.284l1.241-0.996l1.195-1.066l0.191-0.453l-0.111-0.31l-0.271-0.182l-0.479-0.04l-0.191-0.027l-0.128-0.253l0.26-1.88l0.018-0.424l-0.159-0.183l-0.063-0.028l0.496-0.229l0.464-0.087l0.495,0.011l0.942,0.234l0.911-0.048l0.881-0.33l0.88-0.132l0.303,0.097l0.303,0.196l0.367-0.016l0.626-0.314l0.563-0.54l0.3,0.493l0.477,0.463l0.126,0.226l0.027,0.861l0.174,0.465l0.732,1.069l0.224,0.352l0.223,0.606l0.048,0.664l-0.143,0.566l-0.43,0.695l-0.477,0.525l-0.985,0.938l-0.656,0.835l-0.105,0.229l-1.144,2.479h-4.659l-1.277,0.05l-0.319,0.017l-0.554,0.398l-0.458,0.427l-0.431,0.045l-0.546-0.223l-0.064-0.042z"/> - <path id="ID" country:name="Indonesia" d="M713.621,206.298l0.169,7.966l-0.44,0.822l0.431,1.368l0.046,0.805l-0.031,3.438l-0.515-0.512l-0.927-0.888l-0.716-0.902l-0.406-0.056l-0.776,0.101l-0.739,0.143l-0.434-0.013l0.091-0.382l0.435-0.65l0.006-0.283l-0.561-0.521l-0.565-0.775l0.028-0.226l0.442,0.111l0.236-0.042l0.135-0.113l-0.467-0.409l-0.595-0.408l-0.287-0.381l-0.275-0.648l-1.053-1.693l-0.508-0.394l-0.467-0.282l-0.604-0.196l-1.983-0.603l-1.26-0.379l-0.613-0.069l-0.705-0.238l-0.63-0.323l0.072-0.34l-0.098-0.268l-0.193-0.028l-0.617,0.101l-0.389-0.07l-0.412-0.196l-0.408-0.395l-0.209-0.579l0.133-0.494l-0.155-0.226l-0.187,0.113l-0.234,0.396l-0.122,0.664l-0.251,0.608l-0.334,0.269l-0.696,0.354l-0.155-0.169l-0.331-0.677l0.022-0.155l0.384-0.27l-0.152-0.424l-0.173-0.239l-0.564-0.395l-0.707-0.394l-0.338-0.056l-0.059-0.212l0.038-0.226l0.413-0.044l0.388,0.084l0.603,0.239l0.158-0.029l0.368-0.34l0.525-0.41l0.146,0.056l0.3,0.269l1.021-0.045l0.139-0.128l0.09-0.522l-0.063-0.409l-0.238,0.028l-0.345,0.199l-0.604,0.071l-0.656-0.041l-0.766,0.044l-1.026-0.082l-0.411-0.31l-0.135-0.197l-0.148-0.664l-0.202-0.338l-0.42-0.155l-1.249-0.124l0.265-0.297l0.058-0.255l0.004-0.593l0.463-0.029l0.92-0.411l0.49-0.383l0.444-0.283l0.352,0.027l0.4,0.069l1.494,0.646l0.515,0.169l0.913,0.153l0.382,0.705l0.138,0.396l-0.283,0.749l-0.067,0.381l0.221,0.381l0.115,0.494l0.115,0.48l0.215,0.521l0.186,0.197l0.197,0.127l0.226-0.65l0.085,0.113l0.087,0.141l0.309,1.073l0.169,0.169l0.234,0.183l0.294,0.112l0.354,0.056l0.58-0.198l0.504-0.439l1.192-1.853l0.352-0.015l1.078-0.215l0.378-0.142l0.045-0.085l0.014-0.509l0.219-0.17l1.1-0.609l0.335-0.043l1.732,0.759l2.129,0.941l1.54,0.52l1.299,0.404z M691.208,208.707l-0.388-0.069l-0.693-0.38l-0.852-0.647l-0.295-0.141l-0.414,0.028l-0.059,0.1l0.024,0.452l-0.206,0.028l-1.014-0.407l-0.258-0.353l-0.582,0.199l-0.289,0.269l-0.326,0.185l-0.186-0.184l-0.312-0.451l-0.245-0.451l0.246-0.198l0.303-0.029l0.274,0.056l1.104,0.04l0.574,0.31l0.319-0.015l0.544-0.326l0.414-0.015l0.534,0.126l0.857,0.21l0.499,0.395l0.293,0.395l0.179,0.621l-0.049,0.254z M682.045,208.699l-0.419-0.056l-0.715-0.493l-0.232-0.451l0.146-0.283l0.603-0.1l0.766-0.044l0.246,0.126l0.256,0.311l0.313,0.197l0.108,0.226l-0.067,0.226l-0.125,0.057l-0.879,0.285z M707.635,219.095l-1.11-0.209l0.589-1.032l0.56-0.708l0.407-0.269l0.427-0.072l0.527,0.338l0.198,0.24l-0.11,0.184l-0.324,0.637l-0.256,0.17l-0.638,0.693l-0.27,0.028z M673.797,218.703l-0.562,0.257l0.034,0.233l-0.886,0.326l-0.582,0.274l-0.339-0.041l-0.453,0.325l-0.504-0.069l-0.427-0.112l-0.378,0.255l-0.3,0.058l-0.358-0.07l-0.58-0.196l-1.046-0.04l-0.316,0.043l-0.211-0.564l0.027-0.24l0.383-0.198l0.672-0.199l0.528-0.016l1.142,0.407l0.445,0.324l0.338,0.013l0.326-0.297l0.464-0.016l0.429-0.071l0.414,0.187l0.467-0.116l-0.072-0.222l0.421-0.187l0.404-0.233l0.094-0.151l-0.076-0.117l-0.184,0.023l0.116-0.198l0.16,0.012l0.22,0.094l0.177,0.221l0.013,0.304z M662.661,219.065l-0.312-0.099l-0.203-0.127l-0.062-0.169l0.03-0.212l0.256-0.198l0.315-0.036l0.17,0.092l0.053,0.212l0.182,0.098l0.305-0.145l0.34,0.105l0.104,0.151l-0.012,0.451l0.183-0.148l0.163-0.304l0.318-0.029l0.229,0.226l0.021,0.424l0.181-0.036l0.062,0.104l-0.025,0.397l-0.316-0.211l-0.311-0.058l-0.141,0.058l0.072,0.155l-0.852,0.157l-0.143-0.091l0.097-0.268l-0.085-0.059l-0.308,0.269l-0.229,0.256l-0.296-0.046l-0.63,0.225l-0.624,0.199l-0.357-0.051l-0.31,0.123l-0.392-0.07l-0.103-0.07l-0.202-0.123l-0.063-0.279l0.143-0.261l-0.08-0.253l0.193-0.115l0.23-0.113l0.233-0.156l0.224,0.07l0.61,0.013l0.4,0.104l0.089,0.28l0.291,0.109l0.294,0.056l0.189-0.259l0.29-0.012l0.051-0.187l-0.263-0.15z M656.294,219.602l-0.393-0.282l-0.855-0.449l-0.118-0.269l0.417-0.001l0.514-0.185l0.462-0.029l0.925,0.521l-0.338,0.17l-0.232,0.1l-0.381,0.425z M631.053,200.125l-0.061,0.225l-0.413,0.439l-0.204,0.41l-0.381,0.354l0.164,0.353l0.162,0.169l0.806,0.493l0.832,0.055l0.241,0.112l0.151,0.381l0.128,0.763l-0.007,0.409l0.267,0.423l0.212,0.127l0.544,0.041l-0.45,0.933l0.151,0.212l0.703-0.453l0.824,0.252l0.177,0.042l0.265,0.254l0.144,0.438l0.698,0.676l-0.515,1.979l-0.04,0.452l0.23,0.946l-0.021,0.438l0.021,0.664l-0.002,0.268l-0.149,1.06l-0.087,0.156l-0.107,0.07l-0.367-0.253l-0.381-0.522l-0.261-0.084l-0.262,0.481l-0.081,0.268l-1.043-0.619l-0.219,0.086l0.394,0.747l-0.163,0.213l-0.204-0.197l-1.343-1.424l-0.775-0.761l-1.011-0.859l-1.348-0.958l-0.391-0.451l-0.199-0.493l-0.191-0.339l-1.003-0.633l-0.697-0.677l-1.186-1.509l-0.074-0.353l0.039-0.339l-0.324-0.875l-0.841-1.467l-0.667-1.044l-0.612-0.775l-0.369-0.301l-0.287-0.234l-0.64-0.295l-0.254-0.748l-0.688-1.806l0.067-0.24l-0.107-0.311l-0.157-0.197l-0.662-0.507l-0.711-0.394l-0.539-0.21l-0.317-0.099l-0.119-0.353l-0.077-0.734l-0.18-0.409l-0.386-0.479l-0.818-0.831l-0.368-0.423l-0.725,0.128l-0.613-0.676l-0.646-0.606l-0.593-0.69l-0.562-0.945l-0.229-0.635l-0.032-0.367l0.057-0.198l0.149-0.113l0.401-0.043l0.364,0.098l0.25,0.126l0.632,0.563l0.361,0.155l0.922,0.153l0.335,0.027l0.548-0.1l0.454-0.142l0.4-0.015l0.323,0.31l0.919,1.156l0.513,0.31l0.058,0.155l-0.12,0.537l1.066,0.916l0.749,0.493l1.175,0.689l0.678,0.323l0.139,0.169l0.03,0.593l-0.02,0.155l0.573,0.055l0.745,0.944l0.612,0.55l0.271-0.015l0.004-0.198l-0.123-0.226l0.069-0.24l0.507,0.21l0.479,0.804l0.441,0.38l0.446,0.056l0.429,0.197l0.314,0.366l0.28,0.734l0.316,0.437l0.431,0.268l0.511,0.126l0.767,0.083l0.431,0.154l0.494,0.38l0.576,0.606l-0.019,0.071z M684.201,200.125l-0.007-0.172l-0.414-1.058l0.18-0.551l-0.078-0.141l-0.141-0.296l0.036-0.325l0.286-0.89l0.514-0.82l0.263,0.367l0.152,0.353l-0.054,0.283l-0.246,0.396l-0.361,0.763l0.061,0.325l0.19,0.141l0.097-0.141l0.436-0.411l0.135-0.522l0.179-0.142l0.806-0.412l0.141,0.141l-0.052,0.254l0.104,0.55l-0.354,0.212l-0.467,0.354l-0.162,0.311l0.159,0.099l0.446,0.126l0.398,0.211l-0.016,0.141l0.159,0.353l-0.688-0.154l-0.431-0.154l-0.367-0.042l-0.304,0.156l-0.08,0.438l0.049,0.258l0.131,0.688l0.341,0.62l0.405,0.438l0.196,0.282l-0.156,0.212l-0.26-0.211l-0.664-0.648l-0.55-0.733l-0.002-0.396l-0.011-0.251z M637.361,207.144l-0.863-0.394l-0.377-0.239l-0.205-0.367l-0.045-0.367l-0.156-0.395l-0.507-0.395l-0.291-0.099l-0.446,0.029l-0.116-0.141l0.271-0.65l0.234-0.24l0.509,0.55l0.148-0.467l0.313-0.269l0.072,0.395l0.312,0.89l0.648,0.817l0.698,0.31l-0.265,0.184l-0.118,0.283l0.183,0.564zM634.321,215.345l-0.091-0.187l0.316-0.023l0.402,0.093l0.369-0.129l0.068-0.524l0.018-0.14l0.309,0.057l-0.043-0.5l0.222-0.235l0.093-0.277l0.202,0.121l0.631,0.112l0.474-0.047l0.237,0.443l0.524-0.089l0.158-0.297l0.022-0.244l0.259,0.116l0.618,0.168l0.411,0.438l0.338-0.046l0.204,0.271l0.446-0.029l0.453-0.185l0.302,0.211l0.369,0.522l0.179,0.521l0.884,0.041l0.462,0.188l0.49-0.077l1.435,0.124l0.479-0.029l0.34-0.17l0.213-0.65l0.271-0.269l0.447-0.015l0.223,0.211l0.289,0.494l0.633,0.125l0.53,0.027l0.774,0.083l0.796,0.153l0.289,0.24l0.293,0.288l-0.08,0.445l0.275,0.466l0.119,0.099l0.877,0.352l0.422,0.069l0.658,0.013l0.45-0.185l0.415-0.015l0.628,0.238l0.048,0.197l-0.255,0.425l-0.152,0.494l0.578,0.776l-0.499-0.211l-0.802-0.196l-0.599-0.253l-0.891-0.309l-0.528,0.001l-0.589,0.256l-0.348,0.057l-0.714-0.098l-1.454-0.138l-1.47-0.138l-0.805-0.253l-0.839-0.479l-1.099-0.336l-1.125-0.267l-0.948-0.04l-0.556,0.298l-0.445,0.043l-0.957-0.153l-0.805-0.492l-0.357-0.07l-1.606-0.066l-0.363-0.155l0.055-0.141l0.448-0.468l-0.402-0.267l-0.551-0.099l-0.506-0.14l-0.307-0.027l-1.261-0.121z M675.004,223.092l0.249-0.494l0.023-0.537l0.113-0.312l0.674-0.481l1.447-0.624l0.662-0.454l0.36-0.607l0.466-0.157l1.578-0.102l0.91-0.214l0.541-0.044l0.869-0.143l0.118,0.07l0.099,0.197l-0.237,0.212l-0.36,0.256l-1.609,0.61l-1.369,0.44l-0.713,0.256l-0.606,0.354l-1.09,0.963l-0.653,0.481l-0.439,0.086l-0.552,0.228l-0.48,0.015z M667.866,223.149l-0.217-0.069l-0.917-0.605l-0.8-0.45l-0.347-0.099l-0.493-0.126l-0.292-0.197l0.108-0.212l0.371-0.142l0.992-0.03l0.502-0.114l0.35,0.296l1.147,0.746l0.265,0.381l-0.125,0.325l-0.246,0.24l-0.299,0.057z M661.819,191.241l-0.041,0.09l0.319,0.691l-0.23,0.142l-0.546,0.043l-0.579,0.086l0.198,0.226l0.115,0.296l-0.169,0.226l0.216,0.211l0.235,0.112l0.546,0.832l0.536,0.747l0.043,0.198l-0.338,0.721l0.075,0.226l0.406,0.465l0.743,0.45l0.6,0.493l0.551,0.761l-0.465,0.17l-0.75-0.026l-0.797-0.238l-0.337,0.1l-0.387,0.467l-0.354,0.918l-0.08,0.476l-0.046,0.272l0.132,0.649l0.116,0.424l-0.133,0.848h-0.256l-0.466-0.154l-1.037,0.963l-0.433,0.65l-0.751,0.608l0.443,0.381l0.06,0.396l0.17,0.296l-0.685,0.058l0.452,0.578l0.009,0.212l-0.103,0.227l-0.547,0.665l-0.206,0.396l-0.127,0.354l-0.529,0.594l-1.294,0.61l-0.607,0.284l-0.292,0.198l-0.194-0.311l0.024-0.424l-0.33-0.804l-0.306-0.381l-0.265-0.184l-0.286,0.029l-0.503,0.523l-0.302,0.029l-0.328-0.508l-0.313-0.197l-0.437-0.112l-0.387-0.451l-0.342-0.154l-0.35,0.806l-0.135,0.198l-0.381,0.058l-0.356-0.112l-0.442,0.128l-0.318,0.354l-0.364,0.071l-0.059-0.551l0.034-0.311l-0.314-1.03l-0.336,0.396l-1.42,0.44l-0.321-0.408l-0.639,0.015l-0.281,0.156l-0.303,0.029l-0.058-0.649l-0.022-0.65l-0.267-1.411l-0.012-0.48l-0.352-0.747l-0.406-0.409l-0.79-0.422l-0.146-0.141l0.555-0.354l-0.531-0.38l-0.258-0.296l0.188-0.735l-0.074-0.128l-0.278-0.478l-0.352-0.296l0.065-0.466l-0.125-0.593l0.182-0.65l0.133-0.353l0.424-0.58l0.303-0.806l0.318,0.028l0.204,0.11l0.288,0.792l0.253,0.295l1,0.983l0.304,0.083l0.446,0.28l0.928-0.416l0.255-0.001l0.526,0.223l0.543,0.11l0.399-0.172l0.528-0.342l0.403-0.525l0.531-0.441l0.479-0.074l0.431,0.11l0.557,0.251l0.524,0.223l0.559,0.152l0.287-0.03l0.467-0.356l0.465-0.172l0.864-0.175l0.387-0.299l0.928-1.785l-0.076-0.748l0.218-0.34l0.646-0.244l0.22-0.383l-0.106-0.988l0.119-0.565l0.381-0.638l0.247-0.157l0.464-0.017l0.748,0.081l0.651,0.081l0.624-0.018l0.446,0.04l0.753,0.292l0.182,0.09z M666.561,200.125l0.012-0.049l0.48-1.188l0.434-0.41l0.289-0.142l0.429,0.338l0.29-0.311l0.162-0.325l0.293-0.481l0.496-0.058l0.605,0.14l0.729,0.535l0.447,0.027l0.863-0.044l0.478,0.168l0.749,0.267l0.577-0.227l1.853,0.081l0.72-0.128l0.627-0.354l0.211-0.283l-0.156-0.268l0.196-0.283l0.388-0.241l0.295-0.41l0.289-0.057l0.075,0.24l-0.073,0.537l-0.117,0.311l-0.081,0.127l-0.082,0.127l-0.969,1.259l-0.416,0.396l-0.464,0.1l-1.23,0.229l-0.495-0.069l-0.591-0.422l-1.149-0.068l-1.151,0.059l-0.878-0.041l-1.039,0.045l-0.575-0.083l-0.671,0.029l-0.415,0.1l-0.433,0.368l-0.259,0.461l-0.154,0.274l-0.187,0.721l0.068,0.48l0.263,0.494l0.194,0.183l0.403,0.226l0.259,0.196l0.221,0.607l0.179,0.154l0.226,0.042l0.815,0.026l0.249-0.269l0.652-0.976l0.385,0.056l0.307,0.183l0.496,0.041l0.363-0.227l0.669-0.156l0.62-0.143l0.268-0.298l0.271-0.057l0.466,0.196l0.131,0.212l-0.083,0.734l-0.469-0.267l-0.544-0.042l-0.361,0.298l-0.389,0.523l-0.438,0.425l-1.059,0.439l-0.214,0.325l-0.143,0.029l-0.241-0.042l-0.468-0.126l-0.03,0.056l0.025,0.312l0.212,0.126l0.676,0.578l0.467,0.521l0.854,1.24l-0.097,0.325l-0.156,0.679l0.102,0.409l0.447,0.535l0.555,0.438l0.062,0.226l-0.045,0.282l-0.436-0.056l-0.652,0.059l-0.412,0.297l-0.224,0.692l-0.498-0.026l-0.461-0.183l-0.107-0.17l0.052-0.649l0.204-0.58l-0.978-0.845l-0.417-0.31l-0.174-0.269l0.036-0.24l0.284-0.396l0.116-0.579l-0.165-0.494l-0.737-0.055l-0.503,0.213l-0.494,0.396l0.16,0.353l0.143,0.932l-0.068,0.509l-0.236,1.145l0.363,0.903l-0.01,0.311l-0.377,0.636l-0.019,0.227l0.275,0.564l-0.726,0.171l-0.513,0.241l-0.476,0.071l-0.245-0.324l-0.16-0.522l0.156-0.325l0.181-0.466l0.069-0.876l0.06-1.073l-0.125-0.509l0.029-0.339l-0.213-0.395l-0.311-0.127l-0.391,0.171l-0.574,0.029l0.011-0.41l-0.25-1.284l0.131-0.311l0.491-0.524l0.469-0.777l0.161-0.48l-0.089-0.918l-0.006-0.254l0.087-0.452l0.339-0.721l0.447-0.058l-0.043-0.861l0.254-1.053z"/> - <path id="GL" country:name="Greenland" country:shortname="Greenland" d="M341.05,41.069l2.084,0.272l0.344,0.361l-0.869,0.174l-0.541,0.139l-1.678,0.106l-1.159,0.037l-0.689,0.156l-0.372,0.224l-0.308,0.6l-0.361,0.376l1.05,0.39l0.971,0.168l2.117,0.064l0.601-0.001l1.775-0.242l1.93-0.038l0.866,0.135l0.933,0.219l0.417,0.135l0.284-0.018l1.001-0.002l1.277,0.032l0.615,0.05l-1.277,0.626l-1.583,0.457l-1.976,0.523l-0.556-0.016l-0.695-0.116l-0.951,0.671l-1.061,0.503l-1.246,0.452l-1.125,0.296l-0.211,0.056l-2.212,0.054l-0.525,0.134l-0.502,0.001l-0.982,0.201l-0.665,0.167l-0.528,0.051l-0.946-0.413l-0.375,0.05l-0.69,0.913l-0.958,0.118l-0.631-0.065l-0.743-0.197l-0.622-0.463l-0.854-0.43l-0.647-0.215h-0.109l0.008,0.2l0.707,1.043l-0.192,0.249l-0.319,0.017l-0.69,0.249l-0.84,0.249l-0.573,0.38l-1,0.906l-0.657,0.657l-1.051,0.851l-0.776,0.262l-1.034,0.083l-1.023-0.275l-0.148,0.554l-0.438,0.569l-0.783,0.277l-0.992-0.095l-0.616,0.05l-1.18,0.439l0.942-1.723l-0.121,0.017l-0.795-0.015l-1.055-0.177l0.26,0.423l-0.026,0.455l-0.386,0.407l-0.794,0.39l-1.16,0.164l-0.973,0.002l-1.255,0.083l0.467,0.403l0.212,0.403l-0.09,0.387l-0.379,0.097l-0.321-0.063l-0.47,0.033l-1.792-0.157l0.517,0.32l0.765,0.462l0.295,0.351l-0.01,0.224l-0.26,0.176l-1.197,0.034l-1.051,0.129l0.844,0.413l0.47,0.126l0.448,0.222l0.389,0.333l-0.554,0.461l-0.285,0.111l-0.599-0.094l-0.478,0.096l0.345,0.474l-0.009,0.127L308.501,60l-0.486-0.125l-0.583-0.062l0.026,0.158l0.255,0.457l-0.101,0.347l-0.288,0l-0.656-0.093l-0.089-0.016l-0.979,0.112l-1.081,0.018l0.682,0.487l1.108,0.391l0.331,0.204l-0.077,1.035l-0.382,0.938l-0.427,0.094l-0.815-0.061l0.489,0.591l-0.016,0.498l0.156,0.233l-0.068,0.373l-0.316,0.062l-0.495-0.03l-0.771,0.079l0.762,0.386l0.427,0.603l-0.117,0.447l-0.287,0.031l-0.967-0.26l-1.052-0.508l-0.498,0.294l-0.425,0.602l-0.635-0.599l0.158-0.573l-0.387-0.201l-1.124-0.184l-0.577-0.309l0.04-0.187l0.253-0.249l0.066-0.218l-0.325-0.28l-0.366-0.186l-0.668,0.359l-0.276,0.016l-0.3,0.141l-0.444-0.046l-0.98,0.064l-0.417,0.017l-0.571,0.296l-0.476,0.28l-0.426-0.403l-0.104-0.357l-0.222-0.217l-0.513-0.233l-0.817-0.232l-0.772-0.389l-0.517-0.781l0.07-0.737l-0.199-0.156l-0.434-0.094l-0.467,0.048l-0.97-0.266l-0.108-0.094l-0.138-0.236l0.14-0.457l0.459-0.395l0.071-0.269l-0.258-0.062l-0.551-0.031l-0.542-0.094l-0.278-0.221l-0.058-0.633l-0.458-0.126l-0.616,0.049l-0.589-0.57l0.023-0.191l0.198-0.254l0.618-0.367l1.22-0.337l0.405-0.304l0.476-0.128l0.051-0.383l-0.277-0.287l-0.473,0.097l-0.921,0.082l-0.493,0.097l-0.635,0.416l-0.538,0.129l-0.63,0.304l-0.339-0.318l0.038-0.623l-0.114-0.784l-0.206-0.451l0.015-0.355l-0.243-0.323l-0.504,0.082l-0.271-0.032l-0.666-0.355l-0.594-0.485l-0.013-0.357l0.842-0.538l0.265,0.019l-0.556-0.189l-1.083,0.064l-0.103-0.284l0.383-0.176l0.677-0.03l0.586-0.052l0.456-0.087l0.322-0.672l-1.208-0.047l-0.572,0.05l-0.362-0.032l-0.29-0.163l-0.116-0.197l0.223-0.28l0.218-0.008l0.18-0.16l0.427-0.055l-0.375-0.188l-0.552,0.073l-0.22-0.248l0.057-0.188l0.073-0.132l0.259,0l0.309-0.099l0.827-0.25l1.218,0.081l0.854,0.163l0.776,0.032l0.378,0.131l0.927,0.146l1.027,0.097l-0.031-0.363l0.299-0.545l-0.298-0.182l-1.02-0.263l-1.356-0.312l-0.903-0.164l-1.592-0.33l-0.354-0.116l0.336-0.35l0.788-0.001l1.462,0.363l1.034,0.048l0.463-0.067l0.114-0.067l0.088-0.6l0.088-0.301l0.595-0.034l0.528,0.116l0.227-0.101l-0.027-0.351l-0.195-0.184l-0.891-0.317l0.162-0.437l0.528-0.455l-0.258-0.286l-1.21-0.167l-1.154,0.002l-1.178-0.286l-1.649-0.49l-0.78-0.101l-0.903-0.05l-0.76-0.34l-0.811-0.477l0.156-0.035l0.323-0.155l0.605-0.001l0.572-0.019l2.085,0.305l0.716,0.033l1.249,0.306l1.451,0.458l0.729,0.169l0.056-0.307l-0.311-0.426l-0.86-0.546l-0.172-0.446l-0.603-0.446l-0.485-0.051l-0.677-0.24l0.361-0.277l0.542-0.139L285.644,41l-0.704-0.241l-1.101-0.015l-0.625-0.086l-1.132-0.327l-0.88,0.608l-0.324,0.156l-0.274,0.294l-0.875,0.243l-1.402-0.066l-1.031-0.343l-0.306-0.242l-0.027-0.294l0.438-0.313l0.293-0.645l-0.152-1.259l0.582-0.054l0.691,0.192l0.372-0.124l0.151-0.334l-0.383-0.369l-0.933-0.545l-0.452-0.141l-0.946-0.796l-0.895-0.925l-1.105-1.289l-0.578-0.485l-1.855-0.379l-0.667-0.255l-0.291-0.202l-0.052-0.701l-0.904-0.406l-0.962-0.109l-1.589-0.165l-1.928-0.425l-1.903-0.333l-2.133-0.183l-0.997-0.054l-1.632-0.035l-0.785,0.189l-1.043,0.096l-0.806,0.188l-1.419,0.152l-1.228-0.166l-1.46-0.296l0.319,0.747l-0.051,0.093l-1.051-0.017l-1.294-0.184l-3.168-0.611l1.538-0.566l0.463-0.114l-0.092-0.226l-0.423-0.169l-1.067-0.017l-2.21-0.015l-0.812-0.074l-0.629-0.018l-1.238-0.434l-0.87-0.208l0.587-0.306l1.257-0.041l3.036,0.147l2.025,0.034l1.343,0.017l2.117-0.157l1.055-0.212l0.292-0.096l0.054-0.345l-0.627-0.287l-0.82-0.21l-1.217,0.156l-1.11,0.252l-1.31,0.021l-1.138-0.113l-0.753,0.078l-0.879,0.098l-0.68-0.056l-0.857-0.19l-0.664-0.365l-0.816-0.191l-0.662-0.057l-0.726,0.059l-0.486-0.076l-1.416-0.481l-0.044-0.35l0.36-0.45l0.81-0.119l1.235-0.1l1.517-0.14l2.074-0.161l1.29-0.081l0.951-0.396l1.089-0.259l0.843-0.081l2.478-0.005l1.101-0.101l1.942,0.036l0.402-0.139l0.31-0.199l0.609-0.16l0.202-0.658l0.276-0.501l0.116-0.101l-0.89-0.228l-1.947-0.039l-1.155,0.194l-0.959-0.125l-1.243-0.383l0.595-0.781l1.38-0.332l2.845-0.359l1.407-0.225l1.962-0.249l2.112-0.162l1.163,0.087l1.213-0.07l1.319-0.07l0.345-0.181l0.011-0.226l-0.357-0.753l-0.022-0.208l0.522-0.14l1.886-0.05l1.526,0.205l2.141,0.41l1.296,0.226l0.802,0.181l0.823-0.275l-1.657-0.525l-0.697-0.509l0.167-0.047l2.2-0.122l1.166-0.12l1.854-0.216l2.52-0.195l0.73,0.069l1.064,0.116l0.232,1.738l0.913-0.162l0.539-0.322l0.432-1l1.003,0.021l2.004,0.323l1.858,0.414l1.529,0.25l0.205-0.3l-0.644-0.3l-0.816-0.537l-0.894-0.4l0.295-0.287l0.742,0.022l1.758,0.02l1.136,0.212l2.754,0.373l1.284,0.279l2.109,0.322l1.878,0.274l1.872,0.204l0.8-0.209l0.816-1.483l-0.326-0.191l-1.292-0.334l-1.176-0.533l0.708-0.247l2.404-0.005l2.962-0.328l1.329-0.077l1.527,0.17l2.221,0.488l1.567,0.167l2.005,0.142l0.3-0.761l-0.3-0.472l2.646-0.206l2.021-0.08l2.589,0.095l1.989,0.146l1.886-0.18l2.367-0.207l2.043-0.005l1.859,0.223l1.825-0.055l1.315,0.072l0.619,0.099l0.55-0.102l1.946,0.146l1.707,0.046l1.673,0.096l2.438,0.761l1.368,0.241l1.345-0.076l1.118,0.168l2.594,0.237l0.445,0.408l-0.304,0.12l-0.492,0.192l-1.683,0.146l-2.303,0.124l-1.152,0.121l-1.233,0.05l-1.469-0.068l-2.831-0.064l-2.22-0.066l-1.389,0.168l-1.614,0.027l-1.933,0.027l-1.16,0.026l-1.485,0.168l-0.444,0.118l-1.322,0.213l-0.335,0.464l0.743,0.251l2.551-0.281l1.367-0.072l3.912,0.038l2.223-0.12l2.331-0.005l0.997-0.025l0.93,0.067l1.77,0.434l0.671,0.09l1.087-0.186l1.663-0.21l1.536-0.281l1.964-0.144l0.59,0.462l-0.566,0.482l-2.316,0.639l-0.973,0.338l-1.281,0.734l0.12,0.307l0.319,0.152l0.796-0.089l0.477-0.044l1.616-0.553l1.766-0.537l1.413-0.385l1.706-0.32l0.775-0.207l1.662-0.163l1.618,0.111l1.391,0.065l1.497-0.3l0.703-0.324l1.129-0.234l2.148-0.004l1.672,0.112l1.097,0.044l1.197,0.136l1.135,0.228l1.107,0.112l0.316,0.25l-0.181,0.273l-1.97,0.252l-1.491,0.138l-1.245,0.494l-0.557,0.289l-1.604,0.355l-1.57,0.548l-1.063,0.089l-0.918-0.042l-1.592,0.047l-2.213-0.039l-1.491,0.198l-0.731,0.217l-0.495,0.535l0.166,0.322l1.949-0.305l1.581-0.046l1.856,0.101l0.003,0.42l-0.743,0.241l-2.388,0.124l-0.463,0.14l-0.213,0.199l-0.156,0.595l-0.471,0.71l-0.678,0.158l-1.06-0.077l-0.742,0.041l-0.837,0.9l-0.987,1.087l-0.15,0.347l0.454,0.307l0.403,0.095l0.602-0.481l0.743-0.368l0.856-0.041l2.345,0.266l0.353,0.096l0.262,0.288l-0.059,0.211l-1.234-0.074l-0.673-0.018l-0.512,0.097l-0.136,0.191l0.29,0.286l1.756,0.188l0.557,0.132l1.802-0.137l0.526,0.208l0.214,0.323l-0.049,0.436l-0.256,0.133l-1.835-0.186l-1.653-0.054l-0.781-0.074l-1.295,0.078l-1.382,0.475l-0.823-0.13l-0.49-0.15l-1.06,0.04l-0.283,0.377l1.393,0.599l1.187,0.222l1.298,0.128l1.665,0.072l0.696,0.148l0.551,0.482l0.272,0.444l0.014,0.554l-0.434,0.405l-0.384,0.074l-1.292-0.181l-0.82-0.109l-0.372,0.111l0.023,0.55l0.118,0.236l0.426,0.162l0.618,0.089l0.723,0.215l0.914,0.142l0.752,0.16l0.383,0.376l-0.338,0.233l-0.832,0.145l-0.647,0.126l-1.747-0.032l-1.176-0.087l-1.624-0.086l-0.592,0.448l0.551,0.195l1.396,0.051l1.052,0.158l0.724,0.248l0.088,0.319l-0.035,0.549l-0.13-0.005l-1.092-0.045l-1.247,0.108l-0.596,0.266l-1.246,0.02l-1.225-0.139l-1.497-0.404l-0.922-0.478l-0.373-0.07l-1.094,0.286L345,36.811l-1.084,0.09l-0.589,0.178l-1.451-0.033l-0.913-0.087l-0.969,0.143l-0.395,0.125l-0.174,0.283l0.006,0.141l0.354,0.527l0.71,0.245l1.284,0.05l1.515,0.26l1.567-0.056l1.323,0.54l0.758,0.226l0.482,0.226l1.196,0.329l1.252,0.38l0.376,0.276l0.483,0.898l0.892-0.208l0.278-0.139l0.397,0.207l0.298,0.43l0.071,0.344l0.198,1.164l-0.169,0.205l-0.371,0.12l-0.541-0.101l-0.546-0.119l-0.917,0.002l-1.041,0.036l-1.488-0.27l-0.637-0.409l-0.415-0.634l-0.354-0.274l-1.17-0.566l-0.84-0.292l-0.748-0.137l-1.095-0.084l-0.521,0.14l-0.962,0.105z M351.365,40.026l-1.527-0.537l-0.96-0.225l-0.712-0.156l-0.159-0.069l-0.314-0.419l1.483-0.038l0.893,0.139l1.064,0.26l0.819,0.296l0.162,0.488l-0.215,0.209l-0.533,0.053z M281.574,46.135l-0.568-0.133l-0.707-0.318l-0.801-0.183l-0.197-0.101l-0.25-0.218l-0.08-0.844l0.287-0.34l0.368-0.018l0.646,0.135l1.157,0.066l1.287,0.27l0.748,0.269l0.595,0.1l0.777,0.217l0.603,0.335l-0.144,0.202l-0.112,0.034l-0.543,0.051l-0.774,0.035l-0.77,0.186l-1.009,0.153l-0.511,0.102z"/> - <path id="CA" country:name="Canada" d="M105.98,81.688l-0.952-0.826l-0.198-0.342l-0.024-0.476l0.095-0.104l0.408,0.044l0.312-0.045l0.781,0.177l0.658-0.076l0.28,0.119l0.138,0.163l-0.234,0.224l-0.173,0.565l-0.028,0.312l-0.581,0.075l-0.483,0.19z M125.24,92.375l-1.312-0.288l-1.345-0.434l-0.218-0.174l0.061-0.189l0.376-0.466l-1.023,0.002l-0.413,0.248l-0.299-0.072l-0.416-0.188l0.166-0.452l-0.487-0.334l-0.269-0.014l-0.735-0.086l-0.226-0.262l0.317-0.292l-0.976-0.524l-0.556,0.118l-0.386-0.102l-0.852-0.511l-1.277-0.863l-0.219-0.235l0.02-0.117l0.962-0.12l0.337,0.043l1.979,0.598l0.981,0.204l1.772,0.202l0.385,0.263l0.618,0.526l0.426,0.642l0.433,0.422l0.362,0.189l1.587,0.536l0.316,0.203l0.48,0.756l0.116,0.407l-0.279,0.349l-0.407,0.016z M271.379,92.089l-1.202-0.23l0.641-0.743l0.358-0.161l0.279,0.058l0.292,0l0.355-0.263l-0.697-0.653l0.079-0.219L272,89.003l1.121-1.35l1.454-1.31l0.725-0.442l0.496-0.192l1.315-0.194l0.198,0.073l0.11,0.221l-0.299,0.221l-0.582,0.03l-0.242,0.133l0.349,0.44l-0.755,0.78l-1.226,1.438l-0.271,0.526l0.113,0.291h0.11l0.428-0.176l0.483-0.555l0.458-0.191l1.115,0.305l-0.896,0.687l0.261,0.203l0.229,0.072l1.423,0.565l0.758-0.03l0.325-0.408l0.309-0.059l0.718,0.057l0.826,0.202l0.616,0.231l-0.297,0.292l-0.373,0.233l-0.708,0.467l0.339,0.333l0.477,0.362l0.26,0.014l0.417-0.161l0.464-0.132l0.278,0.116l0.02,0.16l-0.254,0.262l-0.404,0.248l-0.892,0.104L280.84,93l0.273,0.362l0.124,0.405l0.28,0.231l0.183-0.203l0.309-0.262l0.527,0.159l-0.099,0.449l0.149,0.275l0.716,0.028l0.085-0.015l0.015,0.203l-0.168,0.304l-0.25,0.652l-0.34,0.651l-0.222-0.072l-0.71-0.128l-0.301-0.144l-0.042-0.651l-0.601,0.406l-0.374,0.015l-0.095-0.274l0.497-0.652l0.011-0.333l-0.421-0.478l-0.279-0.072l-0.388,0.392l-0.423,0.291l-0.365,0.146l-0.435,0.204l-0.552,0.536l-0.496,0.334l-0.881-0.042l-0.222-0.217l0.165-0.145l1.229-0.408l0.466-0.522l0.632-0.363l-0.699-0.129l-0.601-0.057l-0.322,0.464l-0.412,0.015l-0.13-0.159l0.04-0.493l-0.757,0.016l-0.148,0.29l-0.41,0.218l-1.052,0.045l-0.709-0.057l-1.139-0.186l-1.012-0.085l-1.355,0.061l-1.014,0.147l-0.145-0.188l-0.215-0.463l0.187-0.175l0.561-0.334l0.734-0.408l0.502-0.161l0.636-0.335z M265.435,98.655l-0.469-0.057l-0.497-0.273l-0.356-0.562l0.062-0.635l0.742-0.738l0.932-1.043l0.816,0.432l-0.375,0.435l-0.112,0.462l-0.233,0.333l-0.262,0.116l-0.58,0.319l-0.244,0.448l0.522,0.244l0.168-0.029l0.279-0.26l0.42-0.362l0.617-0.319l0.309,0.057l0.495,0.461l-0.177,0.347l-0.246,0.159l-1.134,0.42l-0.682,0.044z M211.34,59.677l-0.68-0.046l0.068-0.872l-0.375-0.333l-0.958,0.161l-2.375,0.29l0.107-0.461l0.56-0.303l1.644-0.561l-0.302-0.478l-0.102-0.415l0.106-0.417l0.398-0.835l0.434-0.566l0.254-0.648l0.331-0.471l1.11,0.566l-0.312,0.518l0.791,0.386l0.527,0.047l0.402-0.469l0.67,0.112l0.806,0.289l0.917,0.514l0.582,0.255l2.168,0.492l0.442,0.271l0.176,0.255l-0.09,0.925l0.539,0.047l0.57-0.065l0.934,0.046l0.701,0.142l1.019,0.427l-0.419,0.096l-0.269,0.127l-0.46,0.271l-0.949-0.046l-0.623-0.125l-1.328-0.125l-0.438-0.126L217.259,58l-0.528-0.301l-1.017-0.237l-0.528,0.017l-0.203,0.271l0.174,0.588l-0.126,0.096l-1.314,0.161l-0.673,0.493l-0.588,0.302l-1.116,0.287z M200.125,19.1l-0.862-0.015l-1.085-0.195l-0.308-0.664l0.819-0.304l0.77-0.072l0.666-0.024l3.475-0.125l1.263-0.12l1.374-0.026l1.714,0.324l0.397-0.094l0.397-0.377l1.303-0.287l1.759-0.099l1.975,0.209l0.746-0.001l2.562,0.137l2.621,0.324l1.424,0.09l1.461,0.161l0.448-0.165l-1.433-0.42l-1.67-0.352l-0.816-0.429l0.293-0.242l1.361-0.148l1.101-0.246l1.431-0.101l2.382-0.201l1.666,0.119l1.944,0.191l1.009,0.265l1.19,0.456l0.354,0.047l0.273-0.362l-0.959-0.508l-0.828-0.292l0.499-0.248l1.45,0.121l1.832,0.168l1.653,0.07l1.639,0.46l0.378,0.023l0.062-0.195l-0.301-0.539l1.781-0.004l1.408,0.046l0.832,0.269l0.831,0.34l0.618-0.001l-0.044-0.268l-0.331-0.467l1.075-0.077l3.691,0.386l2.726,0.288l1.937-0.077l2.987,0.018l0.967,0.047l0.757,0.12l0.126,0l1.419,0.094l1.089,0.191l0.744,0.095l1.685,0.044l1.357,0.357l-0.385,0.358l-1.237,0.121l-1.206,0.356l-1.849,0.191l-0.978-0.045l-2.191-0.159l-2.284,0.005l-0.776,0.142l-1.915,0.168l-0.597,0.465l0.75,0.366l0.761,0.044l1.03-0.048l1.705-0.279l0.79,0.021l0.808,0.434l-0.168,0.114l-1.246,0.139l-1.38,0.207l-1.174,0.295l-2.098,0.518l-1.316,0.224l-1.19,0.355l-0.924,0.286l-2.252,0.005l0.65,0.906l-0.449,0.193l-2.297,0.455l-0.768-0.019l-1.587-0.037l-1.462-0.218l-2.386-0.164l-0.66,0.33l2.591,0.695l-0.662,0.141l-0.967-0.038l-1.297,0.022l-1.068,0.022l-2.58-0.214l-2.009,0.063l-0.134,0.66l1.257-0.105l1.065,0.018l2.312,0.292l0.557,0.157l0.12,0.67l-0.33,0.197l-1.031,0.12l-0.515,0.705l-1.073,0.021l-0.448-0.058l-0.402,0.176l0.297,0.253l0.759,0.25l-0.328,0.136l-1.615,0.08l-0.867-0.037l-1.71-0.171l-0.422,0.078l0.41,0.791l-0.08,0.231l-0.649,0.289l-0.767,0.155l-1.52-0.112l-2.039-0.111l-1.43-0.227l-1.008,0.079l-1.219,0.5l1.031,0.112l0.368,0.057l2.154,0.11l1.759,0.13l1.534,0.168l2.001,0.034l0.66,0.34l0.045,0.359l-0.907,0.398l-2.685,0.268l-0.927,0.115l-1.054,0.227l-1.115,0.077l-0.467-0.28l-0.797-0.638l-0.56,0.039l-0.631,0.001l-1.453-0.318l-0.001,0.17l0.331,0.508l-1.477-0.016l-1.5-0.129l-0.875-0.319l-1.033-0.471l-0.388,0.058l0.527,0.717l-0.24,0.17l-0.821,0.133l-1.72-0.109l-2.276-0.033l-0.972-0.073l-1.382-0.394l-0.642-0.131l-0.282,0.453l-0.619,0.152l-1.843-0.316l0.161-0.586l0.219-0.228l1.525-0.117l0.61-0.249l0.961-0.173l1.179,0.036l0.499-0.172l-1.073-0.4l-1.043-0.651l0.052-0.154l0.479-0.117l1.316,0.036l1.743,0.093l0.888,0.21l1.108,0.517l1.35,0.323l1.085,0.093l1.667-0.022l0.829-0.136l0.086-0.268l0.514-0.304l-3.019,0.001l-1.025-0.171l-0.156-0.85l0.211-0.154l-1.74-0.153l-1.963-0.152l-0.274,0l-0.631,0.114l0.204-0.758l1.159-0.551l1.104-0.16l1.837-0.003l1.164,0.037l1.37,0.076l2.023,0.311l1.342,0.115l0.486-0.158l1.132-0.041l-3.399-0.802l-1.742-0.313l-3.555-1.27l-0.406,0.242l-1.398-0.878l0.025-0.258l0.313-0.108l1.747,0.104l1.905-0.004l2.019,0.06l1.6,0.382l2.535,0.784l1.448-0.043l0.833,0.095l-1.387-0.555l-2.015-0.317l1.208-0.743l1.456-0.329l1.731-0.025l1.529-0.222l2.042-0.07l1.157-0.112l1.414-0.051l-1.778-0.479l-1.425-0.153l-2.501,0.027l-1.243,0.248l-1.305,0.158l-1.425,0.202l-1.447,0.047l-0.586,0.067l-1.532-0.438l-0.214,0.111l-0.543,0.156l-2.16-0.018l-1.58,0.365l0.311-0.828l0.98-0.292l0.007-0.202l-0.606-0.247l-1.375-0.156l-1.39,0.003l-4.189,0.505l-2.031,0.672l-0.408-0.11l-0.569-0.251l0.395-0.133l0.678-0.023l-0.117-0.316l-0.698-0.398l-1.216-0.056l-0.216-0.003z M200.125,20.844l0.899-0.096l0.832,0.196l0.339,0.5l0.511,0.495l0.427,0.063l1.141,0.041l-0.081-0.236l0.056-0.411l0.438-0.109l0.718,0.194l0.718,0.322l0.374,0.3l-0.066,0.171l0.056,0.826l0.764,0.442l0.953-0.017l1.276-0.074l1.646,0.504l-1.123-0.264l-1.528,0.34l-1.599,0.221l-0.83,0.377l-0.287,0.197l-0.265,0.315l-0.448,0.021l-1.493-0.41l-0.656,0.335l0.465,0.43l-0.029,0.235l-0.412,0.196l-0.392,0.04l-1.086-0.31l-0.944-0.311l-0.26,0.645l-0.117,0.068l-0.083,0.049l-0.888,0.041l-1.74-0.094l-1.458-0.153l-0.888-0.154l-0.494,0.021l-3.115-1.31l-0.191-0.276l1.971-0.241l3.32,0.093l0.889,0.097l1.573,0.1l-2.485-0.693l-3.019-0.213l-1.103,0.122l-1.43-0.017l-0.597,0.18l-1.008,0.022l-0.606-0.198l-1.066-0.517l-1.425-0.479l-0.341-0.355l1.971,0.124l2.278-0.175l-1.255-0.249l-0.756-0.351l0.38-0.305l0.729-0.132l0.769-0.023l0.921,0.042l0.156-0.219l-1.799-0.793l1.053-0.114l1.213-0.182l1.13,0.087l0.584-0.046l0.145-0.18l-0.514-0.475l1.362,0.134l0.941,0.066l0.83,0.202l1.589,0.869l0.653,0.264l0.772,0.24l0.674-0.001l0.36-0.039z M179.067,27.216l-1.156-0.056l-0.604-0.173l-0.926-0.638l-0.621-0.193l-3.102-0.091l-1.487,0.081l-0.622,0.001l-1.444-0.056l-0.767-0.154l-1.019-0.37l-0.161-0.234l0.335-0.138l0.802-0.001l1.687,0.232l0.867-0.021l-0.031-0.235l-0.252-0.275l-1.344-0.49l-0.579-0.098l-1.075-0.077l-1.392-0.196l0.065-0.397l2.246-0.124l2.392,0.155l0.77,0.376l0.999,0.453l1.979,0.193l2.189,0.114l1.178,0.233l0.604,0.254l1.123,0.721l0.581,0.446l0.168,0.426l-0.481,0.194l-0.919,0.137z M185.907,26.758l-1.078-0.037L184,26.529l-1.029-0.484l-1.144-0.76l-0.03-0.216l0.239-0.099l2.296-0.044l1.816,0.311l3.101,0.542l-0.047,0.351l-0.254,0.331l-0.436,0.04l-1.563,0.177l-1.043,0.08z M156.886,26.865l-1.573,0.646l-0.558,0.27l-1.85,0.042l-1.019,0.079l-1.898-0.15l-0.577-0.114l-0.302-0.423l0.334-0.291l1.365-0.177l0.899,0.056l2.351-0.102l0.496,0l2.331,0.163z M132.902,31.305l-0.53-0.186l-0.95-0.466l-0.424-0.112l-0.33,0.057l-0.56,0.207l-1.269,0.059l-0.786-0.279l-0.283-0.319l0.23-0.264l1.13-0.097l0.503-0.133l0.771-0.134l0.977-0.399l0.848-0.211l0.726-0.172l0.548-0.344l1.083-0.231l1.277-0.079l2.532-0.158l1.68,0.016l0.888-0.29l1.038-0.079l1.503,0.438l-0.756,0.097l-0.852,0.231l-0.22,0.268l0.12,0.266l0.469,0.474l-0.777,0.001l-0.912,0.115l-0.918,0.662l-1-0.017l-0.867-0.981l-0.694-0.15l-0.379,0.02l-0.229,0.285l-0.588,0.342l-0.63,0.623l-0.595,0.151l-0.284,0.375l-0.705,0.356l-0.787,0.058z M191.827,30.313l-1.266-0.054l-2.278-0.165l-0.426,0.058l-0.332-0.094l-0.896-0.489l-1.185-0.414l0.192-0.229l2.433-0.042l1.542,0.263l1.472,0.054h0.171l0.89,0.358l-0.179,0.246l0.123,0.32l-0.263,0.188z M144.688,31.739l-2.222-0.395l-0.325-0.674l0.503-0.057l0.595-0.17l0.945-0.096l0.953-0.133l1.279-0.059l0.522,0.187l0.65,0.374l0.659,0.186l1.55-0.209l0.617,0.149l1.624,0.762l1.016,0.351l0.897,0.036l0.96-0.058l1.418,0.09l0.591-0.02l1.116-0.169l0.092-0.297l-0.557-0.559l-0.941-0.391l-1.347-0.354l0.96-0.322l0.524-0.379l0.569-0.152l1.097-0.116l0.507,0.17l0.773,0.678l-0.017,0.413l0.518,0.654l0.565,0.111l0.9,0.036l1.805,0.406l-0.334-0.465l0.151-0.28l0.409-0.076l1.495,0.24l0.932,0.39l-0.292,0.409l0.039,0.5l-0.358,0.461l-0.573,0.277l-0.755,0.111l-0.782,0.001l-1.682,0.095l-1.156-0.071l-1.757-0.18l-0.622-0.017l-1.129,0.277l-1.132,0.202l-0.76,0.182l-0.977,0.254l-1.625,0.292l-1.338,0.2L149.23,34.5l-0.748-0.07l-1.445-0.286l-0.276-0.378l0.648-0.128l1.219-0.038l0.738-0.146l0.852-0.075l1.166-0.057l0.622,0.017l1.09-0.149l0.483-0.553l-2.768-0.087l-0.925-0.054l-1.564,0.28l-1.625,0.168l-1.292,0.04l-0.795,0.093l-1.681-0.347l-0.479,0.167l-0.92,0.075l-0.979-0.127l-0.854-0.33l0.023-0.111l0.863-0.427l1.098-0.058l2.047-0.022l0.96-0.159z M178.479,33.234l-0.984-0.219l-0.193-0.294l0.764-0.389l0.433-0.112l0.088-0.167l-0.447-0.333l-1.161-0.054l-2.13,0.227l-0.939,0.076l-0.331,0.019l-0.854-0.276l0.039-0.335l0.739-0.02l0.542-0.244l0.587-0.057l-0.466-0.598l0.176-0.245l0.132-0.226l0.49,0.018l0.859,0.224l1.942,0.746l0.426,0.186l0.46-0.094l-0.101-0.243l-0.959-0.486l-0.371-0.131l-0.407-0.357l0.436-0.095l0.956-0.059l0.713,0.131l1.033,0.262l0.572,0.168l0.27,0.018l0.162-0.452l0.478-0.133l0.73,0.112l0.717,0.168l0.327,0.168l0.367,0.75l-0.034,0.616l-0.247,0.242l-0.831,0.335l-0.017,0.352l0.35,0.625l-0.361,0.147l-1.648-0.089l-0.862,0.112l-1.446,0.003z M200.125,30.572l-0.895,0.045l-0.853,0.17l-0.37,0.467l1.133,0.054l0.984-0.038l0.046-0.001l0.847,0.11l0.463,0.129l0.498,0.463l0.727,0.424l0.621,0.091l0.213-0.074l0.043-0.314l0.286-0.056l1.075-0.002l0.883-0.187l0.766,0.11l0.835,0.239l0.665,0.257l0.976,0.053l0.775-0.463l1.393-0.281l1.704-0.114l1.951-0.246l1.533,0.053l2.59,0.014l0.381,0.037l0.79,0.314l0.911,0.239l1.418,0.146l0.653,0.128l0.21,0.037l0.361,0.166l0.181,0.257l-0.4,0.148l-1.833,0.407l-0.135,0.255l0.469,0.666l-2.486,0.076l-0.592,0.02l-0.651,0.091l-0.768-0.053l-0.846-0.16l-0.405-0.125l-0.306-0.667l-0.833-0.218l-0.366,0.129l0.072,0.723l-0.536,0.127l-0.747-0.053l-0.91,0.109l-0.728-0.017l-0.495,0.001l-1.342-0.213l-0.593-0.197l-0.495-0.017l-0.209,0.433l-1.801,0.111l-0.831,0.074l-1.453-0.069l-0.404-0.251l-0.144-0.686l-1.237,0.129l-0.389,0.181l-0.326,0.325l-0.955,0.2l-1.011-0.034l-0.112-0.027l-0.704-0.169l-1.186-0.575l-0.675,0.489l-1.131-0.07l-0.666-0.688l-0.442-0.717l0.587-0.481l0.019-0.371l-0.292-0.316l-1.249-0.651l-0.617-0.299l-0.047-0.338l0.636-0.133l1.226-0.078l2.472-0.023l0.763,0.093l1.118,0.261l0.188,0.04l0.872,0.184l-0.613,0.189l-0.259,0.013z M128.19,41.985l-0.926-0.016l-1.059-0.102l-0.362-0.466l-0.549-0.467l-0.432-0.259l-1.123-0.363l-1.36-0.067l-0.951-0.138l-0.469-0.19l-0.168-0.174l0.537-0.106l0.589-0.298l0.481-0.211l0.08-0.386l-0.437-0.809l0.552-0.001l0.468-0.177l0.307-0.372l1.104-0.533l0.526-0.588l-0.121-0.32l-0.271-0.16l-1.229-0.677l-0.375-0.448l0.869-0.001l0.823-0.056l1.455,0.051l0.97,0.016l1.515-0.092l1.284-0.146l1.242-0.074l0.495,0.125l3.242,0.801l0.918,0.088l0.708-0.055l1.316-0.127l1.223,0.016l0.771,0.07l1.35,0.373l2.389,0.815l-0.242,0.143l-0.432,0.036l-0.26,0.072l-1.609,0.322l-1.073,0.144l-1.829,0.428l-1.069,0.319l-1.604,0.725l-1.025,0.563l-0.549,0.089l-0.974,0.124l0.066,0.924l-0.271,0.504l-0.662,0.278l-1.215,0.124l-1.213-0.067l-0.521,0.485l-0.898,0.312z M190.483,39.666l-1.146-0.208l-0.146-0.524l-0.941-0.806l-0.207-0.582l0.058-0.389l0.27-0.657l0.377-0.321l1.256,0.033l-0.089-0.16l-0.416-0.266l-0.185-0.286l0.211-0.09l0.234-0.072l2.154-0.058l1.215,0.087l1.464,0.248l1.282,0.051l1.316-0.146l1.051,0.016l0.694,0.105l0.639,0.213l-0.007,0.089l-0.224,0.179l-0.824,0.428l-0.874,0.746l-1.513,0.92l-1.386,0.073l-2.379-0.154l-1.269,0.055l1.392,0.717l-0.188,0.315l-0.855,0.369l-0.964,0.072z M181.204,41.523l-0.491-0.085l-1.101-0.552l-0.952-0.641l-1.014-0.468l-0.978-0.225l-1.438-0.12l-0.55-0.174l-2.255-1.066l0.866-0.654l0.653,0.14l1.032,0.474l1.063,0.227l0.46,0.052l0.615-0.283l0.908-0.619l0.415-0.036l0.018-0.212l-1.062-0.565l-1.068-0.424l-0.177-0.231l0.132-0.107l1.683,0.086l0.711-0.215l0.42,0l0.996,0.39l0.56,0.035l0.58-0.055l0.435-0.25l1.232-0.127l1.354,0.069l0.912,0.23l-0.324,0.268l-0.58,0.125l-0.323,0.338l-1.55,0.375l-0.392,0.16l-0.069,0.194l0.253,0.247l0.506,0.105l0.692-0.089l1.08,0.174l0.868,0.245l0.391,0.017l0.564,0.262l0.186,0.438l-0.681,0.352l-0.156,0.35l-0.271,0.68l-0.457,0.366l-0.508,0.14l-0.658,0.019l-0.582-0.103l-0.773-0.346l-0.653-0.103l0.013,0.208l1.054,0.553l-0.817,0.399l-0.77,0.036z M243.524,60.394l-0.234-0.208l-1.199-0.235l-0.673-0.331l-0.154-0.269l0.346-0.064l0.616-0.461l-1.378-0.521l-1.132-0.125l-0.76-0.349l-0.929-0.731l-0.035-0.511l-1.115-0.062l-1.311-0.366l-0.675-0.031l0.284,0.767l-0.155,0.096l-0.409-0.015l-1.704-0.332l-0.309,0.033l-0.325,0.304l-0.441,0.288l-1.312,0.082l-1.349-0.173l-1.343-0.189l-0.813-0.254l-0.052-0.319l0.196-0.4l0.382-0.354l1.066-0.163l0.192-0.178l-0.128-0.516l0.206-0.033l1.357,0.11l1.408,0.175l0.517,0.144l0.962,0.626l0.051-0.386l-0.154-0.193l0.077-0.194l0.585-0.033l0.977-0.099l0.652-0.163l0.649-0.114l0.515,0.063l0.785,0.031l0.166-0.275l-1.138-0.825l-0.773-0.356l-0.119-0.228l0.167-0.163l0.586-0.066l0.72-0.246l1.409-0.591l0.361-0.541l0.771-0.46l0.493-0.379l-0.109-0.593l-0.899-0.841l-0.407-0.496l-0.541-0.364l-0.414,0.001l-1.258-0.33l-1.041-0.481l-0.244-0.467l-0.527-0.384l-0.442,0.202l-0.551,0.202l-0.825-0.015l-0.293,0.117l-0.62,0.018l-1.255,0.169l-0.214-0.667l1.032-0.052l1.23-0.103l0.163-0.269l-1.604-0.618l-1.552-0.67l-0.879-0.015l-0.567-0.185l-0.169-0.542l-0.677-0.339l-0.45-0.05l-0.918-0.306l-0.687-0.341l-0.385-0.119l-0.611,0.155l-0.81-0.187l-1.177-0.238l-0.489-0.085l-0.379,0.138l0.529,0.307l0.453,0.05l2.838,0.712l0.438,0.271l0.069,0.306l-0.505,0.221l-0.669,0.069l-0.541-0.033l-0.757-0.049l-0.818-0.252l-1.153-0.27l-0.667-0.066l-0.323,0.17l0.044,0.204l0.426,0.236l0.259,0.438l-1.703-0.553l-0.47-0.05l-0.396,0.119l-0.63,0.153l-0.767-0.218l-0.693-0.117l-0.859,0.12l-1.474-0.184l-1.995-0.167l-1.321,0.037l-1.146-0.032l-0.862-0.186l-0.003-0.597l-0.363-0.153l-0.904-0.049l-0.396,0.342l-0.623,0.086l-1.214-0.049l-1.076-0.168l-1.303-0.477l-0.415-0.376l0.123-0.275l0.868-0.07l1.131,0.067l1.212,0.101l0.879-0.019l0.312-0.19l-0.934-0.463l-0.8-0.275l-0.905-0.102l-1.106-0.119l-0.752,0.036l-0.539-0.017l-1.249-0.223l0.114-0.416l0.292-0.557l0.34-0.14l0.646-0.054l0.081-0.227l-1.082-0.4l-0.044-0.175l0.449-0.79l1.197-0.919l0.565-0.284l0.918-0.321l0.74-0.374l0.423-0.037l0.37-0.178l0.698-0.001l0.481-0.125l0.71-0.09l1.436-0.109l1.348,0.033l0.857,0.194l-0.92,0.393l-0.815,0.48l-1.394,0.639l-0.43,0.529l0.169,0.369l1.256,0.541l-0.444,0.298l-0.076,0.402l0.257,0.313l0.862,0.554l1.559,0.621l-0.096,0.121l-1.272,0.331l-0.072,0.31l0.959,0.033l1.504,0.101l0.654-0.639l-0.103-0.415l-0.343-0.277l-0.724-0.103l-0.422-0.138l-0.884-0.538l0.101-0.157l0.506-0.245l0.473-0.193l1.001,0.12l0.837-0.071l-1.204-0.47l-0.703-0.034l-0.793-0.279l-0.056-0.193l0.053-0.545l0.886-0.319l1.207,0.086l1.509-0.056l-0.939-0.281l-1.233-0.351l0.793-0.303l1.288-0.198l1.044-0.126l1.688-0.323l1.114,0.016l0.642,0.052l0.833,0.141l0.782,0.478l1.536,0.97l0.058,0.141l-0.583,0.687l-0.709,0.632l0.038,0.733l0.364,0.086l0.65,0.033l1.088-0.315l0.284-0.455l0.595-0.088l0.791,0.034l0.454,0.174l-0.006,0.262l0.16,0.47l0.875,0.189l0.196-0.122l-0.204-0.854l0.218-0.123l0.456-0.474l1.038-0.265l0.98-0.054l0.748,0.034l0.98,0.174l1.172,0.138l1.151-0.09l0.688,0.139l0.327,0.262l0.621,0.331l0.574,0.191L235.438,40l0,0.191l-0.531,0.088l-0.484,0.279l-0.818,0.262l-0.148,0.225l0.45,0.259l0.427,0.068l0.897-0.417l0.652-0.174l0.502,0.051l0.476,0.242l0.365,0.466l0.516,0.413l0.342-0.242l1.304-0.798l1.935,0.256l0.915,0.361l-0.051,0.069l-0.638,0.346l-0.708,0.517l1.167-0.054l0.455-0.173l1.078-0.105l0.033,0.704l0.797,0.324l0.523-0.069l0.831-0.207l1.316-0.088l0.816,0.221l0.566,0.273l-0.162,0.154l-0.461,0.223l-1.87,0.43l-0.238,0.272l0.523,0.253l0.456-0.068l0.747-0.171l1.235-0.122l0.406-0.29l0.361-0.103l0.479,0.067l0.51,0.187l0.544,0.339l0.636,0.522l-1.019,0.002l-1.2,0.053l-0.424,0.135l0.059,0.269l0.372,0.134l1.333,0.065l0.938,0.183l0.543,0.217l0.233,0.301l-0.37,0.034l-0.748,0.001l-1.011-0.082l-0.875-0.216l-0.824-0.065l-0.316,0.185l1.23,0.583l-0.216,0.201l-1.552,0.12l0.245,0.283l0.437,0.166l0.551,0.032l1.331,0.364l1.312,0.347l0.247,0.182l0.039,0.282l0.351,0.38l0.75-0.217l0.536,0.049l1.413,0.295l0.298-0.067l0.649-0.15l0.61,0.032l0.752,0.379l0.862,0.477l0.376,0.346l-0.685,0.1l-0.801,0.117l-0.027,0.444l0.795-0.001l1.405-0.052l0.51-0.132l0.895,0.048l-0.386,0.559l0.918,0.179l0.514-0.001l0.943-0.379l0.685,0.343l1.089,0.407l0.194,0.098l-0.275,0.229l-0.254,0.099l-0.103,0.326l-0.819,0.05l-0.718-0.21l-0.247-0.048l-0.794,0.213l0.968,0.454l0.279,0.162l0.057,0.276l-1.057,0.197l-0.356,0.228l-0.312,0.292l-0.372-0.113l-0.819-0.583l-0.29,1.103l0.354,0.903l-0.419,0.065l-0.677-0.257l-0.751-0.176l-0.205-0.177l-0.018-0.243l-0.315-0.274l-0.93,0.276l-0.743-0.613l0.051-0.292l0.27-0.374l-0.304-0.129l-0.224-0.016l-0.992-0.08l-0.718-0.292l-1.17-0.617l-0.769-0.292l-0.762-0.048l-0.452,0.23l-0.645,0.083L250,52.592l0.281,0.179l1.05,0.682l-0.321,0.114l-0.686,0.05l-0.359-0.259L249.277,53l-0.646-0.21l0.275,0.488l0.859,0.972l0.604,0.015l0.587,0.08l0.5,0.581l0.612,0.805l0.513,0.432l0.615-0.321l0.285,0.047l0.592,0.399l0.585,0.271l1.38,0.396l-0.634,0.113l-0.213,0.208l0.254,0.19l0.568,0.286l0.962,0.444l0.324,0.237l0.242,0.682l-0.112,0.428l-1.302-1.155l-0.554-0.237l-0.027,0.238l0.118,0.27l1.055,1.281l-0.01,0.3l-0.926-0.125l0.053,0.205l0.432,0.409l0.378,0.519l-0.563-0.172l-0.615-0.313l-0.889-0.693l-0.145-0.031l-0.719,0.064l-0.91-0.188l-1.44-0.662l-0.319-0.285l-1.062-0.665l0.187,0.777l-1.22-0.473l-0.567-0.158l-0.872-0.03l0.095,0.222l0.799,0.696l0.853,0.426l1.842,0.645l1.296,0.644l0.774,0.549l0.442,0.486l0.429,0.689l-1.833-0.341l-1.524-0.421l-1.251-0.28l-1.444-0.107l-1.092-0.25l-0.898-0.644l-1.146-0.14l-0.638-0.204l-0.635-0.141l-0.058,0.145z M146.194,38.698l0.818-0.037l0.78-0.125l1.138-0.548l0.895-0.019l1.723,0.243l0.939,0.262l-0.188,0.877l0.515-0.071l0.66-0.019l0.792-0.229l0.599-0.141l0.758,0.016l0.334-0.071l-0.989-0.965l0.156-0.036l1.38,0.138l1.208,0.245l0.675,0.245l0.259,0.245l0.194,0.508l0.965,1.063l0.638,0.346l1.045-0.315l0.14-0.261l-1.243-1.361l-0.439-1.321l0.228-0.354l1.91,0.262l1.775,0.156l2.031,0.719l0.36,0.175l0.3,0.316l0.16,0.701l0.511,0.645l0.352,0.26l0.856,0.606l0.048,0.19l-0.178,0.243l-0.333,0.605l0.179,0.31l0.224,0.12l1.4,0.649l0.509,0.171l1.151,0.254l1.513,0.1l2.056,0.576l1.012,0.39l0.364,0.793l-0.168,0.101l-1.071-0.082l-0.811-0.234l-0.945-0.234l-0.551,0.169l-0.665,0.204l-1.021,0.036l-0.256,0.118l0.208,0.689l1.087-0.069l0.614-0.152l0.676-0.119l0.876,0.536l-0.01,0.235l-0.526,0.151l-0.517,0.252l-0.583,0.102l-1.417,0.12l-1.049-0.015l-1.194-0.082l-1.594-0.248l-2.278-0.499l-0.553-0.217l-0.436-0.335l-0.482-0.033l-0.581,0.102l-0.402,0.37l-1.114,0.505l-1.055,0.019l-1.411,0.103l-1.253,0.42l-2.753,0.356l-1.42,0.019l-1.205,0.086l-1.984-0.063l-0.483,0.101l-0.916-0.015l-1-0.282l-0.061-0.468l0.198-0.101l0.002-0.302l-0.395-0.2l-0.462-0.1l-3.146-0.112l-1.258-0.115l-0.864-0.167l-0.801-0.2l-0.753-0.504l-1.274-0.554l0.303-0.069l0.531-0.222l1.572-0.054l0.603-0.188l0.558,0.016l0.91-0.019l0.904-0.087l1.716,0.031l0.935-0.002l2.14,0.047l1.09-0.002l1.711-0.038l0.415-0.154l-0.681-0.221l-2.312-0.492l-1.942-0.202l-4.059-0.061l-1.569-0.014l-1.694,0.055l-0.955,0.053l-0.604,0.001l-1.651-0.529l0.011-0.207l0.28-0.069l0.823-0.053l1.315-0.209l0.996,0.032l1.78-0.141l0.931-0.105l0.5-0.277l-0.392-0.346l-2.023,0.073l-1.578,0.159l-0.393-0.051l-0.554-0.189l-0.677-0.346l-0.65-0.19l-0.692,0.054l-0.709-0.242l-0.039-0.279l1.304-0.981l2.62-0.848l0.909-0.143l0.373-0.177l1.297-0.267l1.324-0.162l0.701-0.267l1.113-0.091l1.026,0.246l-0.07,0.212l-0.548,0.354l-0.021,0.81z M251.273,99.526l-0.188,0.153l-0.16-0.291l0.192-0.077l-0.02-0.256l0.143-0.069l-0.042-0.154h-0.224l-0.606-0.231l0.077-0.229l-0.31-2.819l-0.174-0.274l-0.488-0.288l-0.771-0.025l-0.41,0.176l-0.381-0.085l-0.505-0.36l-0.273-0.085l-0.632,0.526l-0.514,0.626l-1.139,2.22l-1.139,1.45l-1.161-0.124l-0.402,0.06l-0.363,0.435l-0.174,0.375l-1.093-0.095l-1.855-0.004l-2.508-0.029l-1.76,0.009l-0.968,0.523l-0.534,0.305l-1.754,0.814l-0.545,0.164l-0.146,0.434l-0.163,0.512l-0.44,0.275l-1.156,0.197l-1.305-0.138l-1.123-0.01l-0.93,0.091l-0.47,0.203l-0.162,0.375l0.018,0.319l0.16,0.471l0.047,0.362l-0.875,0.427l-1.464,0.452l-0.944,0.163l-0.919,0.062l-0.88,0.262l-0.939,0.478l-0.925,0.506l-0.524,0.117l-0.573-0.068l-0.497-0.169l-0.371-0.427l-0.012-0.33l0.044-0.218l0.707-0.525l0.414-0.294l0.264-0.433l0.294-0.544l0.377-0.576l0.028-0.746l-0.054-0.545l-0.876-3.16l-2.529-1.05l-0.26-0.33l0.11-0.318l-0.307-0.235l-0.916-0.181l-0.184-0.294l-0.178-0.135l-0.628,0.024l-0.46-0.465l-0.101-0.429l-2.15-1.061l-3.975-1.576l-0.977-0.386l-0.797-0.227l-0.805,0.189l-1.469,0.592l-0.707-0.074l-0.542,0.049l-0.196-0.144l-0.156-0.115l-0.474-0.041l-0.855,0.083l-0.197-0.116l-0.028-0.282l-0.373,0.075l-0.412,0.191l-0.219,0.06l-0.573,0.141l-0.506-0.098l-0.064-0.185l-0.469-0.086l-0.241-0.271l-0.502-0.013l-0.16,0.247l-0.338-0.48l-0.271,0.012l-0.02-0.185l-1.425-0.208l-0.518,0.076l-0.833-0.451l-0.468-0.46l-0.279-0.371l-0.896-0.748l-0.501,0.036l0.131,0.347l0.387,0.588l-0.68-0.003l-2.687,0.029l-2.798-0.029l-1.348,0.007l-2.105-0.003l-2.915,0.016l-2.781-0.029l-2.131,0.012l-2.935-0.014l-0.601,0.003l-4.84-0.018l-3.617,0.004l-0.875,0.005l-3.821-0.023l-1.089,0.035l-4.13-0.021l-0.74-0.011l-5.117,0.028l-1.687-0.006l-2.87,0.001l-3.938-0.008l-4.588,0.025l-1.335-0.022l-2.579-0.001l-0.194-0.013l-0.187-0.151l-0.509-0.305l-0.071-0.437l0.074-0.346l-0.708,0.25l-0.373-0.029l-0.331-0.305l-0.162-0.496l-0.125-0.189l-0.385,0.088l-0.23,0.205l-0.483,0.059l-0.721-0.495l-0.119-0.425l-0.201-0.821l-1.051,0.104l-1.01-0.277l-0.487-0.087l-0.173-0.087l-0.143-0.396l-0.438-0.352l-0.591,0.222l-1.236,0.046l-0.461-0.117l-0.383-0.249l-0.106-0.25l0.257-0.648l0.458-0.222l-0.227-0.294l-1.24-0.086l0.617-0.518l0.398-0.281l0.547-0.149l0.605-0.508l-0.874,0.006l-0.621,0.149l-0.362-0.043L116,83.422l-0.039-0.978l-0.789,0.002l-1.015-1.066l0.132-0.238l0.034-0.53l-0.547,0.056l-0.83,0.492l-1.266-0.934l-0.384-0.521l-0.204-0.402l-0.068-0.432l0.419-0.404l0.161-0.254l0.436-0.3l-0.358-0.689l-0.393-0.777l0.163-0.788l-0.402-0.255l-2.025-0.763l-0.98-0.314l-0.189-0.029l-0.512-0.393l-1.67-1.882l-1.769-1.768l-0.814-0.58l-2.048-1.175l-0.35-0.322l-0.371-0.492l-0.316-0.199l-0.832-0.073l-0.495,0.126l-0.731,0.498l-1.225,0.67l-0.848,0.205l-0.238,0.325l-0.945-0.673l-2.162-1.318l-0.348-0.292l-0.173-0.387l-0.332-0.388l-0.739-0.059l-2.424,0.122l-0.84-0.074l-0.196-0.279l-0.089-1.046l-0.026-2.167l0.043-4.334l0.026-2.183l-0.129-2.796l-0.052-2.335l-0.039-2.259l0.003-2.855l-0.102-0.483l0.71,0.024l0.9-0.086l0.964,0.116l2.012,0.451l1.601,0.518l1.214,0.266l1.04,0.115l0.731,0.032l1.619,0.164l0.888,0.232l0.429,0.149l0.254-0.034l-0.452-0.601l-0.357-0.2l-0.345-0.15l-0.064-0.419l1.344-0.423l0.745,0.066l0.578-0.068l0.15-0.102l1.736,0.148l0.771-0.001l1.125-0.373l0.309-0.186l0.442,0l0.656-0.221l0.759-0.069l0.866-0.086l0.734-0.086l0.469-0.239l0.392-0.188l0.771-0.104l1.045-0.002l0.872,0.123l-0.445,0.404l-0.352,0.119l-1.101,0.137l-1.092,0.373l-1.244,0.171l-1.22,0.271l-0.699,0.522l-1.767,0.255l-0.681,0.487l0.846,0.266l1.441,0.748l-0.219-0.55l0.168-0.351l1.196-0.253l0.39-0.235l0.726-0.421l1.727-0.053l0.96-0.372l1.158-0.389l2.066-0.173l0.643-0.338l0.921-0.272l0.821-0.189l0.476-0.239l-0.178-0.272l-0.702-0.392l-0.655-0.444l0.899,0.101l0.764,0.272l0.701,0.306l0.412,0.324l0.376,0.476l0.449,0.523l0.393,0.235l1.246,0.486l0.186,0.067l1.154,0.216l0.394-0.018l0.199-0.151l-0.511-0.639l0.07-0.27l0.548-0.035l0.334-0.136l0.627-0.103l0.383,0.354l0.059,0.421l-0.205,0.287l0.833,0.133l0.938-0.069l1.136-0.457l0.536-0.49l0.479-0.069l1.131,0.015l1.536,0.267l1.745,0.435l1.396,0.334l2.095,0.349l1.024,0.216l0.619,0.066l1.572,0.282l1.121,0.065l1.144,0.148l1.096,0.032l1.4-0.086l0.899,0.099l1.008,0.282l0.982,0.349l0.434,0.249l0.191,0.333l-0.524,0.134l-0.935-0.032l-0.566,0.051l-0.849,0.135l-0.354,0.714l3.323,0.358l1.726,0.079l1.749,0.014l0.868-0.068l0.738-0.051l0.94-0.167l0.895-0.118l0.938-0.101l0.886,0.032l1.432,0.477l1.452,0.179l0.42,0.115l1.225,0.443l-0.013,0.312l-0.504,0.083l-0.35,0.247l0.305,0.147l1.823,0.979l-0.162-0.392l-0.024-0.312l0.456-0.05l0.617-0.132l-0.062-0.181l-0.972-0.656l-0.128-0.198l-0.145-0.445l0.121-0.745l0.35-0.034l1.944-0.136l0.928-0.151l0.207-0.299l0.459-0.217l0.613-0.035l1.098,0.281l1.528,0.279l0.968,0.064l0.969-0.102l0.612,0.414l0.248,0.082l0.962,0.213l1.211,0.13l0.678,0.081l1.146-0.002l0.879-0.2l1.755-0.02l1.876,0.029l1.07-0.052l1.18-0.267l0.959,0.478l0.95,0.296l0.522-0.018l0.243-0.314l-0.017-0.513l-0.666-0.231l-0.732-0.131l-1.377-0.064l0.089-0.449l1.193-0.085l0.575,0.065l0.804,0.214l0.871,0.198l0.858,0.048l0.498,0.198l0.088,0.183l-0.095,0.132l-0.287,0.86l0.179,0.51l0.304,0.164l0.177,0.065l0.792,0.097l0.951,0.311l-0.071-0.559l-0.466-0.989l0.137-0.48l0.258-0.266l0.712,0.015l0.811-0.035l1.229-0.85l0.492-0.051l0.479-0.001l0.517-0.151l0.033-0.133l-0.15-0.367l-0.375-0.35l-0.307,0.001l-0.81,0.185l-0.988-0.082l0.535-0.52l0.806-0.069l0.435-0.168l0.572-0.001l0.739,0.4l0.464,0.167l0.065-0.268l-0.081-0.956l-0.744,0.069l-0.897-0.032l-0.68-0.116l-0.859-0.318l-0.725,0.085l-1.245-0.183l-0.861-0.234l-0.956-0.218l-0.657-0.338l-0.092-0.136l-0.022-0.324l0.33-0.137l0.842-0.463l-0.486-0.221l-1.188-0.375l0.09-0.207l0.58-0.604l0.593-0.294l0.387-0.035l1.032,0.257l0.139-0.035l0.173-0.346l-0.709-0.362l-0.201-0.277l0.23-0.035l0.551-0.331l0.367-0.035l1.841-0.021l0.559,0.086l0.728,0.189l1.26,0.449l0.432,0.328l0.195,0.38l-0.246,0.603l1.261,0.53l0.809,0.495l1.134,0.493l-0.377,0.341l-0.985,0.036l-0.474,0.273l-0.416,0.557l0.471,0.067l1.071,0.233l0.805,0.049l0.387-0.136l0.597-0.001l1.477,0.351l-0.335,0.353l-0.563,0.219l0.092,0.151l0.796,0.467l0.358,0.601l0.025,0.833l0.303-0.063l0.021-0.004l0.411-0.067l0.608-0.367l0.655-1.137l0.668-0.42l0.523,0.016l0.731,0.284l1.064,0.55l0.473,0.383l0.209,0.45l-0.159,0.433l-0.336,0.034l-0.796-0.098l-0.202,0.299l-0.043,0.415l0.35,0.396l1.146,0.659l0.61,0.493l0.463,0.279l0.595-0.166l0.896-0.167l0.369-0.132l0.208-0.66l0.764-0.398l0.599-0.416l0.249-0.664l0.363-0.75l0.237-0.184l1.394,0.081l0.329-0.067l0.134-0.518l-0.985-0.333l-0.918-0.35l0.088-0.891l0.595-0.271l0.787,0.032l0.42-0.068l0.571,0.016l3.459,0.616l1.325,0.669l0.506-0.001l0.553-0.068l0.454,0.201l0.244,1.036l-0.474,0.268l-0.431,0.101l-0.243-0.05l-0.718-0.532l-0.263,0l-0.799,0.269l0.123,0.316l0.309,0.515l0.699,0.729l0.855,0.528l1.108,0.576l0.024,0.313l-0.478,0.642l-0.439,0.181l-1.407,0.772l-0.674,0.083l-1.123,0.509l-0.763-0.276l-1.654-0.962l-0.586-0.262l-0.497-0.048l-0.684,0.281l1.364,0.521l1.483,0.896l-0.708,0.067l-0.691-0.081l-1.288,0.084l-0.375-0.129l-0.596-0.62l-1.147-0.014l-1.857,0.118l-0.253,0.229l0.614,0.244l1.311,0.421l-0.159,0.195l-0.611,0.327l-2.045,1.106l-0.657,0.179l-0.527,0.001l-0.859-0.241l-0.816-0.484l-0.225-0.081l-1.189-0.225l-0.736-0.259l-0.598-0.112l-0.947,0.014l-0.289,0.004l-1.214,0.174l1.503,0.278l1.136,0.21l1.751,0.774l1.629,0.433l1.233,0.126l1.02,0.031l-0.618,1.091l-1.237,0.705l-0.856,0.432l-0.728,0.161l-0.829,0.049l-0.928-0.126l-1.062-0.38l-0.048,0.351l-0.025,0.287l0.321,0.572l-0.02,0.159l-0.741,0.031l-0.058,0.002l-1.365-0.108l-1.649-0.41l-0.884-0.078l-2.962-0.322l2.146,0.864l1.576,0.156l1.367,0.267l0.562,0.205l0.33,0.268l-0.011,0.19l-0.642,0.333l-1.106,0.207l-1.429-0.076l-0.511-0.062l-0.367,0.269l1.254,0.423l-0.469,0.426l-1.06,0.316l-1.454,0.662l-0.421,0.252l0.218,0.704l-0.313,0.235l-0.909,0.205l-0.31,0.282l-0.529,0.64l-0.276,0.296l-0.241,0.669l-0.274,0.543l-0.323,0.666l0.056,0.416l-0.161,0.554l0.123,0.875l0.136,0.536l0.598,0.366l0.25,0.015l0.257,0.091l0.664,0.014l1.164-0.094l0.276,0.045l0.367,0.29l0.413,0.763l0.813,1.157l0.22,0.668l-0.132,0.91l0.673,0.014l1.874-0.428l1.261-0.033l0.723,0.074l0.535,0.157l1.062,0.311l2.129,0.435l1.896,0.903l0.993,0.933l3.5,0.67l0.644,0.225l0.982,0.403l0.986,0.253l0.553,0.104l0.702-0.091l0.453,0.044l0.828-0.077l1.245,0.163l1.407,0.207l0.401,0.194l-0.297,0.702l-0.142,0.85l0.154,0.283l0.307,0.342l0.07,0.416l-0.115,1.025l-0.309,0.593l0.022,0.208l0.604,0.266l0.481,0.339l0.264,0.354l0.046,0.488l-0.076,0.354l0.97,0.116l0.963,0.47l0.676,0.588l0.392,0.588l0.078,0.162l0.64,0.014l0.726,0.41l0.907,0.601l-0.349-0.66l-0.22-0.279l0.134-0.338l0.573-0.414l0.365,0.176l0.381,0.456l0.262,0.353l0.165-0.354l0.107-0.545l-0.215-0.456l0.541-0.532l0.139-0.546l-0.183-0.517l-0.337-0.458l-0.261-0.754l-0.004-0.548l-0.205-0.593l-0.218-0.43l0.615-0.016l-0.097-0.476l-0.296-0.252l-0.657-0.163l-0.375-0.282l-0.326-0.923l1.252-0.271l0.872-0.241l0.625-0.271l1.758-0.949l0.629-0.302l1.043-0.935l0.434-0.544l0.237-0.665l0.054-0.529l-0.257-1.045l-0.246-0.531l-0.239-0.319l-0.938-0.729l-0.467-0.274l-1.105-0.532l-0.363-0.122l-0.453-0.274l-0.151-0.046l-0.293-0.351l0.08-0.107l0.868-0.522l0.553-0.875l0.293-0.416l0.25-0.092l0.447-0.017l0.295-0.277l-0.106-0.523l-0.18-0.355l-0.316-0.402l-0.048-0.202l0.258-0.357l0.005-0.264l-1.751-0.105l1.084-0.92l0.503-0.704l0.007-0.125l-0.316-0.203l-0.609-0.265l-0.244-0.266l-0.043-0.533l0.305-0.425l0.554-0.315l0.57-0.19l0.827,0.062l1.781,0.374l1.097,0.234l0.753,0.077l1.44,0.013l1.08-0.144l0.86-0.222l0.21-0.047l0.179-0.063l0.589,0.078l0.991,0.407l0.254,0.125l0.754,0.454l0.918,0.375l0.796,0.437l-0.294,0.391l0.406,0.233l1.698,0.496l1.958,0.354l0.725-0.033l0.368-0.203l0.339,0.295l-0.013,0.404l-0.577,0.343l-0.123,0.45l0.438,1.327l0.136,0.722l0.23,0.414l-0.049,0.353l-0.248,0.169l-0.445-0.014l-0.347-0.015l-0.138,0.674l0.375,0.274l1.137-0.415l0.366-0.047l0.781-0.047l0.286,0.015l0.677,0.32l0.378,0.351l0.004,0.259l-0.081,0.123l0.277,0.32l0.516-0.184l0.306-0.046l1.173-0.079l0.636-0.184l0.436-0.383l0.333-0.551l0.326,0.015l0.194,0.122l0.693,0.717l0.042-0.062l0.108-0.764l0.317-0.583l0.475-0.262l0.539-0.385l-0.651-0.505l0.008-0.308l0.272-0.139l0.98-0.094l0.193-0.139l0.512-0.665l0.667,0.37l0.607,0.599l0.785,0.506l0.596,0.797l1.045,0.764l0.264,0.352l-0.344,0.291l0.095,0.335l0.573-0.031l0.365,0.777l0.182,0.183l0.324,0.121l0.743,0.136l0.281,0.258l0.133,0.38l-0.379,0.092l-0.416,0.168l0.411,0.318l0.397,0.227l0.77,0.196l0.279,0.227l0.034,0.424l-0.056,0.076l-0.409,0.106l-0.676-0.029l-0.745-0.12l-0.316,0.061l0.091,0.166l0.273,0.181l0.189,0.241l0.333,0.513l0.411,0.226l0.634,0.029l0.462,0.18l0.838,0.496l0.899,0.435l0.246,0.33l-0.035,0.195l-0.447,0.781l0.508,0.059l0.663-0.166l0.786-0.077l0.79,0.164l0.574,0.194l1.162,0.49l0.981,0.132l1.517,0.295l-0.184,0.253l-0.718,0.21l-0.736,0.21l-0.663,0.046l-0.834,0.24l-0.583,0.402l-0.65,0.225l-1.032,0.061l-0.286,0.075l-0.324,0.268l0.029,0.371l-0.271,0.535l1.175-0.343l0.542-0.09l0.649-0.105l1.201-0.774l1.251-0.478l1.146-0.106l0.662,0.237l0.35,0.341l-0.398,0.446l0.036,0.119l0.307,0.296l0.616-0.224l0.455-0.164l0.655,0.192l1.051,0.487l0.226,0.251l0.022,0.178l-0.299,0.43l-0.05,0.355l-0.406,0.444l1.001,0.929l-0.365,0.37l-0.795,0.282l-1.078,0.621l-0.662,0.281l-1.097,0.046l-0.823,0.119l-1.548,0.077l-0.433,0.413l-0.916,0.795l-0.686,0.427l-0.612,0.294l-0.938,0.222l-1.494,0.172l-1.845,0.127l-1.452-0.07l-2.031-0.084l-0.355,0.03l-1.073,0.075l-1.058-0.012l-1.873-0.099l-0.917-0.027l-1.758,0.106l-0.547,0.206l-0.523,0.294l-0.537,0.585l-0.205,0.554l-0.287,0.335l-0.591,0.19l-1.07,0.104l-0.537,0.147l-1.098,0.555l-0.774,0.54l-0.794,0.612l-0.325,0.363l-0.33,0.233l-0.868,0.843l-0.485,0.566l-0.418,0.276l-0.46,0.58l-0.518,0.968l0.749-0.737l0.375-0.131l0.688-0.479l1.059-0.944l1.097-0.785l2.028-0.948l1.245-0.395l1.797-0.512l1.065-0.235l1.03-0.235l1.473-0.148l0.922,0.056l0.895,0.289l0.509,0.29l0.136,0.189l0.144,0.464l-0.125,0.218l-0.326,0.219l-1.059,0.292l-0.753,0.452l-0.581,0.044l-0.845-0.23l-0.726,0.045l-0.645,0.19l0.279,0.08l1.13,0.229l0.17,0.122l0.256,0.444l0.074,0.095l1.299-0.485l-0.028,0.216l0.479-0.148l0.372,0.162l-0.36,0.229l-0.231,0.256l0.112,0.27l-0.163,0.014l-0.074,0.229l-0.91,0.444l1.216,0.013l0.077,0.188l-0.187,0.282l0.091,0.43l0.118-0.081l0.239,0.134l-0.063,0.134l0.048,0.202l0.351,0.457l0.009,0.147l0.824,0.054l0.154,0.094l0.04-0.067l0.727,0.147l-0.315,0.134l-0.373-0.013l-0.047,0.134l0.525,0.147l0.211,0.241l0.569-0.081l0.135,0.134l0.212-0.014l0.134,0.174l0.418-0.04l-0.075-0.107l0.843,0.067l0.241,0.107l-0.207,0.201l0.242-0.107l0.26,0.027l0.245-0.013l0.696-0.362l0.303-0.081l0.104,0.362l0.377,0.161l0.538-0.121l0.488,0.416l-0.405,0.254l0.089,0.107l0.825,0.027l0.164,0.174l-0.521,0.121l-0.161-0.121l-0.3,0.134l0.118,0.094h-0.515l-0.23-0.04l0.109,0.161l-0.45,0.04l0.056,0.107l-0.443,0.014l-0.128,0.147l-0.45,0.04l-0.368,0.253l-0.09-0.106l-0.706,0.28l-0.046,0.053l-0.529,0.133l-0.119-0.267l-0.274,0.106l-0.163,0.267l-0.188-0.187l-0.068,0.253l-0.218,0.08l-0.094,0.187h-0.513l-0.081-0.08l-0.169-0.053l0.032-0.347l-0.242,0.36l-0.202,0.12l-0.131-0.253l-0.354,0.027l0.043,0.24l-0.233,0.04l0.312,0.08l0.033,0.213l-0.103,0.12l-0.174-0.067l-0.768,0.453l0.127,0.16l-0.235,0.12l-0.194,0.053l0.015,0.213l-0.161-0.12l0.083,0.173l-0.217,0.08l-0.14-0.107l0.096,0.253l-0.222,0.066l-0.146-0.08h-0.148l-0.064,0.133l-0.156-0.106l-0.243,0.227l-0.086,0.292l-0.201-0.226l-0.344,0.133l-0.154-0.187l-0.349-0.479l-0.138,0.24l-0.419-0.866l0.456-0.773l0.284-0.16l0.035-0.12l-0.35,0.12l-0.357,0.267l-0.076-0.106l0.924-0.507l0.125,0.146l0.195-0.093l-0.258-0.107l1.103-0.52l1.109-0.562l0.658-0.361l0.336,0.094l-0.067,0.428l0.179-0.054l0.258,0.281l-0.044-0.201l-0.017-0.174l0.632-0.214l0.73-0.134l0.192,0.067l0.202-0.081l-0.152-0.094l-0.653-0.053l-0.595,0.053l-0.42-0.053l-0.804-0.014l-0.306,0.027l-0.251,0.081l-0.246,0.094l0.033-0.214l1.128-0.563l0.054-0.201l0.252-0.08l-0.052-0.174l-0.523,0.281l0.097-0.134l-0.502-0.51l0.309,0.443l-0.36,0.482l-0.328,0.013l-1.974,0.817l-0.284,0.08l-0.362-0.201l-0.227-0.067l0.23,0.201l-0.788,0.401l-0.219-0.174l-1.019-0.054l-0.124,0.147l-0.38-0.241z M186.193,47.833l-0.713-0.032l-0.922-0.181l-0.882-0.065l-1.25-0.314l-0.973-0.182l-0.604-0.049l-1.083-0.199l0.43-0.335l1.542-0.405l0.385-0.186l0.115-0.673l0.305-0.236l0.831-0.069l0.743,0.184l1.436,0.603l1.287,0.4l0.074,0.285l0.315,0.284l1.094,0.516l-0.288,0.117l-1.263,0.486l-0.578,0.051z M231.09,50.646l-1.319-0.03l-0.449-0.147l-0.232-0.247l-0.173-0.478l0.3-0.43l0.708-0.664l0.662-0.267l1.359-0.168l0.911,0.197l0.79,0.314l-0.021,0.464l-0.039,0.727l-0.362,0.265l-1.025,0.348l-1.108,0.117z"/> - <path id="RU" country:name="Russia" country:shortname="Russia" d="M444.972,79.145l0.47-0.218l0.307-0.093l-0.294-0.024l-0.419,0.061l-0.15-0.135l-0.125,0.184l-0.108-0.012l0.066-0.491l0.177-0.218l0.41,0.009l1.489,0.062l0.417,0.014l0.339-0.075l0.121-0.253l-0.175-0.288l0.246-0.05l-0.068-0.122l-0.068-0.123l0.353-0.096l0.12-0.034l0.051,0.154l0.086,0.052h0.24l0.223,0.12l0.257,0.069l0.514,0.068l0.086,0.103l0.223-0.051h0.445h0.257l0.223-0.017l0.086,0.137l0.103,0.103l0.188,0.034l0.171,0.069l0.018,0.137l0.052,0.12l-0.224,0.12l-0.068,0.154l-0.068,0.206l0.018,0.171l0.034,0.137l0.029,0.038l-2.96,0.101l-2.246-0.115l-0.842-0.006z M717.633,81.109l0.42,0.443l0.429,0.62l0.183,0.457l0.01,0.767l-0.244,0.442l-0.197,0.78l-0.002,0.764l0.29,0.777l0.592,0.849l0.65,1.446l0.899,1.614l1.115,1.679l-1.26-0.677l-0.832-0.39l-0.99-0.056l-0.268,0.088l-0.396,0.204l-0.462,1.045l-0.266,1.101l-0.082,0.579l0.277,0.982l0.183,0.216l0.659,0.908l0.54,0.201l0.463,0.648l-0.314,1.246l-0.664-1.258l-0.866-0.301l-0.224,0.029l-0.415,0.303l-0.311,0.534l-0.643,0.907l-0.422-0.5l-0.19-0.929l0.637-1.146l-0.395-0.884l0.175-0.454l0.502-0.63l-0.131-0.723l-0.196-0.376l-0.27-0.55l-0.062-0.235l0.403-0.302l0.284-0.915l0.075-0.784l0.005-1.326l0.15-1.302l-0.09-0.732l-0.213-0.469l-0.83-0.85l-0.1-0.897l0.114-0.192l0.359-0.722l0.065-0.738l-0.336-0.457l0.172-0.237l0.374-0.03l0.62-0.031l1.023-0.534z M471.158,84.281l-0.002-0.142l-0.165-0.066l-0.082-0.115l-0.164-0.082l0.033-0.099l-0.033-0.23l-0.033-0.164l0.082-0.099l-0.147-0.131l-0.099-0.148l0.132-0.066v-0.165l-0.296-0.164l-0.279-0.263l-0.017-0.164l0.099-0.131l0.131-0.165l0.362-0.017l0.328,0.049l0.197,0.132l0.51,0.016l0.525-0.099l0.444-0.247l0.049-0.065l0.148-0.083h0.296l0.065-0.164l-0.033-0.131l-0.279-0.066l-0.296-0.148l-0.099-0.181l0.082-0.017l0.066-0.049l0.032-0.065l-0.263-0.066l-0.361-0.099l-0.378-0.066l-0.361,0.066l-0.182-0.066l0.066-0.181l0.099-0.197l-0.066-0.148l-0.164-0.099l-0.279-0.082l-0.23-0.066l-0.443-0.213l-0.115-0.23l-0.164-0.263l-0.214-0.017l-0.017-0.099l0.066-0.131l0.099-0.115l-0.132-0.033l-0.181,0.049l-0.082-0.115l-0.132-0.181l-0.345-0.049l0.049-0.147l0.033-0.165l0.099-0.049l0.115-0.082v-0.083h0.114l0.066-0.131l-0.05-0.164l-0.147-0.099l-0.197-0.247l0.131-0.165l0.033-0.164v-0.083l0.065-0.115l-0.049-0.115l-0.147,0.033l-0.165-0.033l-0.147-0.099l-0.099-0.099l-0.279-0.099l-0.132-0.131l-0.542-0.115l-0.247,0.049l-0.099-0.049l-0.131-0.049l-0.23,0.083l-0.147,0.099h-0.165l-0.279,0.016l-0.214,0.197h-0.197l-0.164-0.148l-0.065-0.148l0.017-0.099l0.164-0.099v-0.115l-0.147-0.017l-0.296-0.065l-0.312-0.049l-0.361,0.049l-0.214,0.065l-0.197,0.033l-0.082-0.148l-0.132-0.148l-0.312-0.033l-0.181-0.016l-0.197,0.131l-0.229-0.066l-0.165-0.147l0.061-0.042l0.015-0.117l0.044-0.087l-0.088-0.233l0.015-0.189l-0.131-0.117l0.059-0.087l-0.16-0.043l-0.146-0.102l-0.029-0.16l-0.131-0.058l-0.116-0.102l0.043-0.073l0.059-0.087l-0.073-0.044l-0.087-0.014l-0.131-0.073l-0.146,0.015l-0.204,0.059l0.044-0.102l0.102-0.073l0.073-0.087l-0.029-0.117l0.072-0.131l-0.131-0.087l0.103-0.029l0.087-0.015l0.102-0.073l0.015-0.087l0.029-0.116l0.015-0.087l-0.204-0.058l-0.087-0.073l-0.204-0.087l-0.232-0.073v-0.117l0.015-0.116l-0.37,0.004l-0.081-0.106l0.116-0.058L461.402,72l0.029-0.117h0.131l0.087-0.116l0.059-0.102l0.16-0.058l0.262-0.043l0.175-0.073l-0.059-0.059l-0.175-0.043l-0.043-0.146l-0.015-0.087v-0.073l-0.088-0.073l-0.203-0.087l-0.175-0.233v-0.175l0.175-0.131l-0.029-0.16l-0.073-0.189l-0.131-0.437l-0.029-0.16l0.088-0.16l0.204-0.131l0.319-0.131l0.219-0.204l0.175-0.277l0.058-0.131l0.088-0.043h0.116h0.189l0.175-0.044l0.043-0.174l-0.16-0.131l-0.145-0.053l-0.089-0.13l-0.17-0.038l0.1-0.253l0.339-0.038l0.153,0.165l0.229,0.063l0.188-0.088l-0.094-0.139l0.301-0.154l0.485,0.199l0.296-0.062l0.312-0.338l0.311-0.185l0.75,0.106l0.781,0.275l0.439,0l0.363-0.154l-0.386-0.399l-0.59-0.323l-0.393-0.03l-1.204,0.08l-0.616-0.091l-0.271-0.108l-0.299-0.309l0.258-0.434l-0.065-0.201l-0.199,0.044l0.174-0.285l1.946-1.145l1.983-1.195l1.385-0.758l0.591-0.536l0.43-0.536l0.105-0.409l-0.161-0.346l-0.436-0.392l-0.703-0.265l-1.357-0.499l-0.439-0.33l0.327-0.191l0.542-0.415l0.057-0.254l-0.151-0.253l-1.286-1.395l-0.37-0.509l0.029-0.37l0.187-0.403l0.44-0.535l0.196-0.356l-0.772-1.195l-1.402-1.394l0.328-0.296l1.303-0.777l0.421-0.364l-0.543-0.392l-0.964-0.506l-0.872-0.194l-0.563-0.212l-0.116-0.529l0.258-0.465l0.024-0.283l0.689-0.303l1.013-0.672l1.023-0.49l0.77-0.121l0.824-0.021l0.514-0.204l0.404-0.288l0.617-0.051l1.002-0.254l0.643-0.237l0.01,0.151l0.255,0.386l0.358,0.284l0.543,0.2l0.919,0.082l0.602,0.1l0.078,0.602l0.695-0.319l0.421,0.049l1.083,0.048l0.875,0.015l0.522,0.032l1.116-0.002l1.293,0.281l2.728,0.512l0.984,0.364l1.595,0.86l0.583,0.214l1.48,0.246l1.296,0.212l2.018,0.623l0.328,0.279l-0.051,0.444l0.147,0.295l0.426,0.294l0.104,0.294l-0.24,0.344l-0.69,0.491l-1.092,0.54l-0.816,0.262l-1.75,0.36l-0.907,0.083l-1.631-0.013l-1.391-0.192l-2.038-0.175l-1.63-0.192l-1.342-0.339l-2.256-0.485l-1.114-0.112l-0.476-0.048l-0.621-0.473l-0.371-0.163l-0.771-0.13l-0.943,0.117l0.307,0.163l0.149,0.065l0.73,0.538l0.482,0.146l1.109,0.601l0.832,0.291l0.921,0.161l0.634,0.242l0.405,0.453l-0.002,0.405l-0.276,0.291l-0.684,0.195l0.086,0.113l0.208,0.531l0.771,0.943l0.093,0.494l0.155,0.207l0.438,0.174l1.203,0.078l0.872,0.125l0.499,0.619l0.401,0.095l1.26,0.077l0.575,0.126l0.364,0.079l0.402-0.128l0.785-0.097l0.243-0.302l-0.001-0.318l-0.387-0.397l-0.471-0.079l-0.455,0.096l-0.447-0.031l-0.589-0.206l-0.952-0.795l0.701-0.674l0.484-0.001l1.116,0.479l1.441,0.333l2.09,0.427l0.952,0.078l0.834-0.146l0.723,0.174l0.261-0.224l0.05-0.415l-0.214-0.239l-0.858-0.656l-0.348-0.628l0.285-0.323l0.19-0.049l1.432-0.423l1.495-0.359l0.599-0.244l1.133-0.717l0.172-0.049l0.462,0.064l1.829,0.29l1.41,0.533l0.341-0.001l0.052-0.065l0.154-0.503l0.581-0.767l-0.048-0.653l-0.317-0.408l-0.847-0.163l-0.3-0.229l1.139-1.005l0.101-0.247l-0.205-0.594l-0.771-0.512l0.069-0.315l0.353-0.051l1.458,0.23l2.025-0.12l0.631,0.132l0.664,0.611l0.616,0.445l0.433,0.461l-1.045,0.051l-1.559,0.085l-0.822,0.215l-0.492,0.51l0.191,0.18l0.952,0.293l0.732,0.555l0.804,0.194l0.723,0.097l1.268-0.133l1.33-0.084l0.301-0.164l0.257-0.491l0.291-0.591l0.284-0.412l1.232-0.2l1.223-0.414l0.988-0.216l1.924-0.483l1.429-0.251l1.537-0.318l0.921-0.3l0.205,0.464l0.278,0.083l0.571-0.117l0.487-0.266l0.148-0.465l0.386-0.167l0.718-0.135l0.859,0.065l-0.18,0.399l-0.058,0.597l-0.858,0.084l-0.178,0.149l0.002,0.215l0.687,0.197l0.507-0.083l1.169-0.167l0.436-0.001l0.161,0.198l0.23,0.049l0.278-0.133l0.264-0.216l0.29-0.431l0.464-0.183l0.861-0.118l1.049-0.068l0.768,0.032l1.075,0.23l0.755-0.018l0.36-0.083l0.963-0.467l1-0.285l0.803-0.052l0.952,0.182l0.326,0.166l-0.631,0.45l0.129,0.232l0.217,0.099l0.632,0.131l0.579-0.018l0.288-0.232l0.074-0.398l0.342-0.084l0.962,0.065l0.543-0.184l0.395-0.316l0.115-0.417l-1.37-1.033l0.405-0.168l0.66-0.37l0.403-0.068l0.609,0.016l2.171,0.063l1.272,0.199l1.241,0.149l1.135,0.199l2.111,0.515l1.071,0.098l1.712,0.414l1.02,0.248l1.305,0.53l1.455,0.611l0.864,0.379l0.376,0.049l0.229-0.1l1.145-1.047l0.236-0.3l-0.927,0.035l-0.4-0.049l-0.564-0.232l-0.365-0.433l0.027-0.652l-0.727-0.283l-1.987-0.147l-0.19-0.268l0.064-0.168l0.305-0.303l0.693-0.255l0.236-0.153l0.085-0.187l-0.052-0.833l-0.251-0.238l-1.135-0.066l-0.232-0.29l0.328-0.532l0.359-0.241l0.391-0.035l1.482-0.416l1.098-0.485l0.521-0.416l0.581-0.608l0.544-1.22l0.637-0.421l0.374,0.069l1.562,0.155l1.613-0.125l1.605-0.091l0.695,0.069l1.066-0.055l0.574,0.122l0.309,0.279l-0.018,0.332l-0.423,0.836l-0.348,0.348l-1.334,0.833l-0.223,0.345l0.752,0.342l0.931,0.667l0.277,0.342l0.21,0.818l-0.174,0.222l-0.575,0.375l0.254,1.179l-0.058,1.305l0.263,0.583l0.45,0.381l1.027,0.264l0.19,0.166l-0.001,0.133l-0.485,0.481l-0.417,0.826l-0.333,0.33l-0.784,0.462l-1.232,0.625l-0.63,0.198l-0.55,0.263l0.321,0.522l-0.433,0.115L558,52.195l-1.599-0.372l-0.731-0.08l-0.97,0.034l-0.601,0.115l0.195,0.31l0.583,0.276l0.738,0.21l1.569,0.208l1.133,0.079l0.613-0.05l1.188,0.144l0.922-0.034l0.472-0.358l0.303-0.358l1.352-0.328l1.166-0.492l0.268-0.278l0.386-0.606l0.818-0.313l0.864-0.626l0.064-0.362l-0.225-0.561l-0.609-0.545l0.244-0.548l0.237-0.1l0.677-0.151l1.38-0.152l1.757-0.003l0.74,0.231l0.842,0.463l0.151,0.778l-0.34,1.023l0.302,0.279l0.92,0.212l1.298,0.047l0.864-0.149l0.129-0.296l-0.514-0.18l-0.797-0.18l-0.571,0.034l-0.457-0.098l0.068-0.379l1.03-0.382l0.065-0.249l-0.218-0.148l-0.166-0.331l-0.441-0.763l-0.511-0.266l-0.836-0.098l-1.093-0.231l-0.801-0.116l-1.288-0.165l-0.91,0.186l-0.638,0.101l-1.297-0.181l-0.896,0.019l-0.015-0.267l-0.564-1.071l0.305-0.657l0.736-0.697l0.282-0.46l-0.134-0.221l-1.092-1.042l-0.949-0.514l-0.12-0.189l0.833-0.554l1.213-0.106l0.998-0.262l0.744-0.348l0.172-0.226l0.169-0.644l-0.13-0.663l0.23,0.069l0.64,0.051l0.466,0.086l0.108,0.471l-0.186,0.54l-0.636,0.608l-0.167,0.554l0.14,0.448l0.373,0.274l0.485,0.274l1.384,0.134l1.574,0.169l1.632,0.083l0.819,0.409l0.321,0.017l0.799-0.036l-0.527-0.89l-0.521-0.274l-1.893-0.1l-0.931-0.067l-0.576-0.154l-0.609-0.448l0.275-0.329l1.374-0.054l0.444,0.172l1.145,0.084l0.747-0.157l-0.09-0.728l0.408-0.088l0.84-0.105l1.278-0.02l1.067,0.207l1.413,0.379l1.088,0.535l1.326,0.343l0.547,0.085l1.822,0.014l0.727-0.174l0.138,0.345l-0.781,0.38l-0.696,0.259l-0.248,0.771l-0.129,0.972l0.333,0.136l0.68-0.785l0.387-0.292l0.285,0.051l0.604,0.528l-0.088,0.749l0.743-0.205l0.681-0.273l-0.044-0.306l-0.191-0.119l-0.147-0.358l-0.748-0.821l0.188-0.223l0.686-0.759l-0.797-0.448l-0.772-0.258l-0.93-0.241l-0.257-0.382l-0.655-0.051l-0.979-0.242l-1.34-0.207l-0.307-0.296l0.062-0.577l-0.096-0.386l-0.811-0.667l0.081-0.247l0.266-0.16l0.484-0.125l2.31-0.11l2.54-0.022l2.125-0.128l1.421-0.162l0.475,0.317l0.382,0.052l0.844-0.267l1.056-0.286l1.413-0.109l0.589,0.194l-0.957,0.338l-0.451,0.407l1.737-0.233l0.521-0.107l0.955-0.374l0.27-0.284l-0.334-0.444l-0.326-0.177l-0.925-0.266l-0.365-0.303l-0.002-0.232l0.324-0.539l1.176-0.397l0.966-0.22l3.028-0.903l0.889-0.094l0.248-0.036l0.522-0.076l1.899-0.096l1.663-0.114l2.302-0.244l2.048-0.263l1.595-0.43l0.855-0.243l1.763,0.034l1.065-0.002l0.383,0.185l-0.351,0.409l1.504,0.108l1.018-0.039l1.261-0.188l1.345-0.225l0.95-0.039l0.982,0.166l0.687,0.073l0.693-0.206l0.12-0.335l-0.133-0.167l0.466-0.337l0.942-0.077l0.939,0.036l1.243-0.377l-0.618-0.506l0.122-0.34l1.165-0.438l1.554-0.383l2.23-0.406l1.229-0.077l0.993,0.056l1.486-0.003l0.86,0.265l0.045,0.266l-1.528,0.401l-0.66,0.342l0.488,0.15l1.83-0.117l1.588,0.148l2.039-0.079l0.177,0.113l-0.375,0.283l-1.187,0.453l-0.296,0.3l1.971-0.004l0.833-0.02l0.234,0.093l1.052-0.545l1.366-0.002l1.771-0.097l0.631,0.13l1.35-0.021l1.954,0.165l1.4,0.259l1.181,0.427l0.52,0.445l0.726-0.001l0.854-0.076l0.422,0.5l-1.354,0.832l0.241,0.128l0.896,0.365l-2.329,0.859l-1.035,0.235l-1.166,0.11l-3.404,1.061l-3.018,0.965l-0.793,0.285l-2.388,0.375l-2.35,0.586l-2.065,1.126l0.715,0.017l1.081-0.247l0.922-0.458l1.663-0.161l1.231-0.02l2.101-0.268l1.879-0.286l0.879-0.107l1.004-0.284l-0.094-0.389l-0.492-0.123l-0.034-0.071l0.281-0.249l0.581-0.214l0.873,0.211l0.603,0.389l0.621,0.052l0.593,0.193l0.737,0.052l0.853-0.055l1.155-0.268l0.499,0.07l0.192,0.3l0.009,0.512l0.522,0.404l1.422-0.778l1.66-0.021l1.506-0.145l2.354,0.014l1.919,0.155l0.854,0.034l1.204,0.033l-0.271,0.74l0.354,0.333l2.043,0.154l0.848,0.121l0.698,0.069l1.035,0.103l2.49-0.145l1.209-0.02l1.42,0.348l1.405-0.932l-0.161-0.352l-0.038-0.229l-0.034-0.105l1.806-0.48l0.521-0.019l0.802,0.104l1.148,0.298l0.851,0.281l1.711,0.032l1.354-0.073l1.384,0.033l1.323,0.431l0.409,0.181l0.058,0.386l-0.52,0.088l-0.268,0.036l-1.905,0.406l-2.438,0.737l-0.233,0.227l0.253,0.069l1.033,0.067l0.957,0.016l0.659,0.155l0.659,0.293l1.014,0.396l0.583,0.172l0.78,0.481l1.27,0.805l1.814,0.801l1.351,0.305l0.612-0.018l0.795-0.394l0.843-0.72l1.093-1.051l0.601-0.329l0.29,0.017l0.236,0.465l0.772,0.308l1.346,0.29l1.105,0.135l0.848-0.087l1.973-0.468l0.778-0.07l0.813,0.067l1.196,0.239l1.921,0.734l0.315-0.052l0.186-0.069l0.491-0.258l0.221-0.258l-0.137-0.051l0.013-0.189l0.726-0.312l0.509-0.018l0.5,0.257l0.575,0.188l1.302,0.032l0.181-0.5l-0.194-0.466l0.15-0.363l0.093-0.521l-1.131,0.159l-0.643,0.001l-0.179-0.104l0.442-0.296l0.318-0.087l0.986-0.089l1.021-0.02l0.832-0.141l1.566-0.648l0.254,0l1.76,0.241l1.561,0.137l2.036,0.188l0.997,0.068l0.654,0.103l2.307,0.065l-1.732,0.628l0.865,0.051l1.011-0.089l0.335,0.138l-0.305,0.381l-0.926,0.192l-0.846,0.261l-0.177,0.293l0.664,0.033l0.52-0.122l0.916-0.14l0.978-0.33l1.62-0.799l2.766,0.012l1.196,0.067l0.903,0.172l0.946,0.137l0.205,0.19l0.221,0.104l-2.247,0.59l0.559,0.137l1.674,0.289l2.174,0.202l0.946,0.204l0.801,0.375l0.367,0.427l0.564,0.357l0.522,0.152l1.459-0.037l1.364-0.105l1.138-0.139l2.518-0.329l2.208-0.107l3.008,0.131l1.515,0.134l0.734,0.118l1.168,0.424l0.655,0.169l0.525,0.338l0.361,0.39l-0.123,0.491l-0.286,0.521l0.509,0.25l0.764,0.065l0.835,0.015l0.643,0.083l-0.017,0.685l0.419,0.416l0.686-0.168l0.545-0.435l1.211-0.387l0.348-0.067l0.35,0.049l1.696-0.02l1.521-0.288l0.736,0.032l0.588,0.434l0.707,0.116l1.541,0.014l2.176,0.062l0.869-0.118l1.378-0.504l0.406,0.2l0.93,0.533l0.396,0.216l1.095,0.265l0.875,0.332l0.282,0.398l0.612,0.148l1.556-0.136l1.653-0.319l0.16-0.25l-0.248-0.333l-0.805-0.833l-0.833-0.115l0.4-0.336l0.479-0.571l1.89,0.098l1.214,0.082l1.135,0.065l1.221,0.166l0.222,0.318l1.396-0.153l2.084-0.054l2.304,0.013l1.292,0.148l0.786,0.199l1.185,0.199l1.391,0.098l0.751,0.182l1.302,0.332l0.747,0.065l0.703,0.182l1.145,0.505v2.126v2.222v2.222v1.292v0.157v0.576v0.219l-1.083,0.371l-0.651,0.03l-0.645,0.37l-0.56,0.065l-1.044,0.065l-0.355-0.079l-0.928-0.052l-0.118-0.343l-0.271-0.211l-0.501,0.027l0.241-0.185l-0.938,0.324l-0.846,0.02l-0.337-0.211l-0.478-0.079l0.424,0.501l-0.569,0.29l0.32,0.103l0.942,0.205l0.634-0.36l0.395,0.041l0.335,0.079v0.477l0.248,0.206l0.76,0.269l1.059-0.228l-0.439,0.322l0.741-0.243l0.065,0.336l0.247,0.206l0.187,0.363l0.068,0.189l-0.722,0.522l0.593-0.064l0.349,0.172l0.473,0.503l0.501,0.157l0.145,0.251l-0.162,0.456l0.792-0.111l-0.125,0.393l0.023,0.25l-0.43,0.299l-0.691,0.205l-0.635-0.046l-0.448-0.14l-1.243-0.154l-0.889-0.077l-0.347-0.14l0.123-0.267l-0.493-0.046l-0.304,0.032l-0.559,0.55l-0.069,0.11l-3.06,0.913l-1.155,0.174l-0.245,0l-0.43,0.203l-0.219,0.188l-0.719,0.22l-0.991,0.033l-0.308,0.11l-0.48,0.405l-0.462,0.203l-0.946,0.033l-0.854,0.622l-0.24,0.279l-1.67,0.452l-0.392,0.449l-1.229,0.25l-0.406,0.14l-0.151,0.293l0.01,0.292l-0.473,0.292l-0.406,0.016l-0.586-0.306l-0.183-0.262l-0.169-0.37l-0.67-0.308l-1.074-0.044l-1.021,0.048l-1.159,0.172l-1.301,0.188l-0.523,0.217l-1.333,0.756l-0.536,0.277l-0.184-0.138l0.575-1.293l-0.55,0.094l-0.392-0.097l-0.811,0.531l-0.67,0.186l-0.401,0.155l-0.114,0.506l-0.66,0.154l-0.317-0.168l-0.253-0.49l-0.483-0.261l-1.024,0.636l0.261-0.204l-0.557,0.062l-0.283,0.092l-0.628,0.522l-0.141,0.261l0.126,0.229l0.344,0.152l-0.932,0.521l-0.182,0.199l0.342,0.167l-0.647,0.352l-0.88,0.55l-0.626,0.503l-0.298,0.35l-0.01,0.531l0.421,0.317l0.477,0.09l1.382-0.048l0.562,0.166l0.11,0.167l-0.436,0.394l-0.752,0.455l-0.181,0.302l0.224,0.512l0.292,0.452l0.786,0.089l0.165,0.391l-0.014,0.616l-0.349,0.361l-0.528,0.061l-0.481-0.209l-0.017-0.21l0.388-0.527l-0.444-0.014l-0.454,0.242l-1.014,0.843l-0.56,0.675l-0.237,0.599l0.321,0.672l0.647,0.311l0.154,0.237l-0.294,0.387l-0.688,0.313l-0.956,0.031l-0.664-0.088l-0.344,0.001l-0.619,0.179l-0.837,0.476l-0.214,0.149l-0.525,0.504l-0.137,0.341l0.111,0.281l0.492,0.398l0.038,0.221l-0.056,0.133l-0.679,0.238l-0.604,0.016L753.44,82.4l-0.727,0.296l-0.065,0.251l0.067,0.28l-0.161,0.854l-0.293,0.412l-0.8,0.78l-1.53,0.971l-0.854,0.5l-0.285,0.103l-0.295-0.614l-0.198-0.821l-0.25-0.69l-0.064-0.794l-0.351-0.75l-0.305-0.383l-0.214-0.915l-0.514-1.36l-0.008-0.578l-0.154-0.563l-0.017-0.327l-0.105-0.193l-0.262-0.817l-0.026-0.792l0.116-0.808l0.271-1.396l0.167-0.226l1.185-0.86l0.716-0.424l0.57-0.695l0.14-0.227l-0.085-0.318l-0.139-0.166l1.632-0.367l1.001-0.305l0.811-0.32l1.729-0.884l0.641-0.412l0.431-0.428l0.14-0.335l1.784-0.889l0.872-0.445l1.535-0.861l0.368-0.293l0.26-0.433l1.252-0.435l2.106-0.514l0.257-0.434l0.773-0.528l0.086-0.233l-0.568-0.216l0.814-0.904l-0.036-0.483l0.183-0.391l0.598-0.204l1.729-0.082l0.513-0.063l-0.485-0.328l-2.065-0.215l-0.71,0.095l-1.062,0.174l-0.777,0.189l0.042,0.328l-0.664,0.923l0.125,0.202l-0.04,0.14l-0.662,0.11l-0.479,0.11l-1.555,0.718l-1.979,1.042l-1.169,0.342l-0.249-0.062l0.156-0.325l0.352-0.465l-0.933-0.076l-0.16-0.263l0.252-0.451l0.442-0.467l0.207-0.328l-0.069-0.202l-0.339-0.031l-1.136,0.454l-0.496,0.032l-0.277-0.358l-0.589-0.17l-1.606,0.144l-1.312,0.111l-0.956,0.08l-0.606,0.157l-0.894,0.359l-0.093,0.436l0.082,0.186l-1.262,0.53l-0.408,0.233l0.149,0.495l-1.294,0.357l-1.019,0.434l-0.84,0.479l-0.496,0.461l-0.332,0.46l0.004,0.383l0.527,0.213l1.269,0.043l0.278,0.275l0.062,0.122l-1.152,0.139l-1.028,0.262l-1.045-0.059l-0.698-0.136l-0.382,0.031l-0.311,0.107l-0.721,0.398l-0.695-0.35l-1.112,0.383l-0.747,0.139l-0.487-0.09l-0.284-0.137l0.108-0.29l0.748-0.124l0.868-0.124l0.164-0.046l-0.741-0.64L736.444,68l-1.06,0.017l-0.854,0.155l-0.353-0.061l-0.868-0.458l-0.775-0.029l-0.745,0.047l-0.704,0.246l0.042,0.398l-0.26,0.229l-0.477,0.215l-0.695-0.243l-0.408-0.122l-1.26,0.063l-0.784,0.093l-0.651-0.075l-0.887-0.136l-0.563,0.078l-0.067,0.122l-0.147,0.474l-0.677,0.017l-0.311-0.137l-0.038-0.382l-0.203-0.259l-1.241,0.094l-1.014-0.059l-1.257,0.033l-1.158,0.063l-0.836-0.029l-0.18,0.016l-1.085,0.292l-0.964,0.444l-0.74,0.474l-0.536,0.504l-0.789,0.245l-0.904,0.336l-0.194,0.152l-1.047,1.17l-1.634,0.684l-0.949,0.471l-1.157,0.711l-1.653,1.253l-0.828,0.572l-1.573,0.873l-0.893,0.376l-1.889,0.871l-0.632,0.388l-0.203,0.298l0.018,0.357l0.428,0.281l0.485,0.043l0.918,0.013l1.046-0.15l0.656,0.043l-0.329,1.261l0.016,0.415l0.303,0.103l0.63-0.09l0.601-0.371l0.761,0.117l-0.127,0.148L705.293,81l-0.112,0.222l0.373,0.073l1.645-0.018l0.566-0.238l0.39-0.519l0.017-0.638l0.763,0.014l0.647-0.001l0.726,0.014l0.951,0.265l0.658,0.354l0.486,0.591l0.847,0.575l0.426,0.176l0.506,0.324l-0.07,0.148l-0.581,0.355l0.453,0.221l0.13,0.309l-0.336,0.723l0.491,0.117l0.215,0.235l-0.291,0.515l-0.348,0.397l-0.532,0.559l-0.724,1.364l-0.181,0.688l0.057,0.219l0.24,0.701l-0.188,0.917l-0.098,0.741l-0.403,1.408l-0.146,0.493l-1.928,1.538l-0.371,0.435l-0.217,0.65l-0.587,0.42l-0.741,0.579l-0.241,0.361l-0.574,0.981l-0.587,0.606l-0.941,0.778l-1.784,1.512l-0.464,0.474l-0.235,0.458l-0.323,0.33l-0.758,0.388l-0.618,0.416l-0.574,0.702l-0.431,0.458l-0.875,0.673l-0.955,0.487l-1.838,0.475l-0.798,0.244l-0.278-0.427l-0.519-0.085l-0.243,0.043l-0.337-0.185l-0.337-0.513l-0.663,0.272l-0.464,0.101l0.424-0.586l-0.624,0.173l-0.506,0.486l-0.649,0.543l-1.326,1.001l-0.072,0.049l-0.167-0.393l-0.298-0.439l0.111-0.058l1.252-0.462l0.511-0.43l0.156-0.329l-0.112-0.299l0.097-0.128l0.025-0.385l0.006-0.613l-0.062-0.656l-0.332-0.897l0.048-0.557l1.664-0.982l0.396,0.041l0.685,0.24l0.679,0.225l0.547,0.098l0.47-0.347l0.551-0.69l0.329-0.432l0.627-1.08l0.538-1.066l0.278-0.893l0.291-0.707l0.66-0.393l0.566-0.407l-0.017-0.504l-0.116-0.389l-0.064-0.259l-0.246-0.114l-0.902,0.034l-1.181,0.208l-1.357,0.31l-0.953,0.308l-0.604,0.22l-1.657,0.052l-0.649,0.018l-0.68,0.033l-0.261-0.446l-0.44-1.283l-0.297-0.866l-0.205-0.144l-2.659-0.839l-1.523-0.253l-1.247-0.341l-0.507-0.2l-0.436-0.389l-0.927-1.903l-0.94-1.588l-1.087-2.384l-0.742-0.952l-0.763-0.467l-0.539-0.026l-1.386,0.125l-0.683-0.188l-1.037-0.481l-1.148-0.215l-0.917,0.049l-1.203,0.109l-0.836,0.123l-1.854,0.143l-0.602,0.136l-0.478,0.165l-1.193,0.787l-0.375,0.282l-0.119,0.25l0.822-0.078l0.558,0.026l0.465,0.306l0.107,0.249l-0.167,0.794l-1.371,0.608l-0.599,0.545l-0.667,0.779l-0.416,0.543l-0.422,0.426l-0.103,0.249l0.062,0.146l0.35,0.348l0.056,0.306l-0.123,0.233l-0.779,0.339l-2.44,0.752l-0.438,0.089l-0.343,0.016l-1.126-0.574l-0.452-0.172l-0.046-0.018l-0.431-0.168l-0.622,0.018l-1.228,0.297l-0.86-0.169l-0.34-0.129l-0.751-0.506l-0.74-0.156l-0.609,0.047l-0.333,0.002l-1.165,0.487l-0.755,0.498l-0.447,0.394l-0.604,0.264l-0.526,0.163l-1.147,0.136l-0.867,0.106l-0.532,0.075l-1.018,0.063l-1.602,0.11l-0.739-0.039l-0.984-0.082l-0.905-0.241l-1.318-0.254l-0.812-0.373l-1.132-0.313l-0.623-0.331l-1.333-0.75l-0.769-0.229l-1.423-0.022l-1.172-0.037l-0.796,0.077l-2.48,0.538l-0.673-0.113l-1.643-0.531l-0.421-0.333l-0.408-0.451l-0.182-0.481l-0.004-0.541l-0.145-0.204l-0.767-0.143l-0.989-0.317l-0.702-0.231l-1.748-0.328l-1.036-0.185l-1.028-0.098l-0.84-0.201l-1.269,0.96l-0.905,0.839l-0.098,0.293l0.409,0.86l0.396,0.304l0.116,0.204l-0.163,0.526l-0.744,0.572l-0.31,0.162l-0.755,0.28l-0.562,0.018l-0.576-0.186l-0.312-0.114l-0.875-0.068l-0.85,0.004l-0.719-0.083l-1.458,0.008l-0.699-0.113l-0.393-0.406l-0.694-0.755l-0.831-0.083l-1.842-0.122l-0.932-0.156l-0.953-0.097l-0.84,0.18l-1.512,0.476l-1.143,0.341l-0.787,0.398l-0.971,0.692l-0.017,0.012l-0.727,0.381l-0.603,0.148l-1.387,0.08l-0.599,0.207l-0.799,0.425l-0.154,0.044l-0.244,0.074l-0.569,0.003l-0.228,0.014l-0.064-0.145h-0.589l-0.294-0.478l-0.441-0.331l0.073-0.331l-0.625,0.184l-0.478,0.368l-0.993-0.074l-0.882-0.073l-0.662-0.699l-0.588-0.552l-0.956-0.147l-0.331-0.625l-0.772-0.588l-0.698-0.441l-0.993,0.037l-0.771,0.221l-0.993,0.221h-0.992h-0.589l-0.184-0.184l-0.258-0.257h-0.478v-0.368l-0.367-0.331h-0.92l-0.367,0.515l-0.331,0.257l-0.515,0.257l-1.104-1.434l-0.846-0.882l-1.69-2.133l-1.066-1.029l-1.287-0.772l-0.809-0.294l-1.104-0.588l0.11-0.368l0.515-0.11v-0.441l-0.809,0.074l-0.515,0.22l-0.772,0.221l-0.956,0.515l-1.103,0.257l-0.772,0.441l-0.294,0.294l-0.552-0.184l-0.441-0.037l-0.771,0.073l-0.441,0.11l-0.331-0.184l0.331-0.441l0.441-0.184l0.146-0.294h-0.367l-0.441,0.221l-0.478-0.11l-0.405-0.294l-0.478-0.037l-0.184,0.147l-0.147,0.147l-0.367-0.221l-0.295-0.368l-0.294-0.11l-0.331,0.221l-0.367-0.074l-0.368,0.147l-0.44-0.11l-0.295,0.147l-0.478-0.074l-0.184-0.257l0.33-0.037l-0.073-0.331l0.147-0.257l0.11-0.331l-0.515-0.22l-0.147-0.221l0.037-0.331l-0.368-0.404l-0.882,0.037l-0.625,0.11l-0.772-0.257l-0.515-0.11l-0.919-0.147l-0.735,0.037l-0.11,0.221l-0.589,0.184l-0.515,0.037v0.294l-0.367,0.368l-0.625,0.074l-1.876,0.073l-2.021,0.405l-1.177,0.037l-0.625,0.331l-0.221,0.331l-0.331-0.073l-0.588,0.073l-1.545,0.11l-0.735,0.11l-1.029,0.037l-1.396,0.405l-0.368,0.184h-0.772h-0.515L537.304,80l-0.33,0.074l-0.185,0.515l0.074,0.441l0.294,0.221l-0.294,0.074v0.331l1.065,0.11l0.956,0.294l-0.11,0.257l-0.515,0.073l-1.103-0.147l-0.698,0.184l-0.662,0.515l0.146,0.257l0.441,0.478l-0.331,0.294l-0.588,0.147l-0.735,0.368l-0.467,0.067l0.164,0.274h0.239l0.377,0.137l-0.068,0.171l0.377,0.137l0.651,0.069l0.274,0.308l1.165,0.171l0.24,0.24l-0.138,0.686l-0.137,0.309l-1.577,0.411l-0.959-0.034l-0.343-0.343h-0.24l-0.171,0.309l-0.651,0.343l-0.411-0.171l-0.754-0.137l-0.926-0.309l-0.274-0.548l-0.754-0.103l-1.062,0.103l-0.137,0.412l-0.617,0.068l-0.651-0.411l-0.65-0.035l-0.823-0.068l-0.514,0.377l-0.377,0.343l-0.274,0.274l-0.686,0.171l-0.411-0.24l-0.686-0.137l-0.582-0.548l-0.72-0.068l0.034,0.24l0.205,0.48l-0.239,0.274l-0.274-0.137l-0.068-0.583l-0.411-0.274l-0.789-0.343l-0.582-0.206v-0.343l-0.96-0.171l-0.617,0.069l-0.788-0.035l-0.411-0.514l-0.411-0.069l-0.617,0.24l-0.273,0.137l-0.651,0.137l-0.309-0.274h-0.479l-0.651-0.069l-0.515,0.309l-0.548,0.343l-0.788,0.377l-0.549,0.068l-0.514,0.171l-0.309,0.309l-0.172,0.24L509.58,87.5l-0.479,0.206l0.068,0.445l0.171,0.411l-0.068,0.446l-0.411,0.24h-0.651l-0.514-0.411l-0.48-0.548l-0.514-0.24l-0.411,0.069l-0.103,0.308l-0.343,0.549l-0.823,0.137l-0.205,1.303l0.343,0.171l0.239,0.274l-0.239,0.206l-0.446,0.274l-0.65,1.165l1.37,0.343l0.138,0.377l-0.068,0.309l0.514,0.514l0.103-0.343l0.583,0.206l0.343-0.034l0.514,0.034l0.515,0.445l0.479,0.206l0.343,0.514l0.96,1.131l-0.138,0.103l-0.445-0.103l-0.309-0.103l-0.343,0.103l0.068,0.308l0.857,0.377l0.616,0.19l-0.167,0.2l-0.399,0.28l-0.38,0.12h-0.12v0.14v0.22l-0.14,0.08l-0.3-0.2l-0.34,0.2l-0.399,0.26l-0.64,0.12l-0.319,0.08l-0.26-0.08l-0.181-0.08l-0.1,0.04l-0.06,0.16l0.12,0.26l-0.221,0.2l-0.18,0.3l-0.18,0.319l-0.319,0.42l-0.18,0.28l-0.32,0.16l-0.34,0.24l-0.14,0.32l0.08,0.2l0.34,0.2l0.319,0.04l0.18,0.3l0.24,0.04l0.239,0.34l0.28,0.419l-0.06,0.38l-0.101,0.2l0.061,0.16l0.1-0.2l0.1-0.34l0.12-0.22l0.16-0.02l-0.141,0.439l-0.22,0.36l0.061,0.4l0.12,0.1l-0.16,0.2l-0.04,0.4l0.38,0.24l0.119,0.1l0.12,0.52l0.28,0.06l0.359,0.42l0.2,0.28l0.439,0.419l0.18,0.36l0.359,0.06l0.047,0.146l-0.292,0.449l-0.496,0.284l-0.283,0.094l-0.308,0.331l-0.165,0.213l-0.379,0.047l-0.449-0.142l-0.591-0.094v-0.308l-0.283-0.284h-0.118l-0.095-0.118l-0.473-0.284l-0.142-0.189H504.5l-0.213,0.047L504.264,107l-0.229,0.023l-0.126-0.189l-0.236-0.071l-0.236,0.023l-0.284-0.047l-0.26-0.094l-0.284-0.166l-0.354-0.284l0.118-0.307l0.118-0.189l-0.118-0.142l-0.354-0.024h-0.378l-0.213-0.166l-0.189-0.118h-0.212l-0.143-0.094l-0.236-0.118h-0.118l-0.095,0.071l-0.142,0.166l-0.188-0.142l-0.261-0.071h-0.354l-0.213,0.071l-0.094,0.095l-0.166,0.166h-0.283l-0.261,0.118l-0.212-0.071l-0.261-0.118l0.048-0.118l0.142-0.118l-0.308-0.119l-0.236-0.118l-0.354-0.071l-0.52-0.118l-0.284-0.213l-0.095-0.142l-0.354-0.166l-0.283,0.047h-0.189l-0.401-0.166h-0.544l-0.426,0.095h-0.307l-0.355-0.047l-0.307-0.071l-0.261-0.095l-0.212-0.166h-0.213h-0.331l-0.189-0.047l-0.188-0.094l-0.284-0.142l-0.283-0.095l-0.449-0.023l-0.402-0.023l-0.07-0.047l-0.284-0.047l-0.26,0.166l-0.112,0.309l-1.421-1.012l-1.188-0.842l-0.817-0.385l-0.62-0.084l-0.373-0.157l-0.509-0.5l-0.236-0.057l-0.338,0.159l-0.329-0.042l-0.347-0.515l-0.795-0.674l0.595-0.188l0.519-0.001l0.445-0.073l0.1-0.519l0.359-0.476L485,97.85l0.526-0.03l0.516-0.131l-0.432-0.532l-0.654-0.273l-0.474-0.36l0.243-0.116l0.367-0.03l0.82-0.117l0.715-0.348l1.244-0.436l-0.196-0.375l-0.076-0.058l-0.799,0.088l-1.312,0.175l0.012-0.126l0.021-0.112v-0.224l0.09-0.514l0.224-0.089l0.357-0.022l0.38-0.134l0.223-0.179l0.022-0.179h0.269l0.736-0.045l0.805,0.157l0.335-0.134v-0.156l0.156-0.291l0.156-0.491l-0.066-0.067l-0.09-0.201l-0.045-0.179l-0.044-0.134l-0.179-0.067l-0.156-0.067l0.044-0.224l0.045-0.179h0.246h0.312l0.134-0.156l-0.29-0.044l-0.269-0.089l-0.223-0.246l0.312-0.044l0.357-0.201l0.156-0.067l0.201-0.089l0.045-0.224l-0.09-0.179l-0.111-0.089l0.022-0.179l0.089-0.111l-0.156-0.089l-0.201,0.089l-0.134,0.044h-0.269l-0.357-0.156l-0.111-0.224l-0.469-0.022l-0.291-0.089l-0.201-0.179l-0.357,0.067l-0.268-0.112l-0.469-0.112l-0.425-0.067l-0.29-0.268l-0.224,0.067l-0.045,0.157l-0.29,0.134l-0.224-0.112l-0.179-0.179l-0.402-0.044l-0.022-0.134l-0.201-0.179v-0.134l-0.268-0.179l-0.111-0.156l-0.357,0.067l-0.536,0.134h-0.269l-0.312,0.112l-0.425,0.112l-0.179-0.156l-0.179-0.022l-0.201,0.067l-0.469-0.291l-0.268-0.067l-0.47,0.067l-0.268,0.179l-0.291-0.29l-0.179-0.089l-0.089-0.224l0.089-0.179l-0.089-0.246l-0.224-0.268v-0.357h-0.402v-0.312l-0.38-0.022l-0.514,0.067l-0.156-0.112h-0.647l-0.269-0.29l-0.111-0.357l-0.134-0.291l0.312-0.134l0.312,0.022v-0.268l-0.312-0.156l-0.246-0.156l-0.134-0.201l-0.246-0.335l-0.312-0.134l-0.201-0.268l-0.514,0.134l-0.692-0.112l-0.67,0.223l-0.536,0.022l-0.536-0.246l-0.134,0.268l-0.179,0.291l-0.313,0.156l-0.469-0.022l-0.357-0.089z M527.156,37.071l-0.59-0.14l-0.955-0.21l-1.128-0.139l-0.739,0.054l-0.959,0.037l-0.732,0.143l-0.411-0.105l-1.025-0.476l0.737-0.303l1.21-0.429l0.654-0.09l1.549-0.002l0.135-0.357l-0.728-0.338l0.351-0.269l0.419-0.144l0.676-0.02l0.852-0.181l-0.25-0.161l-0.526-0.233l1.539-0.895l0.513-0.129l0.226,0.073l0.892,0.017l0.981-0.535l0.863-0.333l1.02-0.261l0.975-0.15l1.305-0.113l1.274,0.053l0.738-0.15l0.786-0.615l0.273,0.018l0.873-0.132l1.722,0.276l0.471-0.038l1.93-0.321l0.958-0.039l2.184-0.247l1.864-0.116l0.771-0.564l0.376-0.152l2.511-0.137l1.965-0.079l0.471,0.131l0.442,0.225l0.154,0.357l-0.812,0.47l-0.541,0.169l-1.346,0.319l-2.609,0.433l-4.329,0.49l-2.187,0.281l-2.122,0.299l-1.842,0.316l-2.102,0.242l-0.941,0.203l-0.288,0.274l0.644,0.216l-0.422,0.217l-0.943,0.361l-0.527,0.037l-2.047-0.068l-0.432,0.18l-0.119,0.233l0.621,0.249l-0.331,0.233l-1.206,0.448l-0.402-0.142l-0.752-0.087l-0.592,0.304l0.877,0.283l0.052,0.319l-1.094,0.657l-0.822,0.284z M517.491,38.443l1.041-0.37l0.512-0.299l0.428-0.212l1.426-0.021l1.316-0.249l0.987-0.02l1.412-0.091l0.551,0.069l0.988,0.227l-0.063,0.176l-0.463,0.528l-0.302,0.158l-0.697,0.071l-0.443,0.228l-0.233,0.385l0.006,0.818l0.445,1.039l0.957,0.826l0.505,0.308l0.775,0.307l1.162,0.392l-0.028,0.282l-2.62-0.089l-0.844,0.053l-0.917,0.326l-0.596,0.086l-0.676-0.494l-0.382-0.034l-1.091,0.088l-0.673-0.102l-0.031-0.359l1.347-0.362l0.073-0.24l-0.102-0.017l-0.944-0.273l-1.442-0.411l-1.519-0.17l-0.33,0.156l-0.624,0.122l-0.681-0.033l-0.625-0.396l-0.114-0.415l0.229-0.312l0.39-0.209l0.344-0.036l0.318,0.104l0.65,0.016l0.518-0.192l1.121-0.768l0.243-0.35l-0.322,0l-0.981-0.243z M0.125,56.089v-0.562v-0.576v-0.157v-1.292V51.28v-2.222v-2.12l2.917,0.61l1.693,0.598l0.933,0.181l3.819,0.99l1.059,0.395l0.204,0.149l0.074,0.214l0.445,0.429l0.406,0.789l-0.209,0.428l1.034,0.8l0.982,0.26l-0.02-0.18l0.297-0.148l-0.051-0.196l-0.638-0.392l0.016-0.542l0.077-0.296l1.026-0.183l0.984,0.278l0.573,0.098l0.767,0.064l1.003-0.117l0.933,0.13l0.93,0.425l0.694,0.359l1.676,0.684l0.32,0.081l0.584,0.179l0.43,0.211l0.09,0.13l-0.343,0.033l-1.026-0.096l-0.364,0.034l-0.808,0.798l-1.539-0.468l0.138,0.178l0.438,0.227l0.465,0.324l-1.177-0.111l-1.008,0.05l-1.202-0.387l-0.708-0.096l0.135,0.129l0.289,0.259h0.084l0.561,0.259l0.205,0.307l0.131,0.453l-0.056,0.339l-0.814,0.05l-0.805,0.065l-0.189,0.161l0.5,0.865l-0.115,0.272l-1.04-0.078l-0.397,0.081l-1.193-0.174l-0.264-0.352l-1.795-0.51l-0.253,0.273L9.85,55.79l-0.276-0.161l-0.265-0.403l0.174-0.178l-0.321-0.42l-0.87-0.339l-0.565-0.063l-0.762,0.034l-0.858,0.229l-1.343,0.084L3.57,54.443l0.059-0.325l-0.155-0.325l-0.618-0.487L1.958,53.43l-0.45,0.409l-0.655,1.228l-0.166,0.715l-0.562,0.307z"/> - <path id="NO" country:name="Norway" d="M449.401,22.792l-1.596-0.014l-2.019-0.016l-1.739,0.063l-0.764,0.061l-1.972-0.316l0.812-0.456l0.826-0.172l0.735-0.453l1.148-0.588l1.354,0.691l0.998,0.105l1.116-0.088l0.9,0.084l0.704,0.341l0.865-0.323l0.53-0.454l0.868-0.306l-0.311,0.823l0.086,0.32l0.851-0.001l0.991-0.495l1.061-0.261l0.803,0.128l0.559,0.472l0.705,0.041l2.007-0.111l1.543,0.189l0.551,0.376l-0.507,0.201l-2.004,0.622l-1.623,0.38l-1.069,0.062l-0.976,0.14l-1.324,0.366l-6.271-0.097l-0.033-0.377l1.492-0.26l0.702-0.677z M430.027,22.752l0.068,0.697l0.252,0.119l1.694,0.155l0.221-0.377l0.13-0.418l0.573-0.141l0.523-0.041l0.949,0.477l1.192,0.771l0.798,0.235l0.568-0.218l-0.222-0.296l-0.46-0.356l-0.327-0.477l-0.04-0.22l0.91-0.407l1.001,0.103l0.485,0.18l1.278,0.018l0.586,0.179l-0.08,0.419l-0.169,0.298l0.104,0.159l0.549,0.118l0.743-0.338l0.44-0.1l0.662,0.396l0.678,0.335l0.785,0.156l0.948,0.117l1.672,0.429l0.498,0.234l-1.305,0.277l-1.981,0.218l-0.696,0.293l-0.731,1.144l-0.885,0.885l-1.243,0.117l-0.766,0.535l-0.455,0.589l-0.029,0.378l-0.786,0.209l-0.556-0.018l-1.593-0.355l-1.883-0.507l-1.365-0.568l0.651-0.364l1.565-0.041l1.788-0.137l0.944-0.386l-0.652-0.249l-1.822,0.139l-1.566,0.118l-1.694,0.042l-0.502-0.519l0.959-0.06l1.371-0.215l2.149-0.314l1.547-0.45l-2.525-0.405l-0.881-0.292l-0.589,0.138l-1.036,0.646l-1.069,0.293l-0.562,0.059l-1.236-0.172l-0.338-0.174l-1.05-0.368l-0.807-0.233l-0.698-0.41l1.698-0.396l-0.817-0.571l-1.359,0.319l-0.467-0.078l-0.924-0.751l0.812-0.36l0.516-0.021l1.075-0.122l1.017,0.038l0.577-0.061l1.188-0.042z M425.42,68.82l-0.148-0.21l-0.629,0.132l-0.134-0.026l-0.249-0.237l-0.239-0.343l0.188-0.158l-0.143-0.291l-0.361,0.185l-0.062,0.29l0.113,0.237l-0.147,0.105l-0.339,0.316l-0.086,0.185l-0.521,0.105l-0.533-0.131l-0.781,0.342l0.057,0.131l-0.502,0.289l-0.498,0.263l-1.658,0.813L418.697,71l-0.274,0.052h-0.271l-2.111,0.209l-0.188-0.236l-0.33-0.131l-0.183,0.209L414.976,71l0.384-0.184l-0.935-0.236l-0.794-0.341l-0.574-0.052l-0.479-0.578l0.292-0.368l-0.126-0.21l0.34,0.026l0.085,0.316l0.284-0.21l0.667,0.263l-0.244-0.197l0.127-0.145l0.5-0.092l-0.479,0.026l-0.245,0.105l-0.263-0.184l-0.111-0.132l0.579-0.276l0.455-0.185l-0.482,0.066l-0.317-0.132l0.441-0.237l0.083-0.237l-0.661,0.475l-0.036-0.264l-0.265-0.171l0.005,0.211l0.076,0.171l-0.419,0.158h-0.41l0.014-0.277l-0.15,0.264l-0.235-0.079l-0.2-0.448l0.658-0.449l0.08,0.436l0.068-0.317l0.438,0.158l0.211-0.092l-0.166-0.106l0.674-0.079l0.479-0.251l-0.611,0.159h-0.48l-0.335-0.159l0.196-0.132l0.387-0.146l0.196-0.471l-0.821-0.014l-0.546,0.094l-0.406-0.309l0.368-0.14l0.643-0.404l-0.212-0.186l-0.445,0.063l-0.399-0.062l-0.211-0.217l0.284-0.482l0.619-0.265l-0.595-0.248l-0.225-0.374l0.272-0.188l-0.089-0.687l0.106-0.094l0.594-0.063l0.392-0.045l0.455,0.044l0.082-0.11l-0.255-0.134l-0.425-0.118l-0.228-0.17l0.098-0.188l0.211-0.125l0.575-0.064l0.511-0.346l0.567,0.109l0.498-0.111l0.179-0.55l0.835,0.093l0.668,0.125l0.571-0.252l-0.989-0.234l-0.266-0.314l0.236-0.143l1.151,0.014l0.851-0.08l0.538,0.219l0.06-0.473l0.477-0.27l0.297-0.333l0.78-0.175l0.438,0.189l0.138,0.079l0.5-0.476l0.869-0.413l0.084-0.429l0.437-0.398l1.497-0.735l0.335-0.192l0.235-0.048l0.481,0.175l0.335-0.001l0.319-0.224l-0.225-0.223l0.141-0.128l0.488-0.224l0.457-0.305l0.481-0.483l0.245,0.064l0.676-0.017l-0.067-0.612l-0.471-0.112l0.434-0.405l0.511-0.648l0.841,0.063l0.047-0.341l0.096-0.228l0.954-0.116l-0.396-0.357l-0.327-0.097l-0.193-0.146l0.164-0.245l0.313-0.246l0.464,0.048l0.888-0.067l-0.543-0.522l0.249-0.082l0.435-0.034l0.707-0.263l0.592-0.067l0.308-0.208l-0.358-0.064l-0.105-0.187l0.289-0.1l0.616-0.33l0.557,0.032l0.351,0.098l0.434-0.264l0.369-0.031l0.035-0.176l-0.421-0.321l0.627-0.232l0.146-0.275l0.336,0.01l0.359,0.297l0.397,0.082l0.526-0.381l-0.281-0.656l0.438,0.065l0.698-0.058l0.207-0.174l-0.604-0.315l0.411-0.224l0.816-0.251l0.093-0.257l0.261-0.194l0.73-0.135l0.074,0.067l0.274-0.051l0.102-0.067l0.492-0.67l0.521,0.25l0.96-0.153l0.411,0.133l0.265,0.1l0.646,0.065l0.536-0.419l0.747-0.84l0.286-0.085l0.16,0.168l-0.178,0.286l-0.182,0.587l0.791-0.454l0.403-0.572l0.819-0.085l0.688-0.439l0.437,0.117l0.665,0.353l0.567-0.643l0.318-0.272l0.976,0.1l1.019,0.506l0.197-0.152l0.479-0.595l0.709-0.444l0.283-0.052l0.562,0.067l0.338-0.308l0.469-0.291l0.619-0.189l1.2-0.173l0.984,0.015l-1.337,0.755l-0.24,0.273l-0.107,0.646l0.42,0.084l0.691-0.579l1.53-0.941l0.764-0.275l0.028,0.257l-0.004,0.905l0.704-0.172l0.438-0.239l0.855-0.874l0.959-0.104l0.586-0.001l0.216,0.154l-0.383,0.257l-0.335,0.257l0.074,0.239l-0.319,0.41l0.921,0.118l0.221-0.443l0.902-0.651l0.421,0.017l1.682,0.561l0.667,0.135l0.935,0.015l0.649,0.237l0.1,0.272l-1.216,0.393l-1.148,0.036l-2.233-0.047l0.193,0.084l0.585,0.304l1.058,0.284l0.383,0.302l0.728-0.052l0.679-0.102l0.831,0.032l0.708,0.25l-0.404,0.288l-0.514,0.204l-0.824,0.021l-0.77,0.121l-1.023,0.49l-1.013,0.672l-0.689,0.303l-0.001-0.2l0.096-0.367l0.874-0.923l-0.044-0.268l-0.88-0.348l-0.672-0.114l-1.125-0.431l-0.556,0.003l-0.555,0.07l-2.004,0.095l-0.865,0.374l-0.567,0.422l-0.26,0.437l-0.079,0.501l-0.188,0.5l-1.25,0.472l-0.582,0.368l-0.31-0.148l-1.288-0.492l-1.657,0.225l-1.411-0.042l-0.536-0.13l-0.861-0.595l-0.994-0.612l-0.486-0.082l-0.355,0.103l-1.012,0.656l-0.114-0.063l-0.41-0.031l-0.865,0.038l-0.281,1.066l-0.164,0.449l-0.271,0.25l-0.323-0.015l-0.67-0.129l-0.972-0.144l-1.731-0.389l-0.168,0.183l-0.021,0.663l-0.083,0.199l-0.318,0.299l-0.695,0.004l-0.871-0.095l-0.279-0.015l-0.465,0.167l-1.484,1.176l0.05,0.213l0.171,0.507l-0.188,0.345l-0.615,0.346l-1.325,0.919l-0.687,0.442l-0.981,0.021l-0.121,0.244l-0.06,0.971l-0.32,0.598l-0.383,0.469l-0.574,0.499l-0.495,0.545l0.339,0.125l0.381,0.269l0.252,0.587l-0.17,0.176l-0.44,0.177l-0.733,0.036l-0.932-0.027l-0.618,0.114l-0.613,0.257l-0.617,0.479l-0.389,0.492l-0.077,0.664l-0.349,1.093l0.65,0.729l-0.335,1.171l0.582,0.39l0.715,0.186l0.297,0.243l-0.432,0.67l-0.941,0.16l0.571,0.735l0.26,0.427l-0.249,0.346l-0.029,0.532l-0.769,0.384l-0.414,0.013l-0.117,0.423l-0.506,0.224l0.22,0.831l-0.324,0.737l-0.41,0.013l-0.15-0.342l-0.293-0.132z"/> - <path id="FI" country:name="Finland" d="M464.349,47.431l-0.024,0.283l-0.258,0.465l0.116,0.529l0.563,0.212l0.872,0.194l0.964,0.506l0.543,0.392l-0.421,0.364l-1.303,0.777l-0.328,0.296l1.402,1.394l0.772,1.195l-0.196,0.356l-0.44,0.535l-0.187,0.403l-0.029,0.37l0.37,0.509l1.286,1.395l0.151,0.253l-0.057,0.254l-0.542,0.415l-0.327,0.191l0.439,0.33l1.357,0.499l0.703,0.265l0.436,0.392l0.161,0.346l-0.105,0.409l-0.43,0.536l-0.591,0.536l-1.385,0.758l-1.983,1.195l-1.946,1.145l-0.174,0.285l-0.935,0.206l-1.195,0.188l-0.149,0.181l-0.506-0.217l-0.518,0.146l-0.052,0.134l-0.688-0.07l-0.193-0.108l0.057-0.387l-0.241,0.527l-0.268,0.14l-0.633,0.047l-0.328,0.03l-0.1,0.267l-0.589-0.326l-0.29,0.275l-0.676,0.064l-0.34,0.178l-0.052-0.127l-0.504,0.108l-0.504,0.108l-0.211,0.266l-0.311-0.152l-0.672,0.126l-0.04-0.114l-0.658,0.215l-0.547,0.013l-0.482,0.025l-0.487-0.253l-0.223-0.274l0.273-0.34l-0.846,0.017l-0.517,0.177l0.065-0.382l-0.446,0.076l-0.644-0.271l-0.409-0.061l-0.415-0.231l-0.26-0.403l-0.036-0.714l0.158-0.374l0.05-0.436l0.09-0.234l-0.347-0.483l-0.431-0.375l0.3-0.658l-0.02-0.392l-0.305-0.204l-0.37-0.093l0.062-0.299l0.295-0.331l0.637-0.285l0.144-0.189l-0.113-0.331l0.382-0.143l0.633,0.125l0.274,0.063l0.483-0.222l0.303-0.427l0.104-0.459l0.207-0.27l0.301,0.316l0.27,0l1.678-1.114l1.142-0.654l0.835-0.576l1.026-0.401l0.874,0.03l0.06-0.304l-0.13-0.144l-0.357-0.16l0.119-0.371l0.146-0.387l-0.329-0.274l-1.139-0.095l-0.836-0.451l-0.594-0.024l-0.113-0.234l-0.327-0.307l-0.208-0.535l0.5-0.8l-0.028-0.392l-0.405-0.685l-0.507-0.637l0.004-0.526l0.062-0.413l-0.77-0.558l-0.508-0.229l-1.583-0.207l-1.085-0.292l-1.286-0.658l-0.616-0.463l-0.146-0.033l1.012-0.656l0.355-0.103l0.486,0.082l0.994,0.612l0.861,0.595l0.536,0.13l1.411,0.042l1.657-0.225l1.288,0.492l0.31,0.148l0.582-0.368l1.25-0.472l0.188-0.5l0.079-0.501l0.26-0.437l0.567-0.422l0.865-0.374l2.004-0.095l0.555-0.07l0.556-0.003l1.125,0.431l0.672,0.114l0.88,0.348l0.044,0.268l-0.874,0.923l-0.096,0.367l0.001,0.2z"/> - <path id="SE" country:name="Sweden" d="M453.795,53.873l-0.23-0.004l-0.975,0.164l-0.447,0.098l-0.902-0.387l-0.339-0.178l-0.347,0.114l-0.641,0.374l-0.542,0.599l-0.309,0.146l-0.658,0.018l-0.545,0.355l0.325,0.241l0.146,0.192l-0.355,0.273l-0.907,0.401l0.317,0.271l0.385,0.159l0.33,0.302l-0.749,0.367l-0.405,0.43l-0.368,0.461l-1.591,0.669l-0.699,0.286l-0.456-0.205l-0.326,0.08l-0.538,0.539l-0.646,0.144l-0.663,0.348l-0.217,0.284l-0.191,0.142l-0.746,0.033l-0.221-0.031l0.151,0.535l-0.484,0.425L439,61.33l0.216,0.533l0.243,0.25l-0.244,0.955l-0.498,0.063l-0.217,0.204l0.189,0.757l-0.009,0.544l0.381,0.444l-0.287,0.175l0.926,0.082l0.225,0.187l0.499-0.082l0.652,0.594l0.428,0.314l0.86,0.163l0.198,0.406l0.32,0.139l0.014,0.335h-0.391l-0.508,0.323l-0.861,0.3l-0.492,0.162l-0.521-0.012l-0.146-0.115l-0.805-0.115l-0.66-0.173l-0.634-0.069l-0.137,0.104l-0.446-0.115l-0.257,0.3l0.819-0.069l0.497,0.265l0.591,0.046l0.205,0.208l0.481,0.069l0.021-0.127l0.616,0.069l0.258-0.196l0.297,0.011l0.481-0.104l0.226,0.081l0.026-0.15h0.164l0.214,0.15l-0.029,0.081l-0.722,0.023l0.219,0.288l-0.792,0.265l-0.168,0.288l-0.386,0.08l-0.089-0.092l0.042-0.161l-0.014-0.276l-0.258,0.023l-0.091,0.46l-0.501,0.333l-0.248,0.058l-0.36-0.069l-0.005,0.218l-1.418,0.035l0.156,0.458l0.513,0.258l0.066,0.609l-0.109,0.33l-0.281,0.051l-0.308-0.064l0.038,0.429l0.29,0.081l-0.126,0.268l0.24,0.228l-0.365,0.364l-0.222,0.455l-0.041,0.56l-0.766,1.043l-0.58,0.71l-0.165-0.062l-0.442-0.236l-0.614,0.193l-1.262-0.089l-0.106,0.311l-0.252-0.083l-0.518,0.264l-0.295,0.517l0.356,0.336l-0.376,0.374l-0.48-0.129l-0.173-0.037l-1.158,0.269l-1.11-0.116l-0.001-0.142l0.19-0.078l-0.062-0.181l0.281-0.297l-0.638-0.53l-0.413-0.479l-0.22-0.272l0.529-0.116l-0.082-0.312l0.421,0.077l0.147-0.245l-0.19-0.234l-0.285,0.013l-0.292-0.377l-0.527-0.221l-0.63-0.99h-0.286l0.011-0.408l-0.256-0.364l-0.348-0.298l0.221-0.484l0.206-0.341l-0.418-0.154l-0.405,0.102l-0.055-0.288l-0.412,0.051l-0.18-1.207l-0.225-0.131l0.311-0.355l0.293,0.132l0.15,0.342l0.41-0.013l0.324-0.737l-0.22-0.831l0.506-0.224l0.117-0.423l0.414-0.013l0.769-0.384l0.029-0.532l0.249-0.346l-0.26-0.427l-0.571-0.735l0.941-0.16l0.432-0.67l-0.297-0.243l-0.715-0.186l-0.582-0.39l0.335-1.171l-0.65-0.729l0.349-1.093l0.077-0.664l0.389-0.492l0.617-0.479l0.613-0.257l0.618-0.114l0.932,0.027l0.733-0.036l0.44-0.177l0.17-0.176l-0.252-0.587l-0.381-0.269l-0.339-0.125l0.495-0.545l0.574-0.499l0.383-0.469l0.32-0.598l0.06-0.971l0.121-0.244l0.981-0.021l0.687-0.442l1.325-0.919l0.615-0.346l0.188-0.345l-0.171-0.507l-0.05-0.213l1.484-1.176l0.465-0.167l0.279,0.015l0.871,0.095l0.695-0.004l0.318-0.299l0.083-0.199l0.021-0.663l0.168-0.183l1.731,0.389l0.972,0.144l0.67,0.129l0.323,0.015l0.271-0.25l0.164-0.449l0.281-1.066l0.865-0.038l0.41,0.031l0.114,0.063l0.146,0.033l0.616,0.463l1.286,0.658l1.085,0.292l1.583,0.207l0.508,0.229l0.77,0.558l-0.062,0.413l-0.004,0.526l0.507,0.637l0.405,0.685l0.028,0.392l-0.5,0.8l0.208,0.535l0.327,0.307l0.113,0.234z"/> - <path id="AQ" country:name="Antarctica" country:shortname="Antarctica" d="M238.107,361.753l0.515-0.688h0.859l1.202-0.515l-0.171-0.858l-3.091,0.344l-2.061,0.515l-1.545-0.344l-0.515-0.858l1.374-0.515l1.202-0.172l3.091-0.172l1.374-0.515l-0.172-1.03l0.859-0.516v-1.374l-1.326-1.054l0.982-0.491l1.202-0.344l1.545-0.172l0.858,0.344l0.858,0.858l1.03,1.374l1.374,1.202l1.03,1.373l-0.515,2.061l-1.545,0.516l-1.545,0.858l-3.434,0.172h-3.435z M172.686,360.379l3.091-0.687h3.262h5.495l2.919,1.202l-2.748,0.687l-3.759-0.337l-5.169-0.35l-3.091-0.516z M65.13,371.085l1.194-0.265l1.393,0.133l0.796,0.464h-1.99l-1.393-0.332z M277.944,379.954l0.515-1.202l2.404-1.03l2.748-0.172l2.061-0.171l1.545-0.859l0.343-1.545l1.374-0.687l3.091-0.688h4.464h2.404l3.434,0.688l0.687,1.889v1.202l-2.061,1.201l-11.848,1.03l-11.161,0.344zM36.004,376.434l1.202-0.858l2.061-0.343l4.121,0.515l4.293,1.374l-0.887,0.482l-2.719,0.204l-4.293-0.515l-3.777-0.859z M777.843,385.46l3.823,0.391l0.899,0.029l0.322,0.234l1.202,0.294l2.329,0.088l2.126-0.003l5.218,0.329l3.046,0.348l1.144-0.059l0.762,0.029l1.411,0.37v2.175v2.223v2.222v2.223v2.222v1.551h-0.041h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.182h-0.041h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.222h-2.223h-2.182h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.223h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222h-2.222H9.014H6.792H4.569H2.347H0.125v-1.544v-2.222v-2.223v-2.222v-2.223v-2.223l3.941,0.297h10.131l7.898,0.516l6.868,0.172l8.586,0.858l6.353,0.515l8.757,0.172l4.808-0.172l6.525-0.172l2.404,0.344l3.606-0.858l16.312,0.344l4.638-0.013l1.143-0.467l-14.366-0.551l-9.616-0.688h-2.232l-3.091-0.172l-0.858-0.171l-1.545-0.344l-0.498-0.455l0.155-1.434l0.687-0.858l1.889-0.688l-3.263-0.687l-2.232-0.344l-0.953-0.503l1.589-0.521l-2.891-0.6l-3.074-0.208l-0.104-0.261l2.857-0.312h2.748l6.525,0.343h3.434l2.576,0.344l4.636-1.202l2.404-0.687l-2.748-1.03l-3.778-0.858l-4.391-0.405l-2.649-0.625l-3.262-0.172h-2.919l-2.919-0.858l2.576-0.516l1.28-0.342l-1.28-0.517l-2.919,0.516H52.66l-1.717-0.344L49.054,373l0.343-1.202l1.956-0.07l1.65-0.273h4.98l4.626,0.493l3.272,0.709l1.374,0.172l4.465-0.858l4.089,0.243v-0.729l0.066-0.597l-2.255-0.73l-2.93-0.075l-2.576-0.344l2.404-0.687l4.121,0.171l1.717-0.343l3.091-0.516l3.09-0.343l5.667-0.688l4.465-0.343l3.949-0.516l4.464-0.515l2.748,0.343h5.667l4.464,0.258l4.121-0.515l7.898,0.343l7.555-0.687l3.091,0.172l1.545-0.688l1.545,0.516l5.323-0.172l0.121-0.87l1.758-0.293l1.433,0.325l0.586,0.554l-0.423,0.813l2.364,0.329l1.38-0.264l-0.006-0.938l1.438-0.267l1.48,0.267l0.212,1.036l-1.009,0.423l0.521,0.781l3.024-0.351l1.889,0.343l3.434,0.172l2.576-0.687l3.778,0.086l4.868,0.33l2.344,0.013l1.449,0.109l0.693-0.53l-0.611-0.285l-2.202-0.122l1.305-0.285l0.041-0.408l-0.367-0.245l-1.386,0.123l-0.693,0.04l-0.856-0.979l-2.178-0.337l-0.676-0.193l-0.182-0.665l4.056,0.462l3.874-0.245l-1.224-0.489l-6.035-0.163l-0.774-0.082l-0.653-0.489v-0.815l2.301,0.105l0.839,0.67l5.301-0.204l7.253,0.736l2.404-0.172l3.262-0.172l4.464,0.172l3.263,0.172l2.061-0.516l0.687-0.687h1.202l0.344,1.03l2.576,0.343l2.404-0.343l0.858,0.515l3.435,0.688l3.777,0.343l2.061,0.172l1.03-0.515l0.687-1.202l2.747-0.172l1.03,0.515l1.717,0.688l3.091-0.172l3.434,0.258l4.121-0.344l4.979-0.516l5.495-0.858l3.091-0.515l1.202-0.688v-1.373l-1.374-1.202l-0.859-1.545l-1.202-0.688l-0.344-1.03l1.202-1.03l1.717-0.343l0.858-1.202l-0.343-0.858l-0.172-1.03l-1.202-0.516l0.344-1.545l1.889-0.172l2.404-1.374l1.545-0.515l0.859-0.859l1.03-0.687l2.919-1.202l3.606-0.515l2.404-1.202l2.404-0.172l2.232-1.03l1.545-0.343l0.343,1.03l-1.374,0.515l-1.03,0.344l-1.202,0.515h-0.858h-1.202l-2.919,1.202l-1.03,0.687l-1.717,1.374l-0.172,1.202l-0.687,0.687l-1.374-0.344h-1.03l-1.202,0.516l-1.202,0.687l-1.03,0.688l-0.687,1.201l0.515,0.688l0.687,0.687l1.374,0.344h1.545l0.858,0.515l0.687,1.202l1.545,1.546l0.687,0.858l1.03,0.687l0.687,1.374l0.858,1.373l0.344,1.546l-0.344,0.858l-0.858,1.717l-2.919,1.889l-1.202,0.172l-1.03,0.858l-1.717,1.03l-3.263,0.344l-4.979,0.858l-2.404,0.344l-2.919,0.687l-7.377-0.141l-4.556-0.316l-0.773-0.401l-1.717-0.344l-1.717-0.343h-1.374l-0.859,0.515l0.515,0.858l2.061,0.688l4.121,1.202l4.995,0.04l1.202,0.759l-3.278,0.574l-5.667-0.343l-4.979-0.516l-3.097-0.285l-2.151,0.253l0.823,0.696l1.164,0.538l3.262,0.172h2.232l1.374,0.343l-0.249,0.402l-0.782,0.113l-2.232,0.515l-5.151-0.171l-1.374-0.172l-2.232-1.202h-2.404l0.128,0.917l2.62,1.144l1.03,0.172l1.202-0.172l1.374,0.344h2.404l4.98-0.516l3.09,0.687l0.385,0.431l-0.041,0.6l-2.061,0.172l-3.263,0.172l-2.608-0.185l3.811,0.871l3.656-0.238l1.324,0.41l2.576,0.687l6.869,0.859l8.585,0.858l10.646,1.373l6.525,0.516l2.061,0.858l0.687,1.03l3.091-0.344l5.323-1.545l6.525-0.687l2.455-0.066l6.474-0.105l9.788-0.344l1.889,0.344l2.576-1.202l8.414-1.03l11.333-0.172l8.929-0.858l1.202-0.858l-1.202-0.516l-0.271-1.07l-1.184-0.338l-5.071,0.035l-2.232,0.172l-4.808-0.344h-3.091v-1.202l3.263-1.545l3.949-1.202l2.404-0.172l4.121-1.03l9.444-1.202l5.323-0.858h6.525l4.979-0.516l2.747-2.061l6.039-1.541l-1.23-0.52l-2.576,0.516l-2.061-0.344l1.545-1.03l1.545-0.343l2.48-0.249l0.696-0.742l3.85-0.742l1.577-0.418l0.603-0.557l-1.716-0.881l-0.093-0.604l1.252-0.231l0.464,0.742l1.017-0.097l2.061-0.858l1.03-0.343l0.858,0.171l1.203,1.544l2.403-0.342l0.242-0.91l0.96-0.807l1.889-0.516l1.374,0.516l-1.162,0.574l-0.139,0.604l3.189-0.319l4.808,0.258l3.263-0.172l1.03,0.858l1.545-0.344l1.717-0.515l5.839-0.858l7.212-1.03l4.292-0.858h2.061l2.061,1.373l1.718,0.344l1.889-0.344l1.545-0.858l7.556-0.344l3.434-0.171l4.293,0.171l6.697,0.945h2.575l4.293-0.516l6.01-0.687l5.151-0.688l2.404-0.515l2.231-0.344l0.615-0.959l1.148-0.835l1.671-0.095l0.938,0.965l1.294,0.409l1.732,1.052l1.009,0.139l1.009-0.661l1.322-0.174l0.209,0.522l-0.835,0.312l0.661,0.244l0.8,0.278l0.383-0.383l0.313-0.383l0.312,0.209l-0.174,0.348v0.521l0.592-0.174l1.913-0.557l0.418-1.704l5.102-1.137l1.374-0.687l3.605-0.172l1.363-0.646l2.758-0.126l0.21-0.27l-0.165-0.297l0.692-0.23l1.221,0.165l0.197,0.593l0.66,0.231l2.165-0.536l1.265-0.223l-0.726-0.297l-0.561-0.264l0.099-0.362l1.451-0.1l1.562,0.215l0.647,0.28l0.692-0.132l-0.066-0.33l-0.527-0.33v-0.561l0.297-0.23l0.846-0.242l4.292-0.858l2.92-0.172l3.058,0.115l2.296,1.076l1.316,0.023l0.741,0.144l0.023,0.383l-0.908,0.096l-0.168,0.454l1.723,0.216l4.892,0.646l5.571,0.453l1.546,0.172l1.717-0.172l7.556,0.688h5.323l0.687,0.687l0.2,1.075l-0.73,1.232l-0.672,0.439l-0.425,1.113l-0.73,0.319l-0.905-0.402l-0.83,0.402l-0.73,0.959l1.507,0.457l0.594,0.045l0.959-0.593l0.411,0.365l-0.867,1.05l-1.215,0.062l-1.717,1.374v0.858l1.889,0.688h2.919l1.718-0.859l1.889-1.545l1.717-1.717l1.374-0.688l4.121-1.03l2.231-0.687l3.263-0.344l2.061-1.03l1.03-1.03l3.435-1.03l2.403-0.687l2.061-0.687l2.061-0.172l6.182-0.687l3.778,0.171l1.204-0.542l0.169-0.659l0.54-0.759l0.49-0.101l0.471,0.776l0.305,0.775l4.892-0.35h5.838l4.979-0.172l3.091,0.344l2.112-0.214l1.328,0.085l1.018,0.594l1.188-0.764l2.714-1.046l1.866-0.226l0.664-0.028l0.594-0.028l0.777-0.057l1.512,0.311l1.166-0.172l3.606,0.687l3.777,0.344h1.03l1.064,0.573l0.745,0.088l2.149-0.088l1.271-0.263l1.315-0.438l-0.192-0.216l0.28-0.53l1.447-0.131l0.921-0.088l0.786,0.062l2.195-0.501l2.097,0.501l0.688,0.687l0.373,0.435l1.842-0.131l0.921-0.044l0.985,0.255l1.889,0.688l2.919,0.515l2.919-0.343l4.121-0.258l2.232-0.344h2.404l3.521,0.315l0.702-0.755l2.158-0.162l0.863,1.133l4.909,0.323l0.917-1.133l1.889-0.593l5.988,0.013l0.756-0.283l1.996,0.108l-0.432-1.403l0.054-0.809l1.232-0.36l0.872,1.277l-0.647,1.079l0.805,0.219l2.81,0.482l5.262,0.376l5.494,0.344l2.278,0.583l1.283,0.14l1.396-0.167l2.204,0.446l1.961-0.167l0.719,0.278l-0.435,0.431l-0.151,0.351l0.293,0.123l2.081,0.331l1.078,0.484l2.706-0.134l0.377,0.595l1.038,0.227l4.808,0.515l-0.123,0.536l0.567,0.236l2.695-0.095l3.214,0.181l-0.329-0.984l0.71-0.095l0.804,0.426l0.331,0.709l1.135,0.284l2.672,0.519l2.576-0.343l4.017,0.999l1.626,0.495l1.672,0.871l1.626,0.023l0.504,0.187l0.532-0.021l0.754-0.047l0.777,0.047l0.896,0.589l0.541,0.118l0.542,0.07l0.142-0.259h0.471l1.484-0.048l1.416,0.237l5.951,0.535l0.729,0.516l1.733,0.323l2.979,0.944l0.43-0.335l0.551,0.191l0.454,0.67l-0.741,0.215l-1.124,0.167l-0.216,0.359l0.168,0.263l0.55-0.048l-0.024,0.67l-0.43-0.048l-0.096,0.287l-0.312,0.071l-0.598,0.622l-0.526,0.12l-0.55,0.287l-0.168,0.669l-1.603,0.096l-1.339-0.239l-1.794,0.359l-2.153,0.425l-2.629,0.764l1.271,1.103l-1.907,0.212l-1.23-0.255l-0.763,0.212l-0.043,0.637l-2.374,0.169l0.136,0.514l0.924,0.632l-0.127,0.763l-0.382,0.085l-0.466,0.467l0.551,0.466l0.085,0.764l-0.764,0.424l0.637,0.254h0.763l0.764,0.255l0.339,0.509l0.17,0.721l1.284-0.187l0.836,0.907l2.035,0.297l0.339,0.339l2.672,0.552h-4.113l-2.799,0.138l-2.332,0.541l-1.823-0.085l-0.806,0.212l-1.611,0.339l-1.326-0.32l-0.546,0.426l1.116,0.529l-0.503,0.447l-0.669,0.195l-1.117,0.753l-2.623,0.642l0.475,0.391l2.205-0.111h0.53l0.809,0.307l0.168,0.363l0.499,0.18l0.422,0.183l0.111,0.894l0.209,0.502l3.195,0.279l2.874,0.948l3.662,0.801l5.151,1.202l1.456,0.062l1.015,0.17l-0.146,0.234l-1.67,0.264l-0.47,0.264l1.173,0.088l2.198-0.293l1.988,0.166z"/> - <g id="OTHER"> - <circle cx="60" cy="300" r="6"/> - <text x="68" y="304" font-size="8">Other</text> - </g> - </g> - <text id="copyright" x="10" y="9" font-size="8">Based on map data marked © copyright iMapping Ltd. Used without permission under the auspices of Fair Use to improve interoperability. Source: http://www.wherearewe.co.nz/svg.html</text> - <text id="messages" x="280" y="330" font-size="30">Test not yet started.</text> - <script type="text/javascript"><![CDATA[ - var svg = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'svg')[0]; - var t = document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'text')[2]; - - var delay = 100; - if (window.testRunner) - delay = 1; - var low = 200; - var high = 800; - var delta = 60; - var current = low; - var idealTime = ((high - low) / delta) * delay; - function repaintTest() { - svg.setAttribute("width", current); - if (current < high) { - t.firstChild.data = 'Test in progress... ' + (100 * (current - low) / (high - low)).toFixed(1) + '%'; - current += delta; - window.setTimeout(repaintTest, delay); - } else { - if (window.testRunner) { - t.firstChild.data = 'Test completed'; - } else { - var end = new Date(); - var elapsed = (end - start); - t.firstChild.data = 'Result: ' + elapsed.toFixed(2) + 'ms (target: ' + idealTime.toFixed(1) + 'ms)'; - if (parent.reportResults) parent.reportResults(end - start); - } - finishRepaintTest(); - } - } - ]]></script> -</svg>
diff --git a/third_party/blink/web_tests/svg/hixie/perf/resources/smallcats.gif b/third_party/blink/web_tests/svg/hixie/perf/resources/smallcats.gif deleted file mode 100644 index b6b05600..0000000 --- a/third_party/blink/web_tests/svg/hixie/perf/resources/smallcats.gif +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/backface-visibility-interop/README.md b/third_party/blink/web_tests/virtual/backface-visibility-interop/README.md new file mode 100644 index 0000000..1f43ff1 --- /dev/null +++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/README.md
@@ -0,0 +1,3 @@ +This directory contains tests for the backface-visibility-interop +feature, which was split from the transform-interop feature. Both are +covered by https://crbug.com/1008483.
diff --git a/third_party/blink/web_tests/virtual/backface-visibility-interop/external/wpt/css/css-transforms/3d-rendering-context-behavior.tentative-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/external/wpt/css/css-transforms/3d-rendering-context-behavior.tentative-expected.txt new file mode 100644 index 0000000..7e196f8 --- /dev/null +++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/external/wpt/css/css-transforms/3d-rendering-context-behavior.tentative-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS Direct DOM parent is root of rendering context +PASS Intermediate DOM nodes cause rendering context to end (normal flow) +FAIL Intermediate DOM nodes cause rendering context to end (absolute) assert_equals: expected 100 but got 200 +FAIL Intermediate DOM nodes cause rendering context to end (fixed) assert_equals: expected 100 but got 200 +PASS Perspective applies to direct DOM normal-flow children +PASS Perspective applies to direct DOM abs-pos children +PASS Perspective applies to direct DOM fixed-pos children +PASS Perspective does not apply to DOM normal-flow grandchildren +PASS Perspective does not apply to DOM abs-pos grandchildren +PASS Perspective does not apply to DOM fixed-pos grandchildren +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/css-get-styles-for-node-expected.txt b/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/css-get-styles-for-node-expected.txt index 2ec5394..f9b3febd 100644 --- a/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/css-get-styles-for-node-expected.txt +++ b/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/css-get-styles-for-node-expected.txt
@@ -19,10 +19,13 @@ { padding-top: 55px; margin-top: 33px !important; + padding-top: 55px; + margin-top: 33px !important; } Dumping matched rules: *#inspected* { regular margin-left: 10px !important; + margin-left: 10px !important; } *#inspected* { regular padding: 10px 20px 30px 40px; @@ -30,6 +33,7 @@ padding-right: 20px; padding-bottom: 30px; padding-left: 40px; + padding-top: 50px; } @media (min-width: 1px) *#inspected* { regular @@ -37,15 +41,22 @@ margin-left: 20px; padding-left: 10px; margin-top: 15px !important; + margin-left: 20px; + padding-left: 10px; + margin-top: 15px !important; } @container (min-width: 50px) *#inspected* { regular padding-right: 10px; + padding-right: 10px; } Dumping inherited rules: padding-top: 20px; + padding-top: 20px; *#parent-div* { regular width: 100px; contain: size layout style; + width: 100px; + contain: size layout style; }
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-above-composited-subframe-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-above-composited-subframe-expected.png deleted file mode 100644 index a26c8cfe..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-above-composited-subframe-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-composited-subframe-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-composited-subframe-expected.png deleted file mode 100644 index ca07de2..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-composited-subframe-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-grandparent-composited-grandchild-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-grandparent-composited-grandchild-expected.png deleted file mode 100644 index 3db752c9..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-grandparent-composited-grandchild-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-parent-composited-grandchild-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-parent-composited-grandchild-expected.png deleted file mode 100644 index 5ea3fd4..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-parent-composited-grandchild-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-two-ancestors-composited-grandchild-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-two-ancestors-composited-grandchild-expected.png deleted file mode 100644 index 59313ce..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-on-two-ancestors-composited-grandchild-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-outside-bounds-of-compositing-ancestor-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-outside-bounds-of-compositing-ancestor-expected.png deleted file mode 100644 index f4d9342..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-outside-bounds-of-compositing-ancestor-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-styles-with-composited-child-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-styles-with-composited-child-expected.png deleted file mode 100644 index e655e3a..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/border-radius-styles-with-composited-child-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/composited-layer-under-border-radius-under-composited-layer-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/composited-layer-under-border-radius-under-composited-layer-expected.png deleted file mode 100644 index aa01e8e..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/composited-layer-under-border-radius-under-composited-layer-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/grandchild-composited-with-border-radius-ancestor-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/grandchild-composited-with-border-radius-ancestor-expected.png deleted file mode 100644 index c5449f8..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/grandchild-composited-with-border-radius-ancestor-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/grandchild-with-border-radius-ancestor-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/grandchild-with-border-radius-ancestor-expected.png deleted file mode 100644 index c5449f8..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/grandchild-with-border-radius-ancestor-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/rotate-clip-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/rotate-clip-expected.png deleted file mode 100644 index a66542e..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/rotate-clip-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/rotate-then-clip-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/rotate-then-clip-expected.png deleted file mode 100644 index a66542e..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/rotate-then-clip-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-composited-with-border-radius-ancestor-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-composited-with-border-radius-ancestor-expected.png deleted file mode 100644 index c5449f8..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-composited-with-border-radius-ancestor-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-composited-with-border-radius-ancestor-one-clipped-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-composited-with-border-radius-ancestor-one-clipped-expected.png deleted file mode 100644 index 671988a3..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-composited-with-border-radius-ancestor-one-clipped-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-with-border-radius-ancestor-expected.png b/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-with-border-radius-ancestor-expected.png deleted file mode 100644 index 74ec63d8..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/compositing/overflow/siblings-with-border-radius-ancestor-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/external/wpt/css/css-transforms/animation/rotate-interpolation-expected.txt b/third_party/blink/web_tests/virtual/transform-interop/external/wpt/css/css-transforms/animation/rotate-interpolation-expected.txt deleted file mode 100644 index 533ca6f..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/external/wpt/css/css-transforms/animation/rotate-interpolation-expected.txt +++ /dev/null
@@ -1,364 +0,0 @@ -This is a testharness.js-based test. -Found 360 tests; 312 PASS, 48 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS CSS Transitions: property <rotate> from [100deg] to [180deg] at (-1) should be [20deg] -PASS CSS Transitions: property <rotate> from [100deg] to [180deg] at (0) should be [100deg] -PASS CSS Transitions: property <rotate> from [100deg] to [180deg] at (0.125) should be [110deg] -PASS CSS Transitions: property <rotate> from [100deg] to [180deg] at (0.875) should be [170deg] -PASS CSS Transitions: property <rotate> from [100deg] to [180deg] at (1) should be [180deg] -PASS CSS Transitions: property <rotate> from [100deg] to [180deg] at (2) should be [260deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [180deg] at (-1) should be [20deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [180deg] at (0) should be [100deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [180deg] at (0.125) should be [110deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [180deg] at (0.875) should be [170deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [180deg] at (1) should be [180deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [180deg] at (2) should be [260deg] -PASS CSS Animations: property <rotate> from [100deg] to [180deg] at (-1) should be [20deg] -PASS CSS Animations: property <rotate> from [100deg] to [180deg] at (0) should be [100deg] -PASS CSS Animations: property <rotate> from [100deg] to [180deg] at (0.125) should be [110deg] -PASS CSS Animations: property <rotate> from [100deg] to [180deg] at (0.875) should be [170deg] -PASS CSS Animations: property <rotate> from [100deg] to [180deg] at (1) should be [180deg] -PASS CSS Animations: property <rotate> from [100deg] to [180deg] at (2) should be [260deg] -PASS Web Animations: property <rotate> from [100deg] to [180deg] at (-1) should be [20deg] -PASS Web Animations: property <rotate> from [100deg] to [180deg] at (0) should be [100deg] -PASS Web Animations: property <rotate> from [100deg] to [180deg] at (0.125) should be [110deg] -PASS Web Animations: property <rotate> from [100deg] to [180deg] at (0.875) should be [170deg] -PASS Web Animations: property <rotate> from [100deg] to [180deg] at (1) should be [180deg] -PASS Web Animations: property <rotate> from [100deg] to [180deg] at (2) should be [260deg] -PASS CSS Transitions: property <rotate> from [45deg] to [-1 1 0 60deg] at (-1) should be [0.447214 -0.447214 0.774597 104.478deg] -PASS CSS Transitions: property <rotate> from [45deg] to [-1 1 0 60deg] at (0) should be [45deg] -PASS CSS Transitions: property <rotate> from [45deg] to [-1 1 0 60deg] at (0.125) should be [-0.136456 0.136456 0.981203 40.6037deg] -PASS CSS Transitions: property <rotate> from [45deg] to [-1 1 0 60deg] at (0.875) should be [-0.70246 0.70246 0.114452 53.1994deg] -FAIL CSS Transitions: property <rotate> from [45deg] to [-1 1 0 60deg] at (1) should be [-0.71 0.71 0 60deg] assert_equals: expected "- 0.71 0.71 0 60deg " but got "- 1 1 0 60deg " -PASS CSS Transitions: property <rotate> from [45deg] to [-1 1 0 60deg] at (2) should be [-0.637897 0.637897 -0.431479 124.975deg] -PASS CSS Transitions with transition: all: property <rotate> from [45deg] to [-1 1 0 60deg] at (-1) should be [0.447214 -0.447214 0.774597 104.478deg] -PASS CSS Transitions with transition: all: property <rotate> from [45deg] to [-1 1 0 60deg] at (0) should be [45deg] -PASS CSS Transitions with transition: all: property <rotate> from [45deg] to [-1 1 0 60deg] at (0.125) should be [-0.136456 0.136456 0.981203 40.6037deg] -PASS CSS Transitions with transition: all: property <rotate> from [45deg] to [-1 1 0 60deg] at (0.875) should be [-0.70246 0.70246 0.114452 53.1994deg] -FAIL CSS Transitions with transition: all: property <rotate> from [45deg] to [-1 1 0 60deg] at (1) should be [-0.71 0.71 0 60deg] assert_equals: expected "- 0.71 0.71 0 60deg " but got "- 1 1 0 60deg " -PASS CSS Transitions with transition: all: property <rotate> from [45deg] to [-1 1 0 60deg] at (2) should be [-0.637897 0.637897 -0.431479 124.975deg] -PASS CSS Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (-1) should be [0.447214 -0.447214 0.774597 104.478deg] -PASS CSS Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (0) should be [45deg] -PASS CSS Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (0.125) should be [-0.136456 0.136456 0.981203 40.6037deg] -PASS CSS Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (0.875) should be [-0.70246 0.70246 0.114452 53.1994deg] -FAIL CSS Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (1) should be [-0.71 0.71 0 60deg] assert_equals: expected "- 0.71 0.71 0 60deg " but got "- 1 1 0 60deg " -PASS CSS Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (2) should be [-0.637897 0.637897 -0.431479 124.975deg] -PASS Web Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (-1) should be [0.447214 -0.447214 0.774597 104.478deg] -PASS Web Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (0) should be [45deg] -PASS Web Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (0.125) should be [-0.136456 0.136456 0.981203 40.6037deg] -PASS Web Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (0.875) should be [-0.70246 0.70246 0.114452 53.1994deg] -FAIL Web Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (1) should be [-0.71 0.71 0 60deg] assert_equals: expected "- 0.71 0.71 0 60deg " but got "- 1 1 0 60deg " -PASS Web Animations: property <rotate> from [45deg] to [-1 1 0 60deg] at (2) should be [-0.637897 0.637897 -0.431479 124.975deg] -PASS CSS Transitions: property <rotate> from [none] to [7 -8 9 400grad] at (-1) should be [0.5 -0.57 0.65 -400grad] -FAIL CSS Transitions: property <rotate> from [none] to [7 -8 9 400grad] at (0) should be [0.5 -0.57 0.65 0deg] assert_equals: expected "0.5 - 0.57 0.65 0deg " but got "none " -PASS CSS Transitions: property <rotate> from [none] to [7 -8 9 400grad] at (0.125) should be [0.5 -0.57 0.65 50grad] -PASS CSS Transitions: property <rotate> from [none] to [7 -8 9 400grad] at (0.875) should be [0.5 -0.57 0.65 350grad] -FAIL CSS Transitions: property <rotate> from [none] to [7 -8 9 400grad] at (1) should be [0.5 -0.57 0.65 400grad] assert_equals: expected "0.5 - 0.57 0.65 360deg " but got "7 - 8 9 360deg " -PASS CSS Transitions: property <rotate> from [none] to [7 -8 9 400grad] at (2) should be [0.5 -0.57 0.65 800grad] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [7 -8 9 400grad] at (-1) should be [0.5 -0.57 0.65 -400grad] -FAIL CSS Transitions with transition: all: property <rotate> from [none] to [7 -8 9 400grad] at (0) should be [0.5 -0.57 0.65 0deg] assert_equals: expected "0.5 - 0.57 0.65 0deg " but got "none " -PASS CSS Transitions with transition: all: property <rotate> from [none] to [7 -8 9 400grad] at (0.125) should be [0.5 -0.57 0.65 50grad] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [7 -8 9 400grad] at (0.875) should be [0.5 -0.57 0.65 350grad] -FAIL CSS Transitions with transition: all: property <rotate> from [none] to [7 -8 9 400grad] at (1) should be [0.5 -0.57 0.65 400grad] assert_equals: expected "0.5 - 0.57 0.65 360deg " but got "7 - 8 9 360deg " -PASS CSS Transitions with transition: all: property <rotate> from [none] to [7 -8 9 400grad] at (2) should be [0.5 -0.57 0.65 800grad] -PASS CSS Animations: property <rotate> from [none] to [7 -8 9 400grad] at (-1) should be [0.5 -0.57 0.65 -400grad] -FAIL CSS Animations: property <rotate> from [none] to [7 -8 9 400grad] at (0) should be [0.5 -0.57 0.65 0deg] assert_equals: expected "0.5 - 0.57 0.65 0deg " but got "none " -PASS CSS Animations: property <rotate> from [none] to [7 -8 9 400grad] at (0.125) should be [0.5 -0.57 0.65 50grad] -PASS CSS Animations: property <rotate> from [none] to [7 -8 9 400grad] at (0.875) should be [0.5 -0.57 0.65 350grad] -FAIL CSS Animations: property <rotate> from [none] to [7 -8 9 400grad] at (1) should be [0.5 -0.57 0.65 400grad] assert_equals: expected "0.5 - 0.57 0.65 360deg " but got "7 - 8 9 360deg " -PASS CSS Animations: property <rotate> from [none] to [7 -8 9 400grad] at (2) should be [0.5 -0.57 0.65 800grad] -PASS Web Animations: property <rotate> from [none] to [7 -8 9 400grad] at (-1) should be [0.5 -0.57 0.65 -400grad] -FAIL Web Animations: property <rotate> from [none] to [7 -8 9 400grad] at (0) should be [0.5 -0.57 0.65 0deg] assert_equals: expected "0.5 - 0.57 0.65 0deg " but got "none " -PASS Web Animations: property <rotate> from [none] to [7 -8 9 400grad] at (0.125) should be [0.5 -0.57 0.65 50grad] -PASS Web Animations: property <rotate> from [none] to [7 -8 9 400grad] at (0.875) should be [0.5 -0.57 0.65 350grad] -FAIL Web Animations: property <rotate> from [none] to [7 -8 9 400grad] at (1) should be [0.5 -0.57 0.65 400grad] assert_equals: expected "0.5 - 0.57 0.65 360deg " but got "7 - 8 9 360deg " -PASS Web Animations: property <rotate> from [none] to [7 -8 9 400grad] at (2) should be [0.5 -0.57 0.65 800grad] -PASS CSS Transitions: property <rotate> from [none] to [none] at (-1) should be [none] -PASS CSS Transitions: property <rotate> from [none] to [none] at (0) should be [none] -PASS CSS Transitions: property <rotate> from [none] to [none] at (0.125) should be [none] -PASS CSS Transitions: property <rotate> from [none] to [none] at (0.875) should be [none] -PASS CSS Transitions: property <rotate> from [none] to [none] at (1) should be [none] -PASS CSS Transitions: property <rotate> from [none] to [none] at (2) should be [none] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [none] at (-1) should be [none] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [none] at (0) should be [none] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [none] at (0.125) should be [none] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [none] at (0.875) should be [none] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [none] at (1) should be [none] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [none] at (2) should be [none] -PASS CSS Animations: property <rotate> from [none] to [none] at (-1) should be [none] -PASS CSS Animations: property <rotate> from [none] to [none] at (0) should be [none] -PASS CSS Animations: property <rotate> from [none] to [none] at (0.125) should be [none] -PASS CSS Animations: property <rotate> from [none] to [none] at (0.875) should be [none] -PASS CSS Animations: property <rotate> from [none] to [none] at (1) should be [none] -PASS CSS Animations: property <rotate> from [none] to [none] at (2) should be [none] -PASS Web Animations: property <rotate> from [none] to [none] at (-1) should be [none] -PASS Web Animations: property <rotate> from [none] to [none] at (0) should be [none] -PASS Web Animations: property <rotate> from [none] to [none] at (0.125) should be [none] -PASS Web Animations: property <rotate> from [none] to [none] at (0.875) should be [none] -PASS Web Animations: property <rotate> from [none] to [none] at (1) should be [none] -PASS Web Animations: property <rotate> from [none] to [none] at (2) should be [none] -PASS CSS Transitions: property <rotate> from [none] to [30deg] at (-1) should be [-30deg] -FAIL CSS Transitions: property <rotate> from [none] to [30deg] at (0) should be [0deg] assert_equals: expected "0deg " but got "none " -PASS CSS Transitions: property <rotate> from [none] to [30deg] at (0.25) should be [7.5deg] -PASS CSS Transitions: property <rotate> from [none] to [30deg] at (0.75) should be [22.5deg] -PASS CSS Transitions: property <rotate> from [none] to [30deg] at (1) should be [30deg] -PASS CSS Transitions: property <rotate> from [none] to [30deg] at (2) should be [60deg] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [30deg] at (-1) should be [-30deg] -FAIL CSS Transitions with transition: all: property <rotate> from [none] to [30deg] at (0) should be [0deg] assert_equals: expected "0deg " but got "none " -PASS CSS Transitions with transition: all: property <rotate> from [none] to [30deg] at (0.25) should be [7.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [30deg] at (0.75) should be [22.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [30deg] at (1) should be [30deg] -PASS CSS Transitions with transition: all: property <rotate> from [none] to [30deg] at (2) should be [60deg] -PASS CSS Animations: property <rotate> from [none] to [30deg] at (-1) should be [-30deg] -FAIL CSS Animations: property <rotate> from [none] to [30deg] at (0) should be [0deg] assert_equals: expected "0deg " but got "none " -PASS CSS Animations: property <rotate> from [none] to [30deg] at (0.25) should be [7.5deg] -PASS CSS Animations: property <rotate> from [none] to [30deg] at (0.75) should be [22.5deg] -PASS CSS Animations: property <rotate> from [none] to [30deg] at (1) should be [30deg] -PASS CSS Animations: property <rotate> from [none] to [30deg] at (2) should be [60deg] -PASS Web Animations: property <rotate> from [none] to [30deg] at (-1) should be [-30deg] -FAIL Web Animations: property <rotate> from [none] to [30deg] at (0) should be [0deg] assert_equals: expected "0deg " but got "none " -PASS Web Animations: property <rotate> from [none] to [30deg] at (0.25) should be [7.5deg] -PASS Web Animations: property <rotate> from [none] to [30deg] at (0.75) should be [22.5deg] -PASS Web Animations: property <rotate> from [none] to [30deg] at (1) should be [30deg] -PASS Web Animations: property <rotate> from [none] to [30deg] at (2) should be [60deg] -PASS CSS Transitions: property <rotate> from neutral to [30deg] at (-1) should be [-10deg] -PASS CSS Transitions: property <rotate> from neutral to [30deg] at (0) should be [10deg] -PASS CSS Transitions: property <rotate> from neutral to [30deg] at (0.25) should be [15deg] -PASS CSS Transitions: property <rotate> from neutral to [30deg] at (0.75) should be [25deg] -PASS CSS Transitions: property <rotate> from neutral to [30deg] at (1) should be [30deg] -PASS CSS Transitions: property <rotate> from neutral to [30deg] at (2) should be [50deg] -PASS CSS Transitions with transition: all: property <rotate> from neutral to [30deg] at (-1) should be [-10deg] -PASS CSS Transitions with transition: all: property <rotate> from neutral to [30deg] at (0) should be [10deg] -PASS CSS Transitions with transition: all: property <rotate> from neutral to [30deg] at (0.25) should be [15deg] -PASS CSS Transitions with transition: all: property <rotate> from neutral to [30deg] at (0.75) should be [25deg] -PASS CSS Transitions with transition: all: property <rotate> from neutral to [30deg] at (1) should be [30deg] -PASS CSS Transitions with transition: all: property <rotate> from neutral to [30deg] at (2) should be [50deg] -PASS CSS Animations: property <rotate> from neutral to [30deg] at (-1) should be [-10deg] -PASS CSS Animations: property <rotate> from neutral to [30deg] at (0) should be [10deg] -PASS CSS Animations: property <rotate> from neutral to [30deg] at (0.25) should be [15deg] -PASS CSS Animations: property <rotate> from neutral to [30deg] at (0.75) should be [25deg] -PASS CSS Animations: property <rotate> from neutral to [30deg] at (1) should be [30deg] -PASS CSS Animations: property <rotate> from neutral to [30deg] at (2) should be [50deg] -PASS Web Animations: property <rotate> from neutral to [30deg] at (-1) should be [-10deg] -PASS Web Animations: property <rotate> from neutral to [30deg] at (0) should be [10deg] -PASS Web Animations: property <rotate> from neutral to [30deg] at (0.25) should be [15deg] -PASS Web Animations: property <rotate> from neutral to [30deg] at (0.75) should be [25deg] -PASS Web Animations: property <rotate> from neutral to [30deg] at (1) should be [30deg] -PASS Web Animations: property <rotate> from neutral to [30deg] at (2) should be [50deg] -PASS CSS Transitions: property <rotate> from [inherit] to [270deg] at (-1) should be [-90deg] -PASS CSS Transitions: property <rotate> from [inherit] to [270deg] at (0) should be [90deg] -PASS CSS Transitions: property <rotate> from [inherit] to [270deg] at (0.25) should be [135deg] -PASS CSS Transitions: property <rotate> from [inherit] to [270deg] at (0.75) should be [225deg] -PASS CSS Transitions: property <rotate> from [inherit] to [270deg] at (1) should be [270deg] -PASS CSS Transitions: property <rotate> from [inherit] to [270deg] at (2) should be [450deg] -PASS CSS Transitions with transition: all: property <rotate> from [inherit] to [270deg] at (-1) should be [-90deg] -PASS CSS Transitions with transition: all: property <rotate> from [inherit] to [270deg] at (0) should be [90deg] -PASS CSS Transitions with transition: all: property <rotate> from [inherit] to [270deg] at (0.25) should be [135deg] -PASS CSS Transitions with transition: all: property <rotate> from [inherit] to [270deg] at (0.75) should be [225deg] -PASS CSS Transitions with transition: all: property <rotate> from [inherit] to [270deg] at (1) should be [270deg] -PASS CSS Transitions with transition: all: property <rotate> from [inherit] to [270deg] at (2) should be [450deg] -PASS CSS Animations: property <rotate> from [inherit] to [270deg] at (-1) should be [-90deg] -PASS CSS Animations: property <rotate> from [inherit] to [270deg] at (0) should be [90deg] -PASS CSS Animations: property <rotate> from [inherit] to [270deg] at (0.25) should be [135deg] -PASS CSS Animations: property <rotate> from [inherit] to [270deg] at (0.75) should be [225deg] -PASS CSS Animations: property <rotate> from [inherit] to [270deg] at (1) should be [270deg] -PASS CSS Animations: property <rotate> from [inherit] to [270deg] at (2) should be [450deg] -PASS Web Animations: property <rotate> from [inherit] to [270deg] at (-1) should be [-90deg] -PASS Web Animations: property <rotate> from [inherit] to [270deg] at (0) should be [90deg] -PASS Web Animations: property <rotate> from [inherit] to [270deg] at (0.25) should be [135deg] -PASS Web Animations: property <rotate> from [inherit] to [270deg] at (0.75) should be [225deg] -PASS Web Animations: property <rotate> from [inherit] to [270deg] at (1) should be [270deg] -PASS Web Animations: property <rotate> from [inherit] to [270deg] at (2) should be [450deg] -PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (-1) should be [-30deg] -FAIL CSS Transitions: property <rotate> from [unset] to [30deg] at (0) should be [0deg] assert_equals: expected "0deg " but got "none " -PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (0.25) should be [7.5deg] -PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (0.75) should be [22.5deg] -PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (1) should be [30deg] -PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (2) should be [60deg] -PASS CSS Transitions with transition: all: property <rotate> from [unset] to [30deg] at (-1) should be [-30deg] -FAIL CSS Transitions with transition: all: property <rotate> from [unset] to [30deg] at (0) should be [0deg] assert_equals: expected "0deg " but got "none " -PASS CSS Transitions with transition: all: property <rotate> from [unset] to [30deg] at (0.25) should be [7.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [unset] to [30deg] at (0.75) should be [22.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [unset] to [30deg] at (1) should be [30deg] -PASS CSS Transitions with transition: all: property <rotate> from [unset] to [30deg] at (2) should be [60deg] -PASS CSS Animations: property <rotate> from [unset] to [30deg] at (-1) should be [-30deg] -FAIL CSS Animations: property <rotate> from [unset] to [30deg] at (0) should be [0deg] assert_equals: expected "0deg " but got "none " -PASS CSS Animations: property <rotate> from [unset] to [30deg] at (0.25) should be [7.5deg] -PASS CSS Animations: property <rotate> from [unset] to [30deg] at (0.75) should be [22.5deg] -PASS CSS Animations: property <rotate> from [unset] to [30deg] at (1) should be [30deg] -PASS CSS Animations: property <rotate> from [unset] to [30deg] at (2) should be [60deg] -PASS Web Animations: property <rotate> from [unset] to [30deg] at (-1) should be [-30deg] -FAIL Web Animations: property <rotate> from [unset] to [30deg] at (0) should be [0deg] assert_equals: expected "0deg " but got "none " -PASS Web Animations: property <rotate> from [unset] to [30deg] at (0.25) should be [7.5deg] -PASS Web Animations: property <rotate> from [unset] to [30deg] at (0.75) should be [22.5deg] -PASS Web Animations: property <rotate> from [unset] to [30deg] at (1) should be [30deg] -PASS Web Animations: property <rotate> from [unset] to [30deg] at (2) should be [60deg] -PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (-1) should be [300deg] -PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0) should be [100deg] -PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0.25) should be [50deg] -PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0.75) should be [-50deg] -PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (1) should be [-100deg] -PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (2) should be [-300deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [-100deg] at (-1) should be [300deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [-100deg] at (0) should be [100deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [-100deg] at (0.25) should be [50deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [-100deg] at (0.75) should be [-50deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [-100deg] at (1) should be [-100deg] -PASS CSS Transitions with transition: all: property <rotate> from [100deg] to [-100deg] at (2) should be [-300deg] -PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (-1) should be [300deg] -PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0) should be [100deg] -PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0.25) should be [50deg] -PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0.75) should be [-50deg] -PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (1) should be [-100deg] -PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (2) should be [-300deg] -PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (-1) should be [300deg] -PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0) should be [100deg] -PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0.25) should be [50deg] -PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0.75) should be [-50deg] -PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (1) should be [-100deg] -PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (2) should be [-300deg] -PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (-1) should be [0 1 0 300deg] -PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0) should be [0 1 0 100deg] -PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.25) should be [0 1 0 50deg] -PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.75) should be [0 1 0 -50deg] -PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (1) should be [0 1 0 -100deg] -PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (2) should be [0 1 0 -300deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (-1) should be [0 1 0 300deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0) should be [0 1 0 100deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.25) should be [0 1 0 50deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.75) should be [0 1 0 -50deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (1) should be [0 1 0 -100deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (2) should be [0 1 0 -300deg] -PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (-1) should be [0 1 0 300deg] -PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0) should be [0 1 0 100deg] -PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.25) should be [0 1 0 50deg] -PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.75) should be [0 1 0 -50deg] -PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (1) should be [0 1 0 -100deg] -PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (2) should be [0 1 0 -300deg] -PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (-1) should be [0 1 0 300deg] -PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0) should be [0 1 0 100deg] -PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.25) should be [0 1 0 50deg] -PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.75) should be [0 1 0 -50deg] -PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (1) should be [0 1 0 -100deg] -PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (2) should be [0 1 0 -300deg] -PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (-1) should be [0.22 -0.55 0.8 300deg] -FAIL CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0) should be [0.22 -0.55 0.8 100deg] assert_equals: expected "0.22 - 0.55 0.8 100deg " but got "1 - 2.5 3.64 100deg " -PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.25) should be [0.22 -0.55 0.8 50deg] -PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.75) should be [0.22 -0.55 0.8 -50deg] -FAIL CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (1) should be [0.22 -0.55 0.8 -100deg] assert_equals: expected "0.22 - 0.55 0.8 - 100deg " but got "1 - 2.5 3.64 - 100deg " -PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (2) should be [0.22 -0.55 0.8 -300deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (-1) should be [0.22 -0.55 0.8 300deg] -FAIL CSS Transitions with transition: all: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0) should be [0.22 -0.55 0.8 100deg] assert_equals: expected "0.22 - 0.55 0.8 100deg " but got "1 - 2.5 3.64 100deg " -PASS CSS Transitions with transition: all: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.25) should be [0.22 -0.55 0.8 50deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.75) should be [0.22 -0.55 0.8 -50deg] -FAIL CSS Transitions with transition: all: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (1) should be [0.22 -0.55 0.8 -100deg] assert_equals: expected "0.22 - 0.55 0.8 - 100deg " but got "1 - 2.5 3.64 - 100deg " -PASS CSS Transitions with transition: all: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (2) should be [0.22 -0.55 0.8 -300deg] -PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (-1) should be [0.22 -0.55 0.8 300deg] -FAIL CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0) should be [0.22 -0.55 0.8 100deg] assert_equals: expected "0.22 - 0.55 0.8 100deg " but got "1 - 2.5 3.64 100deg " -PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.25) should be [0.22 -0.55 0.8 50deg] -PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.75) should be [0.22 -0.55 0.8 -50deg] -FAIL CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (1) should be [0.22 -0.55 0.8 -100deg] assert_equals: expected "0.22 - 0.55 0.8 - 100deg " but got "1 - 2.5 3.64 - 100deg " -PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (2) should be [0.22 -0.55 0.8 -300deg] -PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (-1) should be [0.22 -0.55 0.8 300deg] -FAIL Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0) should be [0.22 -0.55 0.8 100deg] assert_equals: expected "0.22 - 0.55 0.8 100deg " but got "1 - 2.5 3.64 100deg " -PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.25) should be [0.22 -0.55 0.8 50deg] -PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.75) should be [0.22 -0.55 0.8 -50deg] -FAIL Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (1) should be [0.22 -0.55 0.8 -100deg] assert_equals: expected "0.22 - 0.55 0.8 - 100deg " but got "1 - 2.5 3.64 - 100deg " -PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (2) should be [0.22 -0.55 0.8 -300deg] -PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (-1) should be [0 1 0 -10deg] -FAIL CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0) should be [0 1 0 0deg] assert_equals: expected "y 0deg " but got "x 0deg " -PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.25) should be [0 1 0 2.5deg] -PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.75) should be [0 1 0 7.5deg] -PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (1) should be [0 1 0 10deg] -PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (2) should be [0 1 0 20deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (-1) should be [0 1 0 -10deg] -FAIL CSS Transitions with transition: all: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0) should be [0 1 0 0deg] assert_equals: expected "y 0deg " but got "x 0deg " -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.25) should be [0 1 0 2.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.75) should be [0 1 0 7.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (1) should be [0 1 0 10deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (2) should be [0 1 0 20deg] -PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (-1) should be [0 1 0 -10deg] -FAIL CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0) should be [0 1 0 0deg] assert_equals: expected "y 0deg " but got "x 0deg " -PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.25) should be [0 1 0 2.5deg] -PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.75) should be [0 1 0 7.5deg] -PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (1) should be [0 1 0 10deg] -PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (2) should be [0 1 0 20deg] -PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (-1) should be [0 1 0 -10deg] -FAIL Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0) should be [0 1 0 0deg] assert_equals: expected "y 0deg " but got "x 0deg " -PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.25) should be [0 1 0 2.5deg] -PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.75) should be [0 1 0 7.5deg] -PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (1) should be [0 1 0 10deg] -PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (2) should be [0 1 0 20deg] -PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (-1) should be [0.67 -0.06 -0.74 124.97deg] -FAIL CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0) should be [0.71 0.71 0 90deg] assert_equals: expected "0.71 0.71 0 90deg " but got "1 1 0 90deg " -PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.25) should be [0.54 0.8 0.26 94.83deg] -PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.75) should be [0.17 0.78 0.61 118.68deg] -FAIL CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (1) should be [0 0.71 0.71 135deg] assert_equals: expected "0 0.71 0.71 135deg " but got "0 1 1 135deg " -PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (2) should be [-0.52 0.29 0.81 208.96deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (-1) should be [0.67 -0.06 -0.74 124.97deg] -FAIL CSS Transitions with transition: all: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0) should be [0.71 0.71 0 90deg] assert_equals: expected "0.71 0.71 0 90deg " but got "1 1 0 90deg " -PASS CSS Transitions with transition: all: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.25) should be [0.54 0.8 0.26 94.83deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.75) should be [0.17 0.78 0.61 118.68deg] -FAIL CSS Transitions with transition: all: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (1) should be [0 0.71 0.71 135deg] assert_equals: expected "0 0.71 0.71 135deg " but got "0 1 1 135deg " -PASS CSS Transitions with transition: all: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (2) should be [-0.52 0.29 0.81 208.96deg] -PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (-1) should be [0.67 -0.06 -0.74 124.97deg] -FAIL CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0) should be [0.71 0.71 0 90deg] assert_equals: expected "0.71 0.71 0 90deg " but got "1 1 0 90deg " -PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.25) should be [0.54 0.8 0.26 94.83deg] -PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.75) should be [0.17 0.78 0.61 118.68deg] -FAIL CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (1) should be [0 0.71 0.71 135deg] assert_equals: expected "0 0.71 0.71 135deg " but got "0 1 1 135deg " -PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (2) should be [-0.52 0.29 0.81 208.96deg] -PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (-1) should be [0.67 -0.06 -0.74 124.97deg] -FAIL Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0) should be [0.71 0.71 0 90deg] assert_equals: expected "0.71 0.71 0 90deg " but got "1 1 0 90deg " -PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.25) should be [0.54 0.8 0.26 94.83deg] -PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.75) should be [0.17 0.78 0.61 118.68deg] -FAIL Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (1) should be [0 0.71 0.71 135deg] assert_equals: expected "0 0.71 0.71 135deg " but got "0 1 1 135deg " -PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (2) should be [-0.52 0.29 0.81 208.96deg] -PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (-1) should be [1 0 0 -450deg] -FAIL CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0) should be [1 0 0 0deg] assert_equals: expected "x 0deg " but got "y 0deg " -PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.25) should be [1 0 0 112.5deg] -PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.75) should be [1 0 0 337.5deg] -PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (1) should be [1 0 0 450deg] -PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (2) should be [1 0 0 900deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (-1) should be [1 0 0 -450deg] -FAIL CSS Transitions with transition: all: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0) should be [1 0 0 0deg] assert_equals: expected "x 0deg " but got "y 0deg " -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.25) should be [1 0 0 112.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.75) should be [1 0 0 337.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (1) should be [1 0 0 450deg] -PASS CSS Transitions with transition: all: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (2) should be [1 0 0 900deg] -PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (-1) should be [1 0 0 -450deg] -FAIL CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0) should be [1 0 0 0deg] assert_equals: expected "x 0deg " but got "y 0deg " -PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.25) should be [1 0 0 112.5deg] -PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.75) should be [1 0 0 337.5deg] -PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (1) should be [1 0 0 450deg] -PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (2) should be [1 0 0 900deg] -PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (-1) should be [1 0 0 -450deg] -FAIL Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0) should be [1 0 0 0deg] assert_equals: expected "x 0deg " but got "y 0deg " -PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.25) should be [1 0 0 112.5deg] -PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.75) should be [1 0 0 337.5deg] -PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (1) should be [1 0 0 450deg] -PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (2) should be [1 0 0 900deg] -PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (-1) should be [1 0 0 900deg] -PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0) should be [1 0 0 450deg] -PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.25) should be [1 0 0 337.5deg] -PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.75) should be [1 0 0 112.5deg] -FAIL CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (1) should be [1 0 0 0deg] assert_equals: expected "x 0deg " but got "y 0deg " -PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (2) should be [1 0 0 -450deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (-1) should be [1 0 0 900deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0) should be [1 0 0 450deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.25) should be [1 0 0 337.5deg] -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.75) should be [1 0 0 112.5deg] -FAIL CSS Transitions with transition: all: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (1) should be [1 0 0 0deg] assert_equals: expected "x 0deg " but got "y 0deg " -PASS CSS Transitions with transition: all: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (2) should be [1 0 0 -450deg] -PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (-1) should be [1 0 0 900deg] -PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0) should be [1 0 0 450deg] -PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.25) should be [1 0 0 337.5deg] -PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.75) should be [1 0 0 112.5deg] -FAIL CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (1) should be [1 0 0 0deg] assert_equals: expected "x 0deg " but got "y 0deg " -PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (2) should be [1 0 0 -450deg] -PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (-1) should be [1 0 0 900deg] -PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0) should be [1 0 0 450deg] -PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.25) should be [1 0 0 337.5deg] -PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.75) should be [1 0 0 112.5deg] -FAIL Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (1) should be [1 0 0 0deg] assert_equals: expected "x 0deg " but got "y 0deg " -PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (2) should be [1 0 0 -450deg] -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/transform-interop/transforms/3d/general/cssmatrix-3d-zoom-expected.png b/third_party/blink/web_tests/virtual/transform-interop/transforms/3d/general/cssmatrix-3d-zoom-expected.png deleted file mode 100644 index a634cd7..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/transforms/3d/general/cssmatrix-3d-zoom-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop/transforms/3d/general/transform-origin-z-change-expected.png b/third_party/blink/web_tests/virtual/transform-interop/transforms/3d/general/transform-origin-z-change-expected.png deleted file mode 100644 index ae64fa91..0000000 --- a/third_party/blink/web_tests/virtual/transform-interop/transforms/3d/general/transform-origin-z-change-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/closure_compiler/README.chromium b/third_party/closure_compiler/README.chromium index 953bae5..dcf5b7e4 100644 --- a/third_party/closure_compiler/README.chromium +++ b/third_party/closure_compiler/README.chromium
@@ -2,7 +2,7 @@ Short Name: closure-compiler URL: http://github.com/google/closure-compiler Version: 20210505.0.0 -Date: 2021/05/19 16:32 +Date: 2021/06/04 10:32 License: Apache 2.0 License File: LICENSE Security Critical: no
diff --git a/third_party/closure_compiler/chromium_patch.diff b/third_party/closure_compiler/chromium_patch.diff index eba343e..94b2487 100644 --- a/third_party/closure_compiler/chromium_patch.diff +++ b/third_party/closure_compiler/chromium_patch.diff
@@ -976,3 +976,131 @@ /** * @const * @see https://developer.chrome.com/apps/syncFileSystem + +diff --git a/third_party/closure_compiler/externs/chrome_extensions.js b/third_party/closure_compiler/externs/chrome_extensions.js +index bd0fd2e51a3bb..12be61c3f581c 100644 +--- a/third_party/closure_compiler/externs/chrome_extensions.js ++++ b/third_party/closure_compiler/externs/chrome_extensions.js +@@ -10607,122 +10607,6 @@ chrome.inlineInstallPrivate = {}; + chrome.inlineInstallPrivate.install = function(id, opt_callback) {}; + + +-/** +- * @see https://cs.chromium.org/chromium/src/chrome/common/extensions/api/input_method_private.json +- */ +-chrome.inputMethodPrivate = {}; +- +-/** +- * @enum {string} +- */ +-chrome.inputMethodPrivate.InputModeType = { +- NO_KEYBOARD: '', +- TEXT: '', +- TEL: '', +- URL: '', +- EMAIL: '', +- NUMERIC: '', +- DECIMAL: '', +- SEARCH: '', +-}; +- +- +-/** +- * @enum {string} +- */ +-chrome.inputMethodPrivate.InputContextType = { +- TEXT: '', +- SEARCH: '', +- TEL: '', +- URL: '', +- EMAIL: '', +- NUMBER: '', +- PASSWORD: '', +-}; +- +- +-/** +- * @enum {string} +- */ +-chrome.inputMethodPrivate.AutoCapitalizeType = { +- OFF: '', +- CHARACTERS: '', +- WORDS: '', +- SENTENCES: '', +-}; +- +- +-/** +- * @enum {string} +- */ +-chrome.inputMethodPrivate.FocusReason = { +- MOUSE: '', +- TOUCH: '', +- PEN: '', +- OTHER: '', +-}; +- +- +-/** @constructor */ +-chrome.inputMethodPrivate.InputContext = function() {}; +- +- +-/** @type {number} */ +-chrome.inputMethodPrivate.InputContext.prototype.contextID; +- +-/** @type {chrome.inputMethodPrivate.InputModeType} */ +-chrome.inputMethodPrivate.InputContext.prototype.mode; +- +-/** @type {chrome.inputMethodPrivate.InputContextType} */ +-chrome.inputMethodPrivate.InputContext.prototype.type; +- +- +-/** @type {boolean} */ +-chrome.inputMethodPrivate.InputContext.prototype.autoCorrect; +- +- +-/** @type {boolean} */ +-chrome.inputMethodPrivate.InputContext.prototype.autoComplete; +- +- +-/** @type {chrome.inputMethodPrivate.AutoCapitalizeType} */ +-chrome.inputMethodPrivate.InputContext.prototype.autoCapitalize; +- +- +-/** @type {boolean} */ +-chrome.inputMethodPrivate.InputContext.prototype.spellCheck; +- +- +-/** @type {boolean} */ +-chrome.inputMethodPrivate.InputContext.prototype.shouldDoLearning; +- +- +-/** @type {chrome.inputMethodPrivate.FocusReason} */ +-chrome.inputMethodPrivate.InputContext.prototype.focusReason; +- +- +-/** @type {boolean} */ +-chrome.inputMethodPrivate.InputContext.prototype.hasBeenPassword; +- +- +-/** +- * Commits the text currently being composed without moving the selected text +- * range. This is a no-op if the context is incorrect. +- * @param {{ +- * contextID: number +- * }} parameters Parameters for the finishComposingText API call. +- * @param {function(): void=} callback Called when the operation completes. +- */ +-chrome.inputMethodPrivate.finishComposingText = function( +- parameters, callback) {}; +- +- +-/** +- * Resets the current engine to its initial state. Fires an OnReset event. +- */ +-chrome.inputMethodPrivate.reset = function() {}; +- +- + /** + * @const + * @see https://goo.gl/7dvJFW
diff --git a/third_party/closure_compiler/externs/chrome_extensions.js b/third_party/closure_compiler/externs/chrome_extensions.js index bd0fd2e..8d26238 100644 --- a/third_party/closure_compiler/externs/chrome_extensions.js +++ b/third_party/closure_compiler/externs/chrome_extensions.js
@@ -2414,6 +2414,33 @@ */ chrome.enterprise.reportingPrivate.getContextInfo = function(callback) {}; + +/** + * Possible states for the Certificate status. + * @enum {number} + */ +chrome.enterprise.reportingPrivate.CertificateStatus = { + OK: 0, + POLICY_UNSET: 1, +}; + +/** + * Type of the object returned by getCertificate. + * @typedef {?{ + * status: chrome.enterprise.reportingPrivate.CertificateStatus, + * encodedCertificate: (!ArrayBuffer|undefined), + * }} + */ +chrome.enterprise.reportingPrivate.Certificate; + +/** + * Returns the certificate object. + * @param {!string} url URL for which certificate needs to be fetched. + * @param {(function(!chrome.enterprise.reportingPrivate.Certificate): void)} + * callback Called back with the response. + */ +chrome.enterprise.reportingPrivate.getCertificate = function(url, callback) {}; + /** * @see https://developer.chrome.com/extensions/extension.html * @const @@ -10608,122 +10635,6 @@ /** - * @see https://cs.chromium.org/chromium/src/chrome/common/extensions/api/input_method_private.json - */ -chrome.inputMethodPrivate = {}; - -/** - * @enum {string} - */ -chrome.inputMethodPrivate.InputModeType = { - NO_KEYBOARD: '', - TEXT: '', - TEL: '', - URL: '', - EMAIL: '', - NUMERIC: '', - DECIMAL: '', - SEARCH: '', -}; - - -/** - * @enum {string} - */ -chrome.inputMethodPrivate.InputContextType = { - TEXT: '', - SEARCH: '', - TEL: '', - URL: '', - EMAIL: '', - NUMBER: '', - PASSWORD: '', -}; - - -/** - * @enum {string} - */ -chrome.inputMethodPrivate.AutoCapitalizeType = { - OFF: '', - CHARACTERS: '', - WORDS: '', - SENTENCES: '', -}; - - -/** - * @enum {string} - */ -chrome.inputMethodPrivate.FocusReason = { - MOUSE: '', - TOUCH: '', - PEN: '', - OTHER: '', -}; - - -/** @constructor */ -chrome.inputMethodPrivate.InputContext = function() {}; - - -/** @type {number} */ -chrome.inputMethodPrivate.InputContext.prototype.contextID; - -/** @type {chrome.inputMethodPrivate.InputModeType} */ -chrome.inputMethodPrivate.InputContext.prototype.mode; - -/** @type {chrome.inputMethodPrivate.InputContextType} */ -chrome.inputMethodPrivate.InputContext.prototype.type; - - -/** @type {boolean} */ -chrome.inputMethodPrivate.InputContext.prototype.autoCorrect; - - -/** @type {boolean} */ -chrome.inputMethodPrivate.InputContext.prototype.autoComplete; - - -/** @type {chrome.inputMethodPrivate.AutoCapitalizeType} */ -chrome.inputMethodPrivate.InputContext.prototype.autoCapitalize; - - -/** @type {boolean} */ -chrome.inputMethodPrivate.InputContext.prototype.spellCheck; - - -/** @type {boolean} */ -chrome.inputMethodPrivate.InputContext.prototype.shouldDoLearning; - - -/** @type {chrome.inputMethodPrivate.FocusReason} */ -chrome.inputMethodPrivate.InputContext.prototype.focusReason; - - -/** @type {boolean} */ -chrome.inputMethodPrivate.InputContext.prototype.hasBeenPassword; - - -/** - * Commits the text currently being composed without moving the selected text - * range. This is a no-op if the context is incorrect. - * @param {{ - * contextID: number - * }} parameters Parameters for the finishComposingText API call. - * @param {function(): void=} callback Called when the operation completes. - */ -chrome.inputMethodPrivate.finishComposingText = function( - parameters, callback) {}; - - -/** - * Resets the current engine to its initial state. Fires an OnReset event. - */ -chrome.inputMethodPrivate.reset = function() {}; - - -/** * @const * @see https://goo.gl/7dvJFW */
diff --git a/third_party/distributed_point_functions/BUILD.gn b/third_party/distributed_point_functions/BUILD.gn new file mode 100644 index 0000000..2d89665 --- /dev/null +++ b/third_party/distributed_point_functions/BUILD.gn
@@ -0,0 +1,53 @@ +# Copyright 2021 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("//testing/libfuzzer/fuzzer_test.gni") +import("//third_party/protobuf/proto_library.gni") + +proto_library("proto") { + sources = [ "src/dpf/distributed_point_function.proto" ] + proto_out_dir = "third_party/distributed_point_functions/dpf" + cc_generator_options = "lite" +} + +if (!defined(dpf_abseil_cpp_dir)) { + dpf_abseil_cpp_dir = "//third_party/abseil-cpp" +} + +config("distributed_point_functions_includes") { + include_dirs = [ + ".", + "src", + "$target_gen_dir", + ] +} + +source_set("distributed_point_functions") { + sources = [ + "glog/logging.h", + "src/dpf/distributed_point_function.cc", + "src/dpf/distributed_point_function.h", + "src/dpf/internal/array_conversions.h", + "src/dpf/internal/pseudorandom_generator.cc", + "src/dpf/internal/pseudorandom_generator.h", + "src/dpf/status_macros.h", + ] + + public_deps = [ + ":proto", + "$dpf_abseil_cpp_dir:absl", + "//third_party/boringssl", + ] + + # Do not apply Chromium code rules to this third-party code. + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + + public_configs = [ ":distributed_point_functions_includes" ] +} + +fuzzer_test("dpf_fuzzer") { + sources = [ "fuzz/dpf_fuzzer.cc" ] + deps = [ ":distributed_point_functions" ] +}
diff --git a/third_party/distributed_point_functions/DIR_METADATA b/third_party/distributed_point_functions/DIR_METADATA new file mode 100644 index 0000000..8d7ede52 --- /dev/null +++ b/third_party/distributed_point_functions/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail: { + component: "Internals>ConversionMeasurement" +}
diff --git a/third_party/distributed_point_functions/LICENSE b/third_party/distributed_point_functions/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/third_party/distributed_point_functions/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/third_party/distributed_point_functions/OWNERS b/third_party/distributed_point_functions/OWNERS new file mode 100644 index 0000000..c35fd95 --- /dev/null +++ b/third_party/distributed_point_functions/OWNERS
@@ -0,0 +1,4 @@ +alexmt@chromium.org +csharrison@chromium.org +# No Chromium committer status: +# linnan@chromium.org
diff --git a/third_party/distributed_point_functions/README.chromium b/third_party/distributed_point_functions/README.chromium new file mode 100644 index 0000000..4032e5b3 --- /dev/null +++ b/third_party/distributed_point_functions/README.chromium
@@ -0,0 +1,23 @@ +Name: The Incremental Distributed Point Functions library +Short Name: distributed_point_functions +URL: https://github.com/google/distributed_point_functions +Version: 0 +Revision: ea175a91e6eda5b22392fdae82080eb9709cd0eb +Date: 2021-04-21 +License: Apache 2.0 +License File: LICENSE +Security Critical: Yes +CPEPrefix: unknown + +Description: +This library contains an implementation of incremental distributed point +functions, based on the paper by Boneh et al. + +Local Modifications: +The directory src/ is an unchanged copy, and parts of +src/dpf/distributed_point_function_test.cc are adapted for fuzzing in +fuzz/dpf_fuzzer.cc. + +The source code pulled in depends on "glog/logging.h" which is not accessible +from chromium. As a workaround, we create a simple glog/logging.h that defines +the macros needed.
diff --git a/third_party/distributed_point_functions/fuzz/dpf_fuzzer.cc b/third_party/distributed_point_functions/fuzz/dpf_fuzzer.cc new file mode 100644 index 0000000..3fc6586 --- /dev/null +++ b/third_party/distributed_point_functions/fuzz/dpf_fuzzer.cc
@@ -0,0 +1,273 @@ +// Copyright 2021 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 "third_party/distributed_point_functions/src/dpf/distributed_point_function.h" + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> + +#include <fuzzer/FuzzedDataProvider.h> + +#include <algorithm> +#include <memory> + +#define DPF_FUZZER_ASSERT(x) \ + if (!(x)) { \ + printf("DPF assertion failed: function %s, file %s, line %d.\n", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + abort(); \ + } + +namespace { + +const size_t UINT128_SIZE = 2 * sizeof(uint64_t); + +// Constructs a `uint128` numeric value from two 64-bit unsigned integers +// consumed from the data provider. +absl::uint128 ConsumeUint128(FuzzedDataProvider& data_provider) { + uint64_t high = data_provider.ConsumeIntegral<uint64_t>(); + uint64_t low = data_provider.ConsumeIntegral<uint64_t>(); + return absl::MakeUint128(high, low); +} + +// Returns the prefix of `index` for the domain of `hierarchy_level`. +// Adapted from `DpfEvaluationTest::GetPrefixForLevel()`. +absl::uint128 GetPrefixForLevel( + int hierarchy_level, + absl::uint128 index, + const std::vector<distributed_point_functions::DpfParameters>& parameters) { + absl::uint128 result = 0; + int shift_amount = parameters.back().log_domain_size() - + parameters[hierarchy_level].log_domain_size(); + if (shift_amount < 128) + result = index >> shift_amount; + return result; +} + +// Evaluates both contexts `ctx0` and `ctx1` at `hierarchy level`, using the +// appropriate prefixes of `evaluation_points`. Checks that the expansion of +// both keys from correct DPF shares, i.e., they add up to +// `beta[ctx.hierarchy_level()]` under prefixes of `alpha`, and to 0 otherwise. +// Adapted from `DpfEvaluationTest::EvaluateAndCheckLevel()`. +template <typename T> +void EvaluateAndCheckLevel( + int hierarchy_level, + absl::Span<const absl::uint128> evaluation_points, + absl::uint128 alpha, + const std::vector<absl::uint128>& beta, + distributed_point_functions::EvaluationContext& ctx0, + distributed_point_functions::EvaluationContext& ctx1, + const std::vector<distributed_point_functions::DpfParameters>& parameters, + const distributed_point_functions::DistributedPointFunction& dpf) { + int previous_hierarchy_level = ctx0.previous_hierarchy_level(); + int current_log_domain_size = parameters[hierarchy_level].log_domain_size(); + int previous_log_domain_size = 0; + int num_expansions = 1; + bool is_first_evaluation = previous_hierarchy_level < 0; + // Generate prefixes if we're not on the first level. + std::vector<absl::uint128> prefixes; + if (!is_first_evaluation) { + num_expansions = static_cast<int>(evaluation_points.size()); + prefixes.resize(evaluation_points.size()); + previous_log_domain_size = + parameters[previous_hierarchy_level].log_domain_size(); + for (int i = 0; i < static_cast<int>(evaluation_points.size()); ++i) + prefixes[i] = GetPrefixForLevel(previous_hierarchy_level, + evaluation_points[i], parameters); + } + + absl::StatusOr<std::vector<T>> result_0 = + dpf.EvaluateUntil<T>(hierarchy_level, prefixes, ctx0); + absl::StatusOr<std::vector<T>> result_1 = + dpf.EvaluateUntil<T>(hierarchy_level, prefixes, ctx1); + DPF_FUZZER_ASSERT(result_0.ok()); + DPF_FUZZER_ASSERT(result_1.ok()); + + DPF_FUZZER_ASSERT(result_0->size() == result_1->size()); + int64_t outputs_per_prefix = + int64_t{1} << (current_log_domain_size - previous_log_domain_size); + int64_t expected_output_size = num_expansions * outputs_per_prefix; + DPF_FUZZER_ASSERT(static_cast<int64_t>(result_0->size()) == + expected_output_size); + + // Iterator over the outputs and check that they sum up to 0 or to + // `beta[current_hierarchy_level]`; + absl::uint128 previous_alpha_prefix = 0; + if (!is_first_evaluation) + previous_alpha_prefix = + GetPrefixForLevel(previous_hierarchy_level, alpha, parameters); + + absl::uint128 current_alpha_prefix = + GetPrefixForLevel(hierarchy_level, alpha, parameters); + for (int64_t i = 0; i < expected_output_size; ++i) { + int prefix_index = i / outputs_per_prefix; + int prefix_expansion_index = i % outputs_per_prefix; + // The output is on the path to `alpha`, if we're at the first level or + // under a prefix of `alpha`, and the current block in the expansion of the + // prefix is also on the path to `alpha`. + if ((is_first_evaluation || + prefixes[prefix_index] == previous_alpha_prefix) && + prefix_expansion_index == (current_alpha_prefix % outputs_per_prefix)) { + // We need to static_cast here since otherwise separator+ returns an + // unsigned int without doing a modular reduction, which causes the test + // to fail on types with sizeof(T) < sizeof(unsigned). + DPF_FUZZER_ASSERT(static_cast<T>((*result_0)[i] + (*result_1)[i]) == + beta[hierarchy_level]); + } else { + DPF_FUZZER_ASSERT(static_cast<T>((*result_0)[i] + (*result_1)[i]) == 0U); + } + } +} + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Use magic separator to split the input into two parts. The first part will + // generate alpha, and an array of parameters and betas. The second part will + // generate level step and an array of evaluation points. + const uint8_t separator[] = {0xDE, 0xAD, 0xBE, 0xEF}; + + const uint8_t* pos = + std::search(data, data + size, separator, separator + sizeof(separator)); + + const uint8_t* data1 = data; + size_t size1 = pos - data; + + const uint8_t* data2 = + (pos == data + size) ? nullptr : pos + sizeof(separator); + size_t size2 = data2 ? (data + size) - (pos + sizeof(separator)) : 0; + + FuzzedDataProvider data_provider1(data1, size1); + + if (data_provider1.remaining_bytes() < UINT128_SIZE) + return 0; + + absl::uint128 alpha = ConsumeUint128(data_provider1); + + std::vector<int32_t> log_domain_sizes; + std::vector<int32_t> element_bitsizes; + std::vector<distributed_point_functions::DpfParameters> parameters; + std::vector<absl::uint128> beta; + + // log_domain_size(int32_t), element_bitsize(int32_t), + // beta(uint128) + while (data_provider1.remaining_bytes() >= + (2 * sizeof(int32_t) + UINT128_SIZE)) { + int32_t log_domain_size = data_provider1.ConsumeIntegral<int32_t>(); + int32_t element_bitsize = data_provider1.ConsumeIntegral<int32_t>(); + log_domain_sizes.push_back(log_domain_size); + element_bitsizes.push_back(element_bitsize); + + distributed_point_functions::DpfParameters parameter; + parameter.set_log_domain_size(log_domain_size); + parameter.set_element_bitsize(element_bitsize); + parameters.push_back(parameter); + + beta.push_back(ConsumeUint128(data_provider1)); + } + + absl::StatusOr< + std::unique_ptr<distributed_point_functions::DistributedPointFunction>> + status_or_dpf = distributed_point_functions::DistributedPointFunction:: + CreateIncremental(parameters); + + size_t num_levels = parameters.size(); + + if (!status_or_dpf.ok()) { + // `log_domain_size` is expected to be in ascending order and + // `element_bitsize` is expected to be non-decreasing. As it is hard for the + // fuzzer to land upon a valid input, we sort the parameters and try again + // if the construction fails. + std::sort(log_domain_sizes.begin(), log_domain_sizes.end()); + std::sort(element_bitsizes.begin(), element_bitsizes.end()); + for (size_t i = 0; i < num_levels; ++i) { + parameters[i].set_log_domain_size(log_domain_sizes[i]); + parameters[i].set_element_bitsize(element_bitsizes[i]); + } + + status_or_dpf = distributed_point_functions::DistributedPointFunction:: + CreateIncremental(parameters); + } + + if (!status_or_dpf.ok()) + return 0; + + std::unique_ptr<distributed_point_functions::DistributedPointFunction> dpf = + std::move(status_or_dpf).value(); + + absl::StatusOr<std::pair<distributed_point_functions::DpfKey, + distributed_point_functions::DpfKey>> + status_or_keys = dpf->GenerateKeysIncremental(alpha, beta); + if (!status_or_keys.ok()) + return 0; + + std::pair<distributed_point_functions::DpfKey, + distributed_point_functions::DpfKey> + keys = std::move(status_or_keys).value(); + + // Adapted from `DpfEvaluationTest.TestCorrectness()`. + absl::StatusOr<distributed_point_functions::EvaluationContext> + status_or_ctx0 = dpf->CreateEvaluationContext(keys.first); + DPF_FUZZER_ASSERT(status_or_ctx0.ok()); + + absl::StatusOr<distributed_point_functions::EvaluationContext> + status_or_ctx1 = dpf->CreateEvaluationContext(keys.second); + DPF_FUZZER_ASSERT(status_or_ctx1.ok()); + + distributed_point_functions::EvaluationContext ctx0 = + std::move(status_or_ctx0).value(); + distributed_point_functions::EvaluationContext ctx1 = + std::move(status_or_ctx1).value(); + + // Generate evaluation points. + FuzzedDataProvider data_provider2(data2, size2); + if (data_provider2.remaining_bytes() < sizeof(int)) + return 0; + + int level_step = data_provider2.ConsumeIntegralInRange<int>(1, 10); + + std::vector<absl::uint128> evaluation_points; + while (data_provider2.remaining_bytes() >= UINT128_SIZE) { + evaluation_points.push_back(ConsumeUint128(data_provider2)); + if (parameters.back().log_domain_size() < 128) + evaluation_points.back() %= + (absl::uint128{1} << parameters.back().log_domain_size()); + } + + // Always evaluate on alpha. + evaluation_points.push_back(alpha); + + for (int i = level_step - 1; i < static_cast<int>(num_levels); + i += level_step) { + switch (parameters[i].element_bitsize()) { + case 8: + EvaluateAndCheckLevel<uint8_t>(i, evaluation_points, alpha, beta, ctx0, + ctx1, parameters, *dpf); + break; + case 16: + EvaluateAndCheckLevel<uint16_t>(i, evaluation_points, alpha, beta, ctx0, + ctx1, parameters, *dpf); + break; + case 32: + EvaluateAndCheckLevel<uint32_t>(i, evaluation_points, alpha, beta, ctx0, + ctx1, parameters, *dpf); + break; + case 64: + EvaluateAndCheckLevel<uint64_t>(i, evaluation_points, alpha, beta, ctx0, + ctx1, parameters, *dpf); + break; + case 128: + EvaluateAndCheckLevel<absl::uint128>(i, evaluation_points, alpha, beta, + ctx0, ctx1, parameters, *dpf); + break; + default: + // DPF construction should've failed if the parameters were invalid. + DPF_FUZZER_ASSERT(false); + break; + } + } + + return 0; +}
diff --git a/third_party/distributed_point_functions/glog/logging.h b/third_party/distributed_point_functions/glog/logging.h new file mode 100644 index 0000000..3f0fe1b2 --- /dev/null +++ b/third_party/distributed_point_functions/glog/logging.h
@@ -0,0 +1,31 @@ +// Copyright 2021 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 THIRD_PARTY_DISTRIBUTED_POINT_FUNCTIONS_GLOG_LOGGING_H_ +#define THIRD_PARTY_DISTRIBUTED_POINT_FUNCTIONS_GLOG_LOGGING_H_ + +#include <stdlib.h> + +#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) +#define DCHECK_IS_ON() false +#else +#define DCHECK_IS_ON() true +#endif + +#if DCHECK_IS_ON() + +#define DCHECK(condition) \ + if (!(condition)) { \ + printf("Check failed: function %s, file %s, line %d.\n", \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + abort(); \ + } + +#else + +#define DCHECK(condition) (void)(condition) + +#endif + +#endif // THIRD_PARTY_DISTRIBUTED_POINT_FUNCTIONS_GLOG_LOGGING_H_
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium index 68bf3e2..e553cc28 100644 --- a/third_party/harfbuzz-ng/README.chromium +++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,10 +1,10 @@ Name: harfbuzz-ng Short Name: harfbuzz-ng URL: http://harfbuzz.org -Version: 2.8.1-30 -CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:2.6.4 -Date: 20210602 -Revision: 7ab0f4eda9a8a1d7ccd334fa7f9fef4b038a1c24 +Version: 2.8.1-45 +CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:2.8.1 +Date: 20210607 +Revision: 4811e8f5d76ef528b4cec00f241cc4ab8110db30 Security Critical: yes License: MIT License File: src/COPYING
diff --git a/third_party/harfbuzz-ng/roll-harfbuzz.sh b/third_party/harfbuzz-ng/roll-harfbuzz.sh index 8a86a34..635f33f 100755 --- a/third_party/harfbuzz-ng/roll-harfbuzz.sh +++ b/third_party/harfbuzz-ng/roll-harfbuzz.sh
@@ -3,17 +3,20 @@ rolldeps() { STEP="roll-deps" && REVIEWERS=$(grep -E -v "^$|#" third_party/harfbuzz-ng/OWNERS | paste -s -d, -) && - roll-dep -r "${REVIEWERS}" --roll-to origin/upstream/master "$@" src/third_party/harfbuzz-ng/src/ + roll-dep -r "${REVIEWERS}" --roll-to origin/upstream/main "$@" src/third_party/harfbuzz-ng/src/ } updatereadme() { STEP="update README.chromium" && - HBVERSION=$(git -C third_party/harfbuzz-ng/src/ describe --long) && - HBCOMMIT=$(git -C third_party/harfbuzz-ng/src/ rev-parse HEAD) && - HBDATE=$(date "+%Y%m%d") - sed -i'' -e "s/^Version: .*\$/Version: ${HBVERSION%-*}/" third_party/harfbuzz-ng/README.chromium && - sed -i'' -e "s/^Revision: .*\$/Revision: ${HBCOMMIT}/" third_party/harfbuzz-ng/README.chromium && - sed -i'' -e "s/^Date: .*\$/Date: ${HBDATE}/" third_party/harfbuzz-ng/README.chromium && + HB_VERSION=$(git -C third_party/harfbuzz-ng/src/ describe --long) && + HB_COMMIT=$(git -C third_party/harfbuzz-ng/src/ rev-parse HEAD) && + HB_DATE=$(date "+%Y%m%d") + HB_CPE_VERSION=$(echo ${HB_VERSION} | sed -r -e's/^([0-9]+)\.([0-9]+)\.([0-9]+)-[0-9]+-g[0-9a-f]+$/\1.\2.\3/') && + [ ${HB_VERSION} != ${HB_CPE_VERSION} ] && + sed -i'' -e "s/^Version: .*\$/Version: ${HB_VERSION%-*}/" third_party/harfbuzz-ng/README.chromium && + sed -i'' -e "s@^CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:.*\$@CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:${HB_CPE_VERSION}@" third_party/harfbuzz-ng/README.chromium && + sed -i'' -e "s/^Revision: .*\$/Revision: ${HB_COMMIT}/" third_party/harfbuzz-ng/README.chromium && + sed -i'' -e "s/^Date: .*\$/Date: ${HB_DATE}/" third_party/harfbuzz-ng/README.chromium && git add third_party/harfbuzz-ng/README.chromium } @@ -23,8 +26,8 @@ } check_added_deleted_files() { - STEP="Check for added or deleted files since last HarfBuzz revision" && previousrev && + STEP="Check for added or deleted files since last HarfBuzz revision" && ADDED_FILES=$(git -C third_party/harfbuzz-ng/src/ diff --diff-filter=A --name-only ${PREVIOUS_HARFBUZZ_REV} -- src/ | paste -s -d, -) && DELETED_FILES=$(git -C third_party/harfbuzz-ng/src/ diff --diff-filter=D --name-only ${PREVIOUS_HARFBUZZ_REV} -- src/ | paste -s -d, -) && RENAMED_FILES=$(git -C third_party/harfbuzz-ng/src/ diff --diff-filter=R --name-only ${PREVIOUS_HARFBUZZ_REV} -- src/ | paste -s -d, -) &&
diff --git a/third_party/wpt_tools/README.chromium b/third_party/wpt_tools/README.chromium index 49b73cf9..c6c54e1e 100644 --- a/third_party/wpt_tools/README.chromium +++ b/third_party/wpt_tools/README.chromium
@@ -1,7 +1,7 @@ Name: web-platform-tests - Test Suites for Web Platform specifications Short Name: wpt URL: https://github.com/web-platform-tests/wpt/ -Version: 95eeb247a0820c5b253d32f5e1888c27afe4d9fd +Version: 405a6ef4c1d4ef4f3dc3d6c41cad768b01bda099 License: LICENSES FOR W3C TEST SUITES (https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html) License File: NOT_SHIPPED Security Critical: no
diff --git a/third_party/wpt_tools/WPTIncludeList b/third_party/wpt_tools/WPTIncludeList index f176973..b58382a 100644 --- a/third_party/wpt_tools/WPTIncludeList +++ b/third_party/wpt_tools/WPTIncludeList
@@ -144,7 +144,7 @@ ./tools/third_party/pywebsocket3/mod_pywebsocket/dispatch.py ./tools/third_party/pywebsocket3/mod_pywebsocket/extensions.py ./tools/third_party/pywebsocket3/mod_pywebsocket/fast_masking.i -./tools/third_party/pywebsocket3/mod_pywebsocket/handshake/_base.py +./tools/third_party/pywebsocket3/mod_pywebsocket/handshake/base.py ./tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py ./tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py ./tools/third_party/pywebsocket3/mod_pywebsocket/http_header_util.py
diff --git a/third_party/wpt_tools/checkout.sh b/third_party/wpt_tools/checkout.sh index 5f018c7..c6a75bb 100755 --- a/third_party/wpt_tools/checkout.sh +++ b/third_party/wpt_tools/checkout.sh
@@ -9,7 +9,7 @@ TARGET_DIR=$DIR/wpt REMOTE_REPO="https://github.com/web-platform-tests/wpt.git" -WPT_HEAD=95eeb247a0820c5b253d32f5e1888c27afe4d9fd +WPT_HEAD=405a6ef4c1d4ef4f3dc3d6c41cad768b01bda099 function clone { # Remove existing repo if already exists.
diff --git a/third_party/wpt_tools/wpt/tools/certs/cacert.key b/third_party/wpt_tools/wpt/tools/certs/cacert.key index 4356414..d59a66a 100644 --- a/third_party/wpt_tools/wpt/tools/certs/cacert.key +++ b/third_party/wpt_tools/wpt/tools/certs/cacert.key
@@ -1,30 +1,30 @@ -----BEGIN ENCRYPTED PRIVATE KEY----- -MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQItVjQV4WbinACAggA -MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECIHphsNo/i2uBIIEyJZ5kb44jJoP -ewq1ZHjhOO9DG9KNtVG9Qa6PnEdssR79Z5LW9G5Rgdrg5Gekv+8tKd+INneG0n++ -JgW7kzwYJobe3htUrcjmQpv4J5bkjAvNyfWoRg/6oGsk3p85ZylqMBI0ZEUeI90A -RgUecyEXoUzR7KemkfIOAlXgETTaHCEUs5mNVUTrLBolK53Xq60Y3LO9JyzKDSi9 -bVAOLLwqzgVjhO8QQ6JFutfUKsI/Yxf4M+ZpT0ebtwKdVVUbmPIw6iNzXVPbUigS -Gy/M8gfpmrD/CIC5wjfzgst3bctnGfoC4wiU/nnAEomSp6BWFa6VsQV1H+Z0Umu5 -I3Mjm9h7tdv+JRn4zNrEqak+br31uvtl62EJ6emMG14/Nz2CP5bSiwiaUqdvvx6c -DGojuFQfk4C5vKJxtm9WB7+Mr5NtSesylMPHQtWDeH41Csm+SDtP01/uhnXKSDXn -xZrC51jwNFDPL4qMpVXFfFZna2OdiPi5nxOOJtLip9FqrvrhwfbrnyTusu0ZbCDk -VGtxtSkpsPVHpcuMx/xOjwXvDQk9IbGVGkuJHsjYL1SuWmPajWY6gfdaC1AgXH7d -gkt3VukqrD4/CBQPiVABejLRKwX7EmJnsXPRZ4QGTKf3SCz3UCPH0AvbF/cR8brR -aPlizCYTLhoEERNyAjl+qqEzlF1+IMTw0hYIBtRMiI6UTLI6dP12O/YbvBL9pk4S -MizOPFgbh4iyAyH1F4LPEp0vgc0gCOGESkuL4s3mte4MZklCtN7egpec7U464aZb -1bbuVrPX7w2k31s0Ha9C9uLJne38lQzkiKABlNy2JDXdUQkaUYJ7mP7+/mdKqEGh -mlh29g+x4gJHcMjagoye3x4Q+tm8tGPJOtqG4OKidNhNLkUEaX/zQ76PiMiUDHZF -uGJqSgX9UrTL7D0MeIh7+oc1V9t0oqrtRxuTi9FEs08WJh7hXBNrGFWGCs5rhzXm -B29wu+eAy2eIYz/fS2GtzKYjYQkhxP0yLnWO4eir0ghYJG32YrZItMRubgAkeMZD -Xyr9tst1WgFg7uBEDoe/GMm+I9THpc2Ynk/F0npUU7r+SkAm5R7084IwVBF3qjG7 -4RyJcrlTihXpuLRS4MiNY0BqPG6n0UTjKyP1Zm0ibCE7Ff0wNOXtJzI/V6dfE+4k -JRXRdpnesAXvGeh/3N1gSTH5U8n69YwKPhzuZskki8qVZYktYhS4U5rEbU86Dc5v -R37IUqvI4nyt05u6KtruZ7Oh7f+6ydmBJAxPbI8L0y7SQXgRpE18l6cnEvqMlPxd -z1whxpSaw6cGjN6YHPWAdGsaisAZKlA+6XbJ+mE+VOANoqPwXrUXY/DboAh9skv/ -Qhecr+MoJwYKPtQMc4Nj4BeecMeqTcsBYhkUrGi3jKYyEChudz9K9Cfp+oSu9/AN -GMZHG5ARorJh5Tq88McYXvvkjW8n9rwmsr5xZejIo25ZTXtmjkuy8g0V1gIrTsaq -rWuWMDqE03IVis4yfEHoSrMwxyxLpUYkzOoZctrasbviQD23Ln8tRnBGr6lk/Qzw -4ePLiYVAammSL+JTxmGX1fgdysJP0DUmMUF7a381HA1v7TI3XriuFSgZ4tuGz7J0 -cityk2PRDRYX8IsB4lzWlg== +MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIxOlV7Of4orwCAggA +MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECLxNe3CZvv7xBIIEyHAUFpNVFUtX +YfGhv/MBkAxqTSECYD+cdiKw6A5BRqnYroIv2JxrCl3Ziv6x7j0dqmGN8rCI/63c +KMeQS7f/dXn698vl/7A23dXEq2ckeNEk7LqMhs6OLw7GxoNjCgnCWQFte8i1TskE +YHW7Mf6078ox7i+FKR6gSBm9OXtCCLuYglZXt44FY6ND0wrYYH2Dcb+Y1emhNMxP +gca24ahGWbxZ2CEbzoF8XMI/xLXxdr8w90/3CrkOnkseEs/Yor1gOZOsIBfmDMMJ +6D06R7CcM/2hUby5+Ma2syqZ9WxfAUItRZ5cx7kdtDWvfmc0qPnW12M4E1CZPLLD +bhx7vCAbYzQYuLUYg/wR2Ez5DtBsfWhtoaJiSPGp2HzQvOpBiHvoyO4dvons5Py2 ++eYZxT9KCRk3TNxQ7rFQDc4DJiQ6CMyrp3zeOmXmFkevadmyAVhnL8wRcpuHhMBT +VCJit9FGtG7hP2MoPFS1TsWoOb3FdButp6sMmVGnOoET8E9xt6cF7j6aJEADbUMY +jg/8jNyE/C3e+IVNlHAwnqCQxgKHYVSNoEJssbG+DtrdM6IDp6/Tq2ACHyFHArXi +0dh3DMBiNI0sYjU0PD5lCS+WqUyeWA+wqW5CyK5Ex3DzXdJ3ZYX8JdlxE4TaX5Om +i5Svzzome2YFZ6bJKQjeOi8Me3B7gld6ej/VpH0JJfNJDUgqisAg3v9Y6cRo6Us4 +wq+SLk1Ki7lQNE9ED3QdmGEBcMoqPtybC5M0N7BclhrlBPpZBiWjhXSzRMgYdAGm +yzsr0rQYbbdMDOklFQPpl7AG0lPJi3N5EfUqzIX8xIf9MqZDIk8DI8VGI8NqMsFW +cLtQ6D/73QoxQ+9lbPpQNLGkdNaSGc3n1SKfLc9uGwlPCSsFsgmQDSKJvNTfVorb +2u2UHELKl20jNay0CbsWsqcFhZGH3ZXUKg3/OfY1BqClrxy3IUyB2hfJEOEqYBjT +5MB4pUh84yqGC++FM+4bfTd6NHnoZbFRM8KEhYEM9x/1zDHIJ9j+/r8ZfhZ6vOoj +gyvTY7nZ3keoHA631Jumk9wCIeWfv9jxdYc8TBj0N8i8GXoEfnOu7uZLLTDtgGu4 +jL0bM0IednEYq+AOE88LuLyTzu1defHiZ4Ae4aEoem+ukigwO5GeSsO9pQoPlaxV +S0MyMBv5JQYdPbHAhPuCyNfxQFu/bl/tRgdqPxgZoDh1lfGnrVClzm5OViYusFdK +qJsqY/DbfJld1DDlIYmKFw+ojXJ8fY4/4gQtD37Hxu1NpDShGL5XDWzDqGkeQurl +JopDTU5NMBOV+lEyX/lRQCpkNi1PXLoXa5Idp47fAmMBm8Suvh8aph6dc9+6BDPi +J+ElN5l8W3dAULiWq8WpjUM4sJ0Te4vRuo+y8DYYTuAjg/kYPgLywxO0GN0cMRjm +K2raf7A5MbuxHTDNXEIkOXTbiwvtReS2H6c6z/IcAze8tf4xTkFyjohOL9n0fwo/ +RXxuZdRjU2D7dpGcUu2iADQaJgYXiOBWbE/GUCOLfMS75MM8us+uozuhVpoNubI+ +cC9SsgqvcZaWiL3uHQy3amsYJVuC2nf4Io73Gz+VeuwPDE/8gpzwtrn5ZN5FPo+B +yeqAS6n9N+wcZ0nd3b/b4A== -----END ENCRYPTED PRIVATE KEY-----
diff --git a/third_party/wpt_tools/wpt/tools/certs/cacert.pem b/third_party/wpt_tools/wpt/tools/certs/cacert.pem index 01dfb45..fd769ed 100644 --- a/third_party/wpt_tools/wpt/tools/certs/cacert.pem +++ b/third_party/wpt_tools/wpt/tools/certs/cacert.pem
@@ -1,176 +1,176 @@ -----BEGIN CERTIFICATE----- -MIJAhzCCP2+gAwIBAgIDCOc6MA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl -Yi1wbGF0Zm9ybS10ZXN0czAeFw0yMTA0MTIwMjMzNDhaFw0yMjA0MTIwMjMzNDha +MIJAhzCCP2+gAwIBAgIDBe8IMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl +Yi1wbGF0Zm9ybS10ZXN0czAeFw0yMTA1MTIwMDAzMjRaFw0yMjA1MTIwMDAzMjRa MB0xGzAZBgNVBAMMEndlYi1wbGF0Zm9ybS10ZXN0czCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAOEa4D3gQxyaGbz3Rich5W0Jr03n45AkRaqTyrtIdh9v -5kQ7fDegUZbSc41ReQbdwd2LbWX0+KzYX502BJg9qs3GqPVQRIxBoKmSHAWLujfi -JPsG3d1/x2POnpivLWE/B+rTHH9sKPwpfv6iUsOB8K2eiQnKfxQlTM0Qxt2Dh8Pc -uYiu5/38eNlvzJCpobEO9YNiFKLTdYkWoZJHhAph4OoCJYq1cvdqSr4XHd+35w+y -TBwDG0wAdXOOT9AXZqnufm4pyU7MoXIMMagdVLMNRBKK4AUhG/1PbOGCt3wIFZNv -T25Nxp2MWrw81a9HWtOqu+Mjnkv1JWoixCCY/FMLkysCAwEAAaOCPc4wgj3KMAwG -A1UdEwQFMAMBAf8wHQYDVR0OBBYEFNMMT+Yh7QefIxGME/HAXRQJsCQyMEcGA1Ud -IwRAMD6AFNMMT+Yh7QefIxGME/HAXRQJsCQyoSGkHzAdMRswGQYDVQQDDBJ3ZWIt -cGxhdGZvcm0tdGVzdHOCAwjnOjALBgNVHQ8EBAMCAgQwgh+bBgNVHR4Egh+SMIIf -jqCCH4owE4IRd2ViLXBsYXRmb3JtLnRlc3QwF4IVb3AxLndlYi1wbGF0Zm9ybS50 -ZXN0MBeCFW5vdC13ZWItcGxhdGZvcm0udGVzdDAXghVvcDkud2ViLXBsYXRmb3Jt -LnRlc3QwF4IVb3AzLndlYi1wbGF0Zm9ybS50ZXN0MBeCFW9wNC53ZWItcGxhdGZv -cm0udGVzdDAXghVvcDgud2ViLXBsYXRmb3JtLnRlc3QwF4IVb3A3LndlYi1wbGF0 -Zm9ybS50ZXN0MBeCFW9wNS53ZWItcGxhdGZvcm0udGVzdDAXghV3d3cud2ViLXBs -YXRmb3JtLnRlc3QwF4IVb3A2LndlYi1wbGF0Zm9ybS50ZXN0MBeCFW9wMi53ZWIt -cGxhdGZvcm0udGVzdDAYghZvcDQ3LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzMu -d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxNy53ZWItcGxhdGZvcm0udGVzdDAYghZv -cDcwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFnd3dzEud2ViLXBsYXRmb3JtLnRlc3Qw -GIIWb3A0MC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDM2LndlYi1wbGF0Zm9ybS50 -ZXN0MBiCFm9wMTIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4MC53ZWItcGxhdGZv -cm0udGVzdDAYghZvcDkwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNjUud2ViLXBs -YXRmb3JtLnRlc3QwGIIWb3AyMC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDkyLndl -Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNjIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A3 -Ni53ZWItcGxhdGZvcm0udGVzdDAYghZvcDE5LndlYi1wbGF0Zm9ybS50ZXN0MBiC -Fm9wNDIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AzOS53ZWItcGxhdGZvcm0udGVz -dDAYghZvcDI5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTUud2ViLXBsYXRmb3Jt -LnRlc3QwGIIWb3A4Ni53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQxLndlYi1wbGF0 -Zm9ybS50ZXN0MBiCFm9wOTEud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AzMy53ZWIt -cGxhdGZvcm0udGVzdDAYghZvcDI1LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNDQu -d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxMy53ZWItcGxhdGZvcm0udGVzdDAYghZv -cDE1LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wOTcud2ViLXBsYXRmb3JtLnRlc3Qw -GIIWb3A2NC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQ4LndlYi1wbGF0Zm9ybS50 -ZXN0MBiCFm9wOTgud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2My53ZWItcGxhdGZv -cm0udGVzdDAYghZvcDEwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wODIud2ViLXBs -YXRmb3JtLnRlc3QwGIIWb3A1Ni53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQzLndl -Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNDkud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1 -My53ZWItcGxhdGZvcm0udGVzdDAYghZvcDc0LndlYi1wbGF0Zm9ybS50ZXN0MBiC -Fm9wODgud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A5NS53ZWItcGxhdGZvcm0udGVz -dDAYghZvcDYxLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTYud2ViLXBsYXRmb3Jt -LnRlc3QwGIIWb3A4Ny53ZWItcGxhdGZvcm0udGVzdDAYghZvcDY3LndlYi1wbGF0 -Zm9ybS50ZXN0MBiCFm9wMjQud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AyNi53ZWIt -cGxhdGZvcm0udGVzdDAYghZvcDk0LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjgu -d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4My53ZWItcGxhdGZvcm0udGVzdDAYghZ3 -d3cyLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzgud2ViLXBsYXRmb3JtLnRlc3Qw -GIIWb3A4OS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQ1LndlYi1wbGF0Zm9ybS50 -ZXN0MBiCFm9wOTMud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4NS53ZWItcGxhdGZv -cm0udGVzdDAYghZvcDgxLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNjYud2ViLXBs -YXRmb3JtLnRlc3QwGIIWb3A5OS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDU0Lndl -Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzgud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3Ay -My53ZWItcGxhdGZvcm0udGVzdDAYghZvcDcyLndlYi1wbGF0Zm9ybS50ZXN0MBiC -Fm9wNjAud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AzNS53ZWItcGxhdGZvcm0udGVz -dDAYghZvcDUwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTEud2ViLXBsYXRmb3Jt -LnRlc3QwGIIWb3AzMi53ZWItcGxhdGZvcm0udGVzdDAYghZvcDE4LndlYi1wbGF0 -Zm9ybS50ZXN0MBiCFm9wNTgud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AyNy53ZWIt -cGxhdGZvcm0udGVzdDAYghZvcDMwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTku -d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4NC53ZWItcGxhdGZvcm0udGVzdDAYghZv -cDY4LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzkud2ViLXBsYXRmb3JtLnRlc3Qw -GIIWb3A3NS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDcxLndlYi1wbGF0Zm9ybS50 -ZXN0MBiCFm9wMzcud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1Mi53ZWItcGxhdGZv -cm0udGVzdDAYghZvcDIxLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNDYud2ViLXBs -YXRmb3JtLnRlc3QwGIIWb3A1Ny53ZWItcGxhdGZvcm0udGVzdDAYghZvcDc3Lndl -Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNjkud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3Az -MS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDE0LndlYi1wbGF0Zm9ybS50ZXN0MBiC -Fm9wOTYud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxMS53ZWItcGxhdGZvcm0udGVz -dDAYghZvcDM0LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjIud2ViLXBsYXRmb3Jt -LnRlc3QwG4IZb3AzLm5vdC13ZWItcGxhdGZvcm0udGVzdDAbghlvcDkubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0MBuCGXd3dy53d3cud2ViLXBsYXRmb3JtLnRlc3QwG4IZ -b3A0Lm5vdC13ZWItcGxhdGZvcm0udGVzdDAbghlvcDgubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MBuCGW9wNi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZb3AyLm5vdC13 -ZWItcGxhdGZvcm0udGVzdDAbghlvcDUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MBuC -GW9wNy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZd3d3Lm5vdC13ZWItcGxhdGZv -cm0udGVzdDAbghlvcDEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTcubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wNjIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTUubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wNDcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -MTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzQubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wNzMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjAubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wOTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODAubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wNDAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -MjIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzIubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wNjcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODgubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODMubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wMTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzEubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wMTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -OTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzgubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wMzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzEubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wNjQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjkubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGnd3dy53d3cxLndlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -MzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTUubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wNzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTQubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzIud3d3LndlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wNDkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTMubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wNDUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -ODUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTEubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wNjYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODEubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjUubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wOTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjUubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wMTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -MjMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzMubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wMzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODkubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODQubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wMzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjEubm90LXdlYi1w +BQADggEPADCCAQoCggEBALvx+aj1vuvoGstEdLMdXSr6g4uDNAKmTCS9ONIXgZ34 +EEIE7Ec1B1g0p/FBqh8wHWy5dYdsgkm5bzItRltws40dPnA208ic8783suMtWIVL +KKo36SCyfyJ+Z1/fhoaesrTYLGJ20qKQuc+z0aHsGkH0U9G2eYtw9Ehi+zz5yHV+ ++Q47Ymq9tygotJSEmgxPxF0a8cA2JmHXYfli54XfWaz5ummeBjJobCNFjQ4mFg2g +VkUDf4aB/+hAtdHZjWW3XaiDG2+VgAtkzhnIo3XXNW/M5Ao0XKV1/wP7eEMUQcbW +Q0IfzFv9Qh2owUZyci4O6V/H0HrIAdCO/XHeiKlB5HkCAwEAAaOCPc4wgj3KMAwG +A1UdEwQFMAMBAf8wHQYDVR0OBBYEFKmUHv3fwFPTratfEyj/xckEnAG5MEcGA1Ud +IwRAMD6AFKmUHv3fwFPTratfEyj/xckEnAG5oSGkHzAdMRswGQYDVQQDDBJ3ZWIt +cGxhdGZvcm0tdGVzdHOCAwXvCDALBgNVHQ8EBAMCAgQwgh+bBgNVHR4Egh+SMIIf +jqCCH4owE4IRd2ViLXBsYXRmb3JtLnRlc3QwF4IVb3AzLndlYi1wbGF0Zm9ybS50 +ZXN0MBeCFW9wOS53ZWItcGxhdGZvcm0udGVzdDAXghVvcDUud2ViLXBsYXRmb3Jt +LnRlc3QwF4IVb3A3LndlYi1wbGF0Zm9ybS50ZXN0MBeCFW9wMi53ZWItcGxhdGZv +cm0udGVzdDAXghVub3Qtd2ViLXBsYXRmb3JtLnRlc3QwF4IVb3A2LndlYi1wbGF0 +Zm9ybS50ZXN0MBeCFW9wMS53ZWItcGxhdGZvcm0udGVzdDAXghVvcDQud2ViLXBs +YXRmb3JtLnRlc3QwF4IVd3d3LndlYi1wbGF0Zm9ybS50ZXN0MBeCFW9wOC53ZWIt +cGxhdGZvcm0udGVzdDAYghZvcDU3LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wOTMu +d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A0OS53ZWItcGxhdGZvcm0udGVzdDAYghZv +cDEzLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjQud2ViLXBsYXRmb3JtLnRlc3Qw +GIIWb3AxNC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDM1LndlYi1wbGF0Zm9ybS50 +ZXN0MBiCFm9wOTEud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A5Mi53ZWItcGxhdGZv +cm0udGVzdDAYghZvcDQ4LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzQud2ViLXBs +YXRmb3JtLnRlc3QwGIIWb3AzMS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDcwLndl +Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzEud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4 +MS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDM3LndlYi1wbGF0Zm9ybS50ZXN0MBiC +Fm9wODYud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A3NS53ZWItcGxhdGZvcm0udGVz +dDAYghZvcDY5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzYud2ViLXBsYXRmb3Jt +LnRlc3QwGIIWb3A3OC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDMwLndlYi1wbGF0 +Zm9ybS50ZXN0MBiCFm9wMTkud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxNS53ZWIt +cGxhdGZvcm0udGVzdDAYghZvcDQ2LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTIu +d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2MC53ZWItcGxhdGZvcm0udGVzdDAYghZv +cDU5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjUud2ViLXBsYXRmb3JtLnRlc3Qw +GIIWb3A5MC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDg0LndlYi1wbGF0Zm9ybS50 +ZXN0MBiCFm9wMjIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A0Ny53ZWItcGxhdGZv +cm0udGVzdDAYghZ3d3cxLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wODkud2ViLXBs +YXRmb3JtLnRlc3QwGIIWb3AyMC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDU0Lndl +Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjMud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1 +Ni53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQzLndlYi1wbGF0Zm9ybS50ZXN0MBiC +Fm9wODMud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A5OC53ZWItcGxhdGZvcm0udGVz +dDAYghZvcDMyLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzQud2ViLXBsYXRmb3Jt +LnRlc3QwGIIWb3A0NS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDUwLndlYi1wbGF0 +Zm9ybS50ZXN0MBiCFm9wNjMud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1MS53ZWIt +cGxhdGZvcm0udGVzdDAYghZvcDgyLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTEu +d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1OC53ZWItcGxhdGZvcm0udGVzdDAYghZv +cDc5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTAud2ViLXBsYXRmb3JtLnRlc3Qw +GIIWd3d3Mi53ZWItcGxhdGZvcm0udGVzdDAYghZvcDY1LndlYi1wbGF0Zm9ybS50 +ZXN0MBiCFm9wNDQud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2MS53ZWItcGxhdGZv +cm0udGVzdDAYghZvcDM4LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNDEud2ViLXBs +YXRmb3JtLnRlc3QwGIIWb3AzOS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDc2Lndl +Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzcud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2 +OC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDUzLndlYi1wbGF0Zm9ybS50ZXN0MBiC +Fm9wNTIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A0Mi53ZWItcGxhdGZvcm0udGVz +dDAYghZvcDg3LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTgud2ViLXBsYXRmb3Jt +LnRlc3QwGIIWb3A5NS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDk0LndlYi1wbGF0 +Zm9ybS50ZXN0MBiCFm9wOTkud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxNy53ZWIt +cGxhdGZvcm0udGVzdDAYghZvcDQwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wODAu +d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2Mi53ZWItcGxhdGZvcm0udGVzdDAYghZv +cDg4LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjgud2ViLXBsYXRmb3JtLnRlc3Qw +GIIWb3A2Ny53ZWItcGxhdGZvcm0udGVzdDAYghZvcDE2LndlYi1wbGF0Zm9ybS50 +ZXN0MBiCFm9wODUud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AyMS53ZWItcGxhdGZv +cm0udGVzdDAYghZvcDI3LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzMud2ViLXBs +YXRmb3JtLnRlc3QwGIIWb3A5Ni53ZWItcGxhdGZvcm0udGVzdDAYghZvcDY2Lndl +Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A5 +Ny53ZWItcGxhdGZvcm0udGVzdDAYghZvcDczLndlYi1wbGF0Zm9ybS50ZXN0MBiC +Fm9wNjQud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1NS53ZWItcGxhdGZvcm0udGVz +dDAYghZvcDI2LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjkud2ViLXBsYXRmb3Jt +LnRlc3QwG4IZd3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdDAbghlvcDYubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0MBuCGW9wNS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZ +b3A4Lm5vdC13ZWItcGxhdGZvcm0udGVzdDAbghlvcDcubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MBuCGW9wMS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZb3AyLm5vdC13 +ZWItcGxhdGZvcm0udGVzdDAbghlvcDQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MBuC +GXd3dy53d3cud2ViLXBsYXRmb3JtLnRlc3QwG4IZb3A5Lm5vdC13ZWItcGxhdGZv +cm0udGVzdDAbghlvcDMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjAubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wOTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTUubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wNjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +ODEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dy53d3cyLndlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wOTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzAubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wMzQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dy53d3cxLndlYi1w bGF0Zm9ybS50ZXN0MByCGm9wNDMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -OTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTQubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wMzYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDEubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzkubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wOTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDQubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wNTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3 -dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjcubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wODYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjYubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wODIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTAubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wMjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3 -dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzAubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wNTMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzIubm90 +MTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTUubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wNjMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODQubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDUubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wNjgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzcubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wODAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +ODIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTYubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wNDYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDEubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDcubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wNjcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjIubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wNzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +ODkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODcubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wNDgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTMubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDAubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wMjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODYubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wNTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +NDQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjcubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wOTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzUubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wNzkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTQubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wOTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +MjMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTMubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wNTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTkubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODgubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wMTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDIubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wOTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +NjQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTYubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wNjYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzIud3d3 +LndlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wMjQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTAubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wNzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +Mzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzEud3d3LndlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wMzYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjIubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTMubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wNTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTkubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wOTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +NDkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODUubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wODMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjUubm90 LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wNjgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTEubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wOTUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3 -dy53d3cyLndlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTgubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wNDYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzkubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjQubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wOTMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTkubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wNDgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -NTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjMubm90LXdlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wODcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzQubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0 -MByCGm9wMjAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDIubm90LXdlYi1w -bGF0Zm9ybS50ZXN0MByCGm9wMjgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w -NzYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzEud3d3LndlYi1wbGF0Zm9y -bS50ZXN0MByCGm9wNjkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzEud3d3 +MByCGm9wNzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzQubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wMTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +NTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTQubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wNzMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTgubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzkubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wMTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjgubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wNTUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3 +dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzMubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wMjUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjYubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjkubm90LXdlYi1wbGF0Zm9ybS50ZXN0 +MByCGm9wNzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzgubm90LXdlYi1w +bGF0Zm9ybS50ZXN0MByCGm9wNzYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w +NTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjkubm90LXdlYi1wbGF0Zm9y +bS50ZXN0MByCGm9wMjAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzEud3d3 MS53ZWItcGxhdGZvcm0udGVzdDAdght3d3cyLnd3dzEud2ViLXBsYXRmb3JtLnRl c3QwHYIbd3d3MS53d3cyLndlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzIud3d3Mi53 ZWItcGxhdGZvcm0udGVzdDAfgh13d3cud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz -dDAggh54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3Lnd3dzEu -bm90LXdlYi1wbGF0Zm9ybS50ZXN0MCCCHnd3dzIud3d3Lm5vdC13ZWItcGxhdGZv -cm0udGVzdDAggh53d3cud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3 -MS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzIud3d3Mi5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3QwIYIfd3d3MS53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVz -dDAhgh93d3cxLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzIud3d3 -MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwJIIid3d3LnhuLS1sdmUtNmxhZC53ZWIt -cGxhdGZvcm0udGVzdDAkgiJ4bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0MCSCInhuLS1sdmUtNmxhZC53d3cud2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4t -LWx2ZS02bGFkLnd3dzEud2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4tLWx2ZS02bGFk -Lnd3dzIud2ViLXBsYXRmb3JtLnRlc3QwJYIjd3d3MS54bi0tbHZlLTZsYWQud2Vi +dDAggh54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3Lnd3dzIu +bm90LXdlYi1wbGF0Zm9ybS50ZXN0MCCCHnd3dzEud3d3Lm5vdC13ZWItcGxhdGZv +cm0udGVzdDAggh53d3cyLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3 +Lnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzEud3d3Mi5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3QwIYIfd3d3MS53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVz +dDAhgh93d3cyLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzIud3d3 +Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwJIIieG4tLWx2ZS02bGFkLnd3dy53ZWIt +cGxhdGZvcm0udGVzdDAkgiJ3d3cueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50 +ZXN0MCSCInhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4t +LWx2ZS02bGFkLnd3dzIud2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4tLWx2ZS02bGFk +Lnd3dzEud2ViLXBsYXRmb3JtLnRlc3QwJYIjd3d3MS54bi0tbHZlLTZsYWQud2Vi LXBsYXRmb3JtLnRlc3QwJYIjd3d3Mi54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3Jt LnRlc3QwKIImeG4tLWx2ZS02bGFkLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3Qw -KIImd3d3LnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYInd3d3 -Mi54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCmCJ3d3dzEueG4t +KIImd3d3LnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYIneG4t +LWx2ZS02bGFkLnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCmCJ3d3dzIueG4t LWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdDApgid4bi0tbHZlLTZsYWQu -d3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYIneG4tLWx2ZS02bGFkLnd3dzEu +d3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYInd3d3MS54bi0tbHZlLTZsYWQu bm90LXdlYi1wbGF0Zm9ybS50ZXN0MCuCKXhuLS1uOGo2ZHM1M2x3d2tycWh2Mjhh LndlYi1wbGF0Zm9ybS50ZXN0MC2CK3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQu -d2ViLXBsYXRmb3JtLnRlc3QwL4IteG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3 -LndlYi1wbGF0Zm9ybS50ZXN0MC+CLXd3dy54bi0tbjhqNmRzNTNsd3drcnFodjI4 -YS53ZWItcGxhdGZvcm0udGVzdDAvgi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS5u -b3Qtd2ViLXBsYXRmb3JtLnRlc3QwMIIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEu -d3d3MS53ZWItcGxhdGZvcm0udGVzdDAwgi53d3cyLnhuLS1uOGo2ZHM1M2x3d2ty +d2ViLXBsYXRmb3JtLnRlc3QwL4Itd3d3LnhuLS1uOGo2ZHM1M2x3d2tycWh2Mjhh +LndlYi1wbGF0Zm9ybS50ZXN0MC+CLXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5v +dC13ZWItcGxhdGZvcm0udGVzdDAvgi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS53 +d3cud2ViLXBsYXRmb3JtLnRlc3QwMIIud3d3Mi54bi0tbjhqNmRzNTNsd3drcnFo +djI4YS53ZWItcGxhdGZvcm0udGVzdDAwgi53d3cxLnhuLS1uOGo2ZHM1M2x3d2ty cWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0MDCCLnhuLS1uOGo2ZHM1M2x3d2tycWh2 -MjhhLnd3dzIud2ViLXBsYXRmb3JtLnRlc3QwMIIud3d3MS54bi0tbjhqNmRzNTNs -d3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdDAxgi94bi0tbHZlLTZsYWQueG4t -LWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdDAzgjF4bi0tbjhqNmRzNTNs -d3drcnFodjI4YS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0MDOCMXd3dy54bi0t -bjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwNIIyd3d3 -Mi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3Qw +MjhhLnd3dzIud2ViLXBsYXRmb3JtLnRlc3QwMIIueG4tLW44ajZkczUzbHd3a3Jx +aHYyOGEud3d3MS53ZWItcGxhdGZvcm0udGVzdDAxgi94bi0tbHZlLTZsYWQueG4t +LWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdDAzgjF3d3cueG4tLW44ajZk +czUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MDOCMXhuLS1uOGo2 +ZHM1M2x3d2tycWh2MjhhLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwNIIyeG4t +LW44ajZkczUzbHd3a3JxaHYyOGEud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3Qw NIIyeG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3MS5ub3Qtd2ViLXBsYXRmb3Jt LnRlc3QwNIIyd3d3MS54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBs -YXRmb3JtLnRlc3QwNIIyeG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3Mi5ub3Qt +YXRmb3JtLnRlc3QwNIIyd3d3Mi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qt d2ViLXBsYXRmb3JtLnRlc3QwOII2eG4tLW44ajZkczUzbHd3a3JxaHYyOGEueG4t LWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0MDiCNnhuLS1sdmUtNmxhZC54bi0t bjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdDA8gjp4bi0tbjhq @@ -180,156 +180,156 @@ LW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3QwR4JFeG4tLW44 ajZkczUzbHd3a3JxaHYyOGEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdl Yi1wbGF0Zm9ybS50ZXN0MBMGA1UdJQQMMAoGCCsGAQUFBwMBMIIdjwYDVR0RBIId -hjCCHYKCEXdlYi1wbGF0Zm9ybS50ZXN0ghVvcDEud2ViLXBsYXRmb3JtLnRlc3SC -FW5vdC13ZWItcGxhdGZvcm0udGVzdIIVb3A5LndlYi1wbGF0Zm9ybS50ZXN0ghVv -cDMud2ViLXBsYXRmb3JtLnRlc3SCFW9wNC53ZWItcGxhdGZvcm0udGVzdIIVb3A4 -LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDcud2ViLXBsYXRmb3JtLnRlc3SCFW9wNS53 -ZWItcGxhdGZvcm0udGVzdIIVd3d3LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDYud2Vi -LXBsYXRmb3JtLnRlc3SCFW9wMi53ZWItcGxhdGZvcm0udGVzdIIWb3A0Ny53ZWIt -cGxhdGZvcm0udGVzdIIWb3A3My53ZWItcGxhdGZvcm0udGVzdIIWb3AxNy53ZWIt -cGxhdGZvcm0udGVzdIIWb3A3MC53ZWItcGxhdGZvcm0udGVzdIIWd3d3MS53ZWIt -cGxhdGZvcm0udGVzdIIWb3A0MC53ZWItcGxhdGZvcm0udGVzdIIWb3AzNi53ZWIt -cGxhdGZvcm0udGVzdIIWb3AxMi53ZWItcGxhdGZvcm0udGVzdIIWb3A4MC53ZWIt -cGxhdGZvcm0udGVzdIIWb3A5MC53ZWItcGxhdGZvcm0udGVzdIIWb3A2NS53ZWIt -cGxhdGZvcm0udGVzdIIWb3AyMC53ZWItcGxhdGZvcm0udGVzdIIWb3A5Mi53ZWIt -cGxhdGZvcm0udGVzdIIWb3A2Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A3Ni53ZWIt -cGxhdGZvcm0udGVzdIIWb3AxOS53ZWItcGxhdGZvcm0udGVzdIIWb3A0Mi53ZWIt -cGxhdGZvcm0udGVzdIIWb3AzOS53ZWItcGxhdGZvcm0udGVzdIIWb3AyOS53ZWIt -cGxhdGZvcm0udGVzdIIWb3A1NS53ZWItcGxhdGZvcm0udGVzdIIWb3A4Ni53ZWIt -cGxhdGZvcm0udGVzdIIWb3A0MS53ZWItcGxhdGZvcm0udGVzdIIWb3A5MS53ZWIt -cGxhdGZvcm0udGVzdIIWb3AzMy53ZWItcGxhdGZvcm0udGVzdIIWb3AyNS53ZWIt -cGxhdGZvcm0udGVzdIIWb3A0NC53ZWItcGxhdGZvcm0udGVzdIIWb3AxMy53ZWIt -cGxhdGZvcm0udGVzdIIWb3AxNS53ZWItcGxhdGZvcm0udGVzdIIWb3A5Ny53ZWIt -cGxhdGZvcm0udGVzdIIWb3A2NC53ZWItcGxhdGZvcm0udGVzdIIWb3A0OC53ZWIt -cGxhdGZvcm0udGVzdIIWb3A5OC53ZWItcGxhdGZvcm0udGVzdIIWb3A2My53ZWIt -cGxhdGZvcm0udGVzdIIWb3AxMC53ZWItcGxhdGZvcm0udGVzdIIWb3A4Mi53ZWIt -cGxhdGZvcm0udGVzdIIWb3A1Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A0My53ZWIt -cGxhdGZvcm0udGVzdIIWb3A0OS53ZWItcGxhdGZvcm0udGVzdIIWb3A1My53ZWIt -cGxhdGZvcm0udGVzdIIWb3A3NC53ZWItcGxhdGZvcm0udGVzdIIWb3A4OC53ZWIt -cGxhdGZvcm0udGVzdIIWb3A5NS53ZWItcGxhdGZvcm0udGVzdIIWb3A2MS53ZWIt -cGxhdGZvcm0udGVzdIIWb3AxNi53ZWItcGxhdGZvcm0udGVzdIIWb3A4Ny53ZWIt -cGxhdGZvcm0udGVzdIIWb3A2Ny53ZWItcGxhdGZvcm0udGVzdIIWb3AyNC53ZWIt -cGxhdGZvcm0udGVzdIIWb3AyNi53ZWItcGxhdGZvcm0udGVzdIIWb3A5NC53ZWIt -cGxhdGZvcm0udGVzdIIWb3AyOC53ZWItcGxhdGZvcm0udGVzdIIWb3A4My53ZWIt -cGxhdGZvcm0udGVzdIIWd3d3Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A3OC53ZWIt -cGxhdGZvcm0udGVzdIIWb3A4OS53ZWItcGxhdGZvcm0udGVzdIIWb3A0NS53ZWIt -cGxhdGZvcm0udGVzdIIWb3A5My53ZWItcGxhdGZvcm0udGVzdIIWb3A4NS53ZWIt -cGxhdGZvcm0udGVzdIIWb3A4MS53ZWItcGxhdGZvcm0udGVzdIIWb3A2Ni53ZWIt -cGxhdGZvcm0udGVzdIIWb3A5OS53ZWItcGxhdGZvcm0udGVzdIIWb3A1NC53ZWIt -cGxhdGZvcm0udGVzdIIWb3AzOC53ZWItcGxhdGZvcm0udGVzdIIWb3AyMy53ZWIt -cGxhdGZvcm0udGVzdIIWb3A3Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A2MC53ZWIt -cGxhdGZvcm0udGVzdIIWb3AzNS53ZWItcGxhdGZvcm0udGVzdIIWb3A1MC53ZWIt -cGxhdGZvcm0udGVzdIIWb3A1MS53ZWItcGxhdGZvcm0udGVzdIIWb3AzMi53ZWIt -cGxhdGZvcm0udGVzdIIWb3AxOC53ZWItcGxhdGZvcm0udGVzdIIWb3A1OC53ZWIt -cGxhdGZvcm0udGVzdIIWb3AyNy53ZWItcGxhdGZvcm0udGVzdIIWb3AzMC53ZWIt -cGxhdGZvcm0udGVzdIIWb3A1OS53ZWItcGxhdGZvcm0udGVzdIIWb3A4NC53ZWIt -cGxhdGZvcm0udGVzdIIWb3A2OC53ZWItcGxhdGZvcm0udGVzdIIWb3A3OS53ZWIt -cGxhdGZvcm0udGVzdIIWb3A3NS53ZWItcGxhdGZvcm0udGVzdIIWb3A3MS53ZWIt -cGxhdGZvcm0udGVzdIIWb3AzNy53ZWItcGxhdGZvcm0udGVzdIIWb3A1Mi53ZWIt -cGxhdGZvcm0udGVzdIIWb3AyMS53ZWItcGxhdGZvcm0udGVzdIIWb3A0Ni53ZWIt -cGxhdGZvcm0udGVzdIIWb3A1Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A3Ny53ZWIt -cGxhdGZvcm0udGVzdIIWb3A2OS53ZWItcGxhdGZvcm0udGVzdIIWb3AzMS53ZWIt -cGxhdGZvcm0udGVzdIIWb3AxNC53ZWItcGxhdGZvcm0udGVzdIIWb3A5Ni53ZWIt -cGxhdGZvcm0udGVzdIIWb3AxMS53ZWItcGxhdGZvcm0udGVzdIIWb3AzNC53ZWIt -cGxhdGZvcm0udGVzdIIWb3AyMi53ZWItcGxhdGZvcm0udGVzdIIZb3AzLm5vdC13 -ZWItcGxhdGZvcm0udGVzdIIZb3A5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZd3d3 -Lnd3dy53ZWItcGxhdGZvcm0udGVzdIIZb3A0Lm5vdC13ZWItcGxhdGZvcm0udGVz -dIIZb3A4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A2Lm5vdC13ZWItcGxhdGZv -cm0udGVzdIIZb3AyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A1Lm5vdC13ZWIt -cGxhdGZvcm0udGVzdIIZb3A3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZd3d3Lm5v -dC13ZWItcGxhdGZvcm0udGVzdIIZb3AxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa -b3A5Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTgubm90LXdlYi1wbGF0Zm9y -bS50ZXN0ghpvcDYyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AxNS5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCGm9wNDcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDEy -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3NC5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCGm9wNzMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDYwLm5vdC13ZWItcGxh -dGZvcm0udGVzdIIab3A1Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTkubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa -b3A0MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjIubm90LXdlYi1wbGF0Zm9y -bS50ZXN0ghpvcDMyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2Ny5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCGm9wODgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgz -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AxMS5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCGm9wMzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE3Lm5vdC13ZWItcGxh -dGZvcm0udGVzdIIab3A5Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzgubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa -b3A3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTQubm90LXdlYi1wbGF0Zm9y -bS50ZXN0ghpvcDY0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyOS5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCGnd3dy53d3cxLndlYi1wbGF0Zm9ybS50ZXN0ghpvcDMw -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1NS5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCGm9wNzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk0Lm5vdC13ZWItcGxh -dGZvcm0udGVzdIIad3d3Mi53d3cud2ViLXBsYXRmb3JtLnRlc3SCGm9wNDkubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDEzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa -b3A0NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODUubm90LXdlYi1wbGF0Zm9y -bS50ZXN0ghpvcDkxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2Ni5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCGm9wODEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDY1 -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5OC5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCGm9wMjUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDEwLm5vdC13ZWItcGxh -dGZvcm0udGVzdIIab3AyMy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzMubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa -b3A4OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODQubm90LXdlYi1wbGF0Zm9y -bS50ZXN0ghpvcDM4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2MS5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCGm9wNDMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDky -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1NC5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCGm9wMzYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQxLm5vdC13ZWItcGxh -dGZvcm0udGVzdIIab3AzOS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTAubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa -b3A1Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzEubm90LXdlYi1wbGF0Zm9y -bS50ZXN0ghpvcDI3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4Ni5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCGm9wMjYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE5 -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4Mi5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCGm9wNTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDIxLm5vdC13ZWItcGxh -dGZvcm0udGVzdIIad3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzAubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDUzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa -b3A3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzUubm90LXdlYi1wbGF0Zm9y -bS50ZXN0ghpvcDY4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1MS5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCGm9wOTUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cu -d3d3Mi53ZWItcGxhdGZvcm0udGVzdIIab3A1OC5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCGm9wNDYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDc5Lm5vdC13ZWItcGxh -dGZvcm0udGVzdIIab3AyNC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTMubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa -b3A0OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTIubm90LXdlYi1wbGF0Zm9y -bS50ZXN0ghpvcDYzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4Ny5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCGm9wMzQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE2 -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyMC5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCGm9wNDIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI4Lm5vdC13ZWItcGxh -dGZvcm0udGVzdIIab3A3Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzEud3d3 -LndlYi1wbGF0Zm9ybS50ZXN0ghpvcDY5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIb +hjCCHYKCEXdlYi1wbGF0Zm9ybS50ZXN0ghVvcDMud2ViLXBsYXRmb3JtLnRlc3SC +FW9wOS53ZWItcGxhdGZvcm0udGVzdIIVb3A1LndlYi1wbGF0Zm9ybS50ZXN0ghVv +cDcud2ViLXBsYXRmb3JtLnRlc3SCFW9wMi53ZWItcGxhdGZvcm0udGVzdIIVbm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghVvcDYud2ViLXBsYXRmb3JtLnRlc3SCFW9wMS53 +ZWItcGxhdGZvcm0udGVzdIIVb3A0LndlYi1wbGF0Zm9ybS50ZXN0ghV3d3cud2Vi +LXBsYXRmb3JtLnRlc3SCFW9wOC53ZWItcGxhdGZvcm0udGVzdIIWb3A1Ny53ZWIt +cGxhdGZvcm0udGVzdIIWb3A5My53ZWItcGxhdGZvcm0udGVzdIIWb3A0OS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AxMy53ZWItcGxhdGZvcm0udGVzdIIWb3AyNC53ZWIt +cGxhdGZvcm0udGVzdIIWb3AxNC53ZWItcGxhdGZvcm0udGVzdIIWb3AzNS53ZWIt +cGxhdGZvcm0udGVzdIIWb3A5MS53ZWItcGxhdGZvcm0udGVzdIIWb3A5Mi53ZWIt +cGxhdGZvcm0udGVzdIIWb3A0OC53ZWItcGxhdGZvcm0udGVzdIIWb3A3NC53ZWIt +cGxhdGZvcm0udGVzdIIWb3AzMS53ZWItcGxhdGZvcm0udGVzdIIWb3A3MC53ZWIt +cGxhdGZvcm0udGVzdIIWb3A3MS53ZWItcGxhdGZvcm0udGVzdIIWb3A4MS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AzNy53ZWItcGxhdGZvcm0udGVzdIIWb3A4Ni53ZWIt +cGxhdGZvcm0udGVzdIIWb3A3NS53ZWItcGxhdGZvcm0udGVzdIIWb3A2OS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AzNi53ZWItcGxhdGZvcm0udGVzdIIWb3A3OC53ZWIt +cGxhdGZvcm0udGVzdIIWb3AzMC53ZWItcGxhdGZvcm0udGVzdIIWb3AxOS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AxNS53ZWItcGxhdGZvcm0udGVzdIIWb3A0Ni53ZWIt +cGxhdGZvcm0udGVzdIIWb3AxMi53ZWItcGxhdGZvcm0udGVzdIIWb3A2MC53ZWIt +cGxhdGZvcm0udGVzdIIWb3A1OS53ZWItcGxhdGZvcm0udGVzdIIWb3AyNS53ZWIt +cGxhdGZvcm0udGVzdIIWb3A5MC53ZWItcGxhdGZvcm0udGVzdIIWb3A4NC53ZWIt +cGxhdGZvcm0udGVzdIIWb3AyMi53ZWItcGxhdGZvcm0udGVzdIIWb3A0Ny53ZWIt +cGxhdGZvcm0udGVzdIIWd3d3MS53ZWItcGxhdGZvcm0udGVzdIIWb3A4OS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AyMC53ZWItcGxhdGZvcm0udGVzdIIWb3A1NC53ZWIt +cGxhdGZvcm0udGVzdIIWb3AyMy53ZWItcGxhdGZvcm0udGVzdIIWb3A1Ni53ZWIt +cGxhdGZvcm0udGVzdIIWb3A0My53ZWItcGxhdGZvcm0udGVzdIIWb3A4My53ZWIt +cGxhdGZvcm0udGVzdIIWb3A5OC53ZWItcGxhdGZvcm0udGVzdIIWb3AzMi53ZWIt +cGxhdGZvcm0udGVzdIIWb3AzNC53ZWItcGxhdGZvcm0udGVzdIIWb3A0NS53ZWIt +cGxhdGZvcm0udGVzdIIWb3A1MC53ZWItcGxhdGZvcm0udGVzdIIWb3A2My53ZWIt +cGxhdGZvcm0udGVzdIIWb3A1MS53ZWItcGxhdGZvcm0udGVzdIIWb3A4Mi53ZWIt +cGxhdGZvcm0udGVzdIIWb3AxMS53ZWItcGxhdGZvcm0udGVzdIIWb3A1OC53ZWIt +cGxhdGZvcm0udGVzdIIWb3A3OS53ZWItcGxhdGZvcm0udGVzdIIWb3AxMC53ZWIt +cGxhdGZvcm0udGVzdIIWd3d3Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A2NS53ZWIt +cGxhdGZvcm0udGVzdIIWb3A0NC53ZWItcGxhdGZvcm0udGVzdIIWb3A2MS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AzOC53ZWItcGxhdGZvcm0udGVzdIIWb3A0MS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AzOS53ZWItcGxhdGZvcm0udGVzdIIWb3A3Ni53ZWIt +cGxhdGZvcm0udGVzdIIWb3A3Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A2OC53ZWIt +cGxhdGZvcm0udGVzdIIWb3A1My53ZWItcGxhdGZvcm0udGVzdIIWb3A1Mi53ZWIt +cGxhdGZvcm0udGVzdIIWb3A0Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A4Ny53ZWIt +cGxhdGZvcm0udGVzdIIWb3AxOC53ZWItcGxhdGZvcm0udGVzdIIWb3A5NS53ZWIt +cGxhdGZvcm0udGVzdIIWb3A5NC53ZWItcGxhdGZvcm0udGVzdIIWb3A5OS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AxNy53ZWItcGxhdGZvcm0udGVzdIIWb3A0MC53ZWIt +cGxhdGZvcm0udGVzdIIWb3A4MC53ZWItcGxhdGZvcm0udGVzdIIWb3A2Mi53ZWIt +cGxhdGZvcm0udGVzdIIWb3A4OC53ZWItcGxhdGZvcm0udGVzdIIWb3AyOC53ZWIt +cGxhdGZvcm0udGVzdIIWb3A2Ny53ZWItcGxhdGZvcm0udGVzdIIWb3AxNi53ZWIt +cGxhdGZvcm0udGVzdIIWb3A4NS53ZWItcGxhdGZvcm0udGVzdIIWb3AyMS53ZWIt +cGxhdGZvcm0udGVzdIIWb3AyNy53ZWItcGxhdGZvcm0udGVzdIIWb3AzMy53ZWIt +cGxhdGZvcm0udGVzdIIWb3A5Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A2Ni53ZWIt +cGxhdGZvcm0udGVzdIIWb3A3Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A5Ny53ZWIt +cGxhdGZvcm0udGVzdIIWb3A3My53ZWItcGxhdGZvcm0udGVzdIIWb3A2NC53ZWIt +cGxhdGZvcm0udGVzdIIWb3A1NS53ZWItcGxhdGZvcm0udGVzdIIWb3AyNi53ZWIt +cGxhdGZvcm0udGVzdIIWb3AyOS53ZWItcGxhdGZvcm0udGVzdIIZd3d3Lm5vdC13 +ZWItcGxhdGZvcm0udGVzdIIZb3A2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A1 +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A4Lm5vdC13ZWItcGxhdGZvcm0udGVz +dIIZb3A3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AxLm5vdC13ZWItcGxhdGZv +cm0udGVzdIIZb3AyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A0Lm5vdC13ZWIt +cGxhdGZvcm0udGVzdIIZd3d3Lnd3dy53ZWItcGxhdGZvcm0udGVzdIIZb3A5Lm5v +dC13ZWItcGxhdGZvcm0udGVzdIIZb3AzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa +b3A2MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzIubm90LXdlYi1wbGF0Zm9y +bS50ZXN0ghpvcDk3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5NS5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3SCGm9wNjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgx +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3Lnd3dzIud2ViLXBsYXRmb3JtLnRl +c3SCGm9wOTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDMwLm5vdC13ZWItcGxh +dGZvcm0udGVzdIIab3AzMS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzQubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3MS53ZWItcGxhdGZvcm0udGVzdIIa +b3A0My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTIubm90LXdlYi1wbGF0Zm9y +bS50ZXN0ghpvcDE1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2My5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3SCGm9wODQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ1 +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2OC5ub3Qtd2ViLXBsYXRmb3JtLnRl +c3SCGm9wMzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgwLm5vdC13ZWItcGxh +dGZvcm0udGVzdIIab3A4Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTYubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa +b3A0MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDcubm90LXdlYi1wbGF0Zm9y +bS50ZXN0ghpvcDY3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyMi5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3SCGm9wNzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDg5 +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4Ny5ub3Qtd2ViLXBsYXRmb3JtLnRl +c3SCGm9wNDgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDkzLm5vdC13ZWItcGxh +dGZvcm0udGVzdIIab3A0MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjEubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDg2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa +b3A1NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDQubm90LXdlYi1wbGF0Zm9y +bS50ZXN0ghpvcDI3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5OS5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3SCGm9wMzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDMy +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3OS5ub3Qtd2ViLXBsYXRmb3JtLnRl +c3SCGm9wOTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDkxLm5vdC13ZWItcGxh +dGZvcm0udGVzdIIab3AyMy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTMubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDUyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa +b3A1OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODgubm90LXdlYi1wbGF0Zm9y +bS50ZXN0ghpvcDE3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A0Mi5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3SCGm9wOTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDY0 +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1Ni5ub3Qtd2ViLXBsYXRmb3JtLnRl +c3SCGm9wNjYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cyLnd3dy53ZWItcGxh +dGZvcm0udGVzdIIab3A5Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjQubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDEwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa +b3A3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzgubm90LXdlYi1wbGF0Zm9y +bS50ZXN0ghp3d3cxLnd3dy53ZWItcGxhdGZvcm0udGVzdIIab3AzNi5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3SCGm9wNjIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDEz +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1Ny5ub3Qtd2ViLXBsYXRmb3JtLnRl +c3SCGm9wMTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk4Lm5vdC13ZWItcGxh +dGZvcm0udGVzdIIab3A0OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODUubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa +b3A2NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzUubm90LXdlYi1wbGF0Zm9y +bS50ZXN0ghpvcDc3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3NC5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3SCGm9wMTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDUw +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AxNC5ub3Qtd2ViLXBsYXRmb3JtLnRl +c3SCGm9wNzMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU4Lm5vdC13ZWItcGxh +dGZvcm0udGVzdIIab3AzOS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTgubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa +b3A1NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzEubm90LXdlYi1wbGF0Zm9y +bS50ZXN0ghpvcDMzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyNS5ub3Qtd2Vi +LXBsYXRmb3JtLnRlc3SCGm9wMjYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDY5 +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRl +c3SCGm9wNzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDc2Lm5vdC13ZWItcGxh +dGZvcm0udGVzdIIab3A1MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjkubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDIwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIb d3d3MS53d3cxLndlYi1wbGF0Zm9ybS50ZXN0ght3d3cyLnd3dzEud2ViLXBsYXRm b3JtLnRlc3SCG3d3dzEud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIbd3d3Mi53d3cy LndlYi1wbGF0Zm9ybS50ZXN0gh13d3cud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz -dIIeeG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0gh53d3cud3d3MS5ub3Qt -d2ViLXBsYXRmb3JtLnRlc3SCHnd3dzIud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz -dIIed3d3Lnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh53d3cxLnd3dy5ub3Qt -d2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCH3d3dzEud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3MS5u -b3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3MS5ub3Qtd2ViLXBsYXRmb3Jt -LnRlc3SCInd3dy54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCInhuLS1s -dmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC53d3cu -d2ViLXBsYXRmb3JtLnRlc3SCI3huLS1sdmUtNmxhZC53d3cxLndlYi1wbGF0Zm9y -bS50ZXN0giN4bi0tbHZlLTZsYWQud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIjd3d3 +dIIeeG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0gh53d3cud3d3Mi5ub3Qt +d2ViLXBsYXRmb3JtLnRlc3SCHnd3dzEud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz +dIIed3d3Mi53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh53d3cud3d3MS5ub3Qt +d2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRl +c3SCH3d3dzEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3MS5u +b3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3Mi5ub3Qtd2ViLXBsYXRmb3Jt +LnRlc3SCInhuLS1sdmUtNmxhZC53d3cud2ViLXBsYXRmb3JtLnRlc3SCInd3dy54 +bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC5ub3Qt +d2ViLXBsYXRmb3JtLnRlc3SCI3huLS1sdmUtNmxhZC53d3cyLndlYi1wbGF0Zm9y +bS50ZXN0giN4bi0tbHZlLTZsYWQud3d3MS53ZWItcGxhdGZvcm0udGVzdIIjd3d3 MS54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCI3d3dzIueG4tLWx2ZS02 bGFkLndlYi1wbGF0Zm9ybS50ZXN0giZ4bi0tbHZlLTZsYWQud3d3Lm5vdC13ZWIt cGxhdGZvcm0udGVzdIImd3d3LnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3Jt -LnRlc3SCJ3d3dzIueG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIn -d3d3MS54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gid4bi0tbHZl -LTZsYWQud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3huLS1sdmUtNmxhZC53 -d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIpeG4tLW44ajZkczUzbHd3a3JxaHYy +LnRlc3SCJ3huLS1sdmUtNmxhZC53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIn +d3d3Mi54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gid4bi0tbHZl +LTZsYWQud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3d3dzEueG4tLWx2ZS02 +bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIpeG4tLW44ajZkczUzbHd3a3JxaHYy OGEud2ViLXBsYXRmb3JtLnRlc3SCK3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQu -d2ViLXBsYXRmb3JtLnRlc3SCLXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dy53 -ZWItcGxhdGZvcm0udGVzdIItd3d3LnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndl -Yi1wbGF0Zm9ybS50ZXN0gi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2Vi -LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzEud2Vi +d2ViLXBsYXRmb3JtLnRlc3SCLXd3dy54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53 +ZWItcGxhdGZvcm0udGVzdIIteG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0gi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cud2Vi LXBsYXRmb3JtLnRlc3SCLnd3dzIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi -LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzIud2Vi LXBsYXRmb3JtLnRlc3SCLnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi +LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzIud2Vi +LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzEud2Vi LXBsYXRmb3JtLnRlc3SCL3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0gjF4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cubm90 -LXdlYi1wbGF0Zm9ybS50ZXN0gjF3d3cueG4tLW44ajZkczUzbHd3a3JxaHYyOGEu -bm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ3d3cyLnhuLS1uOGo2ZHM1M2x3d2tycWh2 -MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdIIyeG4tLW44ajZkczUzbHd3a3JxaHYy +Yi1wbGF0Zm9ybS50ZXN0gjF3d3cueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90 +LXdlYi1wbGF0Zm9ybS50ZXN0gjF4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cu +bm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53 +d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIyeG4tLW44ajZkczUzbHd3a3JxaHYy OGEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCMnd3dzEueG4tLW44ajZkczUz -bHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ4bi0tbjhqNmRzNTNs -d3drcnFodjI4YS53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdII2eG4tLW44ajZk +bHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ3d3cyLnhuLS1uOGo2 +ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdII2eG4tLW44ajZk czUzbHd3a3JxaHYyOGEueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0gjZ4 bi0tbHZlLTZsYWQueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3Jt LnRlc3SCOnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1sdmUtNmxhZC5ub3Qt @@ -337,11 +337,11 @@ cnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCQXhuLS1uOGo2ZHM1M2x3d2ty cWh2MjhhLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0 gkV4bi0tbjhqNmRzNTNsd3drcnFodjI4YS54bi0tbjhqNmRzNTNsd3drcnFodjI4 -YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwDQYJKoZIhvcNAQELBQADggEBAC0scQuh -DWnt9uVlGuyJP76Q6u+O7tA+L2q70OIMteYjdo2L+qio6anykeIU0rvBhomC+G2P -lZ59xsjnG19ST0bs5wSGxbL00N40BqcKapK99X4mjaEBSpCrPshf0me2E35XkWX9 -gGbIRHs6gvF5IZ6u+8dxWONddpylx3wJjn2yJeqm+RzOwa1zZLiUYCwV7EiLNR8T -6iKzSEY//hE2VgQCgkD951QTpOaVIdFZ/GxzyeqcflQFW6z0IwymcwDZo0JyfTpe -KIomp30YTFTCnA6VYVAXv1PhweA2Pfy1A1sQVkvMtckrL6x/If9SN2HednN6JtB3 -MhLyEdWLQ9rcR5o= +YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwDQYJKoZIhvcNAQELBQADggEBADhZ4li3 +NcQPlxDgGdU6ej7NxlcLYT0qCj0kJks2TSPzJm6P8cEwIFjmFwd3ZbpyDvt1/8hJ +7yShhlX9LOafReyNpvzq0I/buApMt5+gajRZ5QxkI2YExsdy9TSAZSJ34umhyBQB +QYRNDSIIVwH4DR/7CS01g4PFeqb/8N17h6TM7Dle8Dc/NRWSgAx6HQ+MD9GCy6ad +pmP5CPLuj9xnfv2I3PbLG3Tb5rZIC/MtG72WTTFC4oKK/lGp33z2zkDiq2tzVXCF +Zlavy0IqwLNZ4tQPF8IfK7rOvmivpTtXZdCOm5vtjSOLcWUJoHRV12pwG7oiL1mF +D5kKvkKK3yRk44w= -----END CERTIFICATE-----
diff --git a/third_party/wpt_tools/wpt/tools/certs/web-platform.test.key b/third_party/wpt_tools/wpt/tools/certs/web-platform.test.key index 6a866e3..9e384f7 100644 --- a/third_party/wpt_tools/wpt/tools/certs/web-platform.test.key +++ b/third_party/wpt_tools/wpt/tools/certs/web-platform.test.key
@@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJKIq0HkGW/p/p -y5t0e1xXdamUFJdb+Krz1+IdfwaPkOJLFDLkjHfJ/P2DtBjk0URpH6HI/zLMfn/X -ubgJYHvcukZQTIHtaqHPXk/fb8DRMSFzKE5mjw2RfRgpm/dztGbJgowqS6U01Jcq -tHHfd9Zjhlzz/EfdyQpypT0VjTGHlTXaqVlfVQXSARC/qPva//rTMGfRDfckOEGq -fy06ZjZCu+b+0wgagy58026k5fLVenmdtZ4bbTOxIPh0KmOWZnnCH8PkRv0ozMdQ -XY1uro3vWOuHzFAJhZLNYjvwhrq5qDlPe+PBCrnZjteRMBsyBbgiPP8ztwvUx8QF -/avZ2WBrAgMBAAECggEAEQN7z8YrWAELN3QAHvb8FW2fPSYMszuyAdPFjSccP/JK -IX2A3HHBA/WA363Q2TGV7qo9PcnP2xnr6CwOE8T0VPPwVIRUDOeS7f4VFVnXXhog -sSO8ldINnLuO2p4VbNTaSLrg7gbd3z0H2BXQ98yj9mD75ar1zR1e49lz9CmwAb6H -iSCVnBM+UChlib65PcgVJu+YirG8pnaqSWYkybgJL+bq2kTJ35PMSa2r5cLVlF6s -tMR77C3xIuQfPugM+QIs19XbzHrmF13s20foomj7IsCaJEU8utNpCYq937LEgMoJ -GD7dXy48nnTbrSoHFBFR7bfI/cOB88NBPBLYC4FoiQKBgQDywY+6zStvOQ5UfQed -kmaLA3O06QodgIw5mFWbGh2jRv1tg35+cARnXN3nayfy2Pod8vixqPwYIrHVIPvE -bxYQQGzfTxv6dXJ6TlkdJ8GR2BQAn+z6M3okzwih9+HmH68T0OdYWRi8BOMHFbQi -uAOytipyIBMSbaXO6nrM65SyxQKBgQDUIgIT2UsN07VHLSR8gtKpioSzihv9GYUc -ENluqbCtlqRAzhAh051P2tKtuS1hhK/4fRlaVdBTQzAXCd+yu6bIpV3uODZ77BzR -r6KfvWgKd2/rjudfEfB23PgKdMICe6bCRwW2xWT0JWzziQeqykIIbCHCWR/+DhRh -HhgKd2o5bwKBgFHtbXqX377LvMBa6gUN8bmc0qINvDI0vh56APo1mCcQwFsDc99s -IrBXsTR2/6Z///m3lKMw6tOice4CEbY733Bgrd23rzOaC6anZn/mePeluypyzuGq -GeDuVnWDWSP3MXk4mbtBZo2eAJjVhFPrUqQvwqd9l7IyezEYBZW/NBIZAoGBAKSN -INluxBacs9DbhqMDBBC5v4hZyK5DXorP0ypRfRiacx1F+yOSOEQadTSHIVm1CJ+T -wtfdGzWLN8GXSiwl/hFEnaFNf44PMKfDOz34Ob1suqeZ+YY4rzQ04j+SJHCypD+t -whPt+QqeAW7ES+tC64gHAQT2B6gWGd7f7jwoN4EHAoGAE4JnNiYKZyklFfVV4DxD -f6Fo207ibCahpKEoL49fWPhyWlxrdmTP0pf/UDS4Q+xsJRzKmsMLGzibMKMSsmgr -8/lzqXzctB8bYimBE470O/9OuY3CFkoPDHaWoFIuinmy+qisyi2ar1jF9tPPxIPx -WbqdaGYram5EUofwBaDicAM= +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCiwQLwPFXR8Q+V +qNHj1szPbG35GMfGIc0sGp61ExomtKI0ZFClGwOVoAwFXLwTHIMlaPWKudtSSY51 +rsssNKNM1nkuFFCID8a0wwBRjIPfFDNLhX7d0v9bUo8gCt8ASU3HqzuAnAlCtvpP +KtN6EqkpaW6i+s13kgWwE4eZq13Ul5g1PJpS72JVjPGSx5z3KMsR6xniji0B/8ns +1xoTImvMBlwiDFHYySfHI75I1HJaX1g5ALX+E033eaOfTVTYsvHummPwn9ER31YY +57OtPnAHWOU+93SPWysCbjtfAoqr/0kNkcwDLPqUu9MppdYkI1CFiWD12pVxR616 +ofB1BlQ5AgMBAAECggEBAJYtlYGJmwMK9f959JrRJNGtUtjMdeKsY/7zXUjmpHXc +reO8QPHouGkDcrQr+tuDrrwBWrk0gF0wxIRw0scqlxiauty7IAg8znUTjqKxDyn0 +INTqDMOxI7Hnv2uovFcuTNgWd+RXlu/5mYUdlmAJAhDVWaKH3LodgqQTkUdJ6l30 +P1+MRgZpnvGMjECb2Dj1vRbewfxn0SqU/xahxKY0TG6ItTEpoALFyvfv7PRXoDwz +VJBBwyLQq4bzHfxhFeEOrO1EwzwejjLBNQ1mlYXyal/8LhFvUCmji/qoK1FQPsis +Lw+Eoq0mPql4muB/RXIqtcuoZYP1SK6yyI0xjzQu7xECgYEAzyr88KsLlPelojSH +3KzkRcfTf28vVDQjGZOuvcLVriEFeNd4BA4lx9CqfpxrygXO8DECcSUW4SCgVy0S +b7MIw4OxOq3KUlInggGSYJHEAvddx/CJsnJ/6Ysc+Nc1ogX2uDQns6UBafj0gd3/ +HcQc0sSeM0KiIMbMf7ol0j9x7HUCgYEAyR36MjgPd5Y74jUwnRQRpzd5jcvxzaOm +tRDUBP1I+7dRSalRJWq8624H4JjGzbYHcGtL5b1urikcmHcyBnd/CSBz42mG9BYG +VwhnbTDOSlsu25lK/e3rPxphCZhIUT7CFjqboM241+k8/1e9rGJyNjfDay7VZNig +V3zwG8wi4DUCgYEAsVPJmLPAQS3NcE9or+KprnVCOwVPzNKn7L+1xiZcwyTuyyYc +S9RUUHnzRlbcCNv56yz4OyMVN3S26ofhDQ2BheFWtbSGxvodaTGxOsnqruNQOdFR +/BX4GU8DaJjGBr72FWxHQ4UM9cmsePEt6yuvxFWaWKRDpKyl5PrQXuwBtvUCgYB8 +P3DapZeoob/NOF8YK9XcIIGQAHcaPAg5xHO3wWLdX5twjpH7M74TFJ75OmlXnSVr +Zl41SJqgLfXkm37kT97DnLD7xa4CDblM+3wqEQThGwQP1txllB7JlVptuw6yYrs1 +UG/lIDMZ8JYmieY8IXW92SV5ii17Z/lnE2CjS7IgIQKBgDWUmO6nyFwvvX9rUkKL ++rdWBZD6bQwTSsXQcYQLrPUdyEI1TuWygaVs9FxcjMcv0zy6sy80oBxnTYONA0ix +FRWGKHAQVPZjEpgISNsJVDg0S0aOA+ptCwZg5RlqacdNeesOTzYgo6WzA595JqkM +J1sFd3MbaL0vTCD+x6qogUPz -----END PRIVATE KEY-----
diff --git a/third_party/wpt_tools/wpt/tools/certs/web-platform.test.pem b/third_party/wpt_tools/wpt/tools/certs/web-platform.test.pem index 8cfbc52..49bed12 100644 --- a/third_party/wpt_tools/wpt/tools/certs/web-platform.test.pem +++ b/third_party/wpt_tools/wpt/tools/certs/web-platform.test.pem
@@ -1,228 +1,228 @@ Certificate: Data: Version: 3 (0x2) - Serial Number: 583483 (0x8e73b) + Serial Number: 388873 (0x5ef09) Signature Algorithm: sha256WithRSAEncryption Issuer: CN=web-platform-tests Validity - Not Before: Apr 12 02:33:49 2021 GMT - Not After : Apr 12 02:33:49 2022 GMT + Not Before: May 12 00:03:24 2021 GMT + Not After : May 12 00:03:24 2022 GMT Subject: CN=web-platform.test Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: - 00:c9:28:8a:b4:1e:41:96:fe:9f:e9:cb:9b:74:7b: - 5c:57:75:a9:94:14:97:5b:f8:aa:f3:d7:e2:1d:7f: - 06:8f:90:e2:4b:14:32:e4:8c:77:c9:fc:fd:83:b4: - 18:e4:d1:44:69:1f:a1:c8:ff:32:cc:7e:7f:d7:b9: - b8:09:60:7b:dc:ba:46:50:4c:81:ed:6a:a1:cf:5e: - 4f:df:6f:c0:d1:31:21:73:28:4e:66:8f:0d:91:7d: - 18:29:9b:f7:73:b4:66:c9:82:8c:2a:4b:a5:34:d4: - 97:2a:b4:71:df:77:d6:63:86:5c:f3:fc:47:dd:c9: - 0a:72:a5:3d:15:8d:31:87:95:35:da:a9:59:5f:55: - 05:d2:01:10:bf:a8:fb:da:ff:fa:d3:30:67:d1:0d: - f7:24:38:41:aa:7f:2d:3a:66:36:42:bb:e6:fe:d3: - 08:1a:83:2e:7c:d3:6e:a4:e5:f2:d5:7a:79:9d:b5: - 9e:1b:6d:33:b1:20:f8:74:2a:63:96:66:79:c2:1f: - c3:e4:46:fd:28:cc:c7:50:5d:8d:6e:ae:8d:ef:58: - eb:87:cc:50:09:85:92:cd:62:3b:f0:86:ba:b9:a8: - 39:4f:7b:e3:c1:0a:b9:d9:8e:d7:91:30:1b:32:05: - b8:22:3c:ff:33:b7:0b:d4:c7:c4:05:fd:ab:d9:d9: - 60:6b + 00:a2:c1:02:f0:3c:55:d1:f1:0f:95:a8:d1:e3:d6: + cc:cf:6c:6d:f9:18:c7:c6:21:cd:2c:1a:9e:b5:13: + 1a:26:b4:a2:34:64:50:a5:1b:03:95:a0:0c:05:5c: + bc:13:1c:83:25:68:f5:8a:b9:db:52:49:8e:75:ae: + cb:2c:34:a3:4c:d6:79:2e:14:50:88:0f:c6:b4:c3: + 00:51:8c:83:df:14:33:4b:85:7e:dd:d2:ff:5b:52: + 8f:20:0a:df:00:49:4d:c7:ab:3b:80:9c:09:42:b6: + fa:4f:2a:d3:7a:12:a9:29:69:6e:a2:fa:cd:77:92: + 05:b0:13:87:99:ab:5d:d4:97:98:35:3c:9a:52:ef: + 62:55:8c:f1:92:c7:9c:f7:28:cb:11:eb:19:e2:8e: + 2d:01:ff:c9:ec:d7:1a:13:22:6b:cc:06:5c:22:0c: + 51:d8:c9:27:c7:23:be:48:d4:72:5a:5f:58:39:00: + b5:fe:13:4d:f7:79:a3:9f:4d:54:d8:b2:f1:ee:9a: + 63:f0:9f:d1:11:df:56:18:e7:b3:ad:3e:70:07:58: + e5:3e:f7:74:8f:5b:2b:02:6e:3b:5f:02:8a:ab:ff: + 49:0d:91:cc:03:2c:fa:94:bb:d3:29:a5:d6:24:23: + 50:85:89:60:f5:da:95:71:47:ad:7a:a1:f0:75:06: + 54:39 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: - 36:AF:C2:D5:E9:DC:41:B0:DA:01:93:2E:54:4D:A7:3A:8D:F4:1D:60 + D1:8D:B3:00:30:03:A3:A0:88:64:1F:C5:7E:C9:EF:0B:10:CF:06:6E X509v3 Authority Key Identifier: - keyid:D3:0C:4F:E6:21:ED:07:9F:23:11:8C:13:F1:C0:5D:14:09:B0:24:32 + keyid:A9:94:1E:FD:DF:C0:53:D3:AD:AB:5F:13:28:FF:C5:C9:04:9C:01:B9 X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Subject Alternative Name: - DNS:web-platform.test, DNS:op1.web-platform.test, DNS:not-web-platform.test, DNS:op9.web-platform.test, DNS:op3.web-platform.test, DNS:op4.web-platform.test, DNS:op8.web-platform.test, DNS:op7.web-platform.test, DNS:op5.web-platform.test, DNS:www.web-platform.test, DNS:op6.web-platform.test, DNS:op2.web-platform.test, DNS:op47.web-platform.test, DNS:op73.web-platform.test, DNS:op17.web-platform.test, DNS:op70.web-platform.test, DNS:www1.web-platform.test, DNS:op40.web-platform.test, DNS:op36.web-platform.test, DNS:op12.web-platform.test, DNS:op80.web-platform.test, DNS:op90.web-platform.test, DNS:op65.web-platform.test, DNS:op20.web-platform.test, DNS:op92.web-platform.test, DNS:op62.web-platform.test, DNS:op76.web-platform.test, DNS:op19.web-platform.test, DNS:op42.web-platform.test, DNS:op39.web-platform.test, DNS:op29.web-platform.test, DNS:op55.web-platform.test, DNS:op86.web-platform.test, DNS:op41.web-platform.test, DNS:op91.web-platform.test, DNS:op33.web-platform.test, DNS:op25.web-platform.test, DNS:op44.web-platform.test, DNS:op13.web-platform.test, DNS:op15.web-platform.test, DNS:op97.web-platform.test, DNS:op64.web-platform.test, DNS:op48.web-platform.test, DNS:op98.web-platform.test, DNS:op63.web-platform.test, DNS:op10.web-platform.test, DNS:op82.web-platform.test, DNS:op56.web-platform.test, DNS:op43.web-platform.test, DNS:op49.web-platform.test, DNS:op53.web-platform.test, DNS:op74.web-platform.test, DNS:op88.web-platform.test, DNS:op95.web-platform.test, DNS:op61.web-platform.test, DNS:op16.web-platform.test, DNS:op87.web-platform.test, DNS:op67.web-platform.test, DNS:op24.web-platform.test, DNS:op26.web-platform.test, DNS:op94.web-platform.test, DNS:op28.web-platform.test, DNS:op83.web-platform.test, DNS:www2.web-platform.test, DNS:op78.web-platform.test, DNS:op89.web-platform.test, DNS:op45.web-platform.test, DNS:op93.web-platform.test, DNS:op85.web-platform.test, DNS:op81.web-platform.test, DNS:op66.web-platform.test, DNS:op99.web-platform.test, DNS:op54.web-platform.test, DNS:op38.web-platform.test, DNS:op23.web-platform.test, DNS:op72.web-platform.test, DNS:op60.web-platform.test, DNS:op35.web-platform.test, DNS:op50.web-platform.test, DNS:op51.web-platform.test, DNS:op32.web-platform.test, DNS:op18.web-platform.test, DNS:op58.web-platform.test, DNS:op27.web-platform.test, DNS:op30.web-platform.test, DNS:op59.web-platform.test, DNS:op84.web-platform.test, DNS:op68.web-platform.test, DNS:op79.web-platform.test, DNS:op75.web-platform.test, DNS:op71.web-platform.test, DNS:op37.web-platform.test, DNS:op52.web-platform.test, DNS:op21.web-platform.test, DNS:op46.web-platform.test, DNS:op57.web-platform.test, DNS:op77.web-platform.test, DNS:op69.web-platform.test, DNS:op31.web-platform.test, DNS:op14.web-platform.test, DNS:op96.web-platform.test, DNS:op11.web-platform.test, DNS:op34.web-platform.test, DNS:op22.web-platform.test, DNS:op3.not-web-platform.test, DNS:op9.not-web-platform.test, DNS:www.www.web-platform.test, DNS:op4.not-web-platform.test, DNS:op8.not-web-platform.test, DNS:op6.not-web-platform.test, DNS:op2.not-web-platform.test, DNS:op5.not-web-platform.test, DNS:op7.not-web-platform.test, DNS:www.not-web-platform.test, DNS:op1.not-web-platform.test, DNS:op97.not-web-platform.test, DNS:op18.not-web-platform.test, DNS:op62.not-web-platform.test, DNS:op15.not-web-platform.test, DNS:op47.not-web-platform.test, DNS:op12.not-web-platform.test, DNS:op74.not-web-platform.test, DNS:op73.not-web-platform.test, DNS:op60.not-web-platform.test, DNS:op56.not-web-platform.test, DNS:op99.not-web-platform.test, DNS:op80.not-web-platform.test, DNS:op40.not-web-platform.test, DNS:op22.not-web-platform.test, DNS:op32.not-web-platform.test, DNS:op67.not-web-platform.test, DNS:op88.not-web-platform.test, DNS:op83.not-web-platform.test, DNS:op11.not-web-platform.test, DNS:op31.not-web-platform.test, DNS:op17.not-web-platform.test, DNS:op96.not-web-platform.test, DNS:op78.not-web-platform.test, DNS:op35.not-web-platform.test, DNS:op71.not-web-platform.test, DNS:op14.not-web-platform.test, DNS:op64.not-web-platform.test, DNS:op29.not-web-platform.test, DNS:www.www1.web-platform.test, DNS:op30.not-web-platform.test, DNS:op55.not-web-platform.test, DNS:op77.not-web-platform.test, DNS:op94.not-web-platform.test, DNS:www2.www.web-platform.test, DNS:op49.not-web-platform.test, DNS:op13.not-web-platform.test, DNS:op45.not-web-platform.test, DNS:op85.not-web-platform.test, DNS:op91.not-web-platform.test, DNS:op66.not-web-platform.test, DNS:op81.not-web-platform.test, DNS:op65.not-web-platform.test, DNS:op98.not-web-platform.test, DNS:op25.not-web-platform.test, DNS:op10.not-web-platform.test, DNS:op23.not-web-platform.test, DNS:op33.not-web-platform.test, DNS:op37.not-web-platform.test, DNS:op89.not-web-platform.test, DNS:op84.not-web-platform.test, DNS:op38.not-web-platform.test, DNS:op61.not-web-platform.test, DNS:op43.not-web-platform.test, DNS:op92.not-web-platform.test, DNS:op54.not-web-platform.test, DNS:op36.not-web-platform.test, DNS:op41.not-web-platform.test, DNS:op39.not-web-platform.test, DNS:op90.not-web-platform.test, DNS:op44.not-web-platform.test, DNS:op57.not-web-platform.test, DNS:www1.not-web-platform.test, DNS:op27.not-web-platform.test, DNS:op86.not-web-platform.test, DNS:op26.not-web-platform.test, DNS:op19.not-web-platform.test, DNS:op82.not-web-platform.test, DNS:op50.not-web-platform.test, DNS:op21.not-web-platform.test, DNS:www2.not-web-platform.test, DNS:op70.not-web-platform.test, DNS:op53.not-web-platform.test, DNS:op72.not-web-platform.test, DNS:op75.not-web-platform.test, DNS:op68.not-web-platform.test, DNS:op51.not-web-platform.test, DNS:op95.not-web-platform.test, DNS:www.www2.web-platform.test, DNS:op58.not-web-platform.test, DNS:op46.not-web-platform.test, DNS:op79.not-web-platform.test, DNS:op24.not-web-platform.test, DNS:op93.not-web-platform.test, DNS:op59.not-web-platform.test, DNS:op48.not-web-platform.test, DNS:op52.not-web-platform.test, DNS:op63.not-web-platform.test, DNS:op87.not-web-platform.test, DNS:op34.not-web-platform.test, DNS:op16.not-web-platform.test, DNS:op20.not-web-platform.test, DNS:op42.not-web-platform.test, DNS:op28.not-web-platform.test, DNS:op76.not-web-platform.test, DNS:www1.www.web-platform.test, DNS:op69.not-web-platform.test, DNS:www1.www1.web-platform.test, DNS:www2.www1.web-platform.test, DNS:www1.www2.web-platform.test, DNS:www2.www2.web-platform.test, DNS:www.www.not-web-platform.test, DNS:xn--lve-6lad.web-platform.test, DNS:www.www1.not-web-platform.test, DNS:www2.www.not-web-platform.test, DNS:www.www2.not-web-platform.test, DNS:www1.www.not-web-platform.test, DNS:www2.www2.not-web-platform.test, DNS:www1.www2.not-web-platform.test, DNS:www1.www1.not-web-platform.test, DNS:www2.www1.not-web-platform.test, DNS:www.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www.web-platform.test, DNS:xn--lve-6lad.www1.web-platform.test, DNS:xn--lve-6lad.www2.web-platform.test, DNS:www1.xn--lve-6lad.web-platform.test, DNS:www2.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www.not-web-platform.test, DNS:www.xn--lve-6lad.not-web-platform.test, DNS:www2.xn--lve-6lad.not-web-platform.test, DNS:www1.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www2.not-web-platform.test, DNS:xn--lve-6lad.www1.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.not-web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.not-web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test + DNS:web-platform.test, DNS:op3.web-platform.test, DNS:op9.web-platform.test, DNS:op5.web-platform.test, DNS:op7.web-platform.test, DNS:op2.web-platform.test, DNS:not-web-platform.test, DNS:op6.web-platform.test, DNS:op1.web-platform.test, DNS:op4.web-platform.test, DNS:www.web-platform.test, DNS:op8.web-platform.test, DNS:op57.web-platform.test, DNS:op93.web-platform.test, DNS:op49.web-platform.test, DNS:op13.web-platform.test, DNS:op24.web-platform.test, DNS:op14.web-platform.test, DNS:op35.web-platform.test, DNS:op91.web-platform.test, DNS:op92.web-platform.test, DNS:op48.web-platform.test, DNS:op74.web-platform.test, DNS:op31.web-platform.test, DNS:op70.web-platform.test, DNS:op71.web-platform.test, DNS:op81.web-platform.test, DNS:op37.web-platform.test, DNS:op86.web-platform.test, DNS:op75.web-platform.test, DNS:op69.web-platform.test, DNS:op36.web-platform.test, DNS:op78.web-platform.test, DNS:op30.web-platform.test, DNS:op19.web-platform.test, DNS:op15.web-platform.test, DNS:op46.web-platform.test, DNS:op12.web-platform.test, DNS:op60.web-platform.test, DNS:op59.web-platform.test, DNS:op25.web-platform.test, DNS:op90.web-platform.test, DNS:op84.web-platform.test, DNS:op22.web-platform.test, DNS:op47.web-platform.test, DNS:www1.web-platform.test, DNS:op89.web-platform.test, DNS:op20.web-platform.test, DNS:op54.web-platform.test, DNS:op23.web-platform.test, DNS:op56.web-platform.test, DNS:op43.web-platform.test, DNS:op83.web-platform.test, DNS:op98.web-platform.test, DNS:op32.web-platform.test, DNS:op34.web-platform.test, DNS:op45.web-platform.test, DNS:op50.web-platform.test, DNS:op63.web-platform.test, DNS:op51.web-platform.test, DNS:op82.web-platform.test, DNS:op11.web-platform.test, DNS:op58.web-platform.test, DNS:op79.web-platform.test, DNS:op10.web-platform.test, DNS:www2.web-platform.test, DNS:op65.web-platform.test, DNS:op44.web-platform.test, DNS:op61.web-platform.test, DNS:op38.web-platform.test, DNS:op41.web-platform.test, DNS:op39.web-platform.test, DNS:op76.web-platform.test, DNS:op77.web-platform.test, DNS:op68.web-platform.test, DNS:op53.web-platform.test, DNS:op52.web-platform.test, DNS:op42.web-platform.test, DNS:op87.web-platform.test, DNS:op18.web-platform.test, DNS:op95.web-platform.test, DNS:op94.web-platform.test, DNS:op99.web-platform.test, DNS:op17.web-platform.test, DNS:op40.web-platform.test, DNS:op80.web-platform.test, DNS:op62.web-platform.test, DNS:op88.web-platform.test, DNS:op28.web-platform.test, DNS:op67.web-platform.test, DNS:op16.web-platform.test, DNS:op85.web-platform.test, DNS:op21.web-platform.test, DNS:op27.web-platform.test, DNS:op33.web-platform.test, DNS:op96.web-platform.test, DNS:op66.web-platform.test, DNS:op72.web-platform.test, DNS:op97.web-platform.test, DNS:op73.web-platform.test, DNS:op64.web-platform.test, DNS:op55.web-platform.test, DNS:op26.web-platform.test, DNS:op29.web-platform.test, DNS:www.not-web-platform.test, DNS:op6.not-web-platform.test, DNS:op5.not-web-platform.test, DNS:op8.not-web-platform.test, DNS:op7.not-web-platform.test, DNS:op1.not-web-platform.test, DNS:op2.not-web-platform.test, DNS:op4.not-web-platform.test, DNS:www.www.web-platform.test, DNS:op9.not-web-platform.test, DNS:op3.not-web-platform.test, DNS:op60.not-web-platform.test, DNS:www2.not-web-platform.test, DNS:op97.not-web-platform.test, DNS:op95.not-web-platform.test, DNS:op61.not-web-platform.test, DNS:op81.not-web-platform.test, DNS:www.www2.web-platform.test, DNS:op96.not-web-platform.test, DNS:op30.not-web-platform.test, DNS:op31.not-web-platform.test, DNS:op34.not-web-platform.test, DNS:www.www1.web-platform.test, DNS:op43.not-web-platform.test, DNS:op12.not-web-platform.test, DNS:op15.not-web-platform.test, DNS:op63.not-web-platform.test, DNS:op84.not-web-platform.test, DNS:op45.not-web-platform.test, DNS:op68.not-web-platform.test, DNS:op37.not-web-platform.test, DNS:op80.not-web-platform.test, DNS:op82.not-web-platform.test, DNS:op16.not-web-platform.test, DNS:op46.not-web-platform.test, DNS:op41.not-web-platform.test, DNS:op47.not-web-platform.test, DNS:op67.not-web-platform.test, DNS:op22.not-web-platform.test, DNS:op70.not-web-platform.test, DNS:op89.not-web-platform.test, DNS:op87.not-web-platform.test, DNS:op48.not-web-platform.test, DNS:op93.not-web-platform.test, DNS:op40.not-web-platform.test, DNS:op21.not-web-platform.test, DNS:op86.not-web-platform.test, DNS:op54.not-web-platform.test, DNS:op44.not-web-platform.test, DNS:op27.not-web-platform.test, DNS:op99.not-web-platform.test, DNS:op35.not-web-platform.test, DNS:op32.not-web-platform.test, DNS:op79.not-web-platform.test, DNS:op94.not-web-platform.test, DNS:op91.not-web-platform.test, DNS:op23.not-web-platform.test, DNS:op53.not-web-platform.test, DNS:op52.not-web-platform.test, DNS:op59.not-web-platform.test, DNS:op88.not-web-platform.test, DNS:op17.not-web-platform.test, DNS:op42.not-web-platform.test, DNS:op90.not-web-platform.test, DNS:op64.not-web-platform.test, DNS:op56.not-web-platform.test, DNS:op66.not-web-platform.test, DNS:www2.www.web-platform.test, DNS:op92.not-web-platform.test, DNS:op24.not-web-platform.test, DNS:op10.not-web-platform.test, DNS:op71.not-web-platform.test, DNS:op38.not-web-platform.test, DNS:www1.www.web-platform.test, DNS:op36.not-web-platform.test, DNS:op62.not-web-platform.test, DNS:op13.not-web-platform.test, DNS:op57.not-web-platform.test, DNS:op19.not-web-platform.test, DNS:op98.not-web-platform.test, DNS:op49.not-web-platform.test, DNS:op85.not-web-platform.test, DNS:op83.not-web-platform.test, DNS:op65.not-web-platform.test, DNS:op75.not-web-platform.test, DNS:op77.not-web-platform.test, DNS:op74.not-web-platform.test, DNS:op11.not-web-platform.test, DNS:op50.not-web-platform.test, DNS:op14.not-web-platform.test, DNS:op73.not-web-platform.test, DNS:op58.not-web-platform.test, DNS:op39.not-web-platform.test, DNS:op18.not-web-platform.test, DNS:op28.not-web-platform.test, DNS:op55.not-web-platform.test, DNS:www1.not-web-platform.test, DNS:op33.not-web-platform.test, DNS:op25.not-web-platform.test, DNS:op26.not-web-platform.test, DNS:op69.not-web-platform.test, DNS:op72.not-web-platform.test, DNS:op78.not-web-platform.test, DNS:op76.not-web-platform.test, DNS:op51.not-web-platform.test, DNS:op29.not-web-platform.test, DNS:op20.not-web-platform.test, DNS:www1.www1.web-platform.test, DNS:www2.www1.web-platform.test, DNS:www1.www2.web-platform.test, DNS:www2.www2.web-platform.test, DNS:www.www.not-web-platform.test, DNS:xn--lve-6lad.web-platform.test, DNS:www.www2.not-web-platform.test, DNS:www1.www.not-web-platform.test, DNS:www2.www.not-web-platform.test, DNS:www.www1.not-web-platform.test, DNS:www1.www2.not-web-platform.test, DNS:www1.www1.not-web-platform.test, DNS:www2.www1.not-web-platform.test, DNS:www2.www2.not-web-platform.test, DNS:xn--lve-6lad.www.web-platform.test, DNS:www.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www2.web-platform.test, DNS:xn--lve-6lad.www1.web-platform.test, DNS:www1.xn--lve-6lad.web-platform.test, DNS:www2.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www.not-web-platform.test, DNS:www.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www2.not-web-platform.test, DNS:www2.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www1.not-web-platform.test, DNS:www1.xn--lve-6lad.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.not-web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.not-web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test Signature Algorithm: sha256WithRSAEncryption - 15:7a:34:3c:51:3f:a0:ca:2d:69:69:ea:3e:69:bc:c9:b5:63: - 77:64:d3:40:a1:33:19:95:81:11:2a:a9:b4:a8:9e:5d:55:ce: - 0e:11:34:b8:f1:0a:2f:be:2e:09:22:56:d9:7b:52:67:52:78: - d1:a2:35:ee:17:dd:c8:cb:40:0b:83:c2:4f:ac:88:dc:17:b1: - 45:14:da:d4:79:7a:b5:f0:6f:02:4a:1a:eb:2e:d8:52:c8:4d: - 64:1b:93:6b:8d:61:5e:c6:ee:70:93:be:db:f2:86:d2:bc:31: - f5:d4:be:8b:eb:7e:9f:8e:70:83:4c:7c:77:51:d6:d3:1c:05: - fc:1d:5e:32:51:6c:68:bb:a1:e9:bc:18:96:aa:ab:d5:e5:de: - d3:00:6e:26:37:09:42:12:53:af:74:73:18:50:86:40:78:bd: - 9e:32:20:19:f5:35:9b:af:c4:e7:07:39:c8:7e:7b:89:19:a2: - 46:5f:a5:78:f4:d4:b9:fb:5b:3d:5d:7b:b9:8c:84:c1:2d:a4: - 52:f3:a8:7b:53:c7:4d:de:2b:d8:7a:56:73:5f:16:fc:85:1a: - f1:5d:b0:a1:8b:83:82:ec:78:6f:31:fb:12:06:77:ce:77:54: - ef:59:a6:63:ee:2a:73:c2:83:25:90:b4:27:72:e2:5c:c9:e4: - 83:a5:83:d7 + 66:52:d6:86:37:00:df:38:69:c6:4c:81:88:a9:23:27:65:c9: + b5:f8:7b:fc:09:6c:fe:12:9c:3c:2a:42:23:7f:6b:08:76:3e: + 1d:0d:91:9c:b1:98:4d:92:36:fe:91:18:95:1e:db:ba:8f:9b: + d4:5a:ef:bc:05:e1:d9:3e:11:2b:a2:2c:c8:67:a1:65:ac:9b: + 8b:1a:5a:97:84:8b:3e:7c:65:e4:58:dc:47:0e:9a:ad:55:8e: + 93:04:75:6a:b7:4e:90:c3:7d:32:a5:77:64:08:44:de:5c:ca: + 65:ac:21:66:07:cb:4b:60:de:93:13:02:0b:78:82:93:b7:8d: + 0a:7d:ea:88:2a:72:dc:ad:b4:39:30:bf:72:bb:e6:2d:c4:b3: + ec:cd:81:84:c4:8b:d8:64:b1:a6:6c:fd:ec:53:ef:ca:18:a5: + 6f:13:8c:97:9b:b2:3d:58:07:87:ab:68:96:21:e9:a9:80:07: + a3:b4:de:6d:89:8d:ad:af:9f:5f:0a:ec:65:0c:8e:cb:46:fc: + 0d:8c:a7:e9:9c:fe:fa:cc:a9:8a:55:48:25:48:49:c9:9b:19: + 24:c6:40:9d:f6:4c:aa:2a:a9:52:86:17:31:90:82:95:9b:16: + 75:4e:00:e0:35:e2:84:de:97:c6:5e:c9:b7:1c:0c:56:24:17: + 12:b6:69:a0 -----BEGIN CERTIFICATE----- -MIIgvDCCH6SgAwIBAgIDCOc7MA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl -Yi1wbGF0Zm9ybS10ZXN0czAeFw0yMTA0MTIwMjMzNDlaFw0yMjA0MTIwMjMzNDla +MIIgvDCCH6SgAwIBAgIDBe8JMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl +Yi1wbGF0Zm9ybS10ZXN0czAeFw0yMTA1MTIwMDAzMjRaFw0yMjA1MTIwMDAzMjRa MBwxGjAYBgNVBAMMEXdlYi1wbGF0Zm9ybS50ZXN0MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAySiKtB5Blv6f6cubdHtcV3WplBSXW/iq89fiHX8Gj5Di -SxQy5Ix3yfz9g7QY5NFEaR+hyP8yzH5/17m4CWB73LpGUEyB7Wqhz15P32/A0TEh -cyhOZo8NkX0YKZv3c7RmyYKMKkulNNSXKrRx33fWY4Zc8/xH3ckKcqU9FY0xh5U1 -2qlZX1UF0gEQv6j72v/60zBn0Q33JDhBqn8tOmY2Qrvm/tMIGoMufNNupOXy1Xp5 -nbWeG20zsSD4dCpjlmZ5wh/D5Eb9KMzHUF2Nbq6N71jrh8xQCYWSzWI78Ia6uag5 -T3vjwQq52Y7XkTAbMgW4Ijz/M7cL1MfEBf2r2dlgawIDAQABo4IeBDCCHgAwCQYD -VR0TBAIwADAdBgNVHQ4EFgQUNq/C1encQbDaAZMuVE2nOo30HWAwHwYDVR0jBBgw -FoAU0wxP5iHtB58jEYwT8cBdFAmwJDIwCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoG +AAOCAQ8AMIIBCgKCAQEAosEC8DxV0fEPlajR49bMz2xt+RjHxiHNLBqetRMaJrSi +NGRQpRsDlaAMBVy8ExyDJWj1irnbUkmOda7LLDSjTNZ5LhRQiA/GtMMAUYyD3xQz +S4V+3dL/W1KPIArfAElNx6s7gJwJQrb6TyrTehKpKWluovrNd5IFsBOHmatd1JeY +NTyaUu9iVYzxksec9yjLEesZ4o4tAf/J7NcaEyJrzAZcIgxR2MknxyO+SNRyWl9Y +OQC1/hNN93mjn01U2LLx7ppj8J/REd9WGOezrT5wB1jlPvd0j1srAm47XwKKq/9J +DZHMAyz6lLvTKaXWJCNQhYlg9dqVcUeteqHwdQZUOQIDAQABo4IeBDCCHgAwCQYD +VR0TBAIwADAdBgNVHQ4EFgQU0Y2zADADo6CIZB/FfsnvCxDPBm4wHwYDVR0jBBgw +FoAUqZQe/d/AU9Otq18TKP/FyQScAbkwCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoG CCsGAQUFBwMBMIIdjwYDVR0RBIIdhjCCHYKCEXdlYi1wbGF0Zm9ybS50ZXN0ghVv -cDEud2ViLXBsYXRmb3JtLnRlc3SCFW5vdC13ZWItcGxhdGZvcm0udGVzdIIVb3A5 -LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDMud2ViLXBsYXRmb3JtLnRlc3SCFW9wNC53 -ZWItcGxhdGZvcm0udGVzdIIVb3A4LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDcud2Vi -LXBsYXRmb3JtLnRlc3SCFW9wNS53ZWItcGxhdGZvcm0udGVzdIIVd3d3LndlYi1w -bGF0Zm9ybS50ZXN0ghVvcDYud2ViLXBsYXRmb3JtLnRlc3SCFW9wMi53ZWItcGxh -dGZvcm0udGVzdIIWb3A0Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A3My53ZWItcGxh -dGZvcm0udGVzdIIWb3AxNy53ZWItcGxhdGZvcm0udGVzdIIWb3A3MC53ZWItcGxh -dGZvcm0udGVzdIIWd3d3MS53ZWItcGxhdGZvcm0udGVzdIIWb3A0MC53ZWItcGxh -dGZvcm0udGVzdIIWb3AzNi53ZWItcGxhdGZvcm0udGVzdIIWb3AxMi53ZWItcGxh -dGZvcm0udGVzdIIWb3A4MC53ZWItcGxhdGZvcm0udGVzdIIWb3A5MC53ZWItcGxh -dGZvcm0udGVzdIIWb3A2NS53ZWItcGxhdGZvcm0udGVzdIIWb3AyMC53ZWItcGxh -dGZvcm0udGVzdIIWb3A5Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A2Mi53ZWItcGxh -dGZvcm0udGVzdIIWb3A3Ni53ZWItcGxhdGZvcm0udGVzdIIWb3AxOS53ZWItcGxh -dGZvcm0udGVzdIIWb3A0Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AzOS53ZWItcGxh -dGZvcm0udGVzdIIWb3AyOS53ZWItcGxhdGZvcm0udGVzdIIWb3A1NS53ZWItcGxh -dGZvcm0udGVzdIIWb3A4Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A0MS53ZWItcGxh -dGZvcm0udGVzdIIWb3A5MS53ZWItcGxhdGZvcm0udGVzdIIWb3AzMy53ZWItcGxh -dGZvcm0udGVzdIIWb3AyNS53ZWItcGxhdGZvcm0udGVzdIIWb3A0NC53ZWItcGxh -dGZvcm0udGVzdIIWb3AxMy53ZWItcGxhdGZvcm0udGVzdIIWb3AxNS53ZWItcGxh -dGZvcm0udGVzdIIWb3A5Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A2NC53ZWItcGxh -dGZvcm0udGVzdIIWb3A0OC53ZWItcGxhdGZvcm0udGVzdIIWb3A5OC53ZWItcGxh -dGZvcm0udGVzdIIWb3A2My53ZWItcGxhdGZvcm0udGVzdIIWb3AxMC53ZWItcGxh -dGZvcm0udGVzdIIWb3A4Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A1Ni53ZWItcGxh -dGZvcm0udGVzdIIWb3A0My53ZWItcGxhdGZvcm0udGVzdIIWb3A0OS53ZWItcGxh -dGZvcm0udGVzdIIWb3A1My53ZWItcGxhdGZvcm0udGVzdIIWb3A3NC53ZWItcGxh -dGZvcm0udGVzdIIWb3A4OC53ZWItcGxhdGZvcm0udGVzdIIWb3A5NS53ZWItcGxh -dGZvcm0udGVzdIIWb3A2MS53ZWItcGxhdGZvcm0udGVzdIIWb3AxNi53ZWItcGxh -dGZvcm0udGVzdIIWb3A4Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A2Ny53ZWItcGxh -dGZvcm0udGVzdIIWb3AyNC53ZWItcGxhdGZvcm0udGVzdIIWb3AyNi53ZWItcGxh -dGZvcm0udGVzdIIWb3A5NC53ZWItcGxhdGZvcm0udGVzdIIWb3AyOC53ZWItcGxh -dGZvcm0udGVzdIIWb3A4My53ZWItcGxhdGZvcm0udGVzdIIWd3d3Mi53ZWItcGxh -dGZvcm0udGVzdIIWb3A3OC53ZWItcGxhdGZvcm0udGVzdIIWb3A4OS53ZWItcGxh -dGZvcm0udGVzdIIWb3A0NS53ZWItcGxhdGZvcm0udGVzdIIWb3A5My53ZWItcGxh -dGZvcm0udGVzdIIWb3A4NS53ZWItcGxhdGZvcm0udGVzdIIWb3A4MS53ZWItcGxh -dGZvcm0udGVzdIIWb3A2Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A5OS53ZWItcGxh -dGZvcm0udGVzdIIWb3A1NC53ZWItcGxhdGZvcm0udGVzdIIWb3AzOC53ZWItcGxh -dGZvcm0udGVzdIIWb3AyMy53ZWItcGxhdGZvcm0udGVzdIIWb3A3Mi53ZWItcGxh -dGZvcm0udGVzdIIWb3A2MC53ZWItcGxhdGZvcm0udGVzdIIWb3AzNS53ZWItcGxh -dGZvcm0udGVzdIIWb3A1MC53ZWItcGxhdGZvcm0udGVzdIIWb3A1MS53ZWItcGxh -dGZvcm0udGVzdIIWb3AzMi53ZWItcGxhdGZvcm0udGVzdIIWb3AxOC53ZWItcGxh -dGZvcm0udGVzdIIWb3A1OC53ZWItcGxhdGZvcm0udGVzdIIWb3AyNy53ZWItcGxh -dGZvcm0udGVzdIIWb3AzMC53ZWItcGxhdGZvcm0udGVzdIIWb3A1OS53ZWItcGxh -dGZvcm0udGVzdIIWb3A4NC53ZWItcGxhdGZvcm0udGVzdIIWb3A2OC53ZWItcGxh -dGZvcm0udGVzdIIWb3A3OS53ZWItcGxhdGZvcm0udGVzdIIWb3A3NS53ZWItcGxh -dGZvcm0udGVzdIIWb3A3MS53ZWItcGxhdGZvcm0udGVzdIIWb3AzNy53ZWItcGxh -dGZvcm0udGVzdIIWb3A1Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AyMS53ZWItcGxh -dGZvcm0udGVzdIIWb3A0Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A1Ny53ZWItcGxh -dGZvcm0udGVzdIIWb3A3Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A2OS53ZWItcGxh -dGZvcm0udGVzdIIWb3AzMS53ZWItcGxhdGZvcm0udGVzdIIWb3AxNC53ZWItcGxh -dGZvcm0udGVzdIIWb3A5Ni53ZWItcGxhdGZvcm0udGVzdIIWb3AxMS53ZWItcGxh -dGZvcm0udGVzdIIWb3AzNC53ZWItcGxhdGZvcm0udGVzdIIWb3AyMi53ZWItcGxh -dGZvcm0udGVzdIIZb3AzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A5Lm5vdC13 -ZWItcGxhdGZvcm0udGVzdIIZd3d3Lnd3dy53ZWItcGxhdGZvcm0udGVzdIIZb3A0 -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A4Lm5vdC13ZWItcGxhdGZvcm0udGVz -dIIZb3A2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AyLm5vdC13ZWItcGxhdGZv -cm0udGVzdIIZb3A1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A3Lm5vdC13ZWIt -cGxhdGZvcm0udGVzdIIZd3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AxLm5v -dC13ZWItcGxhdGZvcm0udGVzdIIab3A5Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC -Gm9wMTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDYyLm5vdC13ZWItcGxhdGZv -cm0udGVzdIIab3AxNS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDcubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0ghpvcDEyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3 -NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzMubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0ghpvcDYwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1Ni5ub3Qtd2ViLXBs -YXRmb3JtLnRlc3SCGm9wOTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgwLm5v -dC13ZWItcGxhdGZvcm0udGVzdIIab3A0MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC -Gm9wMjIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDMyLm5vdC13ZWItcGxhdGZv -cm0udGVzdIIab3A2Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODgubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0ghpvcDgzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3Ax -MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzEubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0ghpvcDE3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5Ni5ub3Qtd2ViLXBs -YXRmb3JtLnRlc3SCGm9wNzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM1Lm5v +cDMud2ViLXBsYXRmb3JtLnRlc3SCFW9wOS53ZWItcGxhdGZvcm0udGVzdIIVb3A1 +LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDcud2ViLXBsYXRmb3JtLnRlc3SCFW9wMi53 +ZWItcGxhdGZvcm0udGVzdIIVbm90LXdlYi1wbGF0Zm9ybS50ZXN0ghVvcDYud2Vi +LXBsYXRmb3JtLnRlc3SCFW9wMS53ZWItcGxhdGZvcm0udGVzdIIVb3A0LndlYi1w +bGF0Zm9ybS50ZXN0ghV3d3cud2ViLXBsYXRmb3JtLnRlc3SCFW9wOC53ZWItcGxh +dGZvcm0udGVzdIIWb3A1Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A5My53ZWItcGxh +dGZvcm0udGVzdIIWb3A0OS53ZWItcGxhdGZvcm0udGVzdIIWb3AxMy53ZWItcGxh +dGZvcm0udGVzdIIWb3AyNC53ZWItcGxhdGZvcm0udGVzdIIWb3AxNC53ZWItcGxh +dGZvcm0udGVzdIIWb3AzNS53ZWItcGxhdGZvcm0udGVzdIIWb3A5MS53ZWItcGxh +dGZvcm0udGVzdIIWb3A5Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A0OC53ZWItcGxh +dGZvcm0udGVzdIIWb3A3NC53ZWItcGxhdGZvcm0udGVzdIIWb3AzMS53ZWItcGxh +dGZvcm0udGVzdIIWb3A3MC53ZWItcGxhdGZvcm0udGVzdIIWb3A3MS53ZWItcGxh +dGZvcm0udGVzdIIWb3A4MS53ZWItcGxhdGZvcm0udGVzdIIWb3AzNy53ZWItcGxh +dGZvcm0udGVzdIIWb3A4Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A3NS53ZWItcGxh +dGZvcm0udGVzdIIWb3A2OS53ZWItcGxhdGZvcm0udGVzdIIWb3AzNi53ZWItcGxh +dGZvcm0udGVzdIIWb3A3OC53ZWItcGxhdGZvcm0udGVzdIIWb3AzMC53ZWItcGxh +dGZvcm0udGVzdIIWb3AxOS53ZWItcGxhdGZvcm0udGVzdIIWb3AxNS53ZWItcGxh +dGZvcm0udGVzdIIWb3A0Ni53ZWItcGxhdGZvcm0udGVzdIIWb3AxMi53ZWItcGxh +dGZvcm0udGVzdIIWb3A2MC53ZWItcGxhdGZvcm0udGVzdIIWb3A1OS53ZWItcGxh +dGZvcm0udGVzdIIWb3AyNS53ZWItcGxhdGZvcm0udGVzdIIWb3A5MC53ZWItcGxh +dGZvcm0udGVzdIIWb3A4NC53ZWItcGxhdGZvcm0udGVzdIIWb3AyMi53ZWItcGxh +dGZvcm0udGVzdIIWb3A0Ny53ZWItcGxhdGZvcm0udGVzdIIWd3d3MS53ZWItcGxh +dGZvcm0udGVzdIIWb3A4OS53ZWItcGxhdGZvcm0udGVzdIIWb3AyMC53ZWItcGxh +dGZvcm0udGVzdIIWb3A1NC53ZWItcGxhdGZvcm0udGVzdIIWb3AyMy53ZWItcGxh +dGZvcm0udGVzdIIWb3A1Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A0My53ZWItcGxh +dGZvcm0udGVzdIIWb3A4My53ZWItcGxhdGZvcm0udGVzdIIWb3A5OC53ZWItcGxh +dGZvcm0udGVzdIIWb3AzMi53ZWItcGxhdGZvcm0udGVzdIIWb3AzNC53ZWItcGxh +dGZvcm0udGVzdIIWb3A0NS53ZWItcGxhdGZvcm0udGVzdIIWb3A1MC53ZWItcGxh +dGZvcm0udGVzdIIWb3A2My53ZWItcGxhdGZvcm0udGVzdIIWb3A1MS53ZWItcGxh +dGZvcm0udGVzdIIWb3A4Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AxMS53ZWItcGxh +dGZvcm0udGVzdIIWb3A1OC53ZWItcGxhdGZvcm0udGVzdIIWb3A3OS53ZWItcGxh +dGZvcm0udGVzdIIWb3AxMC53ZWItcGxhdGZvcm0udGVzdIIWd3d3Mi53ZWItcGxh +dGZvcm0udGVzdIIWb3A2NS53ZWItcGxhdGZvcm0udGVzdIIWb3A0NC53ZWItcGxh +dGZvcm0udGVzdIIWb3A2MS53ZWItcGxhdGZvcm0udGVzdIIWb3AzOC53ZWItcGxh +dGZvcm0udGVzdIIWb3A0MS53ZWItcGxhdGZvcm0udGVzdIIWb3AzOS53ZWItcGxh +dGZvcm0udGVzdIIWb3A3Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A3Ny53ZWItcGxh +dGZvcm0udGVzdIIWb3A2OC53ZWItcGxhdGZvcm0udGVzdIIWb3A1My53ZWItcGxh +dGZvcm0udGVzdIIWb3A1Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A0Mi53ZWItcGxh +dGZvcm0udGVzdIIWb3A4Ny53ZWItcGxhdGZvcm0udGVzdIIWb3AxOC53ZWItcGxh +dGZvcm0udGVzdIIWb3A5NS53ZWItcGxhdGZvcm0udGVzdIIWb3A5NC53ZWItcGxh +dGZvcm0udGVzdIIWb3A5OS53ZWItcGxhdGZvcm0udGVzdIIWb3AxNy53ZWItcGxh +dGZvcm0udGVzdIIWb3A0MC53ZWItcGxhdGZvcm0udGVzdIIWb3A4MC53ZWItcGxh +dGZvcm0udGVzdIIWb3A2Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A4OC53ZWItcGxh +dGZvcm0udGVzdIIWb3AyOC53ZWItcGxhdGZvcm0udGVzdIIWb3A2Ny53ZWItcGxh +dGZvcm0udGVzdIIWb3AxNi53ZWItcGxhdGZvcm0udGVzdIIWb3A4NS53ZWItcGxh +dGZvcm0udGVzdIIWb3AyMS53ZWItcGxhdGZvcm0udGVzdIIWb3AyNy53ZWItcGxh +dGZvcm0udGVzdIIWb3AzMy53ZWItcGxhdGZvcm0udGVzdIIWb3A5Ni53ZWItcGxh +dGZvcm0udGVzdIIWb3A2Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A3Mi53ZWItcGxh +dGZvcm0udGVzdIIWb3A5Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A3My53ZWItcGxh +dGZvcm0udGVzdIIWb3A2NC53ZWItcGxhdGZvcm0udGVzdIIWb3A1NS53ZWItcGxh +dGZvcm0udGVzdIIWb3AyNi53ZWItcGxhdGZvcm0udGVzdIIWb3AyOS53ZWItcGxh +dGZvcm0udGVzdIIZd3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A2Lm5vdC13 +ZWItcGxhdGZvcm0udGVzdIIZb3A1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A4 +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A3Lm5vdC13ZWItcGxhdGZvcm0udGVz +dIIZb3AxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AyLm5vdC13ZWItcGxhdGZv +cm0udGVzdIIZb3A0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZd3d3Lnd3dy53ZWIt +cGxhdGZvcm0udGVzdIIZb3A5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AzLm5v +dC13ZWItcGxhdGZvcm0udGVzdIIab3A2MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC +Gnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk3Lm5vdC13ZWItcGxhdGZv +cm0udGVzdIIab3A5NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNjEubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0ghpvcDgxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3 +Lnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCGm9wOTYubm90LXdlYi1wbGF0Zm9ybS50 +ZXN0ghpvcDMwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AzMS5ub3Qtd2ViLXBs +YXRmb3JtLnRlc3SCGm9wMzQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3 +MS53ZWItcGxhdGZvcm0udGVzdIIab3A0My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC +Gm9wMTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE1Lm5vdC13ZWItcGxhdGZv +cm0udGVzdIIab3A2My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODQubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0ghpvcDQ1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2 +OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzcubm90LXdlYi1wbGF0Zm9ybS50 +ZXN0ghpvcDgwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4Mi5ub3Qtd2ViLXBs +YXRmb3JtLnRlc3SCGm9wMTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ2Lm5v +dC13ZWItcGxhdGZvcm0udGVzdIIab3A0MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC +Gm9wNDcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDY3Lm5vdC13ZWItcGxhdGZv +cm0udGVzdIIab3AyMi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzAubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0ghpvcDg5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4 +Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDgubm90LXdlYi1wbGF0Zm9ybS50 +ZXN0ghpvcDkzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A0MC5ub3Qtd2ViLXBs +YXRmb3JtLnRlc3SCGm9wMjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDg2Lm5v +dC13ZWItcGxhdGZvcm0udGVzdIIab3A1NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC +Gm9wNDQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI3Lm5vdC13ZWItcGxhdGZv +cm0udGVzdIIab3A5OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzUubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0ghpvcDMyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3 +OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTQubm90LXdlYi1wbGF0Zm9ybS50 +ZXN0ghpvcDkxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyMy5ub3Qtd2ViLXBs +YXRmb3JtLnRlc3SCGm9wNTMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDUyLm5v +dC13ZWItcGxhdGZvcm0udGVzdIIab3A1OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC +Gm9wODgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE3Lm5vdC13ZWItcGxhdGZv +cm0udGVzdIIab3A0Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTAubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0ghpvcDY0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1 +Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNjYubm90LXdlYi1wbGF0Zm9ybS50 +ZXN0ghp3d3cyLnd3dy53ZWItcGxhdGZvcm0udGVzdIIab3A5Mi5ub3Qtd2ViLXBs +YXRmb3JtLnRlc3SCGm9wMjQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDEwLm5v dC13ZWItcGxhdGZvcm0udGVzdIIab3A3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC -Gm9wMTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDY0Lm5vdC13ZWItcGxhdGZv -cm0udGVzdIIab3AyOS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dy53d3cxLndl -Yi1wbGF0Zm9ybS50ZXN0ghpvcDMwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1 -NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzcubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0ghpvcDk0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3Mi53d3cud2ViLXBs -YXRmb3JtLnRlc3SCGm9wNDkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDEzLm5v -dC13ZWItcGxhdGZvcm0udGVzdIIab3A0NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC -Gm9wODUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDkxLm5vdC13ZWItcGxhdGZv -cm0udGVzdIIab3A2Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODEubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0ghpvcDY1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5 -OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjUubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0ghpvcDEwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyMy5ub3Qtd2ViLXBs -YXRmb3JtLnRlc3SCGm9wMzMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM3Lm5v -dC13ZWItcGxhdGZvcm0udGVzdIIab3A4OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC -Gm9wODQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM4Lm5vdC13ZWItcGxhdGZv -cm0udGVzdIIab3A2MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDMubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0ghpvcDkyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1 -NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzYubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0ghpvcDQxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AzOS5ub3Qtd2ViLXBs -YXRmb3JtLnRlc3SCGm9wOTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ0Lm5v -dC13ZWItcGxhdGZvcm0udGVzdIIab3A1Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC -Gnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI3Lm5vdC13ZWItcGxhdGZv -cm0udGVzdIIab3A4Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjYubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0ghpvcDE5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4 -Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTAubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0ghpvcDIxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3Mi5ub3Qtd2ViLXBs -YXRmb3JtLnRlc3SCGm9wNzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDUzLm5v -dC13ZWItcGxhdGZvcm0udGVzdIIab3A3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC -Gm9wNzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDY4Lm5vdC13ZWItcGxhdGZv -cm0udGVzdIIab3A1MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTUubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIab3A1 -OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDYubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0ghpvcDc5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyNC5ub3Qtd2ViLXBs -YXRmb3JtLnRlc3SCGm9wOTMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU5Lm5v -dC13ZWItcGxhdGZvcm0udGVzdIIab3A0OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC -Gm9wNTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDYzLm5vdC13ZWItcGxhdGZv -cm0udGVzdIIab3A4Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzQubm90LXdl -Yi1wbGF0Zm9ybS50ZXN0ghpvcDE2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3Ay -MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDIubm90LXdlYi1wbGF0Zm9ybS50 -ZXN0ghpvcDI4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3Ni5ub3Qtd2ViLXBs -YXRmb3JtLnRlc3SCGnd3dzEud3d3LndlYi1wbGF0Zm9ybS50ZXN0ghpvcDY5Lm5v +Gm9wMzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cxLnd3dy53ZWItcGxhdGZv +cm0udGVzdIIab3AzNi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNjIubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0ghpvcDEzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1 +Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTkubm90LXdlYi1wbGF0Zm9ybS50 +ZXN0ghpvcDk4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A0OS5ub3Qtd2ViLXBs +YXRmb3JtLnRlc3SCGm9wODUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgzLm5v +dC13ZWItcGxhdGZvcm0udGVzdIIab3A2NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC +Gm9wNzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDc3Lm5vdC13ZWItcGxhdGZv +cm0udGVzdIIab3A3NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTEubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0ghpvcDUwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3Ax +NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzMubm90LXdlYi1wbGF0Zm9ybS50 +ZXN0ghpvcDU4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AzOS5ub3Qtd2ViLXBs +YXRmb3JtLnRlc3SCGm9wMTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI4Lm5v +dC13ZWItcGxhdGZvcm0udGVzdIIab3A1NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC +Gnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDMzLm5vdC13ZWItcGxhdGZv +cm0udGVzdIIab3AyNS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjYubm90LXdl +Yi1wbGF0Zm9ybS50ZXN0ghpvcDY5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3 +Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzgubm90LXdlYi1wbGF0Zm9ybS50 +ZXN0ghpvcDc2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1MS5ub3Qtd2ViLXBs +YXRmb3JtLnRlc3SCGm9wMjkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDIwLm5v dC13ZWItcGxhdGZvcm0udGVzdIIbd3d3MS53d3cxLndlYi1wbGF0Zm9ybS50ZXN0 ght3d3cyLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCG3d3dzEud3d3Mi53ZWItcGxh dGZvcm0udGVzdIIbd3d3Mi53d3cyLndlYi1wbGF0Zm9ybS50ZXN0gh13d3cud3d3 Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIeeG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9y -bS50ZXN0gh53d3cud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCHnd3dzIud3d3 -Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIed3d3Lnd3dzIubm90LXdlYi1wbGF0Zm9y -bS50ZXN0gh53d3cxLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3 -Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3Mi5ub3Qtd2ViLXBsYXRm -b3JtLnRlc3SCH3d3dzEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIu -d3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCInd3dy54bi0tbHZlLTZsYWQud2Vi -LXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRl -c3SCInhuLS1sdmUtNmxhZC53d3cud2ViLXBsYXRmb3JtLnRlc3SCI3huLS1sdmUt -NmxhZC53d3cxLndlYi1wbGF0Zm9ybS50ZXN0giN4bi0tbHZlLTZsYWQud3d3Mi53 +bS50ZXN0gh53d3cud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCHnd3dzEud3d3 +Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIed3d3Mi53d3cubm90LXdlYi1wbGF0Zm9y +bS50ZXN0gh53d3cud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3 +Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3MS5ub3Qtd2ViLXBsYXRm +b3JtLnRlc3SCH3d3dzIud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIu +d3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC53d3cud2Vi +LXBsYXRmb3JtLnRlc3SCInd3dy54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRl +c3SCInhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCI3huLS1sdmUt +NmxhZC53d3cyLndlYi1wbGF0Zm9ybS50ZXN0giN4bi0tbHZlLTZsYWQud3d3MS53 ZWItcGxhdGZvcm0udGVzdIIjd3d3MS54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3Jt LnRlc3SCI3d3dzIueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0giZ4bi0t bHZlLTZsYWQud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIImd3d3LnhuLS1sdmUt -NmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3d3dzIueG4tLWx2ZS02bGFkLm5v -dC13ZWItcGxhdGZvcm0udGVzdIInd3d3MS54bi0tbHZlLTZsYWQubm90LXdlYi1w -bGF0Zm9ybS50ZXN0gid4bi0tbHZlLTZsYWQud3d3Mi5ub3Qtd2ViLXBsYXRmb3Jt -LnRlc3SCJ3huLS1sdmUtNmxhZC53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIp +NmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3huLS1sdmUtNmxhZC53d3cyLm5v +dC13ZWItcGxhdGZvcm0udGVzdIInd3d3Mi54bi0tbHZlLTZsYWQubm90LXdlYi1w +bGF0Zm9ybS50ZXN0gid4bi0tbHZlLTZsYWQud3d3MS5ub3Qtd2ViLXBsYXRmb3Jt +LnRlc3SCJ3d3dzEueG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIp eG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCK3huLS1s -dmUtNmxhZC54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCLXhuLS1uOGo2 -ZHM1M2x3d2tycWh2MjhhLnd3dy53ZWItcGxhdGZvcm0udGVzdIItd3d3LnhuLS1u -OGo2ZHM1M2x3d2tycWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0gi14bi0tbjhqNmRz -NTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1 -M2x3d2tycWh2MjhhLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzIueG4tLW44 +dmUtNmxhZC54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCLXd3dy54bi0t +bjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdIIteG4tLW44ajZk +czUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gi14bi0tbjhqNmRz +NTNsd3drcnFodjI4YS53d3cud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzIueG4tLW44 +ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzEueG4tLW44 ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1 -M2x3d2tycWh2MjhhLnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzEueG4tLW44 -ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCL3huLS1sdmUtNmxh -ZC54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjF4bi0tbjhqNmRz -NTNsd3drcnFodjI4YS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjF3d3cueG4t -LW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ3d3cy -LnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxhdGZvcm0udGVzdIIy +M2x3d2tycWh2MjhhLnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1 +M2x3d2tycWh2MjhhLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCL3huLS1sdmUtNmxh +ZC54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjF3d3cueG4tLW44 +ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjF4bi0tbjhq +NmRzNTNsd3drcnFodjI4YS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ4bi0t +bjhqNmRzNTNsd3drcnFodjI4YS53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIy eG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRl c3SCMnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9y -bS50ZXN0gjJ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cyLm5vdC13ZWItcGxh +bS50ZXN0gjJ3d3cyLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5vdC13ZWItcGxh dGZvcm0udGVzdII2eG4tLW44ajZkczUzbHd3a3JxaHYyOGEueG4tLWx2ZS02bGFk LndlYi1wbGF0Zm9ybS50ZXN0gjZ4bi0tbHZlLTZsYWQueG4tLW44ajZkczUzbHd3 a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCOnhuLS1uOGo2ZHM1M2x3d2tycWh2 @@ -231,10 +231,10 @@ c3SCQXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1uOGo2ZHM1M2x3d2tycWh2 MjhhLndlYi1wbGF0Zm9ybS50ZXN0gkV4bi0tbjhqNmRzNTNsd3drcnFodjI4YS54 bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwDQYJ -KoZIhvcNAQELBQADggEBABV6NDxRP6DKLWlp6j5pvMm1Y3dk00ChMxmVgREqqbSo -nl1Vzg4RNLjxCi++LgkiVtl7UmdSeNGiNe4X3cjLQAuDwk+siNwXsUUU2tR5erXw -bwJKGusu2FLITWQbk2uNYV7G7nCTvtvyhtK8MfXUvovrfp+OcINMfHdR1tMcBfwd -XjJRbGi7oem8GJaqq9Xl3tMAbiY3CUISU690cxhQhkB4vZ4yIBn1NZuvxOcHOch+ -e4kZokZfpXj01Ln7Wz1de7mMhMEtpFLzqHtTx03eK9h6VnNfFvyFGvFdsKGLg4Ls -eG8x+xIGd853VO9ZpmPuKnPCgyWQtCdy4lzJ5IOlg9c= +KoZIhvcNAQELBQADggEBAGZS1oY3AN84acZMgYipIydlybX4e/wJbP4SnDwqQiN/ +awh2Ph0NkZyxmE2SNv6RGJUe27qPm9Ra77wF4dk+ESuiLMhnoWWsm4saWpeEiz58 +ZeRY3EcOmq1VjpMEdWq3TpDDfTKld2QIRN5cymWsIWYHy0tg3pMTAgt4gpO3jQp9 +6ogqctyttDkwv3K75i3Es+zNgYTEi9hksaZs/exT78oYpW8TjJebsj1YB4eraJYh +6amAB6O03m2Jja2vn18K7GUMjstG/A2Mp+mc/vrMqYpVSCVIScmbGSTGQJ32TKoq +qVKGFzGQgpWbFnVOAOA14oTel8ZeybccDFYkFxK2aaA= -----END CERTIFICATE-----
diff --git a/third_party/wpt_tools/wpt/tools/quic/serve.py b/third_party/wpt_tools/wpt/tools/quic/serve.py index 517b4c34b..f9ae75b 100755 --- a/third_party/wpt_tools/wpt/tools/quic/serve.py +++ b/third_party/wpt_tools/wpt/tools/quic/serve.py
@@ -4,11 +4,12 @@ import logging import os import sys +from typing import Any _dir = os.path.dirname(__file__) -def get_parser(): +def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description='QUIC server') parser.add_argument( '-c', @@ -52,7 +53,8 @@ return parser -def run(venv, **kwargs): +def run(venv: Any, **kwargs: Any) -> None: + # The venv argument is passed with `wpt serve-quic-transport` but is unused. assert sys.version_info.major == 3, 'QUIC server only runs in Python 3' logging.basicConfig( format='%(asctime)s %(levelname)s %(name)s %(message)s', @@ -61,15 +63,15 @@ # Delay import after version check to make the error easier to understand. from .quic_transport_server import start - start(kwargs) + start(**kwargs) -def main(): +def main() -> None: # This is only used when executing the script directly. Users are # responsible for managing venv themselves. `wpt serve-quic-transport` does # NOT use this code path. kwargs = vars(get_parser().parse_args()) - return run(None, **kwargs) + run(None, **kwargs) if __name__ == '__main__':
diff --git a/third_party/wpt_tools/wpt/tools/serve/serve.py b/third_party/wpt_tools/wpt/tools/serve/serve.py index fa3d7434..4694d43 100644 --- a/third_party/wpt_tools/wpt/tools/serve/serve.py +++ b/third_party/wpt_tools/wpt/tools/serve/serve.py
@@ -28,7 +28,6 @@ from wptserve import server as wptserve, handlers from wptserve import stash from wptserve import config -from wptserve.logger import set_logger from wptserve.handlers import filesystem_path, wrap_pipeline from wptserve.utils import get_port, HTTPException, http2_compatible from mod_pywebsocket import standalone as pywebsocket @@ -480,7 +479,7 @@ self.mountpoint_routes[file_url] = [("GET", file_url, handlers.FileHandler(base_path=base_path, url_base=url_base))] -def get_route_builder(aliases, config=None): +def get_route_builder(logger, aliases, config): builder = RoutesBuilder() for alias in aliases: url = alias["url-path"] @@ -500,21 +499,26 @@ self.proc = None self.daemon = None self.mp_context = mp_context - self.stop = mp_context.Event() + self.stop_flag = mp_context.Event() self.scheme = scheme - def start(self, init_func, host, port, paths, routes, bind_address, config, **kwargs): + def start(self, init_func, host, port, paths, routes, bind_address, config, log_handlers, **kwargs): self.proc = self.mp_context.Process(target=self.create_daemon, args=(init_func, host, port, paths, routes, bind_address, - config), + config, log_handlers), name='%s on port %s' % (self.scheme, port), kwargs=kwargs) self.proc.daemon = True self.proc.start() def create_daemon(self, init_func, host, port, paths, routes, bind_address, - config, **kwargs): - ensure_logger(config) + config, log_handlers, **kwargs): + # Ensure that when we start this in a new process we have the global lock + # in the logging module unlocked + importlib.reload(logging) + + logger = get_logger(config.log_level, log_handlers) + if sys.platform == "darwin": # on Darwin, NOFILE starts with a very low limit (256), so bump it up a little # by way of comparison, Debian starts with a limit of 1024, Windows 512 @@ -529,7 +533,7 @@ if soft < new_soft: resource.setrlimit(resource.RLIMIT_NOFILE, (new_soft, hard)) try: - self.daemon = init_func(host, port, paths, routes, bind_address, config, **kwargs) + self.daemon = init_func(logger, host, port, paths, routes, bind_address, config, **kwargs) except socket.error: logger.critical("Socket error on port %s" % port, file=sys.stderr) raise @@ -539,29 +543,26 @@ if self.daemon: try: - self.daemon.start(block=False) + self.daemon.start() try: - self.stop.wait() + self.stop_flag.wait() except KeyboardInterrupt: pass + finally: + self.daemon.stop() except Exception: - print(traceback.format_exc(), file=sys.stderr) + logger.critical(traceback.format_exc()) raise - def wait(self): - self.stop.set() - self.proc.join() - - def kill(self): - self.stop.set() - self.proc.terminate() - self.proc.join() + def stop(self, timeout=None): + self.stop_flag.set() + self.proc.join(timeout) def is_alive(self): return self.proc.is_alive() -def check_subdomains(config, routes, mp_context): +def check_subdomains(logger, config, routes, mp_context, log_handlers): paths = config.paths bind_address = config.bind_address @@ -571,7 +572,7 @@ wrapper = ServerProc(mp_context) wrapper.start(start_http_server, host, port, paths, routes, - bind_address, config) + bind_address, config, log_handlers) url = "http://{}:{}/".format(host, port) connected = False @@ -598,7 +599,7 @@ logger.critical("Failed probing domain {}. {}".format(domain, EDIT_HOSTS_HELP)) sys.exit(1) - wrapper.wait() + wrapper.stop() def make_hosts_file(config, host): @@ -621,8 +622,8 @@ return "".join(rv) -def start_servers(host, ports, paths, routes, bind_address, config, - mp_context, **kwargs): +def start_servers(logger, host, ports, paths, routes, bind_address, config, + mp_context, log_handlers, **kwargs): servers = defaultdict(list) for scheme, ports in ports.items(): assert len(ports) == {"http": 2, "https": 2}.get(scheme, 1) @@ -645,22 +646,18 @@ server_proc = ServerProc(mp_context, scheme=scheme) server_proc.start(init_func, host, port, paths, routes, bind_address, - config, **kwargs) + config, log_handlers, **kwargs) servers[scheme].append((port, server_proc)) return servers -def startup_failed(log=True): - # Log=False is a workaround for https://github.com/web-platform-tests/wpt/issues/22719 - if log: - logger.critical(EDIT_HOSTS_HELP) - else: - print("CRITICAL %s" % EDIT_HOSTS_HELP, file=sys.stderr) +def startup_failed(logger): + logger.critical(EDIT_HOSTS_HELP) sys.exit(1) -def start_http_server(host, port, paths, routes, bind_address, config, **kwargs): +def start_http_server(logger, host, port, paths, routes, bind_address, config, **kwargs): try: return wptserve.WebTestHttpd(host=host, port=port, @@ -674,10 +671,10 @@ certificate=None, latency=kwargs.get("latency")) except Exception: - startup_failed() + startup_failed(logger) -def start_https_server(host, port, paths, routes, bind_address, config, **kwargs): +def start_https_server(logger, host, port, paths, routes, bind_address, config, **kwargs): try: return wptserve.WebTestHttpd(host=host, port=port, @@ -692,10 +689,10 @@ encrypt_after_connect=config.ssl_config["encrypt_after_connect"], latency=kwargs.get("latency")) except Exception: - startup_failed() + startup_failed(logger) -def start_http2_server(host, port, paths, routes, bind_address, config, **kwargs): +def start_http2_server(logger, host, port, paths, routes, bind_address, config, **kwargs): try: return wptserve.WebTestHttpd(host=host, port=port, @@ -713,11 +710,12 @@ latency=kwargs.get("latency"), http2=True) except Exception: - startup_failed() + startup_failed(logger) class WebSocketDaemon(object): def __init__(self, host, port, doc_root, handlers_root, bind_address, ssl_config): + logger = logging.getLogger() self.host = host cmd_args = ["-p", port, "-d", doc_root, @@ -738,22 +736,19 @@ if not ports: # TODO: Fix the logging configuration in WebSockets processes # see https://github.com/web-platform-tests/wpt/issues/22719 - print("Failed to start websocket server on port %s, " - "is something already using that port?" % port, file=sys.stderr) + logger.critical("Failed to start websocket server on port %s, " + "is something already using that port?" % port, file=sys.stderr) raise OSError() assert all(item == ports[0] for item in ports) self.port = ports[0] self.started = False self.server_thread = None - def start(self, block=False): + def start(self): self.started = True - if block: - self.server.serve_forever() - else: - self.server_thread = threading.Thread(target=self.server.serve_forever) - self.server_thread.setDaemon(True) # don't hang on exit - self.server_thread.start() + self.server_thread = threading.Thread(target=self.server.serve_forever) + self.server_thread.setDaemon(True) # don't hang on exit + self.server_thread.start() def stop(self): """ @@ -773,22 +768,7 @@ self.server = None -def release_mozlog_lock(): - try: - from mozlog.structuredlog import StructuredLogger - try: - StructuredLogger._lock.release() - except threading.ThreadError: - pass - except ImportError: - pass - - -def start_ws_server(host, port, paths, routes, bind_address, config, **kwargs): - # Ensure that when we start this in a new process we have the global lock - # in the logging module unlocked - importlib.reload(logging) - release_mozlog_lock() +def start_ws_server(logger, host, port, paths, routes, bind_address, config, **kwargs): try: return WebSocketDaemon(host, str(port), @@ -797,14 +777,10 @@ bind_address, ssl_config=None) except Exception: - startup_failed(log=False) + startup_failed(logger) -def start_wss_server(host, port, paths, routes, bind_address, config, **kwargs): - # Ensure that when we start this in a new process we have the global lock - # in the logging module unlocked - importlib.reload(logging) - release_mozlog_lock() +def start_wss_server(logger, host, port, paths, routes, bind_address, config, **kwargs): try: return WebSocketDaemon(host, str(port), @@ -813,7 +789,7 @@ bind_address, config.ssl_config) except Exception: - startup_failed(log=False) + startup_failed(logger) class QuicTransportDaemon(object): @@ -834,46 +810,39 @@ self.command = args self.proc = None - def start(self, block=False): - if block: - subprocess.call(self.command) - else: - def handle_signal(*_): - if self.proc: - try: - self.proc.terminate() - except OSError: - # It's fine if the child already exits. - pass - self.proc.wait() - sys.exit(0) + def start(self): + def handle_signal(*_): + if self.proc: + try: + self.proc.terminate() + except OSError: + # It's fine if the child already exits. + pass + self.proc.wait() + sys.exit(0) - signal.signal(signal.SIGTERM, handle_signal) - signal.signal(signal.SIGINT, handle_signal) + signal.signal(signal.SIGTERM, handle_signal) + signal.signal(signal.SIGINT, handle_signal) - self.proc = subprocess.Popen(self.command) - # Give the server a second to start and then check. - time.sleep(1) - if self.proc.poll(): - sys.exit(1) + self.proc = subprocess.Popen(self.command) + # Give the server a second to start and then check. + time.sleep(1) + if self.proc.poll(): + sys.exit(1) -def start_quic_transport_server(host, port, paths, routes, bind_address, config, **kwargs): - # Ensure that when we start this in a new process we have the global lock - # in the logging module unlocked - importlib.reload(logging) - release_mozlog_lock() +def start_quic_transport_server(logger, host, port, paths, routes, bind_address, config, **kwargs): try: return QuicTransportDaemon(host, - port, - private_key=config.ssl_config["key_path"], - certificate=config.ssl_config["cert_path"], - log_level=config.log_level) + port, + private_key=config.ssl_config["key_path"], + certificate=config.ssl_config["cert_path"], + log_level=config.log_level) except Exception: - startup_failed(log=False) + startup_failed(logger) -def start(config, routes, mp_context, **kwargs): +def start(logger, config, routes, mp_context, log_handlers, **kwargs): host = config["server_host"] ports = config.ports paths = config.paths @@ -881,20 +850,22 @@ logger.debug("Using ports: %r" % ports) - servers = start_servers(host, ports, paths, routes, bind_address, config, mp_context, **kwargs) + servers = start_servers(logger, host, ports, paths, routes, bind_address, config, mp_context, + log_handlers, **kwargs) return servers -def iter_procs(servers): +def iter_servers(servers): for servers in servers.values(): for port, server in servers: - yield server.proc + yield server def _make_subdomains_product(s, depth=2): return {u".".join(x) for x in chain(*(product(s, repeat=i) for i in range(1, depth+1)))} + def _make_origin_policy_subdomains(limit): return {u"op%d" % x for x in range(1,limit+1)} @@ -963,12 +934,13 @@ computed_properties = ["ws_doc_root"] + config.ConfigBuilder.computed_properties - def __init__(self, *args, **kwargs): + def __init__(self, logger, *args, **kwargs): if "subdomains" not in kwargs: kwargs["subdomains"] = _subdomains if "not_subdomains" not in kwargs: kwargs["not_subdomains"] = _not_subdomains super(ConfigBuilder, self).__init__( + logger, *args, **kwargs ) @@ -987,19 +959,14 @@ else: return os.path.join(data["doc_root"], "websockets", "handlers") - def ws_doc_root(self, v): - self._ws_doc_root = v - - ws_doc_root = property(None, ws_doc_root) - def _get_paths(self, data): rv = super(ConfigBuilder, self)._get_paths(data) rv["ws_doc_root"] = data["ws_doc_root"] return rv -def build_config(override_path=None, config_cls=ConfigBuilder, **kwargs): - rv = config_cls() +def build_config(logger, override_path=None, config_cls=ConfigBuilder, **kwargs): + rv = config_cls(logger) enable_http2 = kwargs.get("h2") if enable_http2 is None: @@ -1069,16 +1036,37 @@ def __getattr__(self, name): return getattr(multiprocessing, name) -def ensure_logger(config): - global logger - try: - logger - except NameError: - logger = config.logger - set_logger(logger) -def run(config_cls=ConfigBuilder, route_builder=None, mp_context=None, **kwargs): - received_signal = threading.Event() +def get_logger(log_level, log_handlers): + """Get a logger configured to log at level log_level + + If the logger has existing handlers the log_handlers argument is ignored. + Otherwise the handlers in log_handlers are added to the logger. If there are + no log_handlers passed and no configured handlers, a stream handler is added + to the logger. + + Typically this is called once per process to set up logging in that process. + + :param log_level: - A string representing a log level e.g. "info" + :param log_handlers: - Optional list of Handler objects. + """ + logger = logging.getLogger() + logger.setLevel(getattr(logging, log_level.upper())) + if not logger.hasHandlers(): + if log_handlers is not None: + for handler in log_handlers: + logger.addHandler(handler) + else: + handler = logging.StreamHandler(sys.stdout) + formatter = logging.Formatter("[%(asctime)s %(processName)s] %(levelname)s - %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + return logger + + +def run(config_cls=ConfigBuilder, route_builder=None, mp_context=None, log_handlers=None, + **kwargs): + logger = get_logger("INFO", log_handlers) if mp_context is None: if hasattr(multiprocessing, "get_context"): @@ -1086,16 +1074,12 @@ else: mp_context = MpContext() - with build_config(os.path.join(repo_root, "config.json"), + with build_config(logger, + os.path.join(repo_root, "config.json"), config_cls=config_cls, **kwargs) as config: - ensure_logger(config) - # Configure the root logger to cover third-party libraries. - logging.getLogger().setLevel(config.log_level) - - def handle_signal(signum, frame): - logger.debug("Received signal %s. Shutting down.", signum) - received_signal.set() + # This sets the right log level + logger = get_logger(config.log_level, log_handlers) bind_address = config["bind_address"] @@ -1110,10 +1094,10 @@ if route_builder is None: route_builder = get_route_builder - routes = route_builder(config.aliases, config).get_routes() + routes = route_builder(logger, config.aliases, config).get_routes() if config["check_subdomains"]: - check_subdomains(config, routes, mp_context) + check_subdomains(logger, config, routes, mp_context, log_handlers) stash_address = None if bind_address: @@ -1121,25 +1105,34 @@ logger.debug("Going to use port %d for stash" % stash_address[1]) with stash.StashServer(stash_address, authkey=str(uuid.uuid4())): - servers = start(config, routes, mp_context, **kwargs) - signal.signal(signal.SIGTERM, handle_signal) - signal.signal(signal.SIGINT, handle_signal) + servers = start(logger, config, routes, mp_context, log_handlers, **kwargs) - while (all(subproc.is_alive() for subproc in iter_procs(servers)) and - not received_signal.is_set() and not kwargs["exit_after_start"]): - for subproc in iter_procs(servers): - subproc.join(1) + if not kwargs["exit_after_start"]: + try: + # Periodically check if all the servers are alive + server_process_exited = False + while not server_process_exited: + for server in iter_servers(servers): + server.proc.join(1) + if not server.proc.is_alive(): + server_process_exited = True + break + except KeyboardInterrupt: + pass failed_subproc = 0 - for subproc in iter_procs(servers): + for server in iter_servers(servers): + subproc = server.proc if subproc.is_alive(): - logger.info('Status of subprocess "%s": running' % subproc.name) + logger.info('Status of subprocess "%s": running', subproc.name) + server.stop(timeout=1) + + if server.proc.exitcode == 0: + logger.info('Status of subprocess "%s": exited correctly', subproc.name) else: - if subproc.exitcode == 0: - logger.info('Status of subprocess "%s": exited correctly' % subproc.name) - else: - logger.warning('Status of subprocess "%s": failed. Exit with non-zero status: %d' % (subproc.name, subproc.exitcode)) - failed_subproc += 1 + logger.warning('Status of subprocess "%s": failed. Exit with non-zero status: %d', + subproc.name, subproc.exitcode) + failed_subproc += 1 return failed_subproc
diff --git a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py index 82be5ae9f..4bc1c67 100644 --- a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py +++ b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py
@@ -38,9 +38,9 @@ from mod_pywebsocket.handshake import hybi # Export AbortedByUserException, HandshakeException, and VersionException # symbol from this module. -from mod_pywebsocket.handshake._base import AbortedByUserException -from mod_pywebsocket.handshake._base import HandshakeException -from mod_pywebsocket.handshake._base import VersionException +from mod_pywebsocket.handshake.base import AbortedByUserException +from mod_pywebsocket.handshake.base import HandshakeException +from mod_pywebsocket.handshake.base import VersionException _LOGGER = logging.getLogger(__name__)
diff --git a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/_base.py b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/_base.py deleted file mode 100644 index 358dd8d4..0000000 --- a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/_base.py +++ /dev/null
@@ -1,179 +0,0 @@ -# Copyright 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. -"""Common functions and exceptions used by WebSocket opening handshake -processors. -""" - -from __future__ import absolute_import -from mod_pywebsocket import common -from mod_pywebsocket import http_header_util - - -class AbortedByUserException(Exception): - """Exception for aborting a connection intentionally. - - If this exception is raised in do_extra_handshake handler, the connection - will be abandoned. No other WebSocket or HTTP(S) handler will be invoked. - - If this exception is raised in transfer_data_handler, the connection will - be closed without closing handshake. No other WebSocket or HTTP(S) handler - will be invoked. - """ - - pass - - -class HandshakeException(Exception): - """This exception will be raised when an error occurred while processing - WebSocket initial handshake. - """ - def __init__(self, name, status=None): - super(HandshakeException, self).__init__(name) - self.status = status - - -class VersionException(Exception): - """This exception will be raised when a version of client request does not - match with version the server supports. - """ - def __init__(self, name, supported_versions=''): - """Construct an instance. - - Args: - supported_version: a str object to show supported hybi versions. - (e.g. '13') - """ - super(VersionException, self).__init__(name) - self.supported_versions = supported_versions - - -def get_default_port(is_secure): - if is_secure: - return common.DEFAULT_WEB_SOCKET_SECURE_PORT - else: - return common.DEFAULT_WEB_SOCKET_PORT - - -def validate_subprotocol(subprotocol): - """Validate a value in the Sec-WebSocket-Protocol field. - - See the Section 4.1., 4.2.2., and 4.3. of RFC 6455. - """ - - if not subprotocol: - raise HandshakeException('Invalid subprotocol name: empty') - - # Parameter should be encoded HTTP token. - state = http_header_util.ParsingState(subprotocol) - token = http_header_util.consume_token(state) - rest = http_header_util.peek(state) - # If |rest| is not None, |subprotocol| is not one token or invalid. If - # |rest| is None, |token| must not be None because |subprotocol| is - # concatenation of |token| and |rest| and is not None. - if rest is not None: - raise HandshakeException('Invalid non-token string in subprotocol ' - 'name: %r' % rest) - - -def parse_host_header(request): - fields = request.headers_in[common.HOST_HEADER].split(':', 1) - if len(fields) == 1: - return fields[0], get_default_port(request.is_https()) - try: - return fields[0], int(fields[1]) - except ValueError as e: - raise HandshakeException('Invalid port number format: %r' % e) - - -def format_header(name, value): - return u'%s: %s\r\n' % (name, value) - - -def get_mandatory_header(request, key): - value = request.headers_in.get(key) - if value is None: - raise HandshakeException('Header %s is not defined' % key) - return value - - -def validate_mandatory_header(request, key, expected_value, fail_status=None): - value = get_mandatory_header(request, key) - - if value.lower() != expected_value.lower(): - raise HandshakeException( - 'Expected %r for header %s but found %r (case-insensitive)' % - (expected_value, key, value), - status=fail_status) - - -def check_request_line(request): - # 5.1 1. The three character UTF-8 string "GET". - # 5.1 2. A UTF-8-encoded U+0020 SPACE character (0x20 byte). - if request.method != u'GET': - raise HandshakeException('Method is not GET: %r' % request.method) - - if request.protocol != u'HTTP/1.1': - raise HandshakeException('Version is not HTTP/1.1: %r' % - request.protocol) - - -def parse_token_list(data): - """Parses a header value which follows 1#token and returns parsed elements - as a list of strings. - - Leading LWSes must be trimmed. - """ - - state = http_header_util.ParsingState(data) - - token_list = [] - - while True: - token = http_header_util.consume_token(state) - if token is not None: - token_list.append(token) - - http_header_util.consume_lwses(state) - - if http_header_util.peek(state) is None: - break - - if not http_header_util.consume_string(state, ','): - raise HandshakeException('Expected a comma but found %r' % - http_header_util.peek(state)) - - http_header_util.consume_lwses(state) - - if len(token_list) == 0: - raise HandshakeException('No valid token found') - - return token_list - - -# vi:sts=4 sw=4 et
diff --git a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/base.py b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/base.py new file mode 100644 index 0000000..ffad0614 --- /dev/null +++ b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/base.py
@@ -0,0 +1,396 @@ +# Copyright 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. +"""Common functions and exceptions used by WebSocket opening handshake +processors. +""" + +from __future__ import absolute_import + +from mod_pywebsocket import common +from mod_pywebsocket import http_header_util +from mod_pywebsocket.extensions import get_extension_processor +from mod_pywebsocket.stream import StreamOptions +from mod_pywebsocket.stream import Stream +from mod_pywebsocket import util + +from six.moves import map +from six.moves import range + +# Defining aliases for values used frequently. +_VERSION_LATEST = common.VERSION_HYBI_LATEST +_VERSION_LATEST_STRING = str(_VERSION_LATEST) +_SUPPORTED_VERSIONS = [ + _VERSION_LATEST, +] + + +class AbortedByUserException(Exception): + """Exception for aborting a connection intentionally. + + If this exception is raised in do_extra_handshake handler, the connection + will be abandoned. No other WebSocket or HTTP(S) handler will be invoked. + + If this exception is raised in transfer_data_handler, the connection will + be closed without closing handshake. No other WebSocket or HTTP(S) handler + will be invoked. + """ + + pass + + +class HandshakeException(Exception): + """This exception will be raised when an error occurred while processing + WebSocket initial handshake. + """ + def __init__(self, name, status=None): + super(HandshakeException, self).__init__(name) + self.status = status + + +class VersionException(Exception): + """This exception will be raised when a version of client request does not + match with version the server supports. + """ + def __init__(self, name, supported_versions=''): + """Construct an instance. + + Args: + supported_version: a str object to show supported hybi versions. + (e.g. '13') + """ + super(VersionException, self).__init__(name) + self.supported_versions = supported_versions + + +def get_default_port(is_secure): + if is_secure: + return common.DEFAULT_WEB_SOCKET_SECURE_PORT + else: + return common.DEFAULT_WEB_SOCKET_PORT + + +def validate_subprotocol(subprotocol): + """Validate a value in the Sec-WebSocket-Protocol field. + + See the Section 4.1., 4.2.2., and 4.3. of RFC 6455. + """ + + if not subprotocol: + raise HandshakeException('Invalid subprotocol name: empty') + + # Parameter should be encoded HTTP token. + state = http_header_util.ParsingState(subprotocol) + token = http_header_util.consume_token(state) + rest = http_header_util.peek(state) + # If |rest| is not None, |subprotocol| is not one token or invalid. If + # |rest| is None, |token| must not be None because |subprotocol| is + # concatenation of |token| and |rest| and is not None. + if rest is not None: + raise HandshakeException('Invalid non-token string in subprotocol ' + 'name: %r' % rest) + + +def parse_host_header(request): + fields = request.headers_in[common.HOST_HEADER].split(':', 1) + if len(fields) == 1: + return fields[0], get_default_port(request.is_https()) + try: + return fields[0], int(fields[1]) + except ValueError as e: + raise HandshakeException('Invalid port number format: %r' % e) + + +def get_mandatory_header(request, key): + value = request.headers_in.get(key) + if value is None: + raise HandshakeException('Header %s is not defined' % key) + return value + + +def validate_mandatory_header(request, key, expected_value, fail_status=None): + value = get_mandatory_header(request, key) + + if value.lower() != expected_value.lower(): + raise HandshakeException( + 'Expected %r for header %s but found %r (case-insensitive)' % + (expected_value, key, value), + status=fail_status) + + +def parse_token_list(data): + """Parses a header value which follows 1#token and returns parsed elements + as a list of strings. + + Leading LWSes must be trimmed. + """ + + state = http_header_util.ParsingState(data) + + token_list = [] + + while True: + token = http_header_util.consume_token(state) + if token is not None: + token_list.append(token) + + http_header_util.consume_lwses(state) + + if http_header_util.peek(state) is None: + break + + if not http_header_util.consume_string(state, ','): + raise HandshakeException('Expected a comma but found %r' % + http_header_util.peek(state)) + + http_header_util.consume_lwses(state) + + if len(token_list) == 0: + raise HandshakeException('No valid token found') + + return token_list + + +class HandshakerBase(object): + def __init__(self, request, dispatcher): + self._logger = util.get_class_logger(self) + self._request = request + self._dispatcher = dispatcher + + """ subclasses must implement the five following methods """ + + def _protocol_rfc(self): + """ Return the name of the RFC that the handshake class is implementing. + """ + + raise AssertionError("subclasses should implement this method") + + def _transform_header(self, header): + """ + :param header: header name + + transform the header name if needed. For example, HTTP/2 subclass will + return the name of the header in lower case. + """ + + raise AssertionError("subclasses should implement this method") + + def _validate_request(self): + """ validate that all the mandatory fields are set """ + + raise AssertionError("subclasses should implement this method") + + def _set_accept(self): + """ Computes accept value based on Sec-WebSocket-Accept if needed. """ + + raise AssertionError("subclasses should implement this method") + + def _send_handshake(self): + """ Prepare and send the response after it has been parsed and processed. + """ + + raise AssertionError("subclasses should implement this method") + + def do_handshake(self): + self._request.ws_close_code = None + self._request.ws_close_reason = None + + # Parsing. + self._validate_request() + self._request.ws_resource = self._request.uri + self._request.ws_version = self._check_version() + + try: + self._get_origin() + self._set_protocol() + self._parse_extensions() + + self._set_accept() + + self._logger.debug('Protocol version is ' + self._protocol_rfc()) + + # Setup extension processors. + self._request.ws_extension_processors = self._get_extension_processors_requested( + ) + + # List of extra headers. The extra handshake handler may add header + # data as name/value pairs to this list and pywebsocket appends + # them to the WebSocket handshake. + self._request.extra_headers = [] + + # Extra handshake handler may modify/remove processors. + self._dispatcher.do_extra_handshake(self._request) + + stream_options = StreamOptions() + self._process_extensions(stream_options) + + self._request.ws_stream = Stream(self._request, stream_options) + + if self._request.ws_requested_protocols is not None: + if self._request.ws_protocol is None: + raise HandshakeException( + 'do_extra_handshake must choose one subprotocol from ' + 'ws_requested_protocols and set it to ws_protocol') + validate_subprotocol(self._request.ws_protocol) + + self._logger.debug('Subprotocol accepted: %r', + self._request.ws_protocol) + else: + if self._request.ws_protocol is not None: + raise HandshakeException( + 'ws_protocol must be None when the client didn\'t ' + 'request any subprotocol') + + self._send_handshake() + except HandshakeException as e: + if not e.status: + # Fallback to 400 bad request by default. + e.status = common.HTTP_STATUS_BAD_REQUEST + raise e + + def _check_version(self): + sec_websocket_version_header = self._transform_header( + common.SEC_WEBSOCKET_VERSION_HEADER) + version = get_mandatory_header(self._request, + sec_websocket_version_header) + if version == _VERSION_LATEST_STRING: + return _VERSION_LATEST + + if version.find(',') >= 0: + raise HandshakeException( + 'Multiple versions (%r) are not allowed for header %s' % + (version, sec_websocket_version_header), + status=common.HTTP_STATUS_BAD_REQUEST) + raise VersionException('Unsupported version %r for header %s' % + (version, sec_websocket_version_header), + supported_versions=', '.join( + map(str, _SUPPORTED_VERSIONS))) + + def _get_origin(self): + origin_header = self._transform_header(common.ORIGIN_HEADER) + origin = self._request.headers_in.get(origin_header) + if origin is None: + self._logger.debug('Client request does not have origin header') + self._request.ws_origin = origin + + def _set_protocol(self): + self._request.ws_protocol = None + + sec_websocket_protocol_header = self._transform_header( + common.SEC_WEBSOCKET_PROTOCOL_HEADER) + protocol_header = self._request.headers_in.get( + sec_websocket_protocol_header) + + if protocol_header is None: + self._request.ws_requested_protocols = None + return + + self._request.ws_requested_protocols = parse_token_list( + protocol_header) + self._logger.debug('Subprotocols requested: %r', + self._request.ws_requested_protocols) + + def _parse_extensions(self): + sec_websocket_extensions_header = self._transform_header( + common.SEC_WEBSOCKET_EXTENSIONS_HEADER) + extensions_header = self._request.headers_in.get( + sec_websocket_extensions_header) + if not extensions_header: + self._request.ws_requested_extensions = None + return + + try: + self._request.ws_requested_extensions = common.parse_extensions( + extensions_header) + except common.ExtensionParsingException as e: + raise HandshakeException( + 'Failed to parse sec-websocket-extensions header: %r' % e) + + self._logger.debug( + 'Extensions requested: %r', + list( + map(common.ExtensionParameter.name, + self._request.ws_requested_extensions))) + + def _get_extension_processors_requested(self): + processors = [] + if self._request.ws_requested_extensions is not None: + for extension_request in self._request.ws_requested_extensions: + processor = get_extension_processor(extension_request) + # Unknown extension requests are just ignored. + if processor is not None: + processors.append(processor) + return processors + + def _process_extensions(self, stream_options): + processors = [ + processor for processor in self._request.ws_extension_processors + if processor is not None + ] + + # Ask each processor if there are extensions on the request which + # cannot co-exist. When processor decided other processors cannot + # co-exist with it, the processor marks them (or itself) as + # "inactive". The first extension processor has the right to + # make the final call. + for processor in reversed(processors): + if processor.is_active(): + processor.check_consistency_with_other_processors(processors) + processors = [ + processor for processor in processors if processor.is_active() + ] + + accepted_extensions = [] + + for index, processor in enumerate(processors): + if not processor.is_active(): + continue + + extension_response = processor.get_extension_response() + if extension_response is None: + # Rejected. + continue + + accepted_extensions.append(extension_response) + + processor.setup_stream_options(stream_options) + + # Inactivate all of the following compression extensions. + for j in range(index + 1, len(processors)): + processors[j].set_active(False) + + if len(accepted_extensions) > 0: + self._request.ws_extensions = accepted_extensions + self._logger.debug( + 'Extensions accepted: %r', + list(map(common.ExtensionParameter.name, accepted_extensions))) + else: + self._request.ws_extensions = None + + +# vi:sts=4 sw=4 et
diff --git a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py index 7fd63eb..cf931db 100644 --- a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py +++ b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py
@@ -35,38 +35,32 @@ from __future__ import absolute_import import base64 -import logging -import os import re from hashlib import sha1 from mod_pywebsocket import common -from mod_pywebsocket.extensions import get_extension_processor -from mod_pywebsocket.handshake._base import check_request_line -from mod_pywebsocket.handshake._base import format_header -from mod_pywebsocket.handshake._base import get_mandatory_header -from mod_pywebsocket.handshake._base import HandshakeException -from mod_pywebsocket.handshake._base import parse_token_list -from mod_pywebsocket.handshake._base import validate_mandatory_header -from mod_pywebsocket.handshake._base import validate_subprotocol -from mod_pywebsocket.handshake._base import VersionException -from mod_pywebsocket.stream import Stream -from mod_pywebsocket.stream import StreamOptions +from mod_pywebsocket.handshake.base import get_mandatory_header +from mod_pywebsocket.handshake.base import HandshakeException +from mod_pywebsocket.handshake.base import parse_token_list +from mod_pywebsocket.handshake.base import validate_mandatory_header +from mod_pywebsocket.handshake.base import HandshakerBase from mod_pywebsocket import util -from six.moves import map -from six.moves import range # Used to validate the value in the Sec-WebSocket-Key header strictly. RFC 4648 # disallows non-zero padding, so the character right before == must be any of # A, Q, g and w. _SEC_WEBSOCKET_KEY_REGEX = re.compile('^[+/0-9A-Za-z]{21}[AQgw]==$') -# Defining aliases for values used frequently. -_VERSION_LATEST = common.VERSION_HYBI_LATEST -_VERSION_LATEST_STRING = str(_VERSION_LATEST) -_SUPPORTED_VERSIONS = [ - _VERSION_LATEST, -] + +def check_request_line(request): + # 5.1 1. The three character UTF-8 string "GET". + # 5.1 2. A UTF-8-encoded U+0020 SPACE character (0x20 byte). + if request.method != u'GET': + raise HandshakeException('Method is not GET: %r' % request.method) + + if request.protocol != u'HTTP/1.1': + raise HandshakeException('Version is not HTTP/1.1: %r' % + request.protocol) def compute_accept(key): @@ -90,7 +84,11 @@ return compute_accept(key) -class Handshaker(object): +def format_header(name, value): + return u'%s: %s\r\n' % (name, value) + + +class Handshaker(HandshakerBase): """Opening handshake processor for the WebSocket protocol (RFC 6455).""" def __init__(self, request, dispatcher): """Construct an instance. @@ -101,11 +99,13 @@ Handshaker will add attributes such as ws_resource during handshake. """ + super(Handshaker, self).__init__(request, dispatcher) - self._logger = util.get_class_logger(self) + def _transform_header(self, header): + return header - self._request = request - self._dispatcher = dispatcher + def _protocol_rfc(self): + return 'RFC 6455' def _validate_connection_header(self): connection = get_mandatory_header(self._request, @@ -127,189 +127,20 @@ '%s header doesn\'t contain "%s"' % (common.CONNECTION_HEADER, common.UPGRADE_CONNECTION_TYPE)) - def do_handshake(self): - self._request.ws_close_code = None - self._request.ws_close_reason = None - - # Parsing. - + def _validate_request(self): check_request_line(self._request) - validate_mandatory_header(self._request, common.UPGRADE_HEADER, common.WEBSOCKET_UPGRADE_TYPE) - self._validate_connection_header() - - self._request.ws_resource = self._request.uri - unused_host = get_mandatory_header(self._request, common.HOST_HEADER) - self._request.ws_version = self._check_version() - - try: - self._get_origin() - self._set_protocol() - self._parse_extensions() - - # Key validation, response generation. - - key = self._get_key() - accept = compute_accept(key) - self._logger.debug('%s: %r (%s)', - common.SEC_WEBSOCKET_ACCEPT_HEADER, accept, - util.hexify(base64.b64decode(accept))) - - self._logger.debug('Protocol version is RFC 6455') - - # Setup extension processors. - - processors = [] - if self._request.ws_requested_extensions is not None: - for extension_request in self._request.ws_requested_extensions: - processor = get_extension_processor(extension_request) - # Unknown extension requests are just ignored. - if processor is not None: - processors.append(processor) - self._request.ws_extension_processors = processors - - # List of extra headers. The extra handshake handler may add header - # data as name/value pairs to this list and pywebsocket appends - # them to the WebSocket handshake. - self._request.extra_headers = [] - - # Extra handshake handler may modify/remove processors. - self._dispatcher.do_extra_handshake(self._request) - processors = [ - processor - for processor in self._request.ws_extension_processors - if processor is not None - ] - - # Ask each processor if there are extensions on the request which - # cannot co-exist. When processor decided other processors cannot - # co-exist with it, the processor marks them (or itself) as - # "inactive". The first extension processor has the right to - # make the final call. - for processor in reversed(processors): - if processor.is_active(): - processor.check_consistency_with_other_processors( - processors) - processors = [ - processor for processor in processors if processor.is_active() - ] - - accepted_extensions = [] - - stream_options = StreamOptions() - - for index, processor in enumerate(processors): - if not processor.is_active(): - continue - - extension_response = processor.get_extension_response() - if extension_response is None: - # Rejected. - continue - - accepted_extensions.append(extension_response) - - processor.setup_stream_options(stream_options) - - # Inactivate all of the following compression extensions. - for j in range(index + 1, len(processors)): - processors[j].set_active(False) - - if len(accepted_extensions) > 0: - self._request.ws_extensions = accepted_extensions - self._logger.debug( - 'Extensions accepted: %r', - list( - map(common.ExtensionParameter.name, - accepted_extensions))) - else: - self._request.ws_extensions = None - - self._request.ws_stream = self._create_stream(stream_options) - - if self._request.ws_requested_protocols is not None: - if self._request.ws_protocol is None: - raise HandshakeException( - 'do_extra_handshake must choose one subprotocol from ' - 'ws_requested_protocols and set it to ws_protocol') - validate_subprotocol(self._request.ws_protocol) - - self._logger.debug('Subprotocol accepted: %r', - self._request.ws_protocol) - else: - if self._request.ws_protocol is not None: - raise HandshakeException( - 'ws_protocol must be None when the client didn\'t ' - 'request any subprotocol') - - self._send_handshake(accept) - except HandshakeException as e: - if not e.status: - # Fallback to 400 bad request by default. - e.status = common.HTTP_STATUS_BAD_REQUEST - raise e - - def _get_origin(self): - origin_header = common.ORIGIN_HEADER - origin = self._request.headers_in.get(origin_header) - if origin is None: - self._logger.debug('Client request does not have origin header') - self._request.ws_origin = origin - - def _check_version(self): - version = get_mandatory_header(self._request, - common.SEC_WEBSOCKET_VERSION_HEADER) - if version == _VERSION_LATEST_STRING: - return _VERSION_LATEST - - if version.find(',') >= 0: - raise HandshakeException( - 'Multiple versions (%r) are not allowed for header %s' % - (version, common.SEC_WEBSOCKET_VERSION_HEADER), - status=common.HTTP_STATUS_BAD_REQUEST) - raise VersionException('Unsupported version %r for header %s' % - (version, common.SEC_WEBSOCKET_VERSION_HEADER), - supported_versions=', '.join( - map(str, _SUPPORTED_VERSIONS))) - - def _set_protocol(self): - self._request.ws_protocol = None - - protocol_header = self._request.headers_in.get( - common.SEC_WEBSOCKET_PROTOCOL_HEADER) - - if protocol_header is None: - self._request.ws_requested_protocols = None - return - - self._request.ws_requested_protocols = parse_token_list( - protocol_header) - self._logger.debug('Subprotocols requested: %r', - self._request.ws_requested_protocols) - - def _parse_extensions(self): - extensions_header = self._request.headers_in.get( - common.SEC_WEBSOCKET_EXTENSIONS_HEADER) - if not extensions_header: - self._request.ws_requested_extensions = None - return - - try: - self._request.ws_requested_extensions = common.parse_extensions( - extensions_header) - except common.ExtensionParsingException as e: - raise HandshakeException( - 'Failed to parse Sec-WebSocket-Extensions header: %r' % e) - - self._logger.debug( - 'Extensions requested: %r', - list( - map(common.ExtensionParameter.name, - self._request.ws_requested_extensions))) + def _set_accept(self): + # Key validation, response generation. + key = self._get_key() + accept = compute_accept(key) + self._logger.debug('%s: %r (%s)', common.SEC_WEBSOCKET_ACCEPT_HEADER, + accept, util.hexify(base64.b64decode(accept))) + self._request._accept = accept def _validate_key(self, key): if key.find(',') >= 0: @@ -348,9 +179,6 @@ return key.encode('UTF-8') - def _create_stream(self, stream_options): - return Stream(self._request, stream_options) - def _create_handshake_response(self, accept): response = [] @@ -385,8 +213,8 @@ return u''.join(response) - def _send_handshake(self, accept): - raw_response = self._create_handshake_response(accept) + def _send_handshake(self): + raw_response = self._create_handshake_response(self._request._accept) self._request.connection.write(raw_response.encode('UTF-8')) self._logger.debug('Sent server\'s opening handshake: %r', raw_response)
diff --git a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/websocket_server.py b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/websocket_server.py index df8cd39..fa24bb9 100644 --- a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/websocket_server.py +++ b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/websocket_server.py
@@ -61,7 +61,7 @@ for line in f: if line[0] == '#' or line.isspace(): continue - m = re.match('(\S+)\s+(\S+)$', line) + m = re.match(r'(\S+)\s+(\S+)$', line) if not m: logging.warning('Wrong format in map file:' + line) continue
diff --git a/third_party/wpt_tools/wpt/tools/wpt/revlist.py b/third_party/wpt_tools/wpt/tools/wpt/revlist.py index bd85612..b3f1f34 100644 --- a/third_party/wpt_tools/wpt/tools/wpt/revlist.py +++ b/third_party/wpt_tools/wpt/tools/wpt/revlist.py
@@ -1,29 +1,19 @@ import argparse -import logging import os import time +from typing import Any, Iterator, Tuple + from tools.wpt.testfiles import get_git_cmd here = os.path.dirname(__file__) wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir)) -logger = logging.getLogger() -MYPY = False -if MYPY: - # MYPY is set to True when run under Mypy. - from typing import Any - from typing import Dict - from typing import List - from typing import Text - - -def calculate_cutoff_date(until, epoch, offset): +def calculate_cutoff_date(until: int, epoch: int, offset: int) -> int: return ((((until - offset) // epoch)) * epoch) + offset -def parse_epoch(string): - # type: (str) -> int +def parse_epoch(string: str) -> int: UNIT_DICT = {"h": 3600, "d": 86400, "w": 604800} base = string[:-1] unit = string[-1:] @@ -32,10 +22,9 @@ raise argparse.ArgumentTypeError('must be digits followed by h/d/w') -def get_tagged_revisions(pattern): - # type: (Text) -> List[..., Dict] +def get_tagged_revisions(pattern: str) -> Iterator[Tuple[str, str, int]]: ''' - Returns the tagged revisions indexed by the committer date. + Iterates the tagged revisions as (tag name, commit sha, committer date) tuples. ''' git = get_git_cmd(wpt_root) args = [ @@ -44,18 +33,16 @@ u'--format=%(refname:lstrip=2) %(objectname) %(committerdate:raw)', u'--count=100000' ] - ref_list = git(u"for-each-ref", *args) + ref_list = git("for-each-ref", *args) # type: ignore for line in ref_list.splitlines(): if not line: continue - tag, commit, date, _ = line.split(u" ") + tag, commit, date, _ = line.split(" ") date = int(date) yield tag, commit, date -def get_epoch_revisions(epoch, until, max_count): - # type: (**Any) -> List[Text] - logger.debug("get_epoch_revisions(%s, %s)" % (epoch, max_count)) +def get_epoch_revisions(epoch: int, until: int, max_count: int) -> Iterator[str]: # Set an offset to start to count the the weekly epoch from # Monday 00:00:00. This is particularly important for the weekly epoch # because fix the start of the epoch to Monday. This offset is calculated @@ -84,7 +71,7 @@ # Expected result: N,M,K,J,H,G,F,C,A cutoff_date = calculate_cutoff_date(until, epoch, epoch_offset) - for _, commit, date in get_tagged_revisions(u"refs/tags/merge_pr_*"): + for _, commit, date in get_tagged_revisions("refs/tags/merge_pr_*"): if count >= max_count: return if date < cutoff_date: @@ -93,8 +80,7 @@ cutoff_date = calculate_cutoff_date(date, epoch, epoch_offset) -def get_parser(): - # type: () -> argparse.ArgumentParser +def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser() parser.add_argument("--epoch", default="1d", @@ -109,14 +95,10 @@ type=int, help="maximum number of revisions to be returned by " "the command") - parser.add_argument("--verbose", action="store_true", help="debug logging") return parser -def run_rev_list(**kwargs): - # type: (**Any) -> None - if kwargs.get('verbose'): - logger.setLevel(logging.DEBUG) +def run_rev_list(**kwargs: Any) -> None: # "epoch_threshold" is a safety margin. After this time it is fine to # assume that any tags are created and pushed. epoch_threshold = 600
diff --git a/third_party/wpt_tools/wpt/tools/wpt/run.py b/third_party/wpt_tools/wpt/tools/wpt/run.py index 1dcb1d4..e32e52f 100644 --- a/third_party/wpt_tools/wpt/tools/wpt/run.py +++ b/third_party/wpt_tools/wpt/tools/wpt/run.py
@@ -3,11 +3,12 @@ import platform import sys from distutils.spawn import find_executable +from typing import ClassVar, Type wpt_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) sys.path.insert(0, os.path.abspath(os.path.join(wpt_root, "tools"))) -from . import browser, install, testfiles, utils, virtualenv +from . import browser, install, testfiles, virtualenv from ..serve import serve logger = None @@ -67,10 +68,16 @@ def args_general(kwargs): - kwargs.set_if_none("tests_root", wpt_root) - kwargs.set_if_none("metadata_root", wpt_root) - kwargs.set_if_none("manifest_update", True) - kwargs.set_if_none("manifest_download", True) + + def set_if_none(name, value): + if kwargs.get(name) is None: + kwargs[name] = value + logger.info("Set %s to %s" % (name, value)) + + set_if_none("tests_root", wpt_root) + set_if_none("metadata_root", wpt_root) + set_if_none("manifest_update", True) + set_if_none("manifest_download", True) if kwargs["ssl_type"] in (None, "pregenerated"): cert_root = os.path.join(wpt_root, "tools", "certs") @@ -146,8 +153,8 @@ class BrowserSetup(object): - name = None - browser_cls = None + name = None # type: ClassVar[str] + browser_cls = None # type: ClassVar[Type[browser.Browser]] def __init__(self, venv, prompt=True): self.browser = self.browser_cls(logger) @@ -757,7 +764,7 @@ def setup_wptrunner(venv, **kwargs): from wptrunner import wptcommandline - kwargs = utils.Kwargs(kwargs.items()) + kwargs = kwargs.copy() kwargs["product"] = kwargs["product"].replace("-", "_") @@ -867,6 +874,6 @@ import pdb from tools import localpaths # noqa: F401 try: - main() + main() # type: ignore except Exception: pdb.post_mortem()
diff --git a/third_party/wpt_tools/wpt/tools/wpt/utils.py b/third_party/wpt_tools/wpt/tools/wpt/utils.py index 6c56f63..98b424fd 100644 --- a/third_party/wpt_tools/wpt/tools/wpt/utils.py +++ b/third_party/wpt_tools/wpt/tools/wpt/utils.py
@@ -11,40 +11,9 @@ from socket import error as SocketError # NOQA: N812 from urllib.request import urlopen -MYPY = False -if MYPY: - from typing import Any - from typing import Callable - logger = logging.getLogger(__name__) -class Kwargs(dict): - def set_if_none(self, - name, # type: str - value, # type: Any - err_fn=None, # type: Callable[[Kwargs, str], Any] - desc=None, # type: str - extra_cond=None # type: Callable[[Kwargs], Any] - ): - # type: (...) -> Any - if desc is None: - desc = name - - if name not in self or self[name] is None: - if extra_cond is not None and not extra_cond(self): - return - if callable(value): - value = value() - if not value: - if err_fn is not None: - return err_fn(self, "Failed to find %s" % desc) - else: - return - self[name] = value - logger.info("Set %s to %s" % (desc, value)) - - def call(*args): """Log terminal command, invoke it as a subprocess.
diff --git a/third_party/wpt_tools/wpt/tools/wpt/wpt.py b/third_party/wpt_tools/wpt/tools/wpt/wpt.py index 1faf7d7..71f9ee6 100644 --- a/third_party/wpt_tools/wpt/tools/wpt/wpt.py +++ b/third_party/wpt_tools/wpt/tools/wpt/wpt.py
@@ -1,6 +1,7 @@ import argparse import json import logging +import multiprocessing import os import sys @@ -131,6 +132,15 @@ def main(prog=None, argv=None): logging.basicConfig(level=logging.INFO) + # Ensure we use the spawn start method for all multiprocessing + try: + multiprocessing.set_start_method('spawn') + except RuntimeError as e: + # This can happen if we call back into wpt having already set the context + start_method = multiprocessing.get_start_method() + if start_method != "spawn": + logging.critical("The multiprocessing start method was set to %s by a caller", start_method) + raise e if prog is None: prog = sys.argv[0] @@ -179,4 +189,4 @@ if __name__ == "__main__": - main() + main() # type: ignore
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/requirements_firefox.txt b/third_party/wpt_tools/wpt/tools/wptrunner/requirements_firefox.txt index 43245f99..63fbdd0 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/requirements_firefox.txt +++ b/third_party/wpt_tools/wpt/tools/wptrunner/requirements_firefox.txt
@@ -5,6 +5,6 @@ moznetwork==1.1.0 mozprocess==1.2.1 mozprofile==2.5.0 -mozrunner==8.1.0 +mozrunner==8.2.0 mozversion==2.3.0 psutil==5.8.0
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py index fb1a847..4bd871d 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py
@@ -1,5 +1,6 @@ +from .base import NullBrowser # noqa: F401 from .base import require_arg -from .base import get_timeout_multiplier # noqa: F401 +from .base import get_timeout_multiplier # noqa: F401 from .chrome import executor_kwargs as chrome_executor_kwargs from .chrome_android import ChromeAndroidBrowserBase from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 @@ -9,7 +10,8 @@ __wptrunner__ = {"product": "android_weblayer", "check_args": "check_args", - "browser": "WeblayerShell", + "browser": {None: "WeblayerShell", + "wdspec": "NullBrowser"}, "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", "wdspec": "ChromeDriverWdspecExecutor"}, @@ -35,16 +37,15 @@ "symbols_path": kwargs.get("symbols_path")} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): # Use update() to modify the global list in place. _wptserve_ports.update(set( - server_config['ports']['http'] + server_config['ports']['https'] + - server_config['ports']['ws'] + server_config['ports']['wss'] + test_environment.config['ports']['http'] + test_environment.config['ports']['https'] + + test_environment.config['ports']['ws'] + test_environment.config['ports']['wss'] )) - executor_kwargs = chrome_executor_kwargs(logger, test_type, server_config, - cache_manager, run_info_data, + executor_kwargs = chrome_executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs) del executor_kwargs["capabilities"]["goog:chromeOptions"]["prefs"] capabilities = executor_kwargs["capabilities"]
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py index b72d0d3e..9d620934 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py
@@ -1,3 +1,4 @@ +from .base import NullBrowser # noqa: F401 from .base import require_arg from .base import get_timeout_multiplier # noqa: F401 from .chrome import executor_kwargs as chrome_executor_kwargs @@ -9,7 +10,8 @@ __wptrunner__ = {"product": "android_webview", "check_args": "check_args", - "browser": "SystemWebViewShell", + "browser": {None: "SystemWebViewShell", + "wdspec": "NullBrowser"}, "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", "wdspec": "ChromeDriverWdspecExecutor"}, @@ -35,16 +37,15 @@ "symbols_path": kwargs.get("symbols_path")} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): # Use update() to modify the global list in place. _wptserve_ports.update(set( - server_config['ports']['http'] + server_config['ports']['https'] + - server_config['ports']['ws'] + server_config['ports']['wss'] + test_environment.config['ports']['http'] + test_environment.config['ports']['https'] + + test_environment.config['ports']['ws'] + test_environment.config['ports']['wss'] )) - executor_kwargs = chrome_executor_kwargs(logger, test_type, server_config, - cache_manager, run_info_data, + executor_kwargs = chrome_executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs) del executor_kwargs["capabilities"]["goog:chromeOptions"]["prefs"] capabilities = executor_kwargs["capabilities"]
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/base.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/base.py index f7388ad7..4d307b7 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/base.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/base.py
@@ -1,33 +1,14 @@ +import enum import os import platform import socket from abc import ABCMeta, abstractmethod -from copy import deepcopy from ..wptcommandline import require_arg # noqa: F401 here = os.path.dirname(__file__) -def inherit(super_module, child_globals, product_name): - super_wptrunner = super_module.__wptrunner__ - child_globals["__wptrunner__"] = child_wptrunner = deepcopy(super_wptrunner) - - child_wptrunner["product"] = product_name - - for k in ("check_args", "browser", "browser_kwargs", "executor_kwargs", - "env_extras", "env_options", "timeout_multiplier"): - attr = super_wptrunner[k] - child_globals[attr] = getattr(super_module, attr) - - for v in super_module.__wptrunner__["executor"].values(): - child_globals[v] = getattr(super_module, v) - - if "run_info_extras" in super_wptrunner: - attr = super_wptrunner["run_info_extras"] - child_globals[attr] = getattr(super_module, attr) - - def cmd_arg(name, value=None): prefix = "-" if platform.system() == "Windows" else "--" rv = prefix + name @@ -191,11 +172,8 @@ def is_alive(self): return True - def on_output(self, line): - raise NotImplementedError - -class ExecutorBrowser(object): +class ExecutorBrowser: """View of the Browser used by the Executor object. This is needed because the Executor runs in a child process and we can't ship Browser instances between processes on Windows. @@ -207,3 +185,93 @@ def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) + + +@enum.unique +class OutputHandlerState(enum.IntEnum): + BEFORE_PROCESS_START = 1 + AFTER_PROCESS_START = 2 + AFTER_HANDLER_START = 3 + AFTER_PROCESS_STOP = 4 + + +class OutputHandler: + """Class for handling output from a browser process. + + This class is responsible for consuming the logging from a browser process + and passing it into the relevant logger. A class instance is designed to + be passed as the processOutputLine argument to mozprocess.ProcessHandler. + + The setup of this class is complex for various reasons: + + * We need to create an instance of the class before starting the process + * We want access to data about the running process e.g. the pid + * We want to launch the process and later setup additional log handling + which is restrospectively applied to any existing output (this supports + prelaunching browsers for performance, but having log output depend on the + tests that are run e.g. for leak suppression). + + Therefore the lifecycle is as follows:: + + output_handler = OutputHandler(logger, command, **output_handler_kwargs) + proc = ProcessHandler(command, ..., processOutputLine=output_handler) + output_handler.after_process_start(proc.pid) + [...] + # All logging to this point was buffered in-memory, but after start() + # it's actually sent to the logger. + output_handler.start(**output_logger_start_kwargs) + [...] + proc.wait() + output_handler.after_process_stop() + + Since the process lifetime and the output handler lifetime are coupled (it doesn't + work to reuse an output handler for multiple processes), it might make sense to have + a single class that owns the process and the output processing for the process. + This is complicated by the fact that we don't always run the process directly, + but sometimes use a wrapper e.g. mozrunner. + """ + + def __init__(self, logger, command, **kwargs): + self.logger = logger + self.command = command + self.pid = None + self.state = OutputHandlerState.BEFORE_PROCESS_START + self.line_buffer = [] + + def after_process_start(self, pid): + assert self.state == OutputHandlerState.BEFORE_PROCESS_START + self.logger.debug("OutputHandler.after_process_start") + self.pid = pid + self.state = OutputHandlerState.AFTER_PROCESS_START + + def start(self, **kwargs): + assert self.state == OutputHandlerState.AFTER_PROCESS_START + self.logger.debug("OutputHandler.start") + # Need to change the state here before we try to empty the buffer + # or we'll just re-buffer the existing output. + self.state = OutputHandlerState.AFTER_HANDLER_START + for item in self.line_buffer: + self(item) + self.line_buffer = None + + def after_process_stop(self, clean_shutdown=True): + # If we didn't get as far as configure, just + # dump all logs with no configuration + self.logger.debug("OutputHandler.after_process_stop") + if self.state < OutputHandlerState.AFTER_HANDLER_START: + self.start() + self.state = OutputHandlerState.AFTER_PROCESS_STOP + + def __call__(self, line): + if self.state < OutputHandlerState.AFTER_HANDLER_START: + self.line_buffer.append(line) + return + + # Could assert that there's no output handled once we're in the + # after_process_stop phase, although technically there's a race condition + # here because we don't know the logging thread has finished draining the + # logs. The solution might be to move this into mozprocess itself. + + self.logger.process_output(self.pid, + line.decode("utf8", "replace"), + command=" ".join(self.command) if self.command else "")
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome.py index 04ac372..1c56ad00 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome.py
@@ -1,5 +1,6 @@ from . import chrome_spki_certs from .base import Browser, ExecutorBrowser, require_arg +from .base import NullBrowser # noqa: F401 from .base import get_timeout_multiplier # noqa: F401 from ..webdriver_server import ChromeDriverServer from ..executors import executor_kwargs as base_executor_kwargs @@ -12,7 +13,8 @@ __wptrunner__ = {"product": "chrome", "check_args": "check_args", - "browser": "ChromeBrowser", + "browser": {None: "ChromeBrowser", + "wdspec": "NullBrowser"}, "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", "print-reftest": "ChromeDriverPrintRefTestExecutor", @@ -34,10 +36,9 @@ "webdriver_args": kwargs.get("webdriver_args")} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True executor_kwargs["supports_eager_pageload"] = False
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py index 5526433..3ba0158 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py
@@ -3,6 +3,7 @@ from .base import Browser, ExecutorBrowser, require_arg from .base import get_timeout_multiplier # noqa: F401 +from .base import NullBrowser # noqa: F401 from .chrome import executor_kwargs as chrome_executor_kwargs from ..webdriver_server import ChromeDriverServer from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 @@ -12,7 +13,8 @@ __wptrunner__ = {"product": "chrome_android", "check_args": "check_args", - "browser": "ChromeAndroidBrowser", + "browser": {None: "ChromeAndroidBrowser", + "wdspec": "NullBrowser"}, "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", "wdspec": "ChromeDriverWdspecExecutor"}, @@ -39,16 +41,15 @@ "symbols_path": kwargs.get("symbols_path")} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): # Use update() to modify the global list in place. _wptserve_ports.update(set( - server_config['ports']['http'] + server_config['ports']['https'] + - server_config['ports']['ws'] + server_config['ports']['wss'] + test_environment.config['ports']['http'] + test_environment.config['ports']['https'] + + test_environment.config['ports']['ws'] + test_environment.config['ports']['wss'] )) - executor_kwargs = chrome_executor_kwargs(logger, test_type, server_config, - cache_manager, run_info_data, + executor_kwargs = chrome_executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs) # Remove unsupported options on mobile. del executor_kwargs["capabilities"]["goog:chromeOptions"]["prefs"] @@ -71,6 +72,7 @@ # allow the use of host-resolver-rules in lieu of modifying /etc/hosts file return {"server_host": "127.0.0.1"} + class LogcatRunner(object): def __init__(self, logger, browser, remote_queue): self.logger = logger @@ -115,11 +117,13 @@ def on_output(self, line): data = { + "action": "process_output", "process": "LOGCAT", "command": "logcat", "data": line } - self._send_message("log", "process_output", data) + self._send_message("log", data) + class ChromeAndroidBrowserBase(Browser): def __init__(self, logger,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_ios.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_ios.py index f349b194..fe4ac5287 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_ios.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_ios.py
@@ -1,5 +1,5 @@ from .base import Browser, ExecutorBrowser, require_arg -from .base import get_timeout_multiplier # noqa: F401 +from .base import NullBrowser, get_timeout_multiplier # noqa: F401 from ..webdriver_server import CWTChromeDriverServer from ..executors import executor_kwargs as base_executor_kwargs from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 @@ -9,7 +9,8 @@ __wptrunner__ = {"product": "chrome_ios", "check_args": "check_args", - "browser": "ChromeiOSBrowser", + "browser": {None: "ChromeiOSBrowser", + "wdspec": "NullBrowser"}, "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor"}, "browser_kwargs": "browser_kwargs", @@ -27,9 +28,9 @@ "webdriver_args": kwargs.get("webdriver_args")} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, cache_manager, run_info_data, + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True executor_kwargs["capabilities"] = {}
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py index 88b8ab2..61f6fcc 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py
@@ -2,7 +2,7 @@ # DO NOT EDIT MANUALLY. # tools/certs/web-platform.test.pem -WPT_FINGERPRINT = 'DLy7/8ZmJoeYt/tazOrcP8q3hQdXtISxJ9/TimV07Ns=' +WPT_FINGERPRINT = 'ASE5x+nbwu7z2WpViJiNP6Qmei8L6qoQJVWjeVmeJPE=' # signed-exchange/resources/127.0.0.1.sxg.pem SXG_WPT_FINGERPRINT = '0Rt4mT6SJXojEMHTnKnlJ/hBKMBcI4kteBlhR1eTTdk='
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge.py index db4795c..6b35306 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge.py
@@ -2,6 +2,7 @@ import time import subprocess from .base import Browser, ExecutorBrowser, require_arg +from .base import NullBrowser # noqa: F401 from ..webdriver_server import EdgeDriverServer from ..executors import executor_kwargs as base_executor_kwargs from ..executors.executorselenium import (SeleniumTestharnessExecutor, # noqa: F401 @@ -10,7 +11,8 @@ __wptrunner__ = {"product": "edge", "check_args": "check_args", - "browser": "EdgeBrowser", + "browser": {None: "EdgeBrowser", + "wdspec": "NullBrowser"}, "executor": {"testharness": "SeleniumTestharnessExecutor", "reftest": "SeleniumRefTestExecutor", "wdspec": "EdgeDriverWdspecExecutor"}, @@ -42,10 +44,9 @@ **kwargs)} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True executor_kwargs["timeout_multiplier"] = get_timeout_multiplier(test_type, run_info_data, @@ -65,7 +66,6 @@ class EdgeBrowser(Browser): - used_ports = set() init_timeout = 60 def __init__(self, logger, webdriver_binary,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge_webdriver.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge_webdriver.py index c2545de4..e5949fe3 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge_webdriver.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge_webdriver.py
@@ -1,12 +1,28 @@ -from .base import inherit -from . import edge +from .base import NullBrowser # noqa: F401 +from .edge import (EdgeBrowser, # noqa: F401 + EdgeDriverWdspecExecutor, # noqa: F401 + check_args, # noqa: F401 + browser_kwargs, # noqa: F401 + executor_kwargs, # noqa: F401 + env_extras, # noqa: F401 + env_options, # noqa: F401 + run_info_extras, # noqa: F401 + get_timeout_multiplier) # noqa: F401 from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 WebDriverRefTestExecutor) # noqa: F401 -inherit(edge, globals(), "edge_webdriver") - -# __wptrunner__ magically appears from inherit, F821 is undefined name -__wptrunner__["executor"]["testharness"] = "WebDriverTestharnessExecutor" # noqa: F821 -__wptrunner__["executor"]["reftest"] = "WebDriverRefTestExecutor" # noqa: F821 +__wptrunner__ = {"product": "edge_webdriver", + "check_args": "check_args", + "browser": {None: "EdgeBrowser", + "wdspec": "NullBrowser"}, + "executor": {"testharness": "WebDriverTestharnessExecutor", + "reftest": "WebDriverRefTestExecutor", + "wdspec": "EdgeDriverWdspecExecutor"}, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options", + "run_info_extras": "run_info_extras", + "timeout_multiplier": "get_timeout_multiplier"}
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py index c2275bd1..4f2e0dd 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py
@@ -1,4 +1,5 @@ from .base import Browser, ExecutorBrowser, require_arg +from .base import NullBrowser # noqa: F401 from .base import get_timeout_multiplier # noqa: F401 from ..webdriver_server import EdgeChromiumDriverServer from ..executors import executor_kwargs as base_executor_kwargs @@ -9,7 +10,8 @@ __wptrunner__ = {"product": "edgechromium", "check_args": "check_args", - "browser": "EdgeChromiumBrowser", + "browser": {None: "EdgeChromiumBrowser", + "wdspec": "NullBrowser"}, "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", "wdspec": "EdgeChromiumDriverWdspecExecutor"}, @@ -30,10 +32,11 @@ "webdriver_args": kwargs.get("webdriver_args")} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, + executor_kwargs = base_executor_kwargs(test_type, + test_environment, + run_info_data, **kwargs) executor_kwargs["close_after_done"] = True executor_kwargs["supports_eager_pageload"] = False
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/epiphany.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/epiphany.py index f378170f..d61f74e 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/epiphany.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/epiphany.py
@@ -1,4 +1,7 @@ -from .base import get_timeout_multiplier, maybe_add_args, certificate_domain_list # noqa: F401 +from .base import (NullBrowser, # noqa: F401 + certificate_domain_list, + get_timeout_multiplier, # noqa: F401 + maybe_add_args) from .webkit import WebKitBrowser from ..executors import executor_kwargs as base_executor_kwargs from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 @@ -8,7 +11,8 @@ __wptrunner__ = {"product": "epiphany", "check_args": "check_args", - "browser": "EpiphanyBrowser", + "browser": {None: "EpiphanyBrowser", + "wdspec": "NullBrowser"}, "browser_kwargs": "browser_kwargs", "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", @@ -49,12 +53,11 @@ "certificates": certificate_domain_list(server_config.domains_set, kwargs["host_cert_path"])}} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True - executor_kwargs["capabilities"] = capabilities(server_config, **kwargs) + executor_kwargs["capabilities"] = capabilities(test_environment.config, **kwargs) return executor_kwargs
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py index 9c0e068..40810c8 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -1,8 +1,12 @@ +import base64 +import io import json import os import platform import signal import subprocess +import tempfile +import zipfile from abc import ABCMeta, abstractmethod import mozinfo @@ -14,25 +18,30 @@ from mozrunner.utils import test_environment, get_stack_fixer_function from mozcrash import mozcrash -from .base import (get_free_port, - Browser, +from .base import (Browser, ExecutorBrowser, - require_arg, + NullBrowser, + OutputHandler, + OutputHandlerState, + browser_command, cmd_arg, - browser_command) + get_free_port, + require_arg) from ..executors import executor_kwargs as base_executor_kwargs from ..executors.executormarionette import (MarionetteTestharnessExecutor, # noqa: F401 MarionetteRefTestExecutor, # noqa: F401 MarionettePrintRefTestExecutor, # noqa: F401 MarionetteWdspecExecutor, # noqa: F401 MarionetteCrashtestExecutor) # noqa: F401 +from ..webdriver_server import WebDriverServer here = os.path.dirname(__file__) __wptrunner__ = {"product": "firefox", "check_args": "check_args", - "browser": "FirefoxBrowser", + "browser": {None: "FirefoxBrowser", + "wdspec": "FirefoxWdSpecBrowser"}, "executor": {"crashtest": "MarionetteCrashtestExecutor", "testharness": "MarionetteTestharnessExecutor", "reftest": "MarionetteRefTestExecutor", @@ -103,10 +112,20 @@ "specialpowers_path": kwargs["specialpowers_path"]} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +class WdSpecProfile(object): + def __init__(self, profile): + self.profile = profile + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + self.profile.cleanup() + + +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = test_type != "reftest" executor_kwargs["timeout_multiplier"] = get_timeout_multiplier(test_type, @@ -120,21 +139,34 @@ executor_kwargs["reftest_internal"] = kwargs["reftest_internal"] executor_kwargs["reftest_screenshot"] = kwargs["reftest_screenshot"] if test_type == "wdspec": - options = {} + options = {"args": []} if kwargs["binary"]: options["binary"] = kwargs["binary"] if kwargs["binary_args"]: options["args"] = kwargs["binary_args"] - if kwargs["headless"]: - if "args" not in options: - options["args"] = [] - if "--headless" not in options["args"]: - options["args"].append("--headless") - options["prefs"] = { - "network.dns.localDomains": ",".join(server_config.domains_set) - } - for pref, value in kwargs["extra_prefs"]: - options["prefs"].update({pref: Preferences.cast(value)}) + + profile_creator = ProfileCreator(logger, + kwargs["prefs_root"], + test_environment.config, + test_type, + kwargs["extra_prefs"], + kwargs["gecko_e10s"], + kwargs["enable_fission"], + kwargs["browser_channel"], + kwargs["binary"], + kwargs["certutil_binary"], + test_environment.config.ssl_config["ca_cert_path"]) + if kwargs["processes"] > 1: + # With multiple processes, we would need a profile directory per process, but we + # don't have an easy way to do that, so include the profile in the capabilties + # directly instead. This means recreating it per session, which is slow + options["profile"] = profile_creator.create_base64() + profile = None + else: + profile = profile_creator.create() + options["args"].extend(["--profile", profile.profile]) + test_environment.env_extras_cms.append(WdSpecProfile(profile)) + capabilities["moz:firefoxOptions"] = options # This gets reused for firefox_android, but the environment setup @@ -147,8 +179,23 @@ kwargs["headless"], kwargs["enable_webrender"], kwargs["chaos_mode_flags"]) + leak_report_file = setup_leak_report(kwargs["leak_check"], profile, environ) + # This doesn't work with wdspec tests + # In particular tests can create a session without passing in the capabilites + # and in those cases we get the default geckodriver profile which doesn't + # guarantee zero network access + del environ["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] executor_kwargs["environ"] = environ + else: + if kwargs["headless"] and "--headless" not in options["args"]: + options["args"].append("--headless") + leak_report_file = None + + executor_kwargs["stackfix_dir"] = kwargs["stackfix_dir"], + executor_kwargs["leak_report_file"] = leak_report_file + executor_kwargs["asan"] = run_info_data.get("asan") + if kwargs["certutil_binary"] is None: capabilities["acceptInsecureCerts"] = True if capabilities: @@ -249,7 +296,22 @@ return env -class FirefoxInstanceManager(object): +def setup_leak_report(leak_check, profile, env): + leak_report_file = None + if leak_check: + filename = "runtests_leaks_%s.log" % os.getpid() + if profile is not None: + leak_report_file = os.path.join(profile.profile, filename) + else: + leak_report_file = os.path.join(tempfile.gettempdir(), filename) + if os.path.exists(leak_report_file): + os.remove(leak_report_file) + env["XPCOM_MEM_BLOAT_LOG"] = leak_report_file + + return leak_report_file + + +class FirefoxInstanceManager: __metaclass__ = ABCMeta def __init__(self, logger, binary, binary_args, profile_creator, debug_info, @@ -314,15 +376,13 @@ args, self.debug_info) - if self.leak_check: - leak_report_file = os.path.join(profile.profile, "runtests_leaks_%s.log" % os.getpid()) - if os.path.exists(leak_report_file): - os.remove(leak_report_file) - env["XPCOM_MEM_BLOAT_LOG"] = leak_report_file - else: - leak_report_file = None - - output_handler = OutputHandler(self.logger, self.stackfix_dir, self.symbols_path, self.asan) + leak_report_file = setup_leak_report(self.leak_check, profile, env) + output_handler = FirefoxOutputHandler(self.logger, + cmd, + stackfix_dir=self.stackfix_dir, + symbols_path=self.symbols_path, + asan=self.asan, + leak_report_file=leak_report_file) runner = FirefoxRunner(profile=profile, binary=cmd[0], cmdargs=cmd[1:], @@ -333,7 +393,9 @@ output_handler, leak_report_file) self.logger.debug("Starting Firefox") - runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive) + runner.start(debug_args=debug_args, + interactive=self.debug_info and self.debug_info.interactive) + output_handler.after_process_start(runner.process_handler.pid) self.logger.debug("Firefox Started") return instance @@ -355,6 +417,7 @@ if instance: instance.stop(force) instance.cleanup() + self.base_profile.cleanup() class PreloadInstanceManager(FirefoxInstanceManager): @@ -377,15 +440,16 @@ return self.current def teardown(self, force=False): - for instance, skip_marionette in [(self.previous, False), - (self.current, False), - (self.pending, True)]: + for instance, unused in [(self.previous, False), + (self.current, False), + (self.pending, True)]: if instance: - instance.stop(force, skip_marionette=skip_marionette) + instance.stop(force, unused) instance.cleanup() + self.base_profile.cleanup() -class BrowserInstance(object): +class BrowserInstance: shutdown_timeout = 70 def __init__(self, logger, runner, marionette_port, output_handler, leak_report_file): @@ -396,8 +460,14 @@ self.output_handler = output_handler self.leak_report_file = leak_report_file - def stop(self, force=False, skip_marionette=False): - """Stop Firefox""" + def stop(self, force=False, unused=False): + """Stop Firefox + + :param force: Signal the firefox process without waiting for a clean shutdown + :param unused: This instance was not used for running tests and so + doesn't have an active marionette session and doesn't require + output postprocessing. + """ is_running = self.runner is not None and self.runner.is_running() if is_running: self.logger.debug("Stopping Firefox %s" % self.pid()) @@ -407,18 +477,18 @@ if hasattr(signal, "SIGKILL"): shutdown_methods.append((False, lambda: self.runner.stop(signal.SIGKILL, self.shutdown_timeout))) - if skip_marionette: + if unused or force: + # Don't wait for the instance to close itself shutdown_methods = shutdown_methods[1:] try: # For Firefox we assume that stopping the runner prompts the # browser to shut down. This allows the leak log to be written for i, (clean, stop_f) in enumerate(shutdown_methods): self.logger.debug("Shutting down attempt %i/%i" % (i + 1, len(shutdown_methods))) - if not force or not clean: - retcode = stop_f() - if retcode is not None: - self.logger.info("Browser exited with return code %s" % retcode) - break + retcode = stop_f() + if retcode is not None: + self.logger.info("Browser exited with return code %s" % retcode) + break except OSError: # This can happen on Windows if the process is already dead pass @@ -426,8 +496,8 @@ # The browser was already stopped, which we assume was a crash # TODO: Should we check the exit code here? clean = False - if not skip_marionette: - self.output_handler.after_stop(clean_shutdown=clean) + if not unused: + self.output_handler.after_process_stop(clean_shutdown=clean) def pid(self): if self.runner.process_handler is None: @@ -444,12 +514,13 @@ return False def cleanup(self): - # mozprofile handles deleting the profile when the refcount reaches 0 + self.runner.cleanup() self.runner = None -class OutputHandler(object): - def __init__(self, logger, stackfix_dir, symbols_path, asan): +class FirefoxOutputHandler(OutputHandler): + def __init__(self, logger, command, symbols_path=None, stackfix_dir=None, asan=False, + leak_report_file=None): """Filter for handling Firefox process output. This receives Firefox process output in the __call__ function, does @@ -460,9 +531,7 @@ of the output handlers. """ - self.logger = logger - # These are filled in after setup() is called - self.instance = None + super().__init__(logger, command) self.symbols_path = symbols_path if stackfix_dir: @@ -474,21 +543,18 @@ else: self.stack_fixer = None self.asan = asan + self.leak_report_file = leak_report_file + # These are filled in after configure_handlers() is called self.lsan_handler = None self.mozleak_allowed = None self.mozleak_thresholds = None self.group_metadata = {} - self.line_buffer = [] - self.setup_ran = False - - def setup(self, instance=None, group_metadata=None, lsan_disabled=False, - lsan_allowed=None, lsan_max_stack_depth=None, mozleak_allowed=None, - mozleak_thresholds=None, **kwargs): + def start(self, group_metadata=None, lsan_disabled=False, lsan_allowed=None, + lsan_max_stack_depth=None, mozleak_allowed=None, mozleak_thresholds=None, + **kwargs): """Configure the output handler""" - self.instance = instance - if group_metadata is None: group_metadata = {} self.group_metadata = group_metadata @@ -504,18 +570,13 @@ allowAll=lsan_disabled) else: self.lsan_handler = None + super().start() - self.setup_ran = True - - for line in self.line_buffer: - self.__call__(line) - self.line_buffer = [] - - def after_stop(self, clean_shutdown=True): - self.logger.info("PROCESS LEAKS %s" % self.instance.leak_report_file) + def after_process_stop(self, clean_shutdown=True): + super().after_process_stop(clean_shutdown) if self.lsan_handler: self.lsan_handler.process() - if self.instance.leak_report_file is not None: + if self.leak_report_file is not None: if not clean_shutdown: # If we didn't get a clean shutdown there probably isn't a leak report file self.logger.warning("Firefox didn't exit cleanly, not processing leak logs") @@ -523,21 +584,24 @@ # We have to ignore missing leaks in the tab because it can happen that the # content process crashed and in that case we don't want the test to fail. # Ideally we would record which content process crashed and just skip those. + self.logger.info("PROCESS LEAKS %s" % self.leak_report_file) mozleak.process_leak_log( - self.instance.leak_report_file, + self.leak_report_file, leak_thresholds=self.mozleak_thresholds, ignore_missing_leaks=["tab", "gmplugin"], log=self.logger, stack_fixer=self.stack_fixer, scope=self.group_metadata.get("scope"), allowed=self.mozleak_allowed) + if os.path.exists(self.leak_report_file): + os.unlink(self.leak_report_file) def __call__(self, line): """Write a line of output from the firefox process to the log""" if b"GLib-GObject-CRITICAL" in line: return if line: - if not self.setup_ran: + if self.state < OutputHandlerState.AFTER_HANDLER_START: self.line_buffer.append(line) return data = line.decode("utf8", "replace") @@ -546,14 +610,12 @@ if self.lsan_handler: data = self.lsan_handler.log(data) if data is not None: - self.logger.process_output(self.instance and - self.instance.runner.process_handler and - self.instance.runner.process_handler.pid, + self.logger.process_output(self.pid, data, - command=" ".join(self.instance.runner.command)) + command=" ".join(self.command)) -class ProfileCreator(object): +class ProfileCreator: def __init__(self, logger, prefs_root, config, test_type, extra_prefs, e10s, enable_fission, browser_channel, binary, certutil_binary, ca_certificate_path): self.logger = logger @@ -578,6 +640,7 @@ preferences = self._load_prefs() profile = FirefoxProfile(preferences=preferences, + restore=False, **kwargs) self._set_required_prefs(profile) if self.ca_certificate_path is not None: @@ -585,6 +648,21 @@ return profile + def create_base64(self, **kwargs): + profile = self.create(**kwargs) + try: + with io.BytesIO() as buf: + with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as zipf: + for dirpath, _, filenames in os.walk(profile.profile): + for filename in filenames: + src_path = os.path.join(dirpath, filename) + dest_path = os.path.relpath(src_path, profile.profile) + with open(src_path, "rb") as f: + zipf.writestr(dest_path, f.read()) + return base64.b64encode(buf.getvalue()).decode("ascii").strip() + finally: + profile.cleanup() + def _load_prefs(self): prefs = Preferences() @@ -773,8 +851,7 @@ def start(self, group_metadata=None, **kwargs): self.instance = self.instance_manager.get() - self.instance.output_handler.setup(self.instance, - group_metadata, + self.instance.output_handler.start(group_metadata, **kwargs) def stop(self, force=False): @@ -811,3 +888,39 @@ except IOError: self.logger.warning("Looking for crash dump files failed") return False + + +class FirefoxWdSpecBrowser(NullBrowser): + def __init__(self, logger, leak_check=False, **kwargs): + super().__init__(logger, **kwargs) + self.leak_check = leak_check + + def settings(self, test): + return {"check_leaks": self.leak_check and not test.leaks, + "lsan_disabled": test.lsan_disabled, + "lsan_allowed": test.lsan_allowed, + "lsan_max_stack_depth": test.lsan_max_stack_depth, + "mozleak_allowed": self.leak_check and test.mozleak_allowed, + "mozleak_thresholds": self.leak_check and test.mozleak_threshold} + + +class GeckoDriverServer(WebDriverServer): + output_handler_cls = FirefoxOutputHandler + + def __init__(self, logger, marionette_port=2828, binary="geckodriver", + host="127.0.0.1", port=None, env=None, args=None): + if env is None: + env = os.environ.copy() + env["RUST_BACKTRACE"] = "1" + WebDriverServer.__init__(self, logger, binary, + host=host, + port=port, + env=env, + args=args) + self.marionette_port = marionette_port + + def make_command(self): + return [self.binary, + "--marionette-port", str(self.marionette_port), + "--host", self.host, + "--port", str(self.port)] + self._args
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/ie.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/ie.py index 5fce29a..c851daf 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/ie.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/ie.py
@@ -1,12 +1,11 @@ -from .base import Browser, ExecutorBrowser, require_arg -from .base import get_timeout_multiplier # noqa: F401 -from ..webdriver_server import InternetExplorerDriverServer +from .base import require_arg +from .base import NullBrowser, get_timeout_multiplier # noqa: F401 from ..executors import executor_kwargs as base_executor_kwargs from ..executors.executorinternetexplorer import InternetExplorerDriverWdspecExecutor # noqa: F401 __wptrunner__ = {"product": "ie", "check_args": "check_args", - "browser": "InternetExplorerBrowser", + "browser": "NullBrowser", "executor": {"wdspec": "InternetExplorerDriverWdspecExecutor"}, "browser_kwargs": "browser_kwargs", "executor_kwargs": "executor_kwargs", @@ -22,14 +21,13 @@ return {"webdriver_binary": kwargs["webdriver_binary"], "webdriver_args": kwargs.get("webdriver_args")} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): options = {} options["requireWindowFocus"] = True capabilities = {} capabilities["se:ieOptions"] = options - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True executor_kwargs["capabilities"] = capabilities return executor_kwargs @@ -39,35 +37,3 @@ def env_options(): return {"supports_debugger": False} - -class InternetExplorerBrowser(Browser): - used_ports = set() - - def __init__(self, logger, webdriver_binary, webdriver_args=None, **kwargs): - Browser.__init__(self, logger) - self.server = InternetExplorerDriverServer(self.logger, - binary=webdriver_binary, - args=webdriver_args) - self.webdriver_host = "localhost" - self.webdriver_port = self.server.port - - def start(self, **kwargs): - self.server.start() - - def stop(self, force=False): - self.server.stop(force=force) - - def pid(self): - return self.server.pid - - def is_alive(self): - # TODO(ato): This only indicates the server is alive, - # and doesn't say anything about whether a browser session - # is active. - return self.server.is_alive() - - def cleanup(self): - self.stop() - - def executor_browser(self): - return ExecutorBrowser, {"webdriver_url": self.server.url}
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/opera.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/opera.py index 80e5a31..f3a2929 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/opera.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/opera.py
@@ -1,4 +1,5 @@ from .base import Browser, ExecutorBrowser, require_arg +from .base import NullBrowser # noqa: F401 from .base import get_timeout_multiplier # noqa: F401 from ..webdriver_server import OperaDriverServer from ..executors import executor_kwargs as base_executor_kwargs @@ -9,7 +10,8 @@ __wptrunner__ = {"product": "opera", "check_args": "check_args", - "browser": "OperaBrowser", + "browser": {None: "OperaBrowser", + "wdspec": "NullBrowser"}, "executor": {"testharness": "SeleniumTestharnessExecutor", "reftest": "SeleniumRefTestExecutor", "wdspec": "OperaDriverWdspecExecutor"}, @@ -30,12 +32,11 @@ "webdriver_args": kwargs.get("webdriver_args")} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): from selenium.webdriver import DesiredCapabilities - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True capabilities = dict(DesiredCapabilities.OPERA.items()) capabilities.setdefault("operaOptions", {})["prefs"] = {
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/safari.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/safari.py index 9565f1c..20a5475 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/safari.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/safari.py
@@ -5,6 +5,7 @@ import psutil from .base import Browser, ExecutorBrowser, require_arg +from .base import NullBrowser # noqa: F401 from .base import get_timeout_multiplier # noqa: F401 from ..webdriver_server import SafariDriverServer from ..executors import executor_kwargs as base_executor_kwargs @@ -16,7 +17,8 @@ __wptrunner__ = {"product": "safari", "check_args": "check_args", - "browser": "SafariBrowser", + "browser": {None: "SafariBrowser", + "wdspec": "NullBrowser"}, "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", "wdspec": "SafariDriverWdspecExecutor", @@ -38,10 +40,8 @@ "kill_safari": kwargs.get("kill_safari", False)} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, - **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True executor_kwargs["capabilities"] = {} if test_type == "testharness":
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/sauce.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/sauce.py index 99ece89d..4913199 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/sauce.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/sauce.py
@@ -101,10 +101,9 @@ return {"sauce_config": sauce_config} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["capabilities"] = get_capabilities(**kwargs)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servo.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servo.py index 4f934aed..1791c1d 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servo.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servo.py
@@ -43,10 +43,9 @@ } -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - rv = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) + rv = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) rv["pause_after_test"] = kwargs["pause_after_test"] if test_type == "wdspec": rv["capabilities"] = {}
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py index 81d6c7e..9a6a1a4 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py
@@ -6,7 +6,12 @@ from tools.serve.serve import make_hosts_file -from .base import Browser, require_arg, get_free_port, browser_command, ExecutorBrowser +from .base import (Browser, + ExecutorBrowser, + OutputHandler, + require_arg, + get_free_port, + browser_command) from .base import get_timeout_multiplier # noqa: F401 from ..executors import executor_kwargs as base_executor_kwargs from ..executors.executorservodriver import (ServoWebDriverTestharnessExecutor, # noqa: F401 @@ -46,9 +51,8 @@ } -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, **kwargs): - rv = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): + rv = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) return rv @@ -91,6 +95,7 @@ self.user_stylesheets = user_stylesheets if user_stylesheets else [] self.headless = headless if headless else False self.ca_certificate_path = server_config.ssl_config["ca_cert_path"] + self.output_handler = None def start(self, **kwargs): self.webdriver_port = get_free_port() @@ -129,11 +134,14 @@ self.command = debug_args + self.command if not self.debug_info or not self.debug_info.interactive: + self.output_handler = OutputHandler(self.logger, self.command) self.proc = ProcessHandler(self.command, processOutputLine=[self.on_output], env=env, storeOutput=False) self.proc.run() + self.output_handler.after_process_start(self.proc.pid) + self.output_handler.start() else: self.proc = subprocess.Popen(self.command, env=env) @@ -147,6 +155,8 @@ except OSError: # This can happen on Windows if the process is already dead pass + if self.output_handler is not None: + self.output_handler.after_process_stop() def pid(self): if self.proc is None: @@ -157,12 +167,6 @@ except AttributeError: return None - def on_output(self, line): - """Write a line of output from the process to the log""" - self.logger.process_output(self.pid(), - line.decode("utf8", "replace"), - command=" ".join(self.command)) - def is_alive(self): return self.proc.poll() is None
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkit.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkit.py index f83de29..ad24771 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkit.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkit.py
@@ -1,5 +1,5 @@ from .base import Browser, ExecutorBrowser, require_arg -from .base import get_timeout_multiplier, certificate_domain_list # noqa: F401 +from .base import NullBrowser, get_timeout_multiplier, certificate_domain_list # noqa: F401 from ..executors import executor_kwargs as base_executor_kwargs from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 WebDriverRefTestExecutor, # noqa: F401 @@ -10,7 +10,8 @@ __wptrunner__ = {"product": "webkit", "check_args": "check_args", - "browser": "WebKitBrowser", + "browser": {None: "WebKitBrowser", + "wdspec": "NullBrowser"}, "browser_kwargs": "browser_kwargs", "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", @@ -54,12 +55,11 @@ return {} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True - executor_kwargs["capabilities"] = capabilities_for_port(server_config, + executor_kwargs["capabilities"] = capabilities_for_port(test_environment.config, **kwargs) return executor_kwargs
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkitgtk_minibrowser.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkitgtk_minibrowser.py index 6c1001e..7a02ad14 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkitgtk_minibrowser.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkitgtk_minibrowser.py
@@ -1,4 +1,7 @@ -from .base import get_timeout_multiplier, maybe_add_args, certificate_domain_list # noqa: F401 +from .base import (NullBrowser, # noqa: F401 + certificate_domain_list, + get_timeout_multiplier, # noqa: F401 + maybe_add_args) from .webkit import WebKitBrowser from ..executors import executor_kwargs as base_executor_kwargs from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 @@ -8,7 +11,8 @@ __wptrunner__ = {"product": "webkitgtk_minibrowser", "check_args": "check_args", - "browser": "WebKitGTKMiniBrowser", + "browser": {None: "WebKitGTKMiniBrowser", + "wdspec": "NullBrowser"}, "browser_kwargs": "browser_kwargs", "executor": {"testharness": "WebDriverTestharnessExecutor", "reftest": "WebDriverRefTestExecutor", @@ -53,12 +57,11 @@ "certificates": certificate_domain_list(server_config.domains_set, kwargs["host_cert_path"])}} -def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): - executor_kwargs = base_executor_kwargs(test_type, server_config, - cache_manager, run_info_data, **kwargs) + executor_kwargs = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) executor_kwargs["close_after_done"] = True - executor_kwargs["capabilities"] = capabilities(server_config, **kwargs) + executor_kwargs["capabilities"] = capabilities(test_environment.config, **kwargs) return executor_kwargs
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/config.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/config.py index 3f5e934..8a9bdbf 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/config.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/config.py
@@ -1,11 +1,12 @@ -from configparser import SafeConfigParser +from configparser import ConfigParser import os import sys from collections import OrderedDict +from typing import Any, Dict here = os.path.dirname(__file__) -class ConfigDict(dict): +class ConfigDict(Dict[str, Any]): def __init__(self, base_path, *args, **kwargs): self.base_path = base_path dict.__init__(self, *args, **kwargs) @@ -20,7 +21,7 @@ def read(config_path): config_path = os.path.abspath(config_path) config_root = os.path.dirname(config_path) - parser = SafeConfigParser() + parser = ConfigParser() success = parser.read(config_path) assert config_path in success, success
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/environment.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/environment.py index 86dcb93..c0611b9 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/environment.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/environment.py
@@ -1,15 +1,14 @@ import json import os - import signal import socket import sys import time -from mozlog import get_default_logger, handlers, proxy +from mozlog import get_default_logger, handlers from . import mpcontext -from .wptlogging import LogLevelRewriter +from .wptlogging import LogLevelRewriter, QueueHandler, LogQueueThread here = os.path.dirname(__file__) repo_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir, os.pardir)) @@ -50,16 +49,48 @@ pass +def get_server_logger(): + logger = get_default_logger(component="wptserve") + log_filter = handlers.LogLevelFilter(lambda x: x, "info") + # Downgrade errors to warnings for the server + log_filter = LogLevelRewriter(log_filter, ["error"], "warning") + logger.component_filter = log_filter + return logger + + +class ProxyLoggingContext: + """Context manager object that handles setup and teardown of a log queue + for handling logging messages from wptserve.""" + + def __init__(self, logger): + mp_context = mpcontext.get_context() + self.log_queue = mp_context.Queue() + self.logging_thread = LogQueueThread(self.log_queue, logger) + self.logger_handler = QueueHandler(self.log_queue) + + def __enter__(self): + self.logging_thread.start() + return self.logger_handler + + def __exit__(self, *args): + self.log_queue.put(None) + # Wait for thread to shut down but not for too long since it's a daemon + self.logging_thread.join(1) + + class TestEnvironment(object): """Context manager that owns the test environment i.e. the http and websockets servers""" def __init__(self, test_paths, testharness_timeout_multipler, pause_after_test, debug_test, debug_info, options, ssl_config, env_extras, enable_quic=False, mojojs_path=None): + self.test_paths = test_paths self.server = None self.config_ctx = None self.config = None + self.server_logger = get_server_logger() + self.server_logging_ctx = ProxyLoggingContext(self.server_logger) self.testharness_timeout_multipler = testharness_timeout_multipler self.pause_after_test = pause_after_test self.debug_test = debug_test @@ -77,6 +108,7 @@ self.mojojs_path = mojojs_path def __enter__(self): + server_log_handler = self.server_logging_ctx.__enter__() self.config_ctx = self.build_config() self.config = self.config_ctx.__enter__() @@ -84,8 +116,6 @@ self.stash.__enter__() self.cache_manager.__enter__() - self.setup_server_logging() - assert self.env_extras_cms is None, ( "A TestEnvironment object cannot be nested") @@ -96,9 +126,11 @@ cm.__enter__() self.env_extras_cms.append(cm) - self.servers = serve.start(self.config, + self.servers = serve.start(self.server_logger, + self.config, self.get_routes(), - mp_context=mpcontext.get_context()) + mp_context=mpcontext.get_context(), + log_handlers=[server_log_handler]) if self.options.get("supports_debugger") and self.debug_info and self.debug_info.interactive: self.ignore_interrupts() @@ -109,7 +141,7 @@ for scheme, servers in self.servers.items(): for port, server in servers: - server.kill() + server.stop() for cm in self.env_extras_cms: cm.__exit__(exc_type, exc_val, exc_tb) @@ -118,6 +150,7 @@ self.cache_manager.__exit__(exc_type, exc_val, exc_tb) self.stash.__exit__() self.config_ctx.__exit__(exc_type, exc_val, exc_tb) + self.server_logging_ctx.__exit__(exc_type, exc_val, exc_tb) def ignore_interrupts(self): signal.signal(signal.SIGINT, signal.SIG_IGN) @@ -128,7 +161,7 @@ def build_config(self): override_path = os.path.join(serve_path(self.test_paths), "config.json") - config = serve.ConfigBuilder() + config = serve.ConfigBuilder(self.server_logger) ports = { "http": [8000, 8001], @@ -163,25 +196,6 @@ return config - def setup_server_logging(self): - server_logger = get_default_logger(component="wptserve") - assert server_logger is not None - log_filter = handlers.LogLevelFilter(lambda x: x, "info") - # Downgrade errors to warnings for the server - log_filter = LogLevelRewriter(log_filter, ["error"], "warning") - server_logger.component_filter = log_filter - - server_logger = proxy.QueuedProxyLogger(server_logger, - mpcontext.get_context()) - - try: - # Set as the default logger for wptserve - serve.set_logger(server_logger) - serve.logger = server_logger - except Exception: - # This happens if logging has already been set up for wptserve - pass - def get_routes(self): route_builder = serve.RoutesBuilder()
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py index b47d0ad..2e268609 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py
@@ -9,27 +9,29 @@ import sys from abc import ABCMeta, abstractmethod from http.client import HTTPConnection +from typing import Any, Callable, ClassVar, Optional, Tuple, Type, TYPE_CHECKING from urllib.parse import urljoin, urlsplit, urlunsplit from .actions import actions from .protocol import Protocol, BaseProtocolPart +if TYPE_CHECKING: + from ..webdriver_server import WebDriverServer + here = os.path.dirname(__file__) - -def executor_kwargs(test_type, server_config, cache_manager, run_info_data, - **kwargs): +def executor_kwargs(test_type, test_environment, run_info_data, **kwargs): timeout_multiplier = kwargs["timeout_multiplier"] if timeout_multiplier is None: timeout_multiplier = 1 - executor_kwargs = {"server_config": server_config, + executor_kwargs = {"server_config": test_environment.config, "timeout_multiplier": timeout_multiplier, "debug_info": kwargs["debug_info"]} if test_type in ("reftest", "print-reftest"): - executor_kwargs["screenshot_cache"] = cache_manager.dict() + executor_kwargs["screenshot_cache"] = test_environment.cache_manager.dict() if test_type == "wdspec": executor_kwargs["binary"] = kwargs.get("binary") @@ -242,8 +244,14 @@ """ __metaclass__ = ABCMeta - test_type = None - convert_result = None + test_type = None # type: ClassVar[str] + # convert_result is a class variable set to a callable converter + # (e.g. reftest_result_converter) converting from an instance of + # URLManifestItem (e.g. RefTest) + type-dependent results object + + # type-dependent extra data, returning a tuple of Result and list of + # SubtestResult. For now, any callable is accepted. TODO: Make this type + # stricter when more of the surrounding code is annotated. + convert_result = None # type: ClassVar[Callable[..., Any]] supports_testdriver = False supports_jsshell = False # Extra timeout to use after internal test timeout at which the harness @@ -423,7 +431,7 @@ if len(lhs_hashes) != len(rhs_hashes): self.logger.info("Got different number of pages") - return False + return relation == "!=", None assert len(lhs_screenshots) == len(lhs_hashes) == len(rhs_screenshots) == len(rhs_hashes) @@ -590,7 +598,7 @@ class WdspecExecutor(TestExecutor): convert_result = pytest_result_converter - protocol_cls = None + protocol_cls = None # type: ClassVar[Type[Protocol]] def __init__(self, logger, browser, server_config, webdriver_binary, webdriver_args, timeout_multiplier=1, capabilities=None, @@ -604,7 +612,12 @@ self.timeout_multiplier = timeout_multiplier self.capabilities = capabilities self.environ = environ if environ is not None else {} - self.protocol = self.protocol_cls(self, browser) + self.output_handler_kwargs = None + self.output_handler_start_kwargs = None + + def setup(self, runner): + self.protocol = self.protocol_cls(self, self.browser) + super().setup(runner) def is_alive(self): return self.protocol.is_alive() @@ -629,8 +642,7 @@ return pytestrunner.run(path, self.server_config, session_config, - timeout=timeout, - environ=self.environ) + timeout=timeout) def do_delayed_imports(self): global pytestrunner @@ -708,7 +720,7 @@ class WdspecProtocol(Protocol): - server_cls = None + server_cls = None # type: ClassVar[Optional[Type[WebDriverServer]]] implements = [ConnectionlessBaseProtocolPart] @@ -719,14 +731,21 @@ self.capabilities = self.executor.capabilities self.session_config = None self.server = None + self.environ = os.environ.copy() + self.environ.update(executor.environ) + self.output_handler_kwargs = executor.output_handler_kwargs + self.output_handler_start_kwargs = executor.output_handler_start_kwargs def connect(self): """Connect to browser via the HTTP server.""" self.server = self.server_cls( self.logger, binary=self.webdriver_binary, - args=self.webdriver_args) - self.server.start(block=False) + args=self.webdriver_args, + env=self.environ) + self.server.start(block=False, + output_handler_kwargs=self.output_handler_kwargs, + output_handler_start_kwargs=self.output_handler_start_kwargs) self.logger.info( "WebDriver HTTP server listening at %s" % self.server.url) self.session_config = {"host": self.server.host, @@ -764,7 +783,7 @@ WebDriver. Things that are more different to WebDriver may need to create a fully custom implementation.""" - unimplemented_exc = (NotImplementedError,) + unimplemented_exc = (NotImplementedError,) # type: ClassVar[Tuple[Type[Exception], ...]] def __init__(self, logger, protocol, test_window): self.protocol = protocol
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py index 81be731b..6d311d42 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
@@ -41,7 +41,6 @@ SetPermissionProtocolPart, PrintProtocolPart, DebugProtocolPart) -from ..webdriver_server import GeckoDriverServer def do_delayed_imports(): @@ -567,12 +566,22 @@ def set_user_verified(self, authenticator_id, uv): raise NotImplementedError("set_user_verified not yet implemented") + class MarionetteSetPermissionProtocolPart(SetPermissionProtocolPart): def setup(self): self.marionette = self.parent.marionette - def set_permission(self, name, state, one_realm): - raise NotImplementedError("set_permission not yet implemented") + def set_permission(self, descriptor, state, one_realm): + body = { + "descriptor": descriptor, + "state": state, + } + if one_realm is not None: + body["oneRealm"] = one_realm + try: + self.marionette._send_message("WebDriver:SetPermission", body) + except errors.UnsupportedOperationException: + raise NotImplementedError("set_permission not yet implemented") class MarionettePrintProtocolPart(PrintProtocolPart): @@ -1099,12 +1108,32 @@ class GeckoDriverProtocol(WdspecProtocol): - server_cls = GeckoDriverServer + server_cls = None # To avoid circular imports we set this at runtime class MarionetteWdspecExecutor(WdspecExecutor): protocol_cls = GeckoDriverProtocol + def __init__(self, logger, browser, server_config, webdriver_binary, + webdriver_args, timeout_multiplier=1, capabilities=None, + debug_info=None, environ=None, stackfix_dir=None, + symbols_path=None, leak_report_file=None, asan=False, + group_metadata=None, browser_settings=None, **kwargs): + + from ..browsers.firefox import GeckoDriverServer + super().__init__(logger, browser, server_config, webdriver_binary, + webdriver_args, timeout_multiplier=timeout_multiplier, + capabilities=capabilities, debug_info=debug_info, + environ=environ, **kwargs) + self.protocol_cls.server_cls = GeckoDriverServer + self.output_handler_kwargs = {"stackfix_dir": stackfix_dir, + "symbols_path": symbols_path, + "asan": asan, + "leak_report_file": leak_report_file} + self.output_handler_start_kwargs = {"group_metadata": group_metadata} + self.output_handler_start_kwargs.update(browser_settings) + + class MarionetteCrashtestExecutor(CrashtestExecutor): def __init__(self, logger, browser, server_config, timeout_multiplier=1,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py index ab16b0ef..03eafb0 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py
@@ -1,6 +1,7 @@ import traceback from abc import ABCMeta, abstractmethod +from typing import ClassVar, List, Type class Protocol(object): @@ -16,7 +17,7 @@ :param Browser browser: The Browser using this protocol""" __metaclass__ = ABCMeta - implements = [] + implements = [] # type: ClassVar[List[Type[ProtocolPart]]] def __init__(self, executor, browser): self.executor = executor @@ -82,7 +83,7 @@ :param Protocol parent: The parent protocol""" __metaclass__ = ABCMeta - name = None + name = None # type: ClassVar[str] def __init__(self, parent): self.parent = parent
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/chromium.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/chromium.py index ae8d96a1..e86f333 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/chromium.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/chromium.py
@@ -5,7 +5,7 @@ from mozlog.formatters import base -class ChromiumFormatter(base.BaseFormatter): +class ChromiumFormatter(base.BaseFormatter): # type: ignore """Formatter to produce results matching the Chromium JSON Test Results format. https://chromium.googlesource.com/chromium/src/+/master/docs/testing/json_test_results_format.md
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/wptreport.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/wptreport.py index 6976624..86d4c42f 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/wptreport.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/wptreport.py
@@ -16,7 +16,7 @@ return LONE_SURROGATE_RE.subn(surrogate_replacement, data)[0] -class WptreportFormatter(BaseFormatter): +class WptreportFormatter(BaseFormatter): # type: ignore """Formatter that produces results in the format that wptreport expects.""" def __init__(self):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/wptscreenshot.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/wptscreenshot.py index f854d95..750548b28 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/wptscreenshot.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/wptscreenshot.py
@@ -4,7 +4,7 @@ DEFAULT_API = "https://wpt.fyi/api/screenshots/hashes" -class WptscreenshotFormatter(BaseFormatter): +class WptscreenshotFormatter(BaseFormatter): # type: ignore """Formatter that outputs screenshots in the format expected by wpt.fyi.""" def __init__(self, api=None):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestupdate.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestupdate.py index 5bccaa2d..2fc4299 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestupdate.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestupdate.py
@@ -3,6 +3,7 @@ from urllib.parse import urljoin, urlsplit from collections import namedtuple, defaultdict, deque from math import ceil +from typing import Any, Callable, ClassVar, Dict, List from .wptmanifest import serialize from .wptmanifest.node import (DataNode, ConditionalNode, BinaryExpressionNode, @@ -320,10 +321,13 @@ class PropertyUpdate(object): - property_name = None - cls_default_value = None - value_type = None - property_builder = None + property_name = None # type: ClassVar[str] + cls_default_value = None # type: ClassVar[Any] + value_type = None # type: ClassVar[type] + # property_builder is a class variable set to either build_conditional_tree + # or build_unconditional_tree. TODO: Make this type stricter when those + # methods are annotated. + property_builder = None # type: ClassVar[Callable[..., Any]] def __init__(self, node): self.node = node @@ -764,7 +768,7 @@ class AppendOnlyListUpdate(PropertyUpdate): - cls_default_value = [] + cls_default_value = [] # type: ClassVar[List[str]] property_builder = build_unconditional_tree def updated_value(self, current, new): @@ -817,7 +821,7 @@ class LeakThresholdUpdate(PropertyUpdate): property_name = "leak-threshold" - cls_default_value = {} + cls_default_value = {} # type: ClassVar[Dict[str, int]] property_builder = build_unconditional_tree def from_result_value(self, result):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/metadata.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/metadata.py index 50cfb737..27bdb39 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/metadata.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/metadata.py
@@ -2,6 +2,7 @@ import array import os from collections import defaultdict, namedtuple +from typing import Dict, List, Tuple from mozlog import structuredlog from six import ensure_str, ensure_text @@ -21,7 +22,7 @@ try: import ujson as json except ImportError: - import json + import json # type: ignore class RunInfo(object): @@ -92,7 +93,7 @@ def do_delayed_imports(serve_root=None): global manifest, manifestitem - from manifest import manifest, item as manifestitem + from manifest import manifest, item as manifestitem # type: ignore def files_in_repo(repo_root): @@ -169,9 +170,10 @@ type_conv = None rev_type_conv = None - def __init__(self, max_bits=8): + def __init__(self, max_bits: int = 8): self.max_idx = 2**max_bits - 2 # Reserve 0 as a sentinal + self._data: Tuple[List[object], Dict[int, object]] self._data = [None], {} def clear(self):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py index 7ba30537..e65df5ee 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
@@ -33,14 +33,18 @@ module = product_module(config, product) data = module.__wptrunner__ self.name = product + if isinstance(data["browser"], str): + self._browser_cls = {None: getattr(module, data["browser"])} + else: + self._browser_cls = {key: getattr(module, value) + for key, value in data["browser"].items()} self.check_args = getattr(module, data["check_args"]) - self.browser_cls = getattr(module, data["browser"]) self.get_browser_kwargs = getattr(module, data["browser_kwargs"]) self.get_executor_kwargs = getattr(module, data["executor_kwargs"]) self.env_options = getattr(module, data["env_options"])() self.get_env_extras = getattr(module, data["env_extras"]) self.run_info_extras = (getattr(module, data["run_info_extras"]) - if "run_info_extras" in data else lambda **kwargs:{}) + if "run_info_extras" in data else lambda **kwargs:{}) self.get_timeout_multiplier = getattr(module, data["timeout_multiplier"]) self.executor_classes = {} @@ -48,19 +52,10 @@ cls = getattr(module, cls_name) self.executor_classes[test_type] = cls - -def load_product(config, product, load_cls=False): - rv = Product(config, product) - if not load_cls: - return (rv.check_args, - rv.browser_cls, - rv.get_browser_kwargs, - rv.executor_classes, - rv.get_executor_kwargs, - rv.env_options, - rv.get_env_extras, - rv.run_info_extras) - return rv + def get_browser_cls(self, test_type): + if test_type in self._browser_cls: + return self._browser_cls[test_type] + return self._browser_cls[None] def load_product_update(config, product):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py index 2265523..eeb5af23 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
@@ -12,8 +12,8 @@ here = os.path.dirname(__file__) localpaths = imp.load_source("localpaths", os.path.abspath(os.path.join(here, os.pardir, os.pardir, "localpaths.py"))) -from ci.tc.github_checks_output import get_gh_checks_outputter -from wpt.markdown import markdown_adjust, table +from ci.tc.github_checks_output import get_gh_checks_outputter # type: ignore +from wpt.markdown import markdown_adjust, table # type: ignore # If a test takes more than (FLAKY_THRESHOLD*timeout) and does not consistently @@ -21,7 +21,7 @@ FLAKY_THRESHOLD = 0.8 -class LogActionFilter(BaseHandler): +class LogActionFilter(BaseHandler): # type: ignore """Handler that filters out messages not of a given set of actions. @@ -43,7 +43,7 @@ return self.inner(item) -class LogHandler(reader.LogHandler): +class LogHandler(reader.LogHandler): # type: ignore """Handle updating test and subtest status in log.
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testloader.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testloader.py index ec0a6871..9492a8b 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testloader.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testloader.py
@@ -20,9 +20,9 @@ def do_delayed_imports(): # This relies on an already loaded module having set the sys.path correctly :( global manifest, manifest_update, download_from_github - from manifest import manifest + from manifest import manifest # type: ignore from manifest import update as manifest_update - from manifest.download import download_from_github + from manifest.download import download_from_github # type: ignore class TestGroupsFile(object):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py index 2b07c13..4258aa6 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py
@@ -24,30 +24,12 @@ pass -class MessageLogger(object): - def __init__(self, message_func): - self.send_message = message_func +class LogMessageHandler: + def __init__(self, send_message): + self.send_message = send_message - def _log_data(self, action, **kwargs): - self.send_message("log", action, kwargs) - - def process_output(self, process, data, command): - self._log_data("process_output", process=process, data=data, command=command) - - -def _log_func(level_name): - def log(self, message): - self._log_data(level_name.lower(), message=message) - log.__doc__ = """Log a message with level %s - -:param message: The string message to log -""" % level_name - log.__name__ = str(level_name).lower() - return log - -# Create all the methods on StructuredLog for debug levels -for level_name in structuredlog.log_levels: - setattr(MessageLogger, level_name.lower(), _log_func(level_name)) + def __call__(self, data): + self.send_message("log", data) class TestRunner(object): @@ -158,7 +140,9 @@ # in the logging module unlocked release_mozlog_lock() - logger = MessageLogger(send_message) + proc_name = mpcontext.get_context().current_process().name + logger = structuredlog.StructuredLogger(proc_name) + logger.add_handler(LogMessageHandler(send_message)) with capture.CaptureIO(logger, capture_stdio): try: @@ -270,7 +254,7 @@ class _RunnerManagerState(object): before_init = namedtuple("before_init", []) - initializing = namedtuple("initializing_browser", + initializing = namedtuple("initializing", ["test", "test_group", "group_metadata", "failure_count"]) running = namedtuple("running", ["test", "test_group", "group_metadata"]) restarting = namedtuple("restarting", ["test", "test_group", "group_metadata"]) @@ -503,6 +487,7 @@ self.state.failure_count + 1) else: self.executor_kwargs["group_metadata"] = self.state.group_metadata + self.executor_kwargs["browser_settings"] = self.browser.browser_settings self.start_test_runner() def start_test_runner(self): @@ -743,8 +728,8 @@ self.stop_runner() return RunnerManagerState.initializing(self.state.test, self.state.test_group, self.state.group_metadata, 0) - def log(self, action, kwargs): - getattr(self.logger, action)(**kwargs) + def log(self, data): + self.logger.log_raw(data) def error(self, message): self.logger.error(message)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/base.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/base.py index 547808e..47ea7ff 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/base.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/base.py
@@ -1,9 +1,11 @@ +from typing import ClassVar, List, Type + exit_unclean = object() exit_clean = object() class Step(object): - provides = [] + provides = [] # type: ClassVar[List[str]] def __init__(self, logger): self.logger = logger @@ -45,7 +47,7 @@ class StepRunner(object): - steps = [] + steps = [] # type: ClassVar[List[Type[Step]]] def __init__(self, logger, state): """Class that runs a specified series of Steps with a common State"""
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/sync.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/sync.py index 4ace28f..2c9834c6 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/sync.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/sync.py
@@ -98,7 +98,7 @@ provides = ["manifest_path", "test_manifest"] def create(self, state): - from manifest import manifest + from manifest import manifest # type: ignore state.manifest_path = os.path.join(state.metadata_path, "MANIFEST.json") state.test_manifest = manifest.load_and_update(state.sync["path"], state.manifest_path,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/vcs.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/vcs.py index 896d8a0..3419a507 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/vcs.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/vcs.py
@@ -1,5 +1,6 @@ import subprocess from functools import partial +from typing import Callable from mozlog import get_default_logger @@ -7,7 +8,7 @@ logger = None -def vcs(bin_name): +def vcs(bin_name: str) -> Callable[..., None]: def inner(command, *args, **kwargs): global logger
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/webdriver_server.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/webdriver_server.py index 510349f1..f3bf56f 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/webdriver_server.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/webdriver_server.py
@@ -5,12 +5,15 @@ import socket import time import traceback +from typing import ClassVar, Type import mozprocess +from .browsers.base import OutputHandler + __all__ = ["SeleniumServer", "ChromeDriverServer", "CWTChromeDriverServer", - "EdgeChromiumDriverServer", "OperaDriverServer", "GeckoDriverServer", + "EdgeChromiumDriverServer", "OperaDriverServer", "InternetExplorerDriverServer", "EdgeDriverServer", "ServoDriverServer", "WebKitDriverServer", "WebDriverServer"] @@ -19,6 +22,7 @@ __metaclass__ = abc.ABCMeta default_base_path = "/" + output_handler_cls = OutputHandler # type: ClassVar[Type[OutputHandler]] def __init__(self, logger, binary, host="127.0.0.1", port=None, base_path="", env=None, args=None): @@ -29,12 +33,14 @@ self.logger = logger self.binary = binary self.host = host + if base_path == "": self.base_path = self.default_base_path else: self.base_path = base_path self.env = os.environ.copy() if env is None else env + self._output_handler = None self._port = port self._cmd = None self._args = args if args is not None else [] @@ -44,17 +50,27 @@ def make_command(self): """Returns the full command for starting the server process as a list.""" - def start(self, block=False): + def start(self, + block=False, + output_handler_kwargs=None, + output_handler_start_kwargs=None): try: - self._run(block) + self._run(block, output_handler_kwargs, output_handler_start_kwargs) except KeyboardInterrupt: self.stop() - def _run(self, block): + def _run(self, block, output_handler_kwargs, output_handler_start_kwargs): + if output_handler_kwargs is None: + output_handler_kwargs = {} + if output_handler_start_kwargs is None: + output_handler_start_kwargs = {} self._cmd = self.make_command() + self._output_handler = self.output_handler_cls(self.logger, + self._cmd, + **output_handler_kwargs) self._proc = mozprocess.ProcessHandler( self._cmd, - processOutputLine=self.on_output, + processOutputLine=self._output_handler, env=self.env, storeOutput=False) @@ -66,6 +82,7 @@ raise IOError( "WebDriver executable not found: %s" % self.binary) raise + self._output_handler.after_process_start(self._proc.pid) self.logger.debug( "Waiting for WebDriver to become accessible: %s" % self.url) @@ -76,27 +93,28 @@ "WebDriver was not accessible " "within the timeout:\n%s" % traceback.format_exc()) raise - + self._output_handler.start(**output_handler_start_kwargs) if block: self._proc.wait() def stop(self, force=False): self.logger.debug("Stopping WebDriver") + clean = True if self.is_alive(): kill_result = self._proc.kill() if force and kill_result != 0: - return self._proc.kill(9) - return kill_result - return not self.is_alive() + clean = False + self._proc.kill(9) + success = not self.is_alive() + if success and self._output_handler is not None: + # Only try to do output post-processing if we managed to shut down + self._output_handler.after_process_stop(clean) + self._output_handler = None + return success def is_alive(self): return hasattr(self._proc, "proc") and self._proc.poll() is None - def on_output(self, line): - self.logger.process_output(self.pid, - line.decode("utf8", "replace"), - command=" ".join(self._cmd)) - @property def pid(self): if self._proc is not None: @@ -121,88 +139,42 @@ class ChromeDriverServer(WebDriverServer): - def __init__(self, logger, binary="chromedriver", port=None, - base_path="", args=None): - WebDriverServer.__init__( - self, logger, binary, port=port, base_path=base_path, args=args) - def make_command(self): return [self.binary, cmd_arg("port", str(self.port)), cmd_arg("url-base", self.base_path) if self.base_path else "", cmd_arg("enable-chrome-logs")] + self._args -class CWTChromeDriverServer(WebDriverServer): - def __init__(self, logger, binary, port=None, args=None): - WebDriverServer.__init__(self, logger, binary, port=port, args=args) +class CWTChromeDriverServer(WebDriverServer): def make_command(self): return [self.binary, "--port=%s" % str(self.port)] + self._args -class EdgeChromiumDriverServer(WebDriverServer): - def __init__(self, logger, binary="msedgedriver", port=None, - base_path="", args=None): - WebDriverServer.__init__( - self, logger, binary, port=port, base_path=base_path, args=args) +class EdgeChromiumDriverServer(WebDriverServer): def make_command(self): return [self.binary, cmd_arg("port", str(self.port)), cmd_arg("url-base", self.base_path) if self.base_path else ""] + self._args -class EdgeDriverServer(WebDriverServer): - def __init__(self, logger, binary="microsoftwebdriver.exe", port=None, - base_path="", host="localhost", args=None): - WebDriverServer.__init__( - self, logger, binary, host=host, port=port, args=args) +class EdgeDriverServer(WebDriverServer): def make_command(self): return [self.binary, "--port=%s" % str(self.port)] + self._args + class OperaDriverServer(ChromeDriverServer): - def __init__(self, logger, binary="operadriver", port=None, - base_path="", args=None): - ChromeDriverServer.__init__( - self, logger, binary, port=port, base_path=base_path, args=args) - + pass class InternetExplorerDriverServer(WebDriverServer): - def __init__(self, logger, binary="IEDriverServer.exe", port=None, - base_path="", host="localhost", args=None): - WebDriverServer.__init__( - self, logger, binary, host=host, port=port, args=args) - def make_command(self): return [self.binary, "--port=%s" % str(self.port)] + self._args -class GeckoDriverServer(WebDriverServer): - def __init__(self, logger, marionette_port=2828, binary="geckodriver", - host="127.0.0.1", port=None, args=None): - env = os.environ.copy() - env["RUST_BACKTRACE"] = "1" - WebDriverServer.__init__(self, logger, binary, - host=host, - port=port, - env=env, - args=args) - self.marionette_port = marionette_port - - def make_command(self): - return [self.binary, - "--marionette-port", str(self.marionette_port), - "--host", self.host, - "--port", str(self.port)] + self._args - - class SafariDriverServer(WebDriverServer): - def __init__(self, logger, binary="safaridriver", port=None, args=None): - WebDriverServer.__init__( - self, logger, binary, port=port, args=args) - def make_command(self): return [self.binary, "--port=%s" % str(self.port)] + self._args @@ -210,8 +182,8 @@ class ServoDriverServer(WebDriverServer): def __init__(self, logger, binary="servo", binary_args=None, host="127.0.0.1", - port=None, args=None): - env = os.environ.copy() + port=None, env=None, args=None): + env = env if env is not None else os.environ.copy() env["RUST_BACKTRACE"] = "1" WebDriverServer.__init__(self, logger, binary, host=host, @@ -231,9 +203,6 @@ class WebKitDriverServer(WebDriverServer): - def __init__(self, logger, binary=None, port=None, args=None): - WebDriverServer.__init__(self, logger, binary, port=port, args=args) - def make_command(self): return [self.binary, "--port=%s" % str(self.port)] + self._args
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptlogging.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptlogging.py index 444d1d9..b5cb58881 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptlogging.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptlogging.py
@@ -1,4 +1,5 @@ import logging +from threading import Thread from mozlog import commandline, stdadapter, set_default_logger from mozlog.structuredlog import StructuredLogger, log_levels @@ -65,3 +66,42 @@ not self.has_log and log_levels[data["level"]] <= self.min_level): self.has_log = True + + +class QueueHandler(logging.Handler): + def __init__(self, queue, level=logging.NOTSET): + self.queue = queue + logging.Handler.__init__(self, level=level) + + def createLock(self): + # The queue provides its own locking + self.lock = None + + def emit(self, record): + msg = self.format(record) + data = {"action": "log", + "level": record.levelname, + "thread": record.threadName, + "pid": record.process, + "source": self.name, + "message": msg} + self.queue.put(data) + + +class LogQueueThread(Thread): + """Thread for handling log messages from a queue""" + def __init__(self, queue, logger): + self.queue = queue + self.logger = logger + super().__init__(name="Thread-Log") + + def run(self): + while True: + try: + data = self.queue.get() + except (EOFError, IOError): + break + if data is None: + # A None message is used to shut down the logging thread + break + self.logger.log_raw(data)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py index f6ae1e2..f235774a 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py
@@ -58,7 +58,7 @@ class TokenTypes(object): - def __init__(self): + def __init__(self) -> None: for type in ["group_start", "group_end", "paren", "list_start", "list_end", "separator", "ident", "string", "number", "atom", "eof"]: setattr(self, type, type)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptrunner.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptrunner.py index b7d2355..1c78554 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptrunner.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptrunner.py
@@ -18,7 +18,6 @@ from mozlog import capture, handlers from .font import FontInstaller from .testrunner import ManagerGroup -from .browsers.base import NullBrowser here = os.path.dirname(__file__) @@ -99,7 +98,7 @@ def list_test_groups(test_paths, product, **kwargs): env.do_delayed_imports(logger, test_paths) - run_info_extras = products.load_product(kwargs["config"], product)[-1](**kwargs) + run_info_extras = products.Product(kwargs["config"], product).run_info_extras(**kwargs) run_info, test_loader = get_loader(test_paths, product, run_info_extras=run_info_extras, **kwargs) @@ -113,7 +112,7 @@ rv = [] - run_info_extras = products.load_product(kwargs["config"], product)[-1](**kwargs) + run_info_extras = products.Product(kwargs["config"], product).run_info_extras(**kwargs) run_info, test_loader = get_loader(test_paths, product, run_info_extras=run_info_extras, **kwargs) @@ -127,7 +126,7 @@ def list_tests(test_paths, product, **kwargs): env.do_delayed_imports(logger, test_paths) - run_info_extras = products.load_product(kwargs["config"], product)[-1](**kwargs) + run_info_extras = products.Product(kwargs["config"], product).run_info_extras(**kwargs) run_info, test_loader = get_loader(test_paths, product, run_info_extras=run_info_extras, **kwargs) @@ -167,7 +166,7 @@ recording.set(["startup"]) env.do_delayed_imports(logger, test_paths) - product = products.load_product(config, product, load_cls=True) + product = products.Product(config, product) env_extras = product.get_env_extras(**kwargs) @@ -276,15 +275,7 @@ for test_type in kwargs["test_types"]: logger.info("Running %s tests" % test_type) - # WebDriver tests may create and destroy multiple browser - # processes as part of their expected behavior. These - # processes are managed by a WebDriver server binary. This - # obviates the need for wptrunner to provide a browser, so - # the NullBrowser is used in place of the "target" browser - if test_type == "wdspec": - browser_cls = NullBrowser - else: - browser_cls = product.browser_cls + browser_cls = product.get_browser_cls(test_type) browser_kwargs = product.get_browser_kwargs(logger, test_type, @@ -296,8 +287,7 @@ executor_cls = product.executor_classes.get(test_type) executor_kwargs = product.get_executor_kwargs(logger, test_type, - test_environment.config, - test_environment.cache_manager, + test_environment, run_info, **kwargs)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wpttest.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wpttest.py index b7a7cec1..0cd72e2 100644 --- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wpttest.py +++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wpttest.py
@@ -2,6 +2,7 @@ import subprocess import sys from collections import defaultdict +from typing import Any, ClassVar, Dict, Type from urllib.parse import urljoin from .wptmanifest.parser import atoms @@ -82,7 +83,7 @@ return RunInfo(metadata_root, product, **kwargs) -class RunInfo(dict): +class RunInfo(Dict[str, Any]): def __init__(self, metadata_root, product, debug, browser_version=None, browser_channel=None, @@ -149,9 +150,9 @@ class Test(object): - result_cls = None - subtest_result_cls = None - test_type = None + result_cls = None # type: ClassVar[Type[Result]] + subtest_result_cls = None # type: ClassVar[Type[SubtestResult]] + test_type = None # type: ClassVar[str] default_timeout = 10 # seconds long_timeout = 60 # seconds
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/config.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/config.py index 4265fcd..82b1b59 100644 --- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/config.py +++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/config.py
@@ -1,5 +1,4 @@ import copy -import logging import os from collections import defaultdict from collections.abc import Mapping @@ -28,11 +27,18 @@ class Config(Mapping): - """wptserve config + """wptserve configuration data - Inherits from Mapping for backwards compatibility with the old dict-based config""" - def __init__(self, logger_name, data): - self.__dict__["_logger_name"] = logger_name + Immutable configuration that's safe to be passed between processes. + + Inherits from Mapping for backwards compatibility with the old dict-based config + + :param data: - Extra configuration data + """ + def __init__(self, data): + for name in data.keys(): + if name.startswith("_"): + raise ValueError("Invalid configuration key %s" % name) self.__dict__.update(data) def __str__(self): @@ -41,7 +47,7 @@ def __setattr__(self, key, value): raise ValueError("Config is immutable") - def __setitem__(self, key): + def __setitem__(self, key, value): raise ValueError("Config is immutable") def __getitem__(self, key): @@ -59,19 +65,15 @@ def __len__(self): return len([item for item in self]) - @property - def logger(self): - logger = logging.getLogger(self._logger_name) - logger.setLevel(self.log_level.upper()) - return logger - def as_dict(self): - return json_types(self.__dict__) + return json_types(self.__dict__, skip={"_logger"}) -def json_types(obj): +def json_types(obj, skip=None): + if skip is None: + skip = set() if isinstance(obj, dict): - return {key: json_types(value) for key, value in obj.items()} + return {key: json_types(value) for key, value in obj.items() if key not in skip} if (isinstance(obj, str) or isinstance(obj, int) or isinstance(obj, float) or @@ -84,7 +86,7 @@ class ConfigBuilder(object): - """Builder object for setting the wptsync config. + """Builder object for setting the wptserve config. Configuration can be passed in as a dictionary to the constructor, or set via attributes after construction. Configuration options must match @@ -109,6 +111,17 @@ dictionary containing the current set of properties. Thus computed properties later in the list may depend on the value of earlier ones. + + + :param logger: - A logger object. This is used for logging during + the creation of the configuration, but isn't + part of the configuration + :param subdomains: - A set of valid subdomains to include in the + configuration. + :param not_subdomains: - A set of invalid subdomains to include in + the configuration. + :param config_cls: - A class to use for the configuration. Defaults + to default_config_cls """ _default = { @@ -157,25 +170,18 @@ "ssl_config"] def __init__(self, - logger=None, + logger, subdomains=set(), not_subdomains=set(), config_cls=None, **kwargs): + self._logger = logger self._data = self._default.copy() self._ssl_env = None self._config_cls = config_cls or self.default_config_cls - if logger is None: - self._logger_name = "web-platform-tests" - else: - level_name = logging.getLevelName(logger.level) - if level_name != "NOTSET": - self.log_level = level_name - self._logger_name = logger.name - for k, v in self._default.items(): self._data[k] = kwargs.pop(k, v) @@ -184,7 +190,7 @@ for k, new_k in _renamed_props.items(): if k in kwargs: - self.logger.warning( + logger.warning( "%s in config is deprecated; use %s instead" % ( k, new_k @@ -201,12 +207,6 @@ else: self.__dict__[key] = value - @property - def logger(self): - logger = logging.getLogger(self._logger_name) - logger.setLevel(self._data["log_level"].upper()) - return logger - def update(self, override): """Load an overrides dict to override config values""" override = override.copy() @@ -217,7 +217,7 @@ for k, new_k in _renamed_props.items(): if k in override: - self.logger.warning( + self._logger.warning( "%s in config is deprecated; use %s instead" % ( k, new_k @@ -243,7 +243,7 @@ prefix = "_get_" for key in self.computed_properties: data[key] = getattr(self, prefix + key)(data) - return self._config_cls(self._logger_name, data) + return self._config_cls(data) def __exit__(self, *args): self._ssl_env.__exit__(*args) @@ -315,7 +315,7 @@ ssl_type = data["ssl"]["type"] ssl_cls = sslutils.get_cls(ssl_type) kwargs = data["ssl"].get(ssl_type, {}) - self._ssl_env = ssl_cls(self.logger, **kwargs) + self._ssl_env = ssl_cls(self._logger, **kwargs) self._ssl_env.__enter__() if self._ssl_env.ssl_enabled: key_path, cert_path = self._ssl_env.host_cert_path(data["domains_set"])
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/logger.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/logger.py index 6c91492..07429d68 100644 --- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/logger.py +++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/logger.py
@@ -1,29 +1,5 @@ -class NoOpLogger(object): - def critical(self, msg): - pass - - def error(self, msg): - pass - - def info(self, msg): - pass - - def warning(self, msg): - pass - - def debug(self, msg): - pass - -logger = NoOpLogger() -_set_logger = False - -def set_logger(new_logger): - global _set_logger - if _set_logger: - raise Exception("Logger must be set at most once") - global logger - logger = new_logger - _set_logger = True +import logging def get_logger(): - return logger + # Use the root logger + return logging.getLogger()
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/response.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/response.py index 8763cca..0b0ea2cb 100644 --- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/response.py +++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/response.py
@@ -243,7 +243,13 @@ ("Content-Length", len(data))] self.content = data if code == 500: - self.logger.error(message) + if isinstance(message, str) and message: + first_line = message.splitlines()[0] + else: + first_line = "<no message given>" + self.logger.error("Exception loading %s: %s" % (self.request.url, + first_line)) + self.logger.info(message) class MultipartContent(object):
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/server.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/server.py index 7446d78..4f74c80 100644 --- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/server.py +++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/server.py
@@ -193,7 +193,8 @@ Server.config = config else: self.logger.debug("Using default configuration") - with ConfigBuilder(browser_host=server_address[0], + with ConfigBuilder(self.logger, + browser_host=server_address[0], ports={"http": [self.server_address[1]]}) as config: assert config["ssl_config"] is None Server.config = config @@ -229,7 +230,9 @@ error.errno in self.acceptable_errors)): pass # remote hang up before the result is sent else: - self.logger.error(traceback.format_exc()) + msg = traceback.format_exc() + self.logger.error("%s %s" % (type(error), error)) + self.logger.info(msg) class BaseWebTestRequestHandler(http.server.BaseHTTPRequestHandler): @@ -623,6 +626,7 @@ self.respond_with_error(response, e) response.write() + class H2ConnectionGuard(object): """H2Connection objects are not threadsafe, so this keeps thread safety""" lock = threading.Lock() @@ -704,7 +708,6 @@ if response: response.set_error(500, err) response.write() - self.logger.error(err) def get_request_line(self): try: @@ -826,7 +829,7 @@ "is something already using that port?" % port) raise - def start(self, block=False): + def start(self): """Start the server. :param block: True to run the server on the current thread, blocking, @@ -834,12 +837,9 @@ http_type = "http2" if self.http2 else "https" if self.use_ssl else "http" self.logger.info("Starting %s server on %s:%s" % (http_type, self.host, self.port)) self.started = True - if block: - self.httpd.serve_forever() - else: - self.server_thread = threading.Thread(target=self.httpd.serve_forever) - self.server_thread.setDaemon(True) # don't hang on exit - self.server_thread.start() + self.server_thread = threading.Thread(target=self.httpd.serve_forever) + self.server_thread.setDaemon(True) # don't hang on exit + self.server_thread.start() def stop(self): """
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/ws_h2_handshake.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/ws_h2_handshake.py index c813ecb..ac88dd9 100644 --- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/ws_h2_handshake.py +++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/ws_h2_handshake.py
@@ -8,29 +8,11 @@ from __future__ import absolute_import from mod_pywebsocket import common -from mod_pywebsocket.stream import Stream -from mod_pywebsocket.stream import StreamOptions -from mod_pywebsocket import util -# TODO: We are using "private" methods of pywebsocket. We might want to -# refactor pywebsocket to expose those methods publicly. Also, _get_origin -# _check_version _set_protocol _parse_extensions and a large part of do_handshake -# are identical with hybi handshake. We need some refactoring to get remove that -# code duplication. -from mod_pywebsocket.extensions import get_extension_processor -from mod_pywebsocket.handshake._base import get_mandatory_header -from mod_pywebsocket.handshake._base import HandshakeException -from mod_pywebsocket.handshake._base import parse_token_list -from mod_pywebsocket.handshake._base import validate_mandatory_header -from mod_pywebsocket.handshake._base import validate_subprotocol -from mod_pywebsocket.handshake._base import VersionException - -# Defining aliases for values used frequently. -_VERSION_LATEST = common.VERSION_HYBI_LATEST -_VERSION_LATEST_STRING = str(_VERSION_LATEST) -_SUPPORTED_VERSIONS = [ - _VERSION_LATEST, -] +from mod_pywebsocket.handshake.base import get_mandatory_header +from mod_pywebsocket.handshake.base import HandshakeException +from mod_pywebsocket.handshake.base import validate_mandatory_header +from mod_pywebsocket.handshake.base import HandshakerBase def check_connect_method(request): @@ -38,9 +20,9 @@ raise HandshakeException('Method is not CONNECT: %r' % request.method) -class WsH2Handshaker(object): +class WsH2Handshaker(HandshakerBase): def __init__(self, request, dispatcher): - """Opening handshake processor for the WebSocket protocol (RFC 6455). + """Bootstrapping handshake processor for the WebSocket protocol with HTTP/2 (RFC 8441). :param request: mod_python request. @@ -49,196 +31,41 @@ WsH2Handshaker will add attributes such as ws_resource during handshake. """ - self._logger = util.get_class_logger(self) + super(WsH2Handshaker, self).__init__(request, dispatcher) - self._request = request - self._dispatcher = dispatcher + def _transform_header(self, header): + return header.lower() - def _get_extension_processors_requested(self): - processors = [] - if self._request.ws_requested_extensions is not None: - for extension_request in self._request.ws_requested_extensions: - processor = get_extension_processor(extension_request) - # Unknown extension requests are just ignored. - if processor is not None: - processors.append(processor) - return processors + def _protocol_rfc(self): + return 'RFC 8441' - def do_handshake(self): - self._request.ws_close_code = None - self._request.ws_close_reason = None - - # Parsing. - + def _validate_request(self): check_connect_method(self._request) - validate_mandatory_header(self._request, ':protocol', 'websocket') - - self._request.ws_resource = self._request.uri - get_mandatory_header(self._request, 'authority') - self._request.ws_version = self._check_version() + def _set_accept(self): + # irrelevant for HTTP/2 handshake + pass - try: - self._get_origin() - self._set_protocol() - self._parse_extensions() - - # Setup extension processors. - self._request.ws_extension_processors = self._get_extension_processors_requested() - - # List of extra headers. The extra handshake handler may add header - # data as name/value pairs to this list and pywebsocket appends - # them to the WebSocket handshake. - self._request.extra_headers = [] - - # Extra handshake handler may modify/remove processors. - self._dispatcher.do_extra_handshake(self._request) - processors = [ - processor - for processor in self._request.ws_extension_processors - if processor is not None - ] - - # Ask each processor if there are extensions on the request which - # cannot co-exist. When processor decided other processors cannot - # co-exist with it, the processor marks them (or itself) as - # "inactive". The first extension processor has the right to - # make the final call. - for processor in reversed(processors): - if processor.is_active(): - processor.check_consistency_with_other_processors( - processors) - processors = [ - processor for processor in processors if processor.is_active() - ] - - accepted_extensions = [] - - stream_options = StreamOptions() - - for index, processor in enumerate(processors): - if not processor.is_active(): - continue - - extension_response = processor.get_extension_response() - if extension_response is None: - # Rejected. - continue - - accepted_extensions.append(extension_response) - - processor.setup_stream_options(stream_options) - - # Inactivate all of the following compression extensions. - for j in range(index + 1, len(processors)): - processors[j].set_active(False) - - if len(accepted_extensions) > 0: - self._request.ws_extensions = accepted_extensions - self._logger.debug( - 'Extensions accepted: %r', - list( - map(common.ExtensionParameter.name, - accepted_extensions))) - else: - self._request.ws_extensions = None - - self._request.ws_stream = self._create_stream(stream_options) - - if self._request.ws_requested_protocols is not None: - if self._request.ws_protocol is None: - raise HandshakeException( - 'do_extra_handshake must choose one subprotocol from ' - 'ws_requested_protocols and set it to ws_protocol') - validate_subprotocol(self._request.ws_protocol) - - self._logger.debug('Subprotocol accepted: %r', - self._request.ws_protocol) - else: - if self._request.ws_protocol is not None: - raise HandshakeException( - 'ws_protocol must be None when the client didn\'t ' - 'request any subprotocol') - - self._prepare_handshake_response() - except HandshakeException as e: - if not e.status: - # Fallback to 400 bad request by default. - e.status = common.HTTP_STATUS_BAD_REQUEST - raise e - - def _get_origin(self): - origin = self._request.headers_in.get('origin') - if origin is None: - self._logger.debug('Client request does not have origin header') - self._request.ws_origin = origin - - def _check_version(self): - sec_websocket_version_header = 'sec-websocket-version' - version = get_mandatory_header(self._request, sec_websocket_version_header) - if version == _VERSION_LATEST_STRING: - return _VERSION_LATEST - - if version.find(',') >= 0: - raise HandshakeException( - 'Multiple versions (%r) are not allowed for header %s' % - (version, sec_websocket_version_header), - status=common.HTTP_STATUS_BAD_REQUEST) - raise VersionException('Unsupported version %r for header %s' % - (version, sec_websocket_version_header), - supported_versions=', '.join( - map(str, _SUPPORTED_VERSIONS))) - - def _set_protocol(self): - self._request.ws_protocol = None - - protocol_header = self._request.headers_in.get('sec-websocket-protocol') - - if protocol_header is None: - self._request.ws_requested_protocols = None - return - - self._request.ws_requested_protocols = parse_token_list( - protocol_header) - self._logger.debug('Subprotocols requested: %r', - self._request.ws_requested_protocols) - - def _parse_extensions(self): - extensions_header = self._request.headers_in.get('sec-websocket-extensions') - if not extensions_header: - self._request.ws_requested_extensions = None - return - - try: - self._request.ws_requested_extensions = common.parse_extensions( - extensions_header) - except common.ExtensionParsingException as e: - raise HandshakeException( - 'Failed to parse sec-websocket-extensions header: %r' % e) - - self._logger.debug( - 'Extensions requested: %r', - list( - map(common.ExtensionParameter.name, - self._request.ws_requested_extensions))) - - def _create_stream(self, stream_options): - return Stream(self._request, stream_options) - - def _prepare_handshake_response(self): + def _send_handshake(self): + # We are not actually sending the handshake, but just preparing it. It + # will be flushed by the caller. self._request.status = 200 self._request.headers_out['upgrade'] = common.WEBSOCKET_UPGRADE_TYPE - self._request.headers_out['connection'] = common.UPGRADE_CONNECTION_TYPE + self._request.headers_out[ + 'connection'] = common.UPGRADE_CONNECTION_TYPE if self._request.ws_protocol is not None: - self._request.headers_out['sec-websocket-protocol'] = self._request.ws_protocol + self._request.headers_out[ + 'sec-websocket-protocol'] = self._request.ws_protocol if (self._request.ws_extensions is not None and len(self._request.ws_extensions) != 0): - self._request.headers_out['sec-websocket-extensions'] = common.format_extensions(self._request.ws_extensions) + self._request.headers_out[ + 'sec-websocket-extensions'] = common.format_extensions( + self._request.ws_extensions) # Headers not specific for WebSocket for name, value in self._request.extra_headers:
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/echo-query_v13_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/echo-query_v13_wsh.py index 4083c49..d670e6e 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/echo-query_v13_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/echo-query_v13_wsh.py
@@ -1,6 +1,6 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil, util +from mod_pywebsocket import msgutil def web_socket_do_extra_handshake(request): pass
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/echo-query_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/echo-query_wsh.py index 8fd7ac3..39219134 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/echo-query_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/echo-query_wsh.py
@@ -1,6 +1,6 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil, util +from mod_pywebsocket import msgutil def web_socket_do_extra_handshake(request): pass # Always accept.
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/echo_close_data_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/echo_close_data_wsh.py index cfc4a96..31ffcbb 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/echo_close_data_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/echo_close_data_wsh.py
@@ -1,5 +1,4 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil _GOODBYE_MESSAGE = u'Goodbye'
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/echo_exit_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/echo_exit_wsh.py index 301c14fe..8f6f7f8 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/echo_exit_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/echo_exit_wsh.py
@@ -1,5 +1,4 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil _GOODBYE_MESSAGE = u'Goodbye'
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/echo_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/echo_wsh.py index f20107e..7367b70 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/echo_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/echo_wsh.py
@@ -1,5 +1,5 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil + from mod_pywebsocket import common _GOODBYE_MESSAGE = u'Goodbye'
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/handshake_sleep_2_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/handshake_sleep_2_wsh.py index 3367ed8f..78de7c7 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/handshake_sleep_2_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/handshake_sleep_2_wsh.py
@@ -1,6 +1,5 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil import time def web_socket_do_extra_handshake(request):
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/invalid_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/invalid_wsh.py index 10950474..4bfc3ce 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/invalid_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/invalid_wsh.py
@@ -1,7 +1,5 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil - def web_socket_do_extra_handshake(request): request.connection.write(b"FOO BAR BAZ\r\n\r\n")
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/protocol_array_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/protocol_array_wsh.py index 098b46a6..be24ee0 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/protocol_array_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/protocol_array_wsh.py
@@ -1,6 +1,6 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil, util +from mod_pywebsocket import msgutil def web_socket_do_extra_handshake(request): line = request.headers_in.get('sec-websocket-protocol')
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/protocol_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/protocol_wsh.py index 6a945dd..10bdf33 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/protocol_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/protocol_wsh.py
@@ -1,6 +1,6 @@ #!/usr/bin/python -from mod_pywebsocket import msgutil, util +from mod_pywebsocket import msgutil def web_socket_do_extra_handshake(request): request.ws_protocol = request.headers_in.get('sec-websocket-protocol')
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/sleep_10_v13_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/sleep_10_v13_wsh.py index f0819101..b0f1dde 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/sleep_10_v13_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/sleep_10_v13_wsh.py
@@ -1,7 +1,7 @@ #!/usr/bin/python import sys, urllib, time -from mod_pywebsocket import common, msgutil, util +from mod_pywebsocket import msgutil def web_socket_do_extra_handshake(request): request.connection.write(b'x')
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/stash_responder_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/stash_responder_wsh.py index 0849561..d18ad3b 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/stash_responder_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/stash_responder_wsh.py
@@ -1,8 +1,7 @@ #!/usr/bin/python import json import urllib -from mod_pywebsocket import common, msgutil, util -from mod_pywebsocket.handshake import hybi +from mod_pywebsocket import msgutil from wptserve import stash address, authkey = stash.load_env_config()
diff --git a/third_party/wpt_tools/wpt/websockets/handlers/wrong_accept_key_wsh.py b/third_party/wpt_tools/wpt/websockets/handlers/wrong_accept_key_wsh.py index 77f703ab..43240e1a 100755 --- a/third_party/wpt_tools/wpt/websockets/handlers/wrong_accept_key_wsh.py +++ b/third_party/wpt_tools/wpt/websockets/handlers/wrong_accept_key_wsh.py
@@ -1,7 +1,6 @@ #!/usr/bin/python import sys, urllib, time -from mod_pywebsocket import common, msgutil, util def web_socket_do_extra_handshake(request):
diff --git a/tools/android/modularization/convenience/lookup_dep.py b/tools/android/modularization/convenience/lookup_dep.py index 6ea1ccc..dd5a6e4 100755 --- a/tools/android/modularization/convenience/lookup_dep.py +++ b/tools/android/modularization/convenience/lookup_dep.py
@@ -32,6 +32,9 @@ sys.path.append(str(_SRC_DIR / 'build' / 'android')) from pylib import constants +# Import list_java_targets so that the dependency is found by print_python_deps. +import list_java_targets + def main(): arg_parser = argparse.ArgumentParser( @@ -282,7 +285,8 @@ # Caching namelist speeds up lookup_dep.py runtime by 1.5s. cache_path = abs_jar_path.with_suffix(abs_jar_path.suffix + '.namelist_cache') - if not abs_jar_path.is_relative_to(abs_build_output_dir): + if (not ClassLookupIndex._is_path_relative_to(abs_jar_path, + abs_build_output_dir)): cache_path = (abs_build_output_dir / 'gen' / cache_path.relative_to(_SRC_DIR)) if (cache_path.exists() @@ -300,6 +304,13 @@ return namelist @staticmethod + def _is_path_relative_to(path: pathlib.Path, other: pathlib.Path) -> bool: + # PurePath.is_relative_to() was introduced in Python 3.9 + resolved_path = path.resolve() + resolved_other = other.resolve() + return str(resolved_path).startswith(str(resolved_other)) + + @staticmethod def _parse_full_java_class(source_path: pathlib.Path) -> str: """Guess the fully qualified class name from the path to the source file.""" if source_path.suffix != '.java': @@ -309,6 +320,8 @@ directory_path: pathlib.Path = source_path.parent package_list_reversed = [] for part in reversed(directory_path.parts): + if part == 'java': + break package_list_reversed.append(part) if part in ('com', 'org'): break
diff --git a/tools/grit/preprocess_if_expr.gni b/tools/grit/preprocess_if_expr.gni index 64d21f9..d88e3a2 100644 --- a/tools/grit/preprocess_if_expr.gni +++ b/tools/grit/preprocess_if_expr.gni
@@ -8,9 +8,11 @@ action(target_name) { script = "//tools/grit/preprocess_if_expr.py" - if (defined(invoker.deps)) { - deps = invoker.deps - } + forward_variables_from(invoker, + [ + "deps", + "public_deps", + ]) inputs = [] outputs = []
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index b39941f..0346c0e 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -5241,6 +5241,26 @@ <description>The user selected 'share' option for a Feed card.</description> </action> +<action name="ContentSuggestions.Feed.DeviceOrientationChanged.Landscape"> + <owner>adamta@google.org</owner> + <owner>sczs@chromium.org</owner> + <owner>feed@chromium.org</owner> + <description> + The user rotates the device to landscape from the NTP with the feed visible. + iOS only. + </description> +</action> + +<action name="ContentSuggestions.Feed.DeviceOrientationChanged.Portrait"> + <owner>adamta@google.org</owner> + <owner>sczs@chromium.org</owner> + <owner>feed@chromium.org</owner> + <description> + The user rotates the device to portrait from the NTP with the feed visible. + iOS only. + </description> +</action> + <action name="ContentSuggestions.Feed.HeaderAction.ManageActivity"> <owner>adamta@google.org</owner> <owner>sczs@chromium.org</owner> @@ -15864,6 +15884,62 @@ </description> </action> +<action name="MobileTabGridSelectionCloseAllIncognitoTabsConfirmed"> + <owner>mrefaat@chromium.org</owner> + <owner>michaeldo@chromium.org</owner> + <description> + User in the incognito iOS tab grid used the Close All control with all + available tab items selected and the action sheet that asks for confirmation + has been Confirmed. + </description> +</action> + +<action name="MobileTabGridSelectionCloseAllRegularTabsConfirmed"> + <owner>mrefaat@chromium.org</owner> + <owner>michaeldo@chromium.org</owner> + <description> + User in the regular iOS tab grid used the Close All control with all + available tab items selected and the action sheet that asks for confirmation + has been Confirmed. + </description> +</action> + +<action name="MobileTabGridSelectionCloseIncognitoTabsConfirmationPresented"> + <owner>mrefaat@chromium.org</owner> + <owner>michaeldo@chromium.org</owner> + <description> + User in the iOS incognito tab grid used the Close Tabs control and the + action sheet that asks for confirmation has been displayed. + </description> +</action> + +<action name="MobileTabGridSelectionCloseRegularTabsConfirmationPresented"> + <owner>mrefaat@chromium.org</owner> + <owner>michaeldo@chromium.org</owner> + <description> + User in the iOS regular tab grid used the Close Tabs control and the action + sheet that asks for confirmation has been displayed. + </description> +</action> + +<action name="MobileTabGridSelectionCloseTabsCanceled"> + <owner>mrefaat@chromium.org</owner> + <owner>michaeldo@chromium.org</owner> + <description> + User in the iOS tab grid used the Close All control and the action sheet + that asks for confirmation has been Canceled. + </description> +</action> + +<action name="MobileTabGridSelectionCloseTabsConfirmed"> + <owner>mrefaat@chromium.org</owner> + <owner>michaeldo@chromium.org</owner> + <description> + User in the iOS tab grid used the Close All control and the action sheet + that asks for confirmation has been Confirmed. + </description> +</action> + <action name="MobileTabGridSelectionDone"> <owner>mrefaat@chromium.org</owner> <owner>michaeldo@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index e911782..8420740c 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -24816,10 +24816,11 @@ <int value="857" label="AdditionalDnsQueryTypesEnabled"/> <int value="858" label="TripleDESEnabled"/> <int value="859" label="CloudUserPolicyMerge"/> - <int value="860" label="ManagedAccountRestriction"/> + <int value="860" label="ManagedAccountsSigninRestriction"/> <int value="861" label="LockIconInAddressBarEnabled"/> <int value="862" label="DeviceScheduledReboot"/> <int value="863" label="ReportDeviceLoginLogout"/> + <int value="864" label="RemoteDebuggingAllowed"/> </enum> <enum name="EnterprisePolicyDeviceIdValidity"> @@ -52906,7 +52907,7 @@ <int value="0" label="The kTranslate feature is disabled"/> <int value="1" label="The network is offline"/> <int value="2" label="API keys for translate are unavailable"/> - <int value="3" label="Translate not supported on MHTML pages"/> + <int value="3" label="Translate not supported for this page MIME type"/> <int value="4" label="URL is of a type not considered translatable"/> <int value="5" label="Could not identify the target language"/> <int value="6" label="Translate is not allowed by policy"/> @@ -56467,6 +56468,12 @@ <int value="7" label="Timeout waiting for connectable"/> </enum> +<enum name="NetworkCellularPSimActivationResult"> + <int value="0" label="Success"/> + <int value="1" label="Already activated (activation not needed)"/> + <int value="2" label="Failed"/> +</enum> + <enum name="NetworkCellularPSimActivationState"> <int value="0" label="Activated"/> <int value="1" label="Activating"/> @@ -65610,6 +65617,8 @@ <int value="14" label="kDevToolsWindow"/> <int value="15" label="kWebAppPermissionDialogWindow"/> <int value="16" label="kSessionDataDeleter"/> + <int value="17" label="kWebAppProtocolHandlerLaunch"/> + <int value="18" label="kExtensionUpdater"/> </enum> <enum name="ProfileMenuActionableItem"> @@ -65821,6 +65830,7 @@ <int value="15" label="Toggle toolbar location to top left"/> <int value="16" label="Toggle toolbar location to top right"/> <int value="17" label="Toggle toolbar location to bottom right"/> + <int value="18" label="Undo"/> </enum> <enum name="PromoBrowserCommandEnum">
diff --git a/tools/metrics/histograms/histograms_xml/ash/histograms.xml b/tools/metrics/histograms/histograms_xml/ash/histograms.xml index cf97e80..6dfc0f6 100644 --- a/tools/metrics/histograms/histograms_xml/ash/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
@@ -2646,6 +2646,16 @@ </summary> </histogram> +<histogram name="Ash.Wallpaper.Preview.Show" enum="BooleanHit" + expires_after="2022-06-03"> + <owner>jasontt@chromium.org</owner> + <owner>assistive-eng@google.com</owner> + <summary> + Tracks the preview mode usage for wallpaper. Recorded each time the + wallpaper image is previewed. + </summary> +</histogram> + <histogram name="Ash.Wallpaper.Source" enum="WallpaperType" expires_after="2021-10-10"> <owner>xdai@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml index e1fbdde..66c5c68 100644 --- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -3140,9 +3140,44 @@ </summary> </histogram> +<histogram name="Blink.{Host}.RenderTaskDuration.{Context}.{Filter}" + units="microseconds" expires_after="2022-05-11"> + <owner>junov@chromium.org</owner> + <owner>fserb@chromium.org</owner> + <owner>aaronhk@chromium.org</owner> + <summary> + Time spent executing a script task that draws content to a {Context} context + of a {Host}. + + Note: This metric drops reports on clients with low-resolution clocks, which + means these reports will be biased against a portion of the population on + Windows. See Windows.HasHighResolutionTimeTicks for the affected sample. + </summary> + <token key="Host"> + <variant name="Canvas"/> + <variant name="OffscreenCanvas"/> + </token> + <token key="Context"> + <variant name="2D.Accelerated"/> + <variant name="2D.Unaccelerated"/> + <variant name="ImageBitmap"/> + <variant name="WebGL"/> + <variant name="WebGL2"/> + <variant name="WebGPU"/> + </token> + <token key="Filter"> + <variant name="All"/> + <variant name="Animation"/> + </token> +</histogram> + <histogram name="Blink.{Host}.RenderTaskDuration.{Thread}.{Context}.{Resource}.{Filter}" units="microseconds" expires_after="2022-05-11"> + <obsolete> + Removed in M93. This metric was replaced with + Blink.{Host}.RenderTaskDuration.{Context}.{Filter} + </obsolete> <owner>junov@chromium.org</owner> <owner>fserb@chromium.org</owner> <owner>aaronhk@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/ios/histograms.xml b/tools/metrics/histograms/histograms_xml/ios/histograms.xml index 5016598..dc4fcd6 100644 --- a/tools/metrics/histograms/histograms_xml/ios/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ios/histograms.xml
@@ -1142,6 +1142,17 @@ </summary> </histogram> +<histogram name="IOS.TabGrid.Selection.CloseTabs" units="Tabs" + expires_after="M95"> + <owner>mrefaat@chromium.org</owner> + <owner>michaeldo@chromium.org</owner> + <owner>bling-team@google.com</owner> + <summary> + The number of Tab Grid items closed with a single Close Tab(s) operation + from the tab grid selection mode. + </summary> +</histogram> + <histogram name="IOS.TabSwitcher.PageChangeInteraction" enum="IOSTabSwitcherPageChangeInteraction" expires_after="M99"> <owner>marq@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/media/histograms.xml b/tools/metrics/histograms/histograms_xml/media/histograms.xml index 11c38588..bdc03ad 100644 --- a/tools/metrics/histograms/histograms_xml/media/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/media/histograms.xml
@@ -3574,7 +3574,7 @@ </histogram> <histogram name="Media.RTCVideoDecoderFirstFrameLatencyMs" units="ms" - expires_after="2021-06-02"> + expires_after="2021-07-02"> <owner>liberato@chromium.org</owner> <owner>webrtc-video@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/network/histograms.xml b/tools/metrics/histograms/histograms_xml/network/histograms.xml index 6f9c47d4..af564127 100644 --- a/tools/metrics/histograms/histograms_xml/network/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/network/histograms.xml
@@ -396,6 +396,17 @@ </summary> </histogram> +<histogram name="Network.Cellular.PSim.OtaActivationResult" + enum="NetworkCellularPSimActivationResult" expires_after="2021-11-01"> + <owner>azeemarshad@chromium.org</owner> + <owner>cros-connectivity@google.com</owner> + <owner>hsuregan@chromium.org</owner> + <summary> + Tracks the result of attempting to activate a physical SIM card via an Over + the Air (OTA) activation. Emitted once the operation completes. + </summary> +</histogram> + <histogram name="Network.Cellular.PSim.ServiceAtLogin.Count" units="units" expires_after="2022-03-01"> <owner>azeemarshad@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index 6b8649c..5ee0658 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -6699,7 +6699,7 @@ </summary> </histogram> -<histogram name="Graphics.Smoothness.Jank" units="%" expires_after="2021-10-04"> +<histogram name="Graphics.Smoothness.Jank" units="%" expires_after="2022-06-01"> <owner>sadrul@chromium.org</owner> <owner>mjzhang@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> @@ -6719,6 +6719,39 @@ </summary> </histogram> +<histogram name="Graphics.Smoothness.Jank.All{Type}" units="%" + expires_after="2022-06-01"> + <owner>sadrul@chromium.org</owner> + <owner>mjzhang@chromium.org</owner> + <owner>graphics-dev@chromium.org</owner> + <summary> + Tracks the percent of janks for a particular frame sequence. {Type} + + Jank is measured by tracking the number of abrupt increases in frame + presentation interval, divided by the total number of frames expected to be + produced and displayed. The lower this number is, the less the smoothness + varies over time. + + Note that this metric is reported only when there are sufficient number of + frames (>= 100). If there are sequences with fewer frames, then these are + aggregated until there are enough frames to produce the metric. + </summary> + <token key="Type"> + <variant name="Animations" + summary="This metric aggregates data reported from all types of + animations (e.g. comositor-driven animations, main-thread + driven animations, and raf-driven animations, etc.)."/> + <variant name="Interactions" + summary="This metric aggregates data reported for all supported + combinations of interaction types (e.g. scrolling, pinching, + etc.) and input device types (e.g. touchscreen, touchpad, + mousewheel, etc.)."/> + <variant name="Sequences" + summary="This metric aggregates data from all animations and all + interactions."/> + </token> +</histogram> + <histogram name="Graphics.Smoothness.MaxPercentDroppedFrames_1sWindow" units="%" expires_after="2021-11-12"> <owner>behdadb@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/power/histograms.xml b/tools/metrics/histograms/histograms_xml/power/histograms.xml index 9ea7f50..abba561 100644 --- a/tools/metrics/histograms/histograms_xml/power/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/power/histograms.xml
@@ -631,9 +631,9 @@ </histogram> <histogram name="Power.ForegroundRadio.SignalLevel.{NetworkType}" - enum="RadioSignalLevel" expires_after="2021-07-03"> + enum="RadioSignalLevel" expires_after="2022-07-03"> <owner>eseckler@chromium.org</owner> - <owner>khokhlov@chromium.org</owner> + <owner>khokhlov@google.com</owner> <owner>skyostil@chromium.org</owner> <summary> Periodically samples the radio (cellular/wifi) signal strength level while @@ -650,9 +650,9 @@ </histogram> <histogram name="Power.ForegroundRadio.Wakeups.Cell.30Seconds" - enum="RadioSignalLevel" expires_after="2021-11-07"> + enum="RadioSignalLevel" expires_after="2022-07-03"> <owner>eseckler@chromium.org</owner> - <owner>khokhlov@chromium.org</owner> + <owner>khokhlov@google.com</owner> <owner>skyostil@chromium.org</owner> <summary> Counts the number of radio wakeups while Chrome is the foreground app, the @@ -668,9 +668,9 @@ </histogram> <histogram name="Power.ForegroundRadio.{Direction}KiB.{NetworkType}.30Seconds" - enum="RadioSignalLevel" expires_after="2021-07-03"> + enum="RadioSignalLevel" expires_after="2022-07-03"> <owner>eseckler@chromium.org</owner> - <owner>khokhlov@chromium.org</owner> + <owner>khokhlov@google.com</owner> <owner>skyostil@chromium.org</owner> <summary> Periodically samples the number of kibibytes received over network while
diff --git a/tools/metrics/histograms/histograms_xml/service/histograms.xml b/tools/metrics/histograms/histograms_xml/service/histograms.xml index dd822ae..d22aae4 100644 --- a/tools/metrics/histograms/histograms_xml/service/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/service/histograms.xml
@@ -118,7 +118,7 @@ </histogram> <histogram name="ServiceWorker.CacheStorageInstalledScript.CachedMetadataSize" - units="bytes" expires_after="2021-06-08"> + units="bytes" expires_after="2022-06-08"> <owner>horo@chromium.org</owner> <owner>wanderview@chromium.org</owner> <summary> @@ -129,7 +129,7 @@ <histogram name="ServiceWorker.CacheStorageInstalledScript.CachedMetadataTotalSize" - units="bytes" expires_after="2021-06-08"> + units="bytes" expires_after="2022-06-08"> <owner>horo@chromium.org</owner> <owner>wanderview@chromium.org</owner> <summary> @@ -139,7 +139,7 @@ </histogram> <histogram name="ServiceWorker.CacheStorageInstalledScript.Count" units="count" - expires_after="2021-06-08"> + expires_after="2022-06-08"> <owner>horo@chromium.org</owner> <owner>wanderview@chromium.org</owner> <summary> @@ -149,7 +149,7 @@ </histogram> <histogram name="ServiceWorker.CacheStorageInstalledScript.ScriptSize" - units="bytes" expires_after="2021-06-08"> + units="bytes" expires_after="2022-06-08"> <owner>horo@chromium.org</owner> <owner>wanderview@chromium.org</owner> <summary> @@ -159,7 +159,7 @@ </histogram> <histogram name="ServiceWorker.CacheStorageInstalledScript.ScriptTotalSize" - units="bytes" expires_after="2021-06-08"> + units="bytes" expires_after="2022-06-08"> <owner>horo@chromium.org</owner> <owner>wanderview@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/simple/histograms.xml b/tools/metrics/histograms/histograms_xml/simple/histograms.xml index 7b86069..4e0cdc840 100644 --- a/tools/metrics/histograms/histograms_xml/simple/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/simple/histograms.xml
@@ -41,7 +41,7 @@ </histogram> <histogram base="true" name="SimpleCache.ConsistencyResult" - enum="SimpleCacheConsistencyResult" expires_after="2021-06-08"> + enum="SimpleCacheConsistencyResult" expires_after="2022-06-08"> <owner>wanderview@chromium.org</owner> <owner>morlovich@chromium.org</owner> <summary> @@ -54,7 +54,7 @@ <histogram base="true" name="SimpleCache.ConsistencyResultAfterIndexFilesDeleted" - enum="SimpleCacheConsistencyResult" expires_after="2021-06-08"> + enum="SimpleCacheConsistencyResult" expires_after="2022-06-08"> <owner>wanderview@chromium.org</owner> <owner>morlovich@chromium.org</owner> <summary> @@ -88,7 +88,7 @@ <histogram base="true" name="SimpleCache.DidDeleteIndexFilesAfterFailedConsistency" enum="Boolean" - expires_after="2021-06-08"> + expires_after="2022-06-08"> <owner>wanderview@chromium.org</owner> <owner>morlovich@chromium.org</owner> <summary> @@ -163,6 +163,9 @@ <histogram base="true" name="SimpleCache.EntryTrailerPrefetchDelta" units="bytes" expires_after="2021-06-08"> + <obsolete> + Removed in June 2021. + </obsolete> <owner>wanderview@chromium.org</owner> <owner>morlovich@chromium.org</owner> <summary> @@ -175,6 +178,9 @@ <histogram base="true" name="SimpleCache.EntryTrailerPrefetchSize" units="bytes" expires_after="2021-06-08"> + <obsolete> + Removed in June 2021. + </obsolete> <owner>wanderview@chromium.org</owner> <owner>morlovich@chromium.org</owner> <summary> @@ -351,7 +357,7 @@ <histogram base="true" name="SimpleCache.OriginalConsistencyResultBeforeSuccessfulRetry" - enum="SimpleCacheConsistencyResult" expires_after="2021-06-08"> + enum="SimpleCacheConsistencyResult" expires_after="2022-06-08"> <owner>wanderview@chromium.org</owner> <owner>morlovich@chromium.org</owner> <summary> @@ -372,7 +378,7 @@ </histogram> <histogram base="true" name="SimpleCache.RetryConsistencyResult" - enum="SimpleCacheConsistencyResult" expires_after="2021-06-08"> + enum="SimpleCacheConsistencyResult" expires_after="2022-06-08"> <owner>wanderview@chromium.org</owner> <owner>morlovich@chromium.org</owner> <summary> @@ -457,7 +463,7 @@ </histogram> <histogram base="true" name="SimpleCache.SyncOpenPrefetchMode" - enum="SimpleCachePrefetchMode" expires_after="2021-06-10"> + enum="SimpleCachePrefetchMode" expires_after="2022-06-10"> <owner>wanderview@chromium.org</owner> <owner>morlovich@chromium.org</owner> <summary>
diff --git a/tools/perf/benchmarks/startup_mobile.py b/tools/perf/benchmarks/startup_mobile.py index 5f80c30..e279f693 100644 --- a/tools/perf/benchmarks/startup_mobile.py +++ b/tools/perf/benchmarks/startup_mobile.py
@@ -211,7 +211,7 @@ def _DriveMobileStartupWithIntent(state, flush_caches): - for _ in xrange(state.number_of_iterations): + for _ in range(state.number_of_iterations): # TODO(pasko): Find a way to fail the benchmark when WPR is set up # incorrectly and error pages get loaded. state.LaunchBrowser('http://bbc.co.uk', flush_caches) @@ -244,7 +244,7 @@ _MobileStartupSharedState, name='cct:coldish:bbc') def Run(self, state): - for _ in xrange(state.number_of_iterations): + for _ in range(state.number_of_iterations): state.LaunchCCT('http://bbc.co.uk') with state.FindBrowser() as browser: action_runner = browser.foreground_tab.action_runner @@ -257,7 +257,7 @@ _MobileStartupSharedState, name='maps_pwa:with_http_cache') def Run(self, state): - for _ in xrange(state.number_of_iterations): + for _ in range(state.number_of_iterations): # TODO(pasko): Flush HTTP cache for 'maps_pwa:no_http_cache'. state.LaunchMapsPwa() with state.FindBrowser() as browser:
diff --git a/tools/perf/cli_tools/flakiness_cli/frames.py b/tools/perf/cli_tools/flakiness_cli/frames.py index 415d851f..8d34d88 100644 --- a/tools/perf/cli_tools/flakiness_cli/frames.py +++ b/tools/perf/cli_tools/flakiness_cli/frames.py
@@ -52,7 +52,7 @@ Each value of the expanded sequence, one at a time. """ for count, value in count_value_pairs: - for _ in xrange(count): + for _ in range(count): yield value
diff --git a/tools/perf/cli_tools/tbmv3/validate_tbmv3_metric.py b/tools/perf/cli_tools/tbmv3/validate_tbmv3_metric.py index 88c98275..65e6f0fe 100644 --- a/tools/perf/cli_tools/tbmv3/validate_tbmv3_metric.py +++ b/tools/perf/cli_tools/tbmv3/validate_tbmv3_metric.py
@@ -49,12 +49,12 @@ def CursorErase(length): """Erase |length| chars starting from cursor.""" - for _ in xrange(length): + for _ in range(length): sys.stdout.write('\b') # Add 80 spaces, because \b only moves back the cursor. - for _ in xrange(80): + for _ in range(80): sys.stdout.write(' ') - for _ in xrange(80): + for _ in range(80): sys.stdout.write('\b') sys.stdout.flush()
diff --git a/tools/perf/contrib/PRESUBMIT.py b/tools/perf/contrib/PRESUBMIT.py index 86f75f0f..7db8fcde 100644 --- a/tools/perf/contrib/PRESUBMIT.py +++ b/tools/perf/contrib/PRESUBMIT.py
@@ -41,6 +41,8 @@ invalid_contrib_files.append(file_path) for f in input_api.os_listdir(contrib_dir): + if f == '__pycache__': + continue path = input_api.os_path.join(contrib_dir, f) if input_api.os_path.isdir(path): results.extend(
diff --git a/tools/perf/contrib/media_router_benchmarks/media_router_base_page.py b/tools/perf/contrib/media_router_benchmarks/media_router_base_page.py index aba5fd4..c476b5591 100644 --- a/tools/perf/contrib/media_router_benchmarks/media_router_base_page.py +++ b/tools/perf/contrib/media_router_benchmarks/media_router_base_page.py
@@ -95,7 +95,7 @@ error_message, timeout=5, retry=1): """Executes async javascript function and waits until it finishes.""" exception = None - for _ in xrange(retry): + for _ in range(retry): try: action_runner.ExecuteJavaScript(script) self._WaitForResult(
diff --git a/tools/perf/contrib/memory_extras/memory_extras.py b/tools/perf/contrib/memory_extras/memory_extras.py index b4b7f37..ff4dd79 100644 --- a/tools/perf/contrib/memory_extras/memory_extras.py +++ b/tools/perf/contrib/memory_extras/memory_extras.py
@@ -41,11 +41,11 @@ def RunPageInteractions(self, action_runner): self._DumpMemory(action_runner, 'pre') - for _ in xrange(_ITERATIONS): + for _ in range(_ITERATIONS): action_runner.ReloadPage() tabs = action_runner.tab.browser.tabs - for _ in xrange(_ITERATIONS): + for _ in range(_ITERATIONS): new_tab = tabs.New() new_tab.action_runner.Navigate(self._url) try:
diff --git a/tools/perf/contrib/orderfile/orderfile_unittest.py b/tools/perf/contrib/orderfile/orderfile_unittest.py index 9aca515..2689c39 100755 --- a/tools/perf/contrib/orderfile/orderfile_unittest.py +++ b/tools/perf/contrib/orderfile/orderfile_unittest.py
@@ -50,15 +50,15 @@ orderfile.OrderfileStorySet.TESTING, num_training=25, num_variations=orderfile.OrderfileStorySet.NUM_VARIATION_BENCHMARKS, test_variation=i).RunSetStories()]) - for i in xrange( + for i in range( orderfile.OrderfileStorySet.NUM_VARIATION_BENCHMARKS)] self.assertEqual(25, len(training)) - for i in xrange(orderfile.OrderfileStorySet.NUM_VARIATION_BENCHMARKS): + for i in range(orderfile.OrderfileStorySet.NUM_VARIATION_BENCHMARKS): self.assertEqual(orderfile.OrderfileStorySet.DEFAULT_TESTING, len(testing[i])) self.assertEqual(0, len(testing[i] & training)) - for j in xrange(i + 1, - orderfile.OrderfileStorySet.NUM_VARIATION_BENCHMARKS): + for j in range(i + 1, + orderfile.OrderfileStorySet.NUM_VARIATION_BENCHMARKS): self.assertEqual(0, len(testing[i] & testing[j]))
diff --git a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py index 9240c6a..ec2ff8da 100644 --- a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py +++ b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
@@ -111,7 +111,7 @@ # forwarding necessary for the local server to work. Since port forwarding # often refuses to work for a short period after rebooting, try several # times. - for _ in xrange(5): + for _ in range(5): try: self.platform.network_controller.Open(self.wpr_mode) break
diff --git a/tools/perf/core/perf_json_config_validator.py b/tools/perf/core/perf_json_config_validator.py index 6982c85..76986d5 100644 --- a/tools/perf/core/perf_json_config_validator.py +++ b/tools/perf/core/perf_json_config_validator.py
@@ -96,7 +96,7 @@ shard_map_data.pop('extra_infos', None) shard_keys = set(shard_map_data.keys()) - expected_shard_keys = set([str(i) for i in xrange(num_shards)]) + expected_shard_keys = set([str(i) for i in range(num_shards)]) if shard_keys != expected_shard_keys: raise ValueError( 'The shard configuration of %s does not match the expected expected '
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 828c0bee..9691f9c 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -9,8 +9,8 @@ "remote_path": "perfetto_binaries/trace_processor_shell/mac/bae8193de6c017394901163b7817157342914679/trace_processor_shell" }, "linux": { - "hash": "a5cb01af2dfe7c3a0fb51427d187501776f672c3", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/5465d9e0184a6fe3e5660cf2b123386569f7d379/trace_processor_shell" + "hash": "140fcdb51e61f30501a4136da9ba4b263f019663", + "remote_path": "perfetto_binaries/trace_processor_shell/linux/0856d6eecd570d889e563399e658803ebc5c0a95/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py index 7923393..af0c5f09 100755 --- a/tools/perf/core/results_dashboard.py +++ b/tools/perf/core/results_dashboard.py
@@ -91,7 +91,7 @@ # instance. So sleep before retrying again. ( # For more details, see crbug.com/867379. wait_before_next_retry_in_seconds = 15 - for i in xrange(1, num_retries + 1): + for i in range(1, num_retries + 1): try: logging.info( 'Sending %s result of %s to dashboard (attempt %i out of %i).' %
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 6af17d3..6dc1e30 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -73,11 +73,6 @@ # Benchmark: blink_perf.shadow_dom crbug.com/702319 [ android-nexus-5x ] blink_perf.shadow_dom/* [ Skip ] -# Benchmark: desktop_ui -crbug.com/1210302 [ linux ] desktop_ui/* [ Skip ] -crbug.com/1210302 [ mac ] desktop_ui/* [ Skip ] -crbug.com/1210302 [ win ] desktop_ui/* [ Skip ] - # Benchmark: dromaeo crbug.com/1050065 [ android-pixel-2 ] dromaeo/http://dromaeo.com?dom-modify [ Skip ]
diff --git a/tools/perf/page_sets/desktop_ui/browser_utils.py b/tools/perf/page_sets/desktop_ui/browser_utils.py index be3fca3e..5329124 100644 --- a/tools/perf/page_sets/desktop_ui/browser_utils.py +++ b/tools/perf/page_sets/desktop_ui/browser_utils.py
@@ -17,8 +17,10 @@ step_interval=0.01): window_id = browser.GetWindowForTarget(tab_id)['result']['windowId'] for _ in range(repeat): - ratios = range(steps + 1) + range(steps, -1, -1) if yoyo else range(steps + - 1) + if yoyo: + ratios = list(range(steps + 1)) + list(range(steps, -1, -1)) + else: + ratios = range(steps + 1) for i in ratios: ratio = 1.0 * i / steps bounds = {}
diff --git a/tools/perf/page_sets/desktop_ui/desktop_ui_stories.py b/tools/perf/page_sets/desktop_ui/desktop_ui_stories.py index 321b5194..da6f4794 100644 --- a/tools/perf/page_sets/desktop_ui/desktop_ui_stories.py +++ b/tools/perf/page_sets/desktop_ui/desktop_ui_stories.py
@@ -51,20 +51,20 @@ for cls in self.TAB_SEARCH_STORIES: self.AddStory( cls(self, [ - '--enable-ui-devtools=enabled', + '--enable-ui-devtools=0', '--top-chrome-touch-ui=disabled', ])) for cls in self.DOWNLOAD_SHELF_STORIES: self.AddStory(cls(self, [ - '--enable-ui-devtools=enabled', + '--enable-ui-devtools=0', ])) for cls in self.DOWNLOAD_SHELF_WEBUI_STORIES: self.AddStory( cls(self, [ '--enable-features=WebUIDownloadShelf', - '--enable-ui-devtools=enabled', + '--enable-ui-devtools=0', ])) # WebUI Tab Strip is not available on Mac. @@ -73,6 +73,6 @@ self.AddStory( cls(self, [ '--enable-features=WebUITabStrip', - '--enable-ui-devtools=enabled', + '--enable-ui-devtools=0', '--top-chrome-touch-ui=enabled', ]))
diff --git a/tools/perf/page_sets/rendering/key_hit_test_cases.py b/tools/perf/page_sets/rendering/key_hit_test_cases.py index 2085834..60ec0ce6 100644 --- a/tools/perf/page_sets/rendering/key_hit_test_cases.py +++ b/tools/perf/page_sets/rendering/key_hit_test_cases.py
@@ -41,7 +41,7 @@ action_runner.WaitForJavaScriptCondition( 'window.__tapTarget != null') - for _ in xrange(100): + for _ in range(100): self.TapButton(action_runner) def TapButton(self, action_runner):
diff --git a/tools/perf/page_sets/rendering/key_silk_cases.py b/tools/perf/page_sets/rendering/key_silk_cases.py index 03a8a847..de632f0 100644 --- a/tools/perf/page_sets/rendering/key_silk_cases.py +++ b/tools/perf/page_sets/rendering/key_silk_cases.py
@@ -380,7 +380,7 @@ URL = 'file://../key_silk_cases/inbox_app.html?toggle_drawer' def PerformPageInteractions(self, action_runner): - for _ in xrange(6): + for _ in range(6): self.ToggleDrawer(action_runner) def ToggleDrawer(self, action_runner): @@ -606,7 +606,7 @@ action_runner.Wait(1) def PerformPageInteractions(self, action_runner): - for i in xrange(9): + for i in range(9): button_func = ('document.getElementById("demo").$.' 'buttons.children[%d]') % i with action_runner.CreateInteraction('Action_TapAction', repeatable=True):
diff --git a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py index b7e1817..191a560 100644 --- a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py +++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
@@ -42,7 +42,7 @@ def RunPageInteractions(self, action_runner): action_runner.tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() - for _ in xrange(0, 3): + for _ in range(3): current_scale_factor = self.target_scale_factor self.RunPinchGesture(action_runner, scale_factor=current_scale_factor) while current_scale_factor > 1.0:
diff --git a/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py b/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py index 12f90a1..0c6b25ae 100644 --- a/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py +++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py
@@ -37,7 +37,7 @@ def RunPageInteractions(self, action_runner): action_runner.tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() - for _ in xrange(0, 3): + for _ in range(3): current_scale_factor = 7.0 self.RunPinchGesture(action_runner, scale_factor=current_scale_factor) while current_scale_factor > 1.0:
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py index 58b5e16e..ee02a9b 100644 --- a/tools/perf/page_sets/system_health/browsing_stories.py +++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -109,7 +109,7 @@ # Scroll main page if needed before we start browsing articles. if self.SCROLL_BEFORE_BROWSE: self._ScrollMainPage(action_runner) - for i in xrange(self.ITEMS_TO_VISIT): + for i in range(self.ITEMS_TO_VISIT): self._NavigateToItem(action_runner, i) self._AfterNavigate(action_runner) self._ReadNextArticle(action_runner) @@ -245,7 +245,7 @@ action_runner.tab.WaitForDocumentReadyStateToBeComplete() # Facebook loads content dynamically. So keep trying to scroll till we find # the elements. Retry 5 times waiting a bit each time. - for _ in xrange(5): + for _ in range(5): action_runner.RepeatableBrowserDrivenScroll( repeat_count=self.MAIN_PAGE_SCROLL_REPEAT) result = action_runner.EvaluateJavaScript( @@ -361,7 +361,7 @@ # Add one to the items to visit since we are going to skip the ad and we # want to still visit the same amount of articles. - for i in xrange(self.ITEMS_TO_VISIT + 1): + for i in range(self.ITEMS_TO_VISIT + 1): # Skip the ad disguised as an article. if i == 1: continue @@ -585,7 +585,7 @@ def _DidLoadDocument(self, action_runner): index = self.ITEM_SELECTOR_INDEX - for _ in xrange(self.ITEMS_TO_VISIT): + for _ in range(self.ITEMS_TO_VISIT): self._NavigateToItem(action_runner, index) self._ViewMediaItem(action_runner, index) if self.INCREMENT_INDEX_AFTER_EACH_ITEM: @@ -621,7 +621,7 @@ # button click it to enable further scroll. This button would only be added # after we scrolled a bit. So can't wait for this button at the start. accepted_continue = False - for _ in xrange(15): + for _ in range(15): result = action_runner.EvaluateJavaScript( 'document.querySelectorAll(".Button-tertiary").length') if result and not accepted_continue:
diff --git a/tools/perf/page_sets/system_health/long_running_stories.py b/tools/perf/page_sets/system_health/long_running_stories.py index a21e187..0e60ef86 100644 --- a/tools/perf/page_sets/system_health/long_running_stories.py +++ b/tools/perf/page_sets/system_health/long_running_stories.py
@@ -24,7 +24,7 @@ action_runner.tab.browser.tabs.New() if self._take_memory_measurement: action_runner.MeasureMemory() - for _ in xrange(STEPS): + for _ in range(STEPS): action_runner.Wait(SAMPLING_INTERVAL_IN_SECONDS) if self._take_memory_measurement: action_runner.MeasureMemory()
diff --git a/tools/perf/page_sets/tough_scheduling_cases/_second_batch_js_generator.py b/tools/perf/page_sets/tough_scheduling_cases/_second_batch_js_generator.py index 3c0dff7..de6b62385 100755 --- a/tools/perf/page_sets/tough_scheduling_cases/_second_batch_js_generator.py +++ b/tools/perf/page_sets/tough_scheduling_cases/_second_batch_js_generator.py
@@ -58,7 +58,7 @@ indent = ' ' * indent rand = _CreateRandomGeneratorForKey(name) print(indent + 'function %s(value) {' % name, file=out) - for _ in xrange(line_count): + for _ in range(line_count): print(indent + ' %s;' % rand.choice(operations), file=out) print(indent + ' return value;', file=out) print(indent + '}\n', file=out) @@ -74,9 +74,9 @@ def _GenerateTopLevelClosures( out, count, inner_function_count, inner_function_line_count): - for closure_index in xrange(count): + for closure_index in range(count): print('(function() { // closure %d' % closure_index, file=out) - for inner_index in xrange(inner_function_count): + for inner_index in range(inner_function_count): _GenerateLeafFunction( out, _ClosureInnerFunctionName(closure_index, inner_index), @@ -85,7 +85,7 @@ print('window.%s = function(value) {' % _TopLevelClosureEntryPoint(closure_index), file=out) - for inner_index in xrange(inner_function_count): + for inner_index in range(inner_function_count): print(' value = %s(value);' % _ClosureInnerFunctionName(closure_index, inner_index), file=out) print(' return value;', file=out) @@ -103,8 +103,8 @@ def _GenerateTopLevelFunctions( out, count, inner_function_count, inner_function_line_count): - for function_index in xrange(count): - for inner_index in xrange(inner_function_count / 2): + for function_index in range(count): + for inner_index in range(inner_function_count / 2): _GenerateLeafFunction( out, _FunctionInnerFunctionName(function_index, inner_index), @@ -113,14 +113,14 @@ print('function %s(value) {' % _TopLevelFunctionEntryPoint(function_index), file=out) - for inner_index in xrange(inner_function_count / 2, inner_function_count): + for inner_index in range(inner_function_count / 2, inner_function_count): _GenerateLeafFunction( out, _FunctionInnerFunctionName(function_index, inner_index), inner_function_line_count, indent=1) - for inner_index in xrange(inner_function_count): + for inner_index in range(inner_function_count): print(' value = %s(value);' % _FunctionInnerFunctionName(function_index, inner_index), file=out) print(' return value;', file=out) @@ -129,10 +129,10 @@ def _GenerateMain(out, loop_count, closure_call_count, function_call_count): print('function main(value) {', file=out) - for _ in xrange(loop_count): - for i in xrange(closure_call_count): + for _ in range(loop_count): + for i in range(closure_call_count): print(' value = %s(value);' % _TopLevelClosureEntryPoint(i), file=out) - for i in xrange(function_call_count): + for i in range(function_call_count): print(' value = %s(value);' % _TopLevelFunctionEntryPoint(i), file=out) print(' return value;', file=out)
diff --git a/tools/typescript/definitions/developer_private.d.ts b/tools/typescript/definitions/developer_private.d.ts index 5a1930ad..12e5398 100644 --- a/tools/typescript/definitions/developer_private.d.ts +++ b/tools/typescript/definitions/developer_private.d.ts
@@ -388,7 +388,7 @@ callback?: VoidCallback): void; export function getExtensionsInfo( options: GetExtensionsInfoOptions, - callback: (info: ExtensionInfo) => void): void; + callback: (info: ExtensionInfo[]) => void): void; export function getExtensionSize(id: string, callback: StringCallback): void; export function getProfileConfiguration(
diff --git a/tools/variations/bisect_variations.py b/tools/variations/bisect_variations.py index ea46aab1..e9424b7 100644 --- a/tools/variations/bisect_variations.py +++ b/tools/variations/bisect_variations.py
@@ -37,13 +37,13 @@ import split_variations_cmd _CHROME_PATH_WIN = { - # The following three paths are relative to %ProgramFiles(x86)% - "stable": r"Google\Chrome\Application\chrome.exe", - "beta": r"Google\Chrome\Application\chrome.exe", - "dev": r"Google\Chrome Dev\Application\chrome.exe", - # The following two paths are relative to %LOCALAPPDATA% - "canary": r"Google\Chrome SxS\Application\chrome.exe", - "chromium": r"Chromium\Application\chrome.exe", + # The following three paths are relative to %ProgramFiles(x86)% + "stable": r"Google\Chrome\Application\chrome.exe", + "beta": r"Google\Chrome Beta\Application\chrome.exe", + "dev": r"Google\Chrome Dev\Application\chrome.exe", + # The following two paths are relative to %LOCALAPPDATA% + "canary": r"Google\Chrome SxS\Application\chrome.exe", + "chromium": r"Chromium\Application\chrome.exe", } _CHROME_PATH_MAC = {
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc index a4b8306..b1953d5 100644 --- a/ui/accessibility/ax_node.cc +++ b/ui/accessibility/ax_node.cc
@@ -49,6 +49,11 @@ return std::move(data_); } +const std::vector<AXNode*>& AXNode::GetAllChildren() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return children_; +} + size_t AXNode::GetChildCount() const { DCHECK(!tree_->GetTreeUpdateInProgressState()); return children_.size(); @@ -59,9 +64,8 @@ const AXTreeManager* child_tree_manager = AXTreeManagerMap::GetInstance().GetManagerForChildTree(*this); - if (child_tree_manager) { + if (child_tree_manager) return 1u; - } return GetChildCount(); } @@ -88,14 +92,14 @@ return unignored_child_count_; } -AXNode* AXNode::GetChildAt(size_t index) const { +AXNode* AXNode::GetChildAtIndex(size_t index) const { DCHECK(!tree_->GetTreeUpdateInProgressState()); if (index >= GetChildCount()) return nullptr; return children_[index]; } -AXNode* AXNode::GetChildAtCrossingTreeBoundary(size_t index) const { +AXNode* AXNode::GetChildAtIndexCrossingTreeBoundary(size_t index) const { DCHECK(!tree_->GetTreeUpdateInProgressState()); const AXTreeManager* child_tree_manager = @@ -107,7 +111,7 @@ return child_tree_manager->GetRootAsAXNode(); } - return GetChildAt(index); + return GetChildAtIndex(index); } AXNode* AXNode::GetUnignoredChildAtIndex(size_t index) const { @@ -188,25 +192,96 @@ return unignored_index_in_parent_; } +AXNode* AXNode::GetFirstChild() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return GetChildAtIndex(0); +} + +AXNode* AXNode::GetFirstChildCrossingTreeBoundary() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return GetChildAtIndexCrossingTreeBoundary(0); +} + AXNode* AXNode::GetFirstUnignoredChild() const { DCHECK(!tree_->GetTreeUpdateInProgressState()); return ComputeFirstUnignoredChildRecursive(); } +AXNode* AXNode::GetFirstUnignoredChildCrossingTreeBoundary() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + + const AXTreeManager* child_tree_manager = + AXTreeManagerMap::GetInstance().GetManagerForChildTree(*this); + if (child_tree_manager) + return child_tree_manager->GetRootAsAXNode(); + + return ComputeFirstUnignoredChildRecursive(); +} + +AXNode* AXNode::GetLastChild() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + size_t n = GetChildCount(); + if (n == 0) + return nullptr; + return GetChildAtIndex(n - 1); +} + +AXNode* AXNode::GetLastChildCrossingTreeBoundary() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + size_t n = GetChildCountCrossingTreeBoundary(); + if (n == 0) + return nullptr; + return GetChildAtIndexCrossingTreeBoundary(n - 1); +} + AXNode* AXNode::GetLastUnignoredChild() const { DCHECK(!tree_->GetTreeUpdateInProgressState()); return ComputeLastUnignoredChildRecursive(); } +AXNode* AXNode::GetLastUnignoredChildCrossingTreeBoundary() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + + const AXTreeManager* child_tree_manager = + AXTreeManagerMap::GetInstance().GetManagerForChildTree(*this); + if (child_tree_manager) + return child_tree_manager->GetRootAsAXNode(); + + return ComputeLastUnignoredChildRecursive(); +} + +AXNode* AXNode::GetDeepestFirstChild() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + if (!GetChildCount()) + return nullptr; + + AXNode* deepest_child = GetFirstChild(); + while (deepest_child->GetChildCount()) + deepest_child = deepest_child->GetFirstChild(); + + return deepest_child; +} + AXNode* AXNode::GetDeepestFirstUnignoredChild() const { DCHECK(!tree_->GetTreeUpdateInProgressState()); if (!GetUnignoredChildCount()) return nullptr; AXNode* deepest_child = GetFirstUnignoredChild(); - while (deepest_child->GetUnignoredChildCount()) { + while (deepest_child->GetUnignoredChildCount()) deepest_child = deepest_child->GetFirstUnignoredChild(); - } + + return deepest_child; +} + +AXNode* AXNode::GetDeepestLastChild() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + if (!GetChildCount()) + return nullptr; + + AXNode* deepest_child = GetLastChild(); + while (deepest_child->GetChildCount()) + deepest_child = deepest_child->GetLastChild(); return deepest_child; } @@ -217,13 +292,25 @@ return nullptr; AXNode* deepest_child = GetLastUnignoredChild(); - while (deepest_child->GetUnignoredChildCount()) { + while (deepest_child->GetUnignoredChildCount()) deepest_child = deepest_child->GetLastUnignoredChild(); - } return deepest_child; } +AXNode* AXNode::GetNextSibling() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + AXNode* parent = GetParent(); + if (!parent) + return nullptr; + DCHECK(parent || !GetIndexInParent()) + << "Root nodes lack a parent. Their index_in_parent should be 0."; + size_t nextIndex = GetIndexInParent() + 1; + if (nextIndex >= parent->GetChildCount()) + return nullptr; + return parent->GetChildAtIndex(nextIndex); +} + // Search for the next sibling of this node, skipping over any ignored nodes // encountered. // @@ -329,6 +416,16 @@ return nullptr; } +AXNode* AXNode::GetPreviousSibling() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + DCHECK(GetParent() || !GetIndexInParent()) + << "Root nodes lack a parent. Their index_in_parent should be 0."; + size_t index = GetIndexInParent(); + if (index == 0) + return nullptr; + return GetParent()->GetChildAtIndex(index - 1); +} + // Search for the previous sibling of this node, skipping over any ignored nodes // encountered. // @@ -427,6 +524,29 @@ return sibling; } +AXNode::AllChildIterator AXNode::AllChildrenBegin() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return AllChildIterator(this, GetFirstChild()); +} + +AXNode::AllChildIterator AXNode::AllChildrenEnd() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return AllChildIterator(this, nullptr); +} + +AXNode::AllChildCrossingTreeBoundaryIterator +AXNode::AllChildrenCrossingTreeBoundaryBegin() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return AllChildCrossingTreeBoundaryIterator( + this, GetFirstChildCrossingTreeBoundary()); +} + +AXNode::AllChildCrossingTreeBoundaryIterator +AXNode::AllChildrenCrossingTreeBoundaryEnd() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return AllChildCrossingTreeBoundaryIterator(this, nullptr); +} + AXNode::UnignoredChildIterator AXNode::UnignoredChildrenBegin() const { DCHECK(!tree_->GetTreeUpdateInProgressState()); return UnignoredChildIterator(this, GetFirstUnignoredChild()); @@ -437,39 +557,17 @@ return UnignoredChildIterator(this, nullptr); } -// The first (direct) child, ignored or unignored. -AXNode* AXNode::GetFirstChild() const { - if (children().empty()) - return nullptr; - return children()[0]; +AXNode::UnignoredChildCrossingTreeBoundaryIterator +AXNode::UnignoredChildrenCrossingTreeBoundaryBegin() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return UnignoredChildCrossingTreeBoundaryIterator( + this, GetFirstUnignoredChildCrossingTreeBoundary()); } -// The last (direct) child, ignored or unignored. -AXNode* AXNode::GetLastChild() const { - size_t n = children().size(); - if (n == 0) - return nullptr; - return children()[n - 1]; -} - -// The previous (direct) sibling, ignored or unignored. -AXNode* AXNode::GetPreviousSibling() const { - // Root nodes lack a parent, their index_in_parent should be 0. - DCHECK(!parent() ? index_in_parent() == 0 : true); - size_t index = index_in_parent(); - if (index == 0) - return nullptr; - return parent()->children()[index - 1]; -} - -// The next (direct) sibling, ignored or unignored. -AXNode* AXNode::GetNextSibling() const { - if (!parent()) - return nullptr; - size_t nextIndex = index_in_parent() + 1; - if (nextIndex >= parent()->children().size()) - return nullptr; - return parent()->children()[nextIndex]; +AXNode::UnignoredChildCrossingTreeBoundaryIterator +AXNode::UnignoredChildrenCrossingTreeBoundaryEnd() const { + DCHECK(!tree_->GetTreeUpdateInProgressState()); + return UnignoredChildCrossingTreeBoundaryIterator(this, nullptr); } bool AXNode::IsText() const {
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h index 8e192d5..1e50cc4 100644 --- a/ui/accessibility/ax_node.h +++ b/ui/accessibility/ax_node.h
@@ -115,10 +115,7 @@ // Accessors. OwnerTree* tree() const { return tree_; } AXNodeID id() const { return data_.id; } - AXNode* parent() const { return parent_; } const AXNodeData& data() const { return data_; } - const std::vector<AXNode*>& children() const { return children_; } - size_t index_in_parent() const { return index_in_parent_; } // Returns ownership of |data_| to the caller; effectively clearing |data_|. AXNodeData&& TakeData(); @@ -126,36 +123,80 @@ // // Methods for walking the tree. // + // These come in four flavors: Methods that walk all the nodes, methods that + // walk only the unignored nodes (effectively re-structuring the tree to + // remove all ignored nodes), and another two variants that do the above plus + // cross tree boundaries, effectively stiching together all accessibility + // trees that are part of the same webpage, PDF or window into a large global + // tree. + const std::vector<AXNode*>& GetAllChildren() const; size_t GetChildCount() const; - // TODO(nektar): Update `BrowserAccessibility` and remove this method. size_t GetChildCountCrossingTreeBoundary() const; size_t GetUnignoredChildCount() const; - // TODO(nektar): Update `BrowserAccessibility` and remove this method. size_t GetUnignoredChildCountCrossingTreeBoundary() const; - AXNode* GetChildAt(size_t index) const; - // TODO(nektar): Update `BrowserAccessibility` and remove this method. - AXNode* GetChildAtCrossingTreeBoundary(size_t index) const; + AXNode* GetChildAtIndex(size_t index) const; + AXNode* GetChildAtIndexCrossingTreeBoundary(size_t index) const; AXNode* GetUnignoredChildAtIndex(size_t index) const; - // TODO(nektar): Update `BrowserAccessibility` and remove this method. AXNode* GetUnignoredChildAtIndexCrossingTreeBoundary(size_t index) const; AXNode* GetParent() const; - // TODO(nektar): Update `BrowserAccessibility` and remove this method. AXNode* GetParentCrossingTreeBoundary() const; AXNode* GetUnignoredParent() const; - // TODO(nektar): Update `BrowserAccessibility` and remove this method. AXNode* GetUnignoredParentCrossingTreeBoundary() const; size_t GetIndexInParent() const; size_t GetUnignoredIndexInParent() const; + AXNode* GetFirstChild() const; + AXNode* GetFirstChildCrossingTreeBoundary() const; AXNode* GetFirstUnignoredChild() const; + AXNode* GetFirstUnignoredChildCrossingTreeBoundary() const; + AXNode* GetLastChild() const; + AXNode* GetLastChildCrossingTreeBoundary() const; AXNode* GetLastUnignoredChild() const; + AXNode* GetLastUnignoredChildCrossingTreeBoundary() const; + AXNode* GetDeepestFirstChild() const; AXNode* GetDeepestFirstUnignoredChild() const; + AXNode* GetDeepestLastChild() const; AXNode* GetDeepestLastUnignoredChild() const; + AXNode* GetNextSibling() const; AXNode* GetNextUnignoredSibling() const; + AXNode* GetPreviousSibling() const; AXNode* GetPreviousUnignoredSibling() const; + + // Traverse the tree in depth-first pre-order. AXNode* GetNextUnignoredInTreeOrder() const; AXNode* GetPreviousUnignoredInTreeOrder() const; + // + // Deprecated methods for walking the tree. + // + + const std::vector<AXNode*>& children() const { return children_; } + AXNode* parent() const { return parent_; } + size_t index_in_parent() const { return index_in_parent_; } + + // + // Iterators for walking the tree in depth-first pre-order. + // + + using AllChildIterator = ChildIteratorBase<AXNode, + &AXNode::GetNextSibling, + &AXNode::GetPreviousSibling, + &AXNode::GetFirstChild, + &AXNode::GetLastChild>; + AllChildIterator AllChildrenBegin() const; + AllChildIterator AllChildrenEnd() const; + + using AllChildCrossingTreeBoundaryIterator = + ChildIteratorBase<AXNode, + &AXNode::GetNextSibling, + &AXNode::GetPreviousSibling, + &AXNode::GetFirstChildCrossingTreeBoundary, + &AXNode::GetLastChildCrossingTreeBoundary>; + AllChildCrossingTreeBoundaryIterator AllChildrenCrossingTreeBoundaryBegin() + const; + AllChildCrossingTreeBoundaryIterator AllChildrenCrossingTreeBoundaryEnd() + const; + using UnignoredChildIterator = ChildIteratorBase<AXNode, &AXNode::GetNextUnignoredSibling, @@ -165,12 +206,16 @@ UnignoredChildIterator UnignoredChildrenBegin() const; UnignoredChildIterator UnignoredChildrenEnd() const; - // Walking the tree including both ignored and unignored nodes. - // These methods consider only the direct children or siblings of a node. - AXNode* GetFirstChild() const; - AXNode* GetLastChild() const; - AXNode* GetPreviousSibling() const; - AXNode* GetNextSibling() const; + using UnignoredChildCrossingTreeBoundaryIterator = + ChildIteratorBase<AXNode, + &AXNode::GetNextUnignoredSibling, + &AXNode::GetPreviousUnignoredSibling, + &AXNode::GetFirstUnignoredChildCrossingTreeBoundary, + &AXNode::GetLastUnignoredChildCrossingTreeBoundary>; + UnignoredChildCrossingTreeBoundaryIterator + UnignoredChildrenCrossingTreeBoundaryBegin() const; + UnignoredChildCrossingTreeBoundaryIterator + UnignoredChildrenCrossingTreeBoundaryEnd() const; // Returns true if the node has any of the text related roles, including // kStaticText, kInlineTextBox and kListMarker (for Legacy Layout). Does not
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc index f4a1aef5..44b0ef7 100644 --- a/ui/accessibility/ax_node_data.cc +++ b/ui/accessibility/ax_node_data.cc
@@ -452,7 +452,7 @@ const std::string& value) { DCHECK_NE(attribute, ax::mojom::StringAttribute::kNone); DCHECK_NE(attribute, ax::mojom::StringAttribute::kChildTreeId) - << "Use AddChildTreeId"; + << "Use AddChildTreeId."; if (HasStringAttribute(attribute)) RemoveStringAttribute(attribute); string_attributes.push_back(std::make_pair(attribute, value));
diff --git a/ui/accessibility/ax_node_unittest.cc b/ui/accessibility/ax_node_unittest.cc index f3e13572..569e1e00 100644 --- a/ui/accessibility/ax_node_unittest.cc +++ b/ui/accessibility/ax_node_unittest.cc
@@ -4,15 +4,395 @@ #include "ui/accessibility/ax_node.h" +#include <memory> +#include <utility> +#include <vector> + +#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_tree.h" #include "ui/accessibility/ax_tree_data.h" #include "ui/accessibility/ax_tree_id.h" +#include "ui/accessibility/test_ax_tree_manager.h" namespace ui { +namespace { + +// The third argument is an optional description string which we don't need +// because, after verifying manually, test errors are descriptive enough. +MATCHER_P(HasAXNodeID, ax_node_data, "") { + return arg->id() == ax_node_data.id; +} + +} // namespace + +using testing::ElementsAre; + +TEST(AXNodeTest, TreeWalking) { + // ++kRootWebArea + // ++++kParagraph + // ++++++kStaticText IGNORED + // ++++kParagraph IGNORED + // ++++++kStaticText + // ++++kParagraph + // ++++++kStaticText + // ++++kParagraph IGNORED + // ++++++kLink IGNORED + // ++++++++kStaticText + // ++++++kButton + + // Numbers at the end of variable names indicate their position under the + // root. + AXNodeData root; + AXNodeData paragraph_0; + AXNodeData static_text_0_0_ignored; + AXNodeData paragraph_1_ignored; + AXNodeData static_text_1_0; + AXNodeData paragraph_2; + AXNodeData static_text_2_0; + AXNodeData paragraph_3_ignored; + AXNodeData link_3_0_ignored; + AXNodeData static_text_3_0_0; + AXNodeData button_3_1; + + root.id = 1; + paragraph_0.id = 2; + static_text_0_0_ignored.id = 3; + paragraph_1_ignored.id = 4; + static_text_1_0.id = 5; + paragraph_2.id = 6; + static_text_2_0.id = 7; + paragraph_3_ignored.id = 8; + link_3_0_ignored.id = 9; + static_text_3_0_0.id = 10; + button_3_1.id = 11; + + root.role = ax::mojom::Role::kRootWebArea; + root.child_ids = {paragraph_0.id, paragraph_1_ignored.id, paragraph_2.id, + paragraph_3_ignored.id}; + + paragraph_0.role = ax::mojom::Role::kParagraph; + paragraph_0.child_ids = {static_text_0_0_ignored.id}; + + static_text_0_0_ignored.role = ax::mojom::Role::kStaticText; + static_text_0_0_ignored.AddState(ax::mojom::State::kIgnored); + static_text_0_0_ignored.SetName("static_text_0_0_ignored"); + + paragraph_1_ignored.role = ax::mojom::Role::kParagraph; + paragraph_1_ignored.AddState(ax::mojom::State::kIgnored); + paragraph_1_ignored.child_ids = {static_text_1_0.id}; + + static_text_1_0.role = ax::mojom::Role::kStaticText; + static_text_1_0.SetName("static_text_1_0"); + + paragraph_2.role = ax::mojom::Role::kParagraph; + paragraph_2.child_ids = {static_text_2_0.id}; + + static_text_2_0.role = ax::mojom::Role::kStaticText; + static_text_2_0.SetName("static_text_2_0"); + + paragraph_3_ignored.role = ax::mojom::Role::kParagraph; + paragraph_3_ignored.AddState(ax::mojom::State::kIgnored); + paragraph_3_ignored.child_ids = {link_3_0_ignored.id, button_3_1.id}; + + link_3_0_ignored.role = ax::mojom::Role::kLink; + link_3_0_ignored.AddState(ax::mojom::State::kLinked); + link_3_0_ignored.AddState(ax::mojom::State::kIgnored); + link_3_0_ignored.child_ids = {static_text_3_0_0.id}; + + static_text_3_0_0.role = ax::mojom::Role::kStaticText; + static_text_3_0_0.SetName("static_text_3_0_0"); + + button_3_1.role = ax::mojom::Role::kButton; + button_3_1.SetName("button_3_1"); + + AXTreeUpdate initial_state; + initial_state.root_id = root.id; + initial_state.nodes = {root, + paragraph_0, + static_text_0_0_ignored, + paragraph_1_ignored, + static_text_1_0, + paragraph_2, + static_text_2_0, + paragraph_3_ignored, + link_3_0_ignored, + static_text_3_0_0, + button_3_1}; + initial_state.has_tree_data = true; + + AXTreeData tree_data; + tree_data.tree_id = AXTreeID::CreateNewAXTreeID(); + tree_data.title = "Application"; + initial_state.tree_data = tree_data; + + AXTree tree; + ASSERT_TRUE(tree.Unserialize(initial_state)); + + const AXNode* root_node = tree.root(); + ASSERT_EQ(root.id, root_node->id()); + + EXPECT_THAT( + root_node->GetAllChildren(), + ElementsAre(HasAXNodeID(paragraph_0), HasAXNodeID(paragraph_1_ignored), + HasAXNodeID(paragraph_2), HasAXNodeID(paragraph_3_ignored))); + EXPECT_EQ(4u, root_node->GetChildCount()); + EXPECT_EQ(4u, root_node->GetChildCountCrossingTreeBoundary()); + EXPECT_EQ(5u, root_node->GetUnignoredChildCount()); + EXPECT_EQ(5u, root_node->GetUnignoredChildCountCrossingTreeBoundary()); + + EXPECT_EQ(paragraph_0.id, root_node->GetChildAtIndex(0)->id()); + EXPECT_EQ(paragraph_1_ignored.id, root_node->GetChildAtIndex(1)->id()); + EXPECT_EQ(paragraph_2.id, root_node->GetChildAtIndex(2)->id()); + EXPECT_EQ(paragraph_3_ignored.id, root_node->GetChildAtIndex(3)->id()); + EXPECT_EQ(nullptr, root_node->GetChildAtIndex(4)); + + EXPECT_EQ(paragraph_0.id, + root_node->GetChildAtIndexCrossingTreeBoundary(0)->id()); + EXPECT_EQ(paragraph_1_ignored.id, + root_node->GetChildAtIndexCrossingTreeBoundary(1)->id()); + EXPECT_EQ(paragraph_2.id, + root_node->GetChildAtIndexCrossingTreeBoundary(2)->id()); + EXPECT_EQ(paragraph_3_ignored.id, + root_node->GetChildAtIndexCrossingTreeBoundary(3)->id()); + EXPECT_EQ(nullptr, root_node->GetChildAtIndexCrossingTreeBoundary(4)); + + EXPECT_EQ(paragraph_0.id, root_node->GetUnignoredChildAtIndex(0)->id()); + EXPECT_EQ(static_text_1_0.id, root_node->GetUnignoredChildAtIndex(1)->id()); + EXPECT_EQ(paragraph_2.id, root_node->GetUnignoredChildAtIndex(2)->id()); + EXPECT_EQ(static_text_3_0_0.id, root_node->GetUnignoredChildAtIndex(3)->id()); + EXPECT_EQ(button_3_1.id, root_node->GetUnignoredChildAtIndex(4)->id()); + EXPECT_EQ(nullptr, root_node->GetUnignoredChildAtIndex(5)); + + EXPECT_EQ(paragraph_0.id, + root_node->GetUnignoredChildAtIndexCrossingTreeBoundary(0)->id()); + EXPECT_EQ(static_text_1_0.id, + root_node->GetUnignoredChildAtIndexCrossingTreeBoundary(1)->id()); + EXPECT_EQ(paragraph_2.id, + root_node->GetUnignoredChildAtIndexCrossingTreeBoundary(2)->id()); + EXPECT_EQ(static_text_3_0_0.id, + root_node->GetUnignoredChildAtIndexCrossingTreeBoundary(3)->id()); + EXPECT_EQ(button_3_1.id, + root_node->GetUnignoredChildAtIndexCrossingTreeBoundary(4)->id()); + EXPECT_EQ(nullptr, + root_node->GetUnignoredChildAtIndexCrossingTreeBoundary(5)); + + EXPECT_EQ(nullptr, root_node->GetParent()); + EXPECT_EQ(nullptr, root_node->GetParentCrossingTreeBoundary()); + EXPECT_EQ(nullptr, root_node->GetUnignoredParent()); + EXPECT_EQ(nullptr, root_node->GetUnignoredParentCrossingTreeBoundary()); + + EXPECT_EQ(root_node, tree.GetFromId(paragraph_0.id)->GetParent()); + EXPECT_EQ(root_node, + tree.GetFromId(paragraph_0.id)->GetParentCrossingTreeBoundary()); + EXPECT_EQ(root_node, tree.GetFromId(paragraph_0.id)->GetUnignoredParent()); + EXPECT_EQ( + root_node, + tree.GetFromId(paragraph_0.id)->GetUnignoredParentCrossingTreeBoundary()); + + EXPECT_EQ(tree.GetFromId(paragraph_1_ignored.id), + tree.GetFromId(static_text_1_0.id)->GetParent()); + EXPECT_EQ( + tree.GetFromId(paragraph_1_ignored.id), + tree.GetFromId(static_text_1_0.id)->GetParentCrossingTreeBoundary()); + EXPECT_EQ(root_node, + tree.GetFromId(static_text_1_0.id)->GetUnignoredParent()); + EXPECT_EQ(root_node, tree.GetFromId(static_text_1_0.id) + ->GetUnignoredParentCrossingTreeBoundary()); + + EXPECT_EQ(0u, root_node->GetIndexInParent()); + EXPECT_EQ(0u, root_node->GetUnignoredIndexInParent()); + + EXPECT_EQ(2u, tree.GetFromId(paragraph_2.id)->GetIndexInParent()); + EXPECT_EQ(1u, + tree.GetFromId(static_text_1_0.id)->GetUnignoredIndexInParent()); + EXPECT_EQ(2u, tree.GetFromId(paragraph_2.id)->GetUnignoredIndexInParent()); + + EXPECT_EQ(paragraph_0.id, root_node->GetFirstChild()->id()); + EXPECT_EQ(paragraph_0.id, + root_node->GetFirstChildCrossingTreeBoundary()->id()); + EXPECT_EQ(paragraph_0.id, root_node->GetFirstUnignoredChild()->id()); + EXPECT_EQ(paragraph_0.id, + root_node->GetFirstUnignoredChildCrossingTreeBoundary()->id()); + + EXPECT_EQ(paragraph_3_ignored.id, root_node->GetLastChild()->id()); + EXPECT_EQ(paragraph_3_ignored.id, + root_node->GetLastChildCrossingTreeBoundary()->id()); + EXPECT_EQ(button_3_1.id, root_node->GetLastUnignoredChild()->id()); + EXPECT_EQ(button_3_1.id, + root_node->GetLastUnignoredChildCrossingTreeBoundary()->id()); + + EXPECT_EQ(static_text_0_0_ignored.id, + root_node->GetDeepestFirstChild()->id()); + EXPECT_EQ(paragraph_0.id, root_node->GetDeepestFirstUnignoredChild()->id()); + + EXPECT_EQ(button_3_1.id, root_node->GetDeepestLastChild()->id()); + EXPECT_EQ(button_3_1.id, root_node->GetDeepestLastUnignoredChild()->id()); + + { + std::vector<const AXNode*> siblings; + for (const AXNode* sibling = tree.GetFromId(paragraph_0.id); sibling; + sibling = sibling->GetNextSibling()) { + siblings.push_back(sibling); + } + EXPECT_THAT(siblings, ElementsAre(HasAXNodeID(paragraph_0), + HasAXNodeID(paragraph_1_ignored), + HasAXNodeID(paragraph_2), + HasAXNodeID(paragraph_3_ignored))); + } + + { + std::vector<const AXNode*> siblings; + for (const AXNode* sibling = tree.GetFromId(paragraph_0.id); sibling; + sibling = sibling->GetNextUnignoredSibling()) { + siblings.push_back(sibling); + } + EXPECT_THAT( + siblings, + ElementsAre(HasAXNodeID(paragraph_0), HasAXNodeID(static_text_1_0), + HasAXNodeID(paragraph_2), HasAXNodeID(static_text_3_0_0), + HasAXNodeID(button_3_1))); + } + + { + std::vector<const AXNode*> siblings; + for (const AXNode* sibling = tree.GetFromId(paragraph_3_ignored.id); + sibling; sibling = sibling->GetPreviousSibling()) { + siblings.push_back(sibling); + } + EXPECT_THAT(siblings, ElementsAre(HasAXNodeID(paragraph_3_ignored), + HasAXNodeID(paragraph_2), + HasAXNodeID(paragraph_1_ignored), + HasAXNodeID(paragraph_0))); + } + + { + std::vector<const AXNode*> siblings; + for (const AXNode* sibling = tree.GetFromId(button_3_1.id); sibling; + sibling = sibling->GetPreviousUnignoredSibling()) { + siblings.push_back(sibling); + } + EXPECT_THAT( + siblings, + ElementsAre(HasAXNodeID(button_3_1), HasAXNodeID(static_text_3_0_0), + HasAXNodeID(paragraph_2), HasAXNodeID(static_text_1_0), + HasAXNodeID(paragraph_0))); + } + + { + std::vector<const AXNode::AllChildIterator> siblings; + for (auto iter = root_node->AllChildrenBegin(); + iter != root_node->AllChildrenEnd(); ++iter) { + siblings.push_back(iter); + } + EXPECT_THAT(siblings, ElementsAre(HasAXNodeID(paragraph_0), + HasAXNodeID(paragraph_1_ignored), + HasAXNodeID(paragraph_2), + HasAXNodeID(paragraph_3_ignored))); + } + + { + std::vector<const AXNode::AllChildCrossingTreeBoundaryIterator> siblings; + for (auto iter = root_node->AllChildrenCrossingTreeBoundaryBegin(); + iter != root_node->AllChildrenCrossingTreeBoundaryEnd(); ++iter) { + siblings.push_back(iter); + } + EXPECT_THAT(siblings, ElementsAre(HasAXNodeID(paragraph_0), + HasAXNodeID(paragraph_1_ignored), + HasAXNodeID(paragraph_2), + HasAXNodeID(paragraph_3_ignored))); + } + + { + std::vector<const AXNode::UnignoredChildIterator> siblings; + for (auto iter = root_node->UnignoredChildrenBegin(); + iter != root_node->UnignoredChildrenEnd(); ++iter) { + siblings.push_back(iter); + } + EXPECT_THAT( + siblings, + ElementsAre(HasAXNodeID(paragraph_0), HasAXNodeID(static_text_1_0), + HasAXNodeID(paragraph_2), HasAXNodeID(static_text_3_0_0), + HasAXNodeID(button_3_1))); + } + + { + std::vector<const AXNode::UnignoredChildCrossingTreeBoundaryIterator> + siblings; + for (auto iter = root_node->UnignoredChildrenCrossingTreeBoundaryBegin(); + iter != root_node->UnignoredChildrenCrossingTreeBoundaryEnd(); + ++iter) { + siblings.push_back(iter); + } + EXPECT_THAT( + siblings, + ElementsAre(HasAXNodeID(paragraph_0), HasAXNodeID(static_text_1_0), + HasAXNodeID(paragraph_2), HasAXNodeID(static_text_3_0_0), + HasAXNodeID(button_3_1))); + } +} + +TEST(AXNodeTest, TreeWalkingCrossingTreeBoundary) { + AXTreeData tree_data_1; + tree_data_1.tree_id = AXTreeID::CreateNewAXTreeID(); + tree_data_1.title = "Application"; + + AXTreeData tree_data_2; + tree_data_2.tree_id = AXTreeID::CreateNewAXTreeID(); + tree_data_2.parent_tree_id = tree_data_1.tree_id; + tree_data_2.title = "Iframe"; + + AXNodeData root_1; + AXNodeData root_2; + root_1.id = 1; + root_2.id = 1; + root_1.role = ax::mojom::Role::kRootWebArea; + root_1.AddChildTreeId(tree_data_2.tree_id); + root_2.role = ax::mojom::Role::kRootWebArea; + + AXTreeUpdate initial_state_1; + initial_state_1.root_id = root_1.id; + initial_state_1.nodes = {root_1}; + initial_state_1.has_tree_data = true; + initial_state_1.tree_data = tree_data_1; + + AXTreeUpdate initial_state_2; + initial_state_2.root_id = root_2.id; + initial_state_2.nodes = {root_2}; + initial_state_2.has_tree_data = true; + initial_state_2.tree_data = tree_data_2; + + auto tree_1 = std::make_unique<AXTree>(initial_state_1); + TestAXTreeManager tree_manager_1(std::move(tree_1)); + auto tree_2 = std::make_unique<AXTree>(initial_state_2); + TestAXTreeManager tree_manager_2(std::move(tree_2)); + + const AXNode* root_node_1 = tree_manager_1.GetRootAsAXNode(); + ASSERT_EQ(root_1.id, root_node_1->id()); + + const AXNode* root_node_2 = tree_manager_2.GetRootAsAXNode(); + ASSERT_EQ(root_2.id, root_node_2->id()); + + EXPECT_EQ(0u, root_node_1->GetChildCount()); + EXPECT_EQ(1u, root_node_1->GetChildCountCrossingTreeBoundary()); + EXPECT_EQ(0u, root_node_1->GetUnignoredChildCount()); + EXPECT_EQ(1u, root_node_1->GetUnignoredChildCountCrossingTreeBoundary()); + + EXPECT_EQ(nullptr, root_node_1->GetChildAtIndex(0)); + EXPECT_EQ(root_node_2, root_node_1->GetChildAtIndexCrossingTreeBoundary(0)); + EXPECT_EQ(nullptr, root_node_1->GetUnignoredChildAtIndex(0)); + EXPECT_EQ(root_node_2, + root_node_1->GetUnignoredChildAtIndexCrossingTreeBoundary(0)); + + EXPECT_EQ(nullptr, root_node_2->GetParent()); + EXPECT_EQ(root_node_1, root_node_2->GetParentCrossingTreeBoundary()); + EXPECT_EQ(nullptr, root_node_2->GetUnignoredParent()); + EXPECT_EQ(root_node_1, root_node_2->GetUnignoredParentCrossingTreeBoundary()); +} + TEST(AXNodeTest, GetLowestPlatformAncestor) { // ++kRootWebArea // ++++kButton (IsLeaf=false)
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h index da51be4..bf255206 100644 --- a/ui/accessibility/ax_position.h +++ b/ui/accessibility/ax_position.h
@@ -2010,7 +2010,7 @@ AXTreeID tree_id = AXTreeIDUnknown(); AXNodeID child_id = kInvalidAXNodeID; const AXNode* child_anchor = - GetAnchor()->GetChildAtCrossingTreeBoundary(child_index); + GetAnchor()->GetChildAtIndexCrossingTreeBoundary(child_index); if (!child_anchor) return CreateNullPosition(); tree_id = child_anchor->tree()->GetAXTreeID();
diff --git a/ui/accessibility/ax_tree_manager_map.cc b/ui/accessibility/ax_tree_manager_map.cc index d921f0c..7d19527 100644 --- a/ui/accessibility/ax_tree_manager_map.cc +++ b/ui/accessibility/ax_tree_manager_map.cc
@@ -54,12 +54,9 @@ // Some platforms do not use AXTreeManagers, so child trees don't exist in // the browser process. - if (!child_tree_manager) - return nullptr; - - DCHECK(child_tree_manager->GetParentNodeFromParentTreeAsAXNode()->id() == - parent_node.id()); - + DCHECK(!child_tree_manager || + child_tree_manager->GetParentNodeFromParentTreeAsAXNode()->id() == + parent_node.id()); return child_tree_manager; }
diff --git a/ui/accessibility/platform/ax_platform_relation_win.h b/ui/accessibility/platform/ax_platform_relation_win.h index 76f2721e..eb180e31 100644 --- a/ui/accessibility/platform/ax_platform_relation_win.h +++ b/ui/accessibility/platform/ax_platform_relation_win.h
@@ -12,7 +12,6 @@ #include "base/compiler_specific.h" #include "base/metrics/histogram_macros.h" -#include "base/observer_list.h" #include "base/win/atl.h" #include "third_party/iaccessible2/ia2_api_all.h" #include "ui/accessibility/ax_export.h"
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager.h b/ui/base/ime/chromeos/component_extension_ime_manager.h index ea34f20e..77d646a9 100644 --- a/ui/base/ime/chromeos/component_extension_ime_manager.h +++ b/ui/base/ime/chromeos/component_extension_ime_manager.h
@@ -12,7 +12,6 @@ #include "base/component_export.h" #include "base/files/file_path.h" #include "base/macros.h" -#include "base/observer_list.h" #include "ui/base/ime/chromeos/component_extension_ime_manager_delegate.h" #include "ui/base/ime/chromeos/input_method_descriptor.h"
diff --git a/ui/base/interaction/element_tracker.h b/ui/base/interaction/element_tracker.h index 9be3626..08ce7a80 100644 --- a/ui/base/interaction/element_tracker.h +++ b/ui/base/interaction/element_tracker.h
@@ -14,7 +14,6 @@ #include "base/gtest_prod_util.h" #include "base/no_destructor.h" #include "base/notreached.h" -#include "base/observer_list.h" #include "base/observer_list_types.h" #include "ui/base/interaction/element_identifier.h"
diff --git a/ui/gfx/image/mojom/image_skia_mojom_traits.h b/ui/gfx/image/mojom/image_skia_mojom_traits.h index eb35165..701b5633 100644 --- a/ui/gfx/image/mojom/image_skia_mojom_traits.h +++ b/ui/gfx/image/mojom/image_skia_mojom_traits.h
@@ -9,7 +9,6 @@ #include <vector> -#include "base/check_op.h" #include "skia/public/mojom/bitmap_skbitmap_mojom_traits.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/image/image_skia.h"
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc index 5b9bab21..c31a6de 100644 --- a/ui/message_center/views/notification_view_md.cc +++ b/ui/message_center/views/notification_view_md.cc
@@ -42,6 +42,7 @@ #include "ui/message_center/views/proportional_image_view.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_host_view.h" #include "ui/views/animation/ink_drop_impl.h" @@ -358,9 +359,11 @@ auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), 0)); - ink_drop_.SetMode(views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); - ink_drop_.SetVisibleOpacity(1); - ink_drop_.SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Install(this, std::make_unique<views::InkDropHost>(this)); + views::InkDrop::Get(this)->SetMode( + views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); + views::InkDrop::Get(this)->SetVisibleOpacity(1); + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](views::View* host) { return host->GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_NotificationInkDropBase); @@ -383,13 +386,19 @@ views::InstallRectHighlightPathGenerator(this); } -NotificationInputContainerMD::~NotificationInputContainerMD() = default; +NotificationInputContainerMD::~NotificationInputContainerMD() { + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); +} void NotificationInputContainerMD::AnimateBackground(const ui::Event& event) { std::unique_ptr<ui::Event> located_event = ConvertToBoundedLocatedEvent(event, this); - ink_drop_.AnimateToState(views::InkDropState::ACTION_PENDING, - ui::LocatedEvent::FromIfValid(located_event.get())); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::ACTION_PENDING, + ui::LocatedEvent::FromIfValid(located_event.get())); } void NotificationInputContainerMD::AddLayerBeneathView(ui::Layer* layer) { @@ -569,23 +578,24 @@ SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical, gfx::Insets(), 0)); - ink_drop_.SetVisibleOpacity(1.0f); - ink_drop_.SetCreateInkDropCallback(base::BindRepeating( + views::InkDrop::Install(this, std::make_unique<views::InkDropHost>(this)); + views::InkDrop::Get(this)->SetVisibleOpacity(1.0f); + views::InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](NotificationViewMD* host) -> std::unique_ptr<views::InkDrop> { - return std::make_unique<NotificationInkDropImpl>(host->ink_drop(), - host->size()); + return std::make_unique<NotificationInkDropImpl>( + views::InkDrop::Get(host), host->size()); }, this)); - ink_drop_.SetCreateRippleCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](NotificationViewMD* host) -> std::unique_ptr<views::InkDropRipple> { return std::make_unique<views::FloodFillInkDropRipple>( host->GetPreferredSize(), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), - host->ink_drop()->GetBaseColor(), - host->ink_drop()->GetVisibleOpacity()); + views::InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), + views::InkDrop::Get(host)->GetBaseColor(), + views::InkDrop::Get(host)->GetVisibleOpacity()); }, this)); - ink_drop_.SetBaseColorCallback(base::BindRepeating( + views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](NotificationViewMD* host) { return host->GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_NotificationBackgroundActive); @@ -673,11 +683,16 @@ } NotificationViewMD::~NotificationViewMD() { + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); + RemovePreTargetHandler(click_activator_.get()); } void NotificationViewMD::AddLayerBeneathView(ui::Layer* layer) { - ink_drop_.GetInkDrop()->AddObserver(this); + views::InkDrop::Get(this)->GetInkDrop()->AddObserver(this); for (auto* child : GetChildrenForLayerAdjustment()) { child->SetPaintToLayer(); child->layer()->SetFillsBoundsOpaquely(false); @@ -689,7 +704,7 @@ ink_drop_container_->RemoveLayerBeneathView(layer); for (auto* child : GetChildrenForLayerAdjustment()) child->DestroyLayer(); - ink_drop_.GetInkDrop()->RemoveObserver(this); + views::InkDrop::Get(this)->GetInkDrop()->RemoveObserver(this); } void NotificationViewMD::Layout() { @@ -1479,16 +1494,19 @@ } void NotificationViewMD::AddBackgroundAnimation(const ui::Event& event) { - ink_drop_.SetMode(views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); + views::InkDrop::Get(this)->SetMode( + views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER); std::unique_ptr<ui::Event> located_event = ConvertToBoundedLocatedEvent(event, this); - ink_drop_.AnimateToState(views::InkDropState::ACTION_PENDING, - ui::LocatedEvent::FromIfValid(located_event.get())); + views::InkDrop::Get(this)->AnimateToState( + views::InkDropState::ACTION_PENDING, + ui::LocatedEvent::FromIfValid(located_event.get())); } void NotificationViewMD::RemoveBackgroundAnimation() { - ink_drop_.SetMode(views::InkDropHost::InkDropMode::OFF); - ink_drop_.AnimateToState(views::InkDropState::HIDDEN, nullptr); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, + nullptr); } std::vector<views::View*> NotificationViewMD::GetChildrenForLayerAdjustment()
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h index a98d0a10..820160a 100644 --- a/ui/message_center/views/notification_view_md.h +++ b/ui/message_center/views/notification_view_md.h
@@ -16,6 +16,7 @@ #include "ui/base/metadata/metadata_header_macros.h" #include "ui/message_center/message_center_export.h" #include "ui/message_center/views/message_view.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_observer.h" #include "ui/views/controls/button/md_text_button.h" #include "ui/views/controls/textfield/textfield_controller.h" @@ -143,7 +144,6 @@ NotificationInputDelegate* const delegate_; - views::InkDropHost ink_drop_{this}; views::InkDropContainerView* const ink_drop_container_; views::Textfield* const textfield_; @@ -180,8 +180,6 @@ void AddBackgroundAnimation(const ui::Event& event); void RemoveBackgroundAnimation(); - views::InkDropHost* ink_drop() { return &ink_drop_; } - // MessageView: void AddLayerBeneathView(ui::Layer* layer) override; void RemoveLayerBeneathView(ui::Layer* layer) override; @@ -286,7 +284,6 @@ // destroyed when the ink drop is visible. std::vector<views::View*> GetChildrenForLayerAdjustment() const; - views::InkDropHost ink_drop_{this}; views::InkDropContainerView* const ink_drop_container_; // View containing close and settings buttons
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc index bba17a3..3d7d6e1 100644 --- a/ui/message_center/views/notification_view_md_unittest.cc +++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -28,6 +28,7 @@ #include "ui/message_center/views/padded_button.h" #include "ui/message_center/views/proportional_image_view.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_observer.h" #include "ui/views/animation/test/ink_drop_impl_test_api.h" @@ -226,8 +227,8 @@ DCHECK(notification_view_ || delete_on_preferred_size_changed_ || delete_on_notification_removed_); if (notification_view_) { - notification_view_->ink_drop()->SetMode( - views::InkDropHost::InkDropMode::OFF); + views::InkDrop::Get(notification_view_) + ->SetMode(views::InkDropHost::InkDropMode::OFF); static_cast<views::View*>(notification_view_)->RemoveObserver(this); notification_view_->GetWidget()->Close(); notification_view_ = nullptr; @@ -1276,14 +1277,14 @@ generator.ClickLeftButton(); EXPECT_TRUE(notification_view()->settings_row_->GetVisible()); - notification_view()->ink_drop()->GetInkDrop()->AddObserver(this); + views::InkDrop::Get(notification_view())->GetInkDrop()->AddObserver(this); // Resize the widget by 1px to simulate the expand animation. gfx::Rect size = notification_view()->GetWidget()->GetWindowBoundsInScreen(); size.Inset(0, 0, 0, 1); notification_view()->GetWidget()->SetBounds(size); - notification_view()->ink_drop()->GetInkDrop()->RemoveObserver(this); + views::InkDrop::Get(notification_view())->GetInkDrop()->RemoveObserver(this); // The ink drop animation should still be running. EXPECT_FALSE(ink_drop_stopped()); @@ -1314,7 +1315,7 @@ notification_view()->ToggleInlineSettings(DummyEvent()); auto* ink_drop = static_cast<views::InkDropImpl*>( - notification_view()->ink_drop()->GetInkDrop()); + views::InkDrop::Get(notification_view())->GetInkDrop()); views::test::InkDropImplTestApi ink_drop_test_api(ink_drop); gfx::Rect clip_rect = ink_drop_test_api.GetRootLayer()->clip_rect();
diff --git a/ui/message_center/views/padded_button.cc b/ui/message_center/views/padded_button.cc index 515af01c..bb13065 100644 --- a/ui/message_center/views/padded_button.cc +++ b/ui/message_center/views/padded_button.cc
@@ -26,10 +26,10 @@ SetBorder(views::CreateEmptyBorder(gfx::Insets(kControlButtonBorderSize))); SetAnimateOnStateChange(false); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - ink_drop()->SetVisibleOpacity(0.12f); + views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + views::InkDrop::Get(this)->SetVisibleOpacity(0.12f); SetHasInkDropActionOnClick(true); - views::InkDrop::UseInkDropForSquareRipple(ink_drop(), + views::InkDrop::UseInkDropForSquareRipple(views::InkDrop::Get(this), /*highlight_on_hover=*/false); } @@ -44,7 +44,7 @@ SkColor background_color = theme->GetSystemColor(ui::NativeTheme::kColorId_WindowBackground); #endif - ink_drop()->SetBaseColor( + views::InkDrop::Get(this)->SetBaseColor( color_utils::GetColorWithMaxContrast(background_color)); }
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.h b/ui/ozone/platform/drm/gpu/crtc_controller.h index babafdea..dcb7be83 100644 --- a/ui/ozone/platform/drm/gpu/crtc_controller.h +++ b/ui/ozone/platform/drm/gpu/crtc_controller.h
@@ -11,7 +11,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "ui/gfx/swap_result.h" #include "ui/ozone/platform/drm/common/scoped_drm_types.h" #include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.h b/ui/ozone/platform/drm/gpu/screen_manager.h index 53abc71..a6dd8f67 100644 --- a/ui/ozone/platform/drm/gpu/screen_manager.h +++ b/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -11,7 +11,6 @@ #include "base/containers/flat_map.h" #include "base/macros.h" -#include "base/observer_list.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/drm/gpu/drm_display.h" #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
diff --git a/ui/ozone/platform/x11/x11_screen_ozone.h b/ui/ozone/platform/x11/x11_screen_ozone.h index 5b0ab16..36acbcf 100644 --- a/ui/ozone/platform/x11/x11_screen_ozone.h +++ b/ui/ozone/platform/x11/x11_screen_ozone.h
@@ -10,7 +10,6 @@ #include <vector> #include "base/macros.h" -#include "base/observer_list.h" #include "ui/base/x/x11_display_manager.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/x/event.h"
diff --git a/ui/views/animation/ink_drop.cc b/ui/views/animation/ink_drop.cc index f5866733..df292d4 100644 --- a/ui/views/animation/ink_drop.cc +++ b/ui/views/animation/ink_drop.cc
@@ -14,10 +14,14 @@ #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_observer.h" +DEFINE_UI_CLASS_PROPERTY_TYPE(views::InkDropHost*) + namespace views { namespace { +DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(InkDropHost, kInkDropKey, nullptr) + // TODO(pbos): Remove this by changing the constructor parameters to // InkDropImpl. std::unique_ptr<InkDrop> CreateInkDropImpl( @@ -36,6 +40,18 @@ InkDrop::~InkDrop() = default; +void InkDrop::Install(View* host, std::unique_ptr<InkDropHost> ink_drop) { + host->SetProperty(kInkDropKey, ink_drop.release()); +} + +void InkDrop::Remove(View* host) { + host->ClearProperty(kInkDropKey); +} + +const InkDropHost* InkDrop::Get(const View* host) { + return host->GetProperty(kInkDropKey); +} + std::unique_ptr<InkDrop> InkDrop::CreateInkDropForSquareRipple( InkDropHost* host, bool highlight_on_hover,
diff --git a/ui/views/animation/ink_drop.h b/ui/views/animation/ink_drop.h index 50e171c..20c142d 100644 --- a/ui/views/animation/ink_drop.h +++ b/ui/views/animation/ink_drop.h
@@ -22,6 +22,7 @@ class InkDropHost; class InkDropObserver; +class View; // Base class that manages the lifetime and state of an ink drop ripple as // well as visual hover state feedback. @@ -31,6 +32,20 @@ InkDrop& operator=(const InkDrop&) = delete; virtual ~InkDrop(); + // TODO(pbos): Make sure what's installed here implements InkDrop so that can + // be used as type instead of InkDropHost. + static void Install(View* host, std::unique_ptr<InkDropHost> ink_drop); + + // Removes the InkDrop from `host`. + static void Remove(View* host); + + // TODO(pbos): Make sure what's installed here implements InkDrop so that can + // be used as type instead of InkDropHost. + static const InkDropHost* Get(const View* host); + static InkDropHost* Get(View* host) { + return const_cast<InkDropHost*>(Get(const_cast<const View*>(host))); + } + // Create an InkDrop appropriate for the "square" InkDropRipple effect. This // InkDrop hides when the ripple effect is active instead of layering // underneath it. @@ -88,8 +103,9 @@ // Immediately snaps the InkDropState to ACTIVATED and HIDDEN specifically. // These are more specific implementations of the non-existent - // SnapToState(InkDropState) function are the only ones available because they - // were the only InkDropState that clients needed to skip animations for. + // SnapToState(InkDropState) function are the only ones available because + // they were the only InkDropState that clients needed to skip animations + // for. virtual void SnapToActivated() = 0; virtual void SnapToHidden() = 0;
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc index 5215b9e..a8b1057 100644 --- a/ui/views/animation/ink_drop_host_view.cc +++ b/ui/views/animation/ink_drop_host_view.cc
@@ -71,11 +71,7 @@ ink_drop_event_handler_delegate_(this), ink_drop_event_handler_(view, &ink_drop_event_handler_delegate_) {} -InkDropHost::~InkDropHost() { - // TODO(bruthig): Improve InkDropImpl to be safer about calling back to - // potentially destroyed InkDropHosts and remove |destroying_|. - destroying_ = true; -} +InkDropHost::~InkDropHost() = default; std::unique_ptr<InkDrop> InkDropHost::CreateInkDrop() { if (create_ink_drop_callback_) @@ -161,7 +157,7 @@ void InkDropHost::SetMode(InkDropMode ink_drop_mode) { ink_drop_mode_ = ink_drop_mode; - ink_drop_ = nullptr; + ink_drop_.reset(); } void InkDropHost::SetVisibleOpacity(float visible_opacity) { @@ -240,14 +236,6 @@ } void InkDropHost::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { - // No need to do anything when called during shutdown. - // TODO(pbos): Reinvestigate this now that this is not part of virtual - // overrides. This looks like it may accidentally leave a layer attached to - // the View? Likely not an issue until InkDropHost start getting removed - // without destroying the associated View. - if (destroying_) - return; - host_view_->RemoveLayerBeneathView(ink_drop_layer); // Remove clipping.
diff --git a/ui/views/animation/ink_drop_host_view.h b/ui/views/animation/ink_drop_host_view.h index ac018b1..bd0975b4 100644 --- a/ui/views/animation/ink_drop_host_view.h +++ b/ui/views/animation/ink_drop_host_view.h
@@ -261,8 +261,6 @@ int ink_drop_small_corner_radius_ = 2; int ink_drop_large_corner_radius_ = 4; - bool destroying_ = false; - std::unique_ptr<views::InkDropMask> ink_drop_mask_; base::RepeatingCallback<std::unique_ptr<InkDrop>()> create_ink_drop_callback_;
diff --git a/ui/views/animation/ink_drop_host_view_unittest.cc b/ui/views/animation/ink_drop_host_view_unittest.cc index 28718c4..6efb00db 100644 --- a/ui/views/animation/ink_drop_host_view_unittest.cc +++ b/ui/views/animation/ink_drop_host_view_unittest.cc
@@ -22,6 +22,7 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/animation/test/ink_drop_impl_test_api.h" @@ -35,14 +36,15 @@ class TestViewWithInkDrop : public View { public: TestViewWithInkDrop() { - ink_drop()->SetCreateInkDropCallback(base::BindRepeating( + InkDrop::Install(this, std::make_unique<InkDropHost>(this)); + InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](TestViewWithInkDrop* host) -> std::unique_ptr<InkDrop> { auto ink_drop = std::make_unique<TestInkDrop>(); host->last_created_inkdrop_ = ink_drop.get(); return ink_drop; }, this)); - ink_drop()->SetBaseColor(gfx::kPlaceholderColor); + InkDrop::Get(this)->SetBaseColor(gfx::kPlaceholderColor); } TestViewWithInkDrop(const TestViewWithInkDrop&) = delete; @@ -53,11 +55,7 @@ TestInkDrop* last_created_inkdrop() const { return last_created_inkdrop_; } - InkDropHost* ink_drop() { return &ink_drop_; } - private: - InkDropHost ink_drop_{this}; - TestInkDrop* last_created_inkdrop_ = nullptr; }; @@ -82,7 +80,7 @@ }; InkDropHostViewTest::InkDropHostViewTest() - : test_api_(host_view_.ink_drop()), + : test_api_(InkDrop::Get(&host_view_)), animation_mode_reset_(gfx::AnimationTestApi::SetRichAnimationRenderMode( gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED)) {} @@ -93,8 +91,8 @@ test_api_.SetInkDropMode(ink_drop_mode); host_view_.SetEnabled(true); - // Call ink_drop()->GetInkDrop() to make sure the test CreateInkDrop() is - // created. + // Call InkDrop::Get(this)->GetInkDrop() to make sure the test + // CreateInkDrop() is created. test_api_.GetInkDrop(); if (ink_drop_mode != views::InkDropHost::InkDropMode::OFF) EXPECT_FALSE(host_view_.last_created_inkdrop()->is_hovered()); @@ -119,7 +117,7 @@ host_view_.SetSize(gfx::Size(20, 20)); test_api_.AnimateToState(InkDropState::ACTION_PENDING, nullptr); EXPECT_EQ(gfx::Point(10, 10), - host_view_.ink_drop()->GetInkDropCenterBasedOnLastEvent()); + InkDrop::Get(&host_view_)->GetInkDropCenterBasedOnLastEvent()); } // Verifies the return value of GetInkDropCenterBasedOnLastEvent() for a located @@ -133,7 +131,7 @@ test_api_.AnimateToState(InkDropState::ACTION_PENDING, &located_event); EXPECT_EQ(gfx::Point(5, 6), - host_view_.ink_drop()->GetInkDropCenterBasedOnLastEvent()); + InkDrop::Get(&host_view_)->GetInkDropCenterBasedOnLastEvent()); } TEST_F(InkDropHostViewTest, HasInkDrop) { @@ -275,9 +273,10 @@ TEST_F(InkDropHostViewTest, HighlightedChangedFired) { bool callback_called = false; auto subscription = - host_view_.ink_drop()->AddHighlightedChangedCallback(base::BindRepeating( - [](bool* called) { *called = true; }, &callback_called)); - host_view_.ink_drop()->OnInkDropHighlightedChanged(); + InkDrop::Get(&host_view_) + ->AddHighlightedChangedCallback(base::BindRepeating( + [](bool* called) { *called = true; }, &callback_called)); + InkDrop::Get(&host_view_)->OnInkDropHighlightedChanged(); EXPECT_TRUE(callback_called); } @@ -285,25 +284,22 @@ class BasicTestViewWithInkDrop : public View { public: BasicTestViewWithInkDrop() { + InkDrop::Install(this, std::make_unique<InkDropHost>(this)); // Call SetBaseColor to avoid hitting a NOTREACHED() for fetching an // undefined color. - ink_drop()->SetBaseColor(gfx::kPlaceholderColor); + InkDrop::Get(this)->SetBaseColor(gfx::kPlaceholderColor); } BasicTestViewWithInkDrop(const BasicTestViewWithInkDrop&) = delete; BasicTestViewWithInkDrop& operator=(const BasicTestViewWithInkDrop&) = delete; ~BasicTestViewWithInkDrop() override = default; - - InkDropHost* ink_drop() { return &ink_drop_; } - - private: - InkDropHost ink_drop_{this}; }; // Tests the existence of layer clipping or layer masking when certain path // generators are applied on an InkDropHostView. class InkDropHostViewClippingTest : public testing::Test { public: - InkDropHostViewClippingTest() : host_view_test_api_(host_view_.ink_drop()) { + InkDropHostViewClippingTest() + : host_view_test_api_(InkDrop::Get(&host_view_)) { // Set up an InkDropHostView. Clipping is based on the size of the view, so // make sure the size is non empty. host_view_test_api_.SetInkDropMode(views::InkDropHost::InkDropMode::ON); @@ -311,7 +307,8 @@ // The root layer of the ink drop is created the first time GetInkDrop is // called and then kept alive until the host view is destroyed. - ink_drop_ = static_cast<InkDropImpl*>(host_view_.ink_drop()->GetInkDrop()); + ink_drop_ = + static_cast<InkDropImpl*>(InkDrop::Get(&host_view_)->GetInkDrop()); ink_drop_test_api_ = std::make_unique<test::InkDropImplTestApi>(ink_drop_); } InkDropHostViewClippingTest(const InkDropHostViewClippingTest&) = delete;
diff --git a/ui/views/animation/ink_drop_impl_unittest.cc b/ui/views/animation/ink_drop_impl_unittest.cc index 7cb9e19..5254600 100644 --- a/ui/views/animation/ink_drop_impl_unittest.cc +++ b/ui/views/animation/ink_drop_impl_unittest.cc
@@ -16,6 +16,7 @@ #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/gfx/animation/animation.h" #include "ui/gfx/animation/animation_test_api.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/animation/test/ink_drop_impl_test_api.h" #include "ui/views/animation/test/test_ink_drop_host.h" @@ -35,7 +36,8 @@ const TestInkDropHost* ink_drop_host() const { return &ink_drop_host_; } InkDropImpl* ink_drop() { - return static_cast<InkDropImpl*>(ink_drop_host()->ink_drop()->GetInkDrop()); + return static_cast<InkDropImpl*>( + InkDrop::Get(ink_drop_host())->GetInkDrop()); } InkDropRipple* ink_drop_ripple() { @@ -83,7 +85,7 @@ InkDropImplTest::InkDropImplTest( InkDropImpl::AutoHighlightMode auto_highlight_mode) : ink_drop_host_(auto_highlight_mode) { - ink_drop_host()->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(ink_drop_host())->SetMode(views::InkDropHost::InkDropMode::ON); test_api_ = std::make_unique<test::InkDropImplTestApi>(ink_drop()); ink_drop_host()->set_disable_timers_for_test(true); } @@ -101,7 +103,7 @@ void InkDropImplTest::DestroyInkDrop() { test_api_.reset(); - ink_drop_host()->ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + InkDrop::Get(ink_drop_host())->SetMode(views::InkDropHost::InkDropMode::OFF); } // AutoHighlightMode parameterized test fixture. @@ -311,19 +313,19 @@ TEST_F(InkDropImplTest, HostTracksHighlightState) { bool callback_called = false; auto subscription = - ink_drop_host()->ink_drop()->AddHighlightedChangedCallback( - base::BindRepeating([](bool* called) { *called = true; }, - &callback_called)); - EXPECT_FALSE(ink_drop_host()->ink_drop()->GetHighlighted()); + InkDrop::Get(ink_drop_host()) + ->AddHighlightedChangedCallback(base::BindRepeating( + [](bool* called) { *called = true; }, &callback_called)); + EXPECT_FALSE(InkDrop::Get(ink_drop_host())->GetHighlighted()); test_api()->SetShouldHighlight(true); EXPECT_TRUE(callback_called); - EXPECT_TRUE(ink_drop_host()->ink_drop()->GetHighlighted()); + EXPECT_TRUE(InkDrop::Get(ink_drop_host())->GetHighlighted()); callback_called = false; test_api()->SetShouldHighlight(false); EXPECT_TRUE(callback_called); - EXPECT_FALSE(ink_drop_host()->ink_drop()->GetHighlighted()); + EXPECT_FALSE(InkDrop::Get(ink_drop_host())->GetHighlighted()); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/animation/ink_drop_unittest.cc b/ui/views/animation/ink_drop_unittest.cc index 00fa497..953d78a 100644 --- a/ui/views/animation/ink_drop_unittest.cc +++ b/ui/views/animation/ink_drop_unittest.cc
@@ -57,7 +57,7 @@ break; case INK_DROP_IMPL: ink_drop_ = std::make_unique<InkDropImpl>( - test_ink_drop_host_.ink_drop(), gfx::Size(), + InkDrop::Get(&test_ink_drop_host_), gfx::Size(), InkDropImpl::AutoHighlightMode::NONE); // The Timer's used by the InkDropImpl class require a // base::ThreadTaskRunnerHandle instance.
diff --git a/ui/views/animation/test/test_ink_drop_host.cc b/ui/views/animation/test/test_ink_drop_host.cc index b8ca4c4..5c2e8c1 100644 --- a/ui/views/animation/test/test_ink_drop_host.cc +++ b/ui/views/animation/test/test_ink_drop_host.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "ui/gfx/geometry/size.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/square_ink_drop_ripple.h" @@ -79,16 +80,17 @@ TestInkDropHost::TestInkDropHost( InkDropImpl::AutoHighlightMode auto_highlight_mode) { - ink_drop()->SetCreateInkDropCallback(base::BindRepeating( + InkDrop::Install(this, std::make_unique<InkDropHost>(this)); + InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](TestInkDropHost* host, InkDropImpl::AutoHighlightMode auto_highlight_mode) -> std::unique_ptr<views::InkDrop> { return std::make_unique<views::InkDropImpl>( - host->ink_drop(), host->size(), auto_highlight_mode); + InkDrop::Get(host), host->size(), auto_highlight_mode); }, this, auto_highlight_mode)); - ink_drop()->SetCreateHighlightCallback(base::BindRepeating( + InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( [](TestInkDropHost* host) -> std::unique_ptr<views::InkDropHighlight> { auto highlight = std::make_unique<TestInkDropHighlight>( host->size(), 0, gfx::PointF(), SK_ColorBLACK); @@ -99,7 +101,7 @@ return highlight; }, this)); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](TestInkDropHost* host) -> std::unique_ptr<views::InkDropRipple> { auto ripple = std::make_unique<TestInkDropRipple>( host->size(), 0, host->size(), 0, gfx::Point(), SK_ColorBLACK, @@ -121,6 +123,11 @@ ++num_ink_drop_layers_removed_; } -TestInkDropHost::~TestInkDropHost() = default; +TestInkDropHost::~TestInkDropHost() { + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); +} } // namespace views
diff --git a/ui/views/animation/test/test_ink_drop_host.h b/ui/views/animation/test/test_ink_drop_host.h index c98c413a..b41827a 100644 --- a/ui/views/animation/test/test_ink_drop_host.h +++ b/ui/views/animation/test/test_ink_drop_host.h
@@ -42,15 +42,11 @@ disable_timers_for_test_ = disable_timers_for_test; } - InkDropHost* ink_drop() { return &ink_drop_; } - // View: void AddLayerBeneathView(ui::Layer* layer) override; void RemoveLayerBeneathView(ui::Layer* layer) override; private: - InkDropHost ink_drop_{this}; - int num_ink_drop_layers_added_ = 0; int num_ink_drop_layers_removed_ = 0;
diff --git a/ui/views/bubble/bubble_border.cc b/ui/views/bubble/bubble_border.cc index 03872cb..eab69d9 100644 --- a/ui/views/bubble/bubble_border.cc +++ b/ui/views/bubble/bubble_border.cc
@@ -11,14 +11,18 @@ #include <vector> #include "base/check_op.h" +#include "base/logging.h" #include "base/no_destructor.h" #include "base/notreached.h" #include "cc/paint/paint_flags.h" #include "third_party/skia/include/core/SkDrawLooper.h" #include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkPoint.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/rrect_f.h" #include "ui/gfx/scoped_canvas.h" #include "ui/gfx/shadow_value.h" #include "ui/gfx/skia_paint_util.h" @@ -89,8 +93,74 @@ } } +gfx::Insets GetVisibleArrowInsets(BubbleBorder::Arrow arrow, bool include_gap) { + DCHECK(BubbleBorder::has_arrow(arrow)); + const int arrow_size = include_gap ? BubbleBorder::kVisibleArrowGap + + BubbleBorder::kVisibleArrowLength + : BubbleBorder::kVisibleArrowLength; + gfx::Insets result; + // Note: VERTICAL arrows are on the sides of the bubble, while !VERTICAL are + // on the top or bottom. + if (arrow & BubbleBorder::VERTICAL) { + if (arrow & BubbleBorder::RIGHT) + result.set_right(arrow_size); + else + result.set_left(arrow_size); + } else { + if (arrow & BubbleBorder::BOTTOM) + result.set_bottom(arrow_size); + else + result.set_top(arrow_size); + } + return result; +} + +enum BubbleArrowPart { kFill, kBorder }; + +SkPath GetVisibleArrowPath(BubbleBorder::Arrow arrow, + const gfx::Rect& bounds, + BubbleArrowPart part) { + SkPoint point1; + SkPoint point2; + SkPoint point3; + if (arrow & BubbleBorder::VERTICAL) { + if (arrow & BubbleBorder::RIGHT) { + point1 = {bounds.x(), bounds.y()}; + point2 = {bounds.right(), bounds.y() + BubbleBorder::kVisibleArrowRadius}; + point3 = {bounds.x(), bounds.bottom()}; + } else { + point1 = {bounds.right(), bounds.bottom()}; + point2 = {bounds.x(), bounds.y() + BubbleBorder::kVisibleArrowRadius}; + point3 = {bounds.right(), bounds.y()}; + } + } else { + if (arrow & BubbleBorder::BOTTOM) { + point1 = {bounds.right(), bounds.y()}; + point2 = {bounds.x() + BubbleBorder::kVisibleArrowRadius, + bounds.bottom()}; + point3 = {bounds.x(), bounds.y()}; + } else { + point1 = {bounds.x(), bounds.bottom()}; + point2 = {bounds.x() + BubbleBorder::kVisibleArrowRadius, bounds.y()}; + point3 = {bounds.right(), bounds.bottom()}; + } + } + + return SkPath::Polygon({point1, point2, point3}, + part == BubbleArrowPart::kFill); +} + } // namespace +constexpr int BubbleBorder::kBorderThicknessDip; +constexpr int BubbleBorder::kShadowBlur; +constexpr int BubbleBorder::kShadowVerticalOffset; +constexpr int BubbleBorder::kVisibleArrowGap; +constexpr int BubbleBorder::kVisibleArrowLength; +constexpr int BubbleBorder::kVisibleArrowRadius; +constexpr int BubbleBorder::kVisibleArrowHorizontalBuffer; +constexpr int BubbleBorder::kVisibleArrowVerticalBuffer; + BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color) : arrow_(arrow), arrow_offset_(0), @@ -135,56 +205,69 @@ shadow_ == NO_SHADOW || md_shadow_elevation_.has_value() ? gfx::Insets() : gfx::Insets(kBorderThicknessDip); - const gfx::Insets shadow_insets = GetInsets() - border_insets; + const gfx::Insets insets = GetInsets(); + const gfx::Insets shadow_insets = insets - border_insets; + // TODO(dfried): Collapse border into visible arrow where applicable. contents_bounds.Inset(-border_insets); + DCHECK(!avoid_shadow_overlap_ || !visible_arrow_); + // If |avoid_shadow_overlap_| is true, the shadow part of the inset is also // applied now, to ensure that the shadow itself doesn't overlap the anchor. if (avoid_shadow_overlap_) contents_bounds.Inset(-shadow_insets); + + // Adjust the contents to align with the arrow. The `anchor_point` is the + // point on `anchor_rect` to offset from; it is also used as part of the + // visible arrow calculation if present. + gfx::Point anchor_point; switch (arrow_) { case TOP_LEFT: - contents_bounds += anchor_rect.bottom_left() - contents_bounds.origin(); + anchor_point = anchor_rect.bottom_left(); + contents_bounds += anchor_point - contents_bounds.origin(); break; case TOP_RIGHT: - contents_bounds += - anchor_rect.bottom_right() - contents_bounds.top_right(); + anchor_point = anchor_rect.bottom_right(); + contents_bounds += anchor_point - contents_bounds.top_right(); break; case BOTTOM_LEFT: - contents_bounds += anchor_rect.origin() - contents_bounds.bottom_left(); + anchor_point = anchor_rect.origin(); + contents_bounds += anchor_point - contents_bounds.bottom_left(); break; case BOTTOM_RIGHT: - contents_bounds += - anchor_rect.top_right() - contents_bounds.bottom_right(); + anchor_point = anchor_rect.top_right(); + contents_bounds += anchor_point - contents_bounds.bottom_right(); break; case LEFT_TOP: - contents_bounds += anchor_rect.top_right() - contents_bounds.origin(); + anchor_point = anchor_rect.top_right(); + contents_bounds += anchor_point - contents_bounds.origin(); break; case RIGHT_TOP: - contents_bounds += anchor_rect.origin() - contents_bounds.top_right(); + anchor_point = anchor_rect.origin(); + contents_bounds += anchor_point - contents_bounds.top_right(); break; case LEFT_BOTTOM: - contents_bounds += - anchor_rect.bottom_right() - contents_bounds.bottom_left(); + anchor_point = anchor_rect.bottom_right(); + contents_bounds += anchor_point - contents_bounds.bottom_left(); break; case RIGHT_BOTTOM: - contents_bounds += - anchor_rect.bottom_left() - contents_bounds.bottom_right(); + anchor_point = anchor_rect.bottom_left(); + contents_bounds += anchor_point - contents_bounds.bottom_right(); break; case TOP_CENTER: - contents_bounds += - CenterBottom(anchor_rect) - CenterTop(contents_bounds); + anchor_point = CenterBottom(anchor_rect); + contents_bounds += anchor_point - CenterTop(contents_bounds); break; case BOTTOM_CENTER: - contents_bounds += - CenterTop(anchor_rect) - CenterBottom(contents_bounds); + anchor_point = CenterTop(anchor_rect); + contents_bounds += anchor_point - CenterBottom(contents_bounds); break; case LEFT_CENTER: - contents_bounds += - RightCenter(anchor_rect) - LeftCenter(contents_bounds); + anchor_point = RightCenter(anchor_rect); + contents_bounds += anchor_point - LeftCenter(contents_bounds); break; case RIGHT_CENTER: - contents_bounds += - LeftCenter(anchor_rect) - RightCenter(contents_bounds); + anchor_point = LeftCenter(anchor_rect); + contents_bounds += anchor_point - RightCenter(contents_bounds); break; default: NOTREACHED(); @@ -195,12 +278,106 @@ insets_.has_value() || shadow_insets.IsEmpty()); if (!avoid_shadow_overlap_) contents_bounds.Inset(-shadow_insets); + // |arrow_offset_| is used to adjust bubbles that would normally be // partially offscreen. if (is_arrow_on_horizontal(arrow_)) contents_bounds += gfx::Vector2d(-arrow_offset_, 0); else contents_bounds += gfx::Vector2d(0, -arrow_offset_); + + // Finally, adjust for a visible arrow; this is done after all other + // adjustments because we don't want the positioning to be altered + // otherwise. Since we've already accounted for the size of the insets in + // the size of `contents_bounds` we merely offset by the size of the inset + // on each side (only one side will be nonzero). + if (visible_arrow_) { + const gfx::Insets visible_arrow_insets = + GetVisibleArrowInsets(arrow_, true); + contents_bounds += gfx::Vector2d( + visible_arrow_insets.left() - visible_arrow_insets.right(), + visible_arrow_insets.top() - visible_arrow_insets.bottom()); + + // We have an anchor point which is appropriate for the arrow type, but + // when anchoring to a small view it looks better to track from the middle + // of the view rather than a corner. We may still adjust this point if + // it's too close to the edge of the bubble (in this case by adjusting the + // bubble by a few pixels rather than the anchor point). + const bool is_vertical_arrow = visible_arrow_insets.height(); + const gfx::Point anchor_center = anchor_rect.CenterPoint(); + const gfx::Point contents_center = contents_bounds.CenterPoint(); + if (is_vertical_arrow) { + const int right_bound = + contents_bounds.right() - + (kVisibleArrowHorizontalBuffer + kVisibleArrowRadius); + const int left_bound = contents_bounds.x() + + kVisibleArrowHorizontalBuffer + + kVisibleArrowRadius; + if (anchor_point.x() > anchor_center.x() && + anchor_center.x() > contents_center.x()) { + anchor_point.set_x(anchor_center.x()); + } else if (anchor_point.x() > right_bound) { + anchor_point.set_x(std::max(anchor_rect.x(), right_bound)); + } else if (anchor_point.x() < anchor_center.x() && + anchor_center.x() < contents_center.x()) { + anchor_point.set_x(anchor_center.x()); + } else if (anchor_point.x() < left_bound) { + anchor_point.set_x(std::min(anchor_rect.right(), left_bound)); + } + if (anchor_point.x() < left_bound) { + contents_bounds -= gfx::Vector2d(left_bound - anchor_point.x(), 0); + } else if (anchor_point.x() > right_bound) { + contents_bounds += gfx::Vector2d(anchor_point.x() - right_bound, 0); + } + } else { + const int bottom_bound = + contents_bounds.bottom() - + (kVisibleArrowVerticalBuffer + kVisibleArrowRadius); + const int top_bound = contents_bounds.y() + + kVisibleArrowVerticalBuffer + kVisibleArrowRadius; + if (anchor_point.y() > anchor_center.y() && + anchor_center.y() > contents_center.y()) { + anchor_point.set_y(anchor_center.y()); + } else if (anchor_point.y() > bottom_bound) { + anchor_point.set_y(std::max(anchor_rect.y(), bottom_bound)); + } else if (anchor_point.y() < anchor_center.y() && + anchor_center.y() < contents_center.y()) { + anchor_point.set_y(anchor_center.y()); + } else if (anchor_point.y() < top_bound) { + anchor_point.set_y(std::min(anchor_rect.bottom(), top_bound)); + } + if (anchor_point.y() < top_bound) { + contents_bounds -= gfx::Vector2d(0, top_bound - anchor_point.y()); + } else if (anchor_point.y() > bottom_bound) { + contents_bounds += gfx::Vector2d(0, anchor_point.y() - bottom_bound); + } + } + + // Also calculate the arrow bounds so that the arrow can be rendered. + constexpr int kVisibleArrowDiameter = 2 * kVisibleArrowRadius; + if (visible_arrow_insets.top()) { + visible_arrow_rect_ = + gfx::Rect(anchor_point.x() - kVisibleArrowRadius, + contents_bounds.y() + insets.top() - kVisibleArrowLength, + kVisibleArrowDiameter, kVisibleArrowLength); + } else if (visible_arrow_insets.bottom()) { + visible_arrow_rect_ = + gfx::Rect(anchor_point.x() - kVisibleArrowRadius, + contents_bounds.bottom() - insets.bottom(), + kVisibleArrowDiameter, kVisibleArrowLength); + } else if (visible_arrow_insets.left()) { + visible_arrow_rect_ = + gfx::Rect(contents_bounds.x() + insets.left() - kVisibleArrowLength, + anchor_point.y() - kVisibleArrowRadius, + kVisibleArrowLength, kVisibleArrowDiameter); + } else if (visible_arrow_insets.right()) { + visible_arrow_rect_ = + gfx::Rect(contents_bounds.right() - insets.right(), + anchor_point.y() - kVisibleArrowRadius, + kVisibleArrowLength, kVisibleArrowDiameter); + } + } + return contents_bounds; } @@ -251,18 +428,30 @@ canvas->sk_canvas()->clipRRect(r_rect, SkClipOp::kDifference, true /*doAntiAlias*/); - DrawBorderAndShadow(std::move(r_rect), &cc::PaintCanvas::drawRRect, canvas, + DrawBorderAndShadow(r_rect, &cc::PaintCanvas::drawRRect, canvas, view.GetNativeTheme(), md_shadow_elevation_); + + if (visible_arrow_) + PaintVisibleArrow(view, canvas); } gfx::Insets BubbleBorder::GetInsets() const { + DCHECK((!insets_ && shadow_ == STANDARD_SHADOW) || !visible_arrow_); if (insets_.has_value()) return insets_.value(); if (shadow_ == NO_SHADOW) return gfx::Insets(); if (shadow_ == NO_SHADOW_LEGACY) return gfx::Insets(kBorderThicknessDip); - return GetBorderAndShadowInsets(md_shadow_elevation_); + gfx::Insets insets = GetBorderAndShadowInsets(md_shadow_elevation_); + if (visible_arrow_) { + const gfx::Insets arrow_insets = GetVisibleArrowInsets(arrow_, false); + insets = gfx::Insets(std::max(insets.top(), arrow_insets.top()), + std::max(insets.left(), arrow_insets.left()), + std::max(insets.bottom(), arrow_insets.bottom()), + std::max(insets.right(), arrow_insets.right())); + } + return insets; } gfx::Size BubbleBorder::GetMinimumSize() const { @@ -387,6 +576,27 @@ canvas->DrawRoundRect(bounds, corner_radius(), flags); } +void BubbleBorder::PaintVisibleArrow(const View& view, gfx::Canvas* canvas) { + gfx::Point arrow_origin = visible_arrow_rect_.origin(); + View::ConvertPointFromScreen(&view, &arrow_origin); + const gfx::Rect arrow_bounds(arrow_origin, visible_arrow_rect_.size()); + cc::PaintFlags flags; + flags.setColor(background_color()); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); + canvas->DrawPath( + GetVisibleArrowPath(arrow_, arrow_bounds, BubbleArrowPart::kFill), flags); + SkColor kBorderColor = view.GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_BubbleBorderWhenShadowPresent); + flags.setColor(kBorderColor); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeCap(cc::PaintFlags::kRound_Cap); + flags.setStrokeWidth(1.5); + canvas->DrawPath( + GetVisibleArrowPath(arrow_, arrow_bounds, BubbleArrowPart::kBorder), + flags); +} + void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const { // Fill the contents with a round-rect region to match the border images. cc::PaintFlags flags;
diff --git a/ui/views/bubble/bubble_border.h b/ui/views/bubble/bubble_border.h index 8330fcb..eae4efed 100644 --- a/ui/views/bubble/bubble_border.h +++ b/ui/views/bubble/bubble_border.h
@@ -86,6 +86,21 @@ static constexpr int kShadowBlur = 6; static constexpr int kShadowVerticalOffset = 2; + // Space between the anchor view and a visible arrow if one is present. + static constexpr int kVisibleArrowGap = 6; + + // Length of the visible arrow (distance from the bubble to the tip of the + // arrow) if one is present. + static constexpr int kVisibleArrowLength = 8; + + // Radius (half-width) of the visible arrow, when one is present. + static constexpr int kVisibleArrowRadius = 6; + + // Distances between the edge of the bubble widget and the edge of the visible + // arrow if one is present. + static constexpr int kVisibleArrowHorizontalBuffer = 16; + static constexpr int kVisibleArrowVerticalBuffer = 12; + BubbleBorder(Arrow arrow, Shadow shadow, SkColor color); ~BubbleBorder() override; @@ -156,6 +171,9 @@ void set_arrow(Arrow arrow) { arrow_ = arrow; } Arrow arrow() const { return arrow_; } + void set_visible_arrow(bool visible_arrow) { visible_arrow_ = visible_arrow; } + bool visible_arrow() const { return visible_arrow_; } + // Get the shadow type. Shadow shadow() const { return shadow_; } @@ -207,6 +225,7 @@ FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetSizeForContentsSizeTest); FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetBoundsOriginTest); FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, ShadowTypes); + FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, VisibleArrowSizesAreConsistent); // Returns the shadows based on |shadow_elevation| to use for painting the // border and shadow, and for getting insets. This is only used for MD @@ -245,12 +264,20 @@ // border. void PaintNoShadowLegacy(const View& view, gfx::Canvas* canvas); + // Paint a visible arrow pointing to the anchor region. + void PaintVisibleArrow(const View& view, gfx::Canvas* canvas); + Arrow arrow_; int arrow_offset_; // Corner radius for the bubble border. If supplied the border will use // material design. int corner_radius_ = 0; + // Whether a visible arrow should be present. + bool visible_arrow_ = false; + // Cached arrow bounding box, calculated when bounds are calculated. + mutable gfx::Rect visible_arrow_rect_; + Shadow shadow_; // Elevation for the MD shadow. absl::optional<int> md_shadow_elevation_;
diff --git a/ui/views/bubble/bubble_border_unittest.cc b/ui/views/bubble/bubble_border_unittest.cc index e8a7389..d4e29da 100644 --- a/ui/views/bubble/bubble_border_unittest.cc +++ b/ui/views/bubble/bubble_border_unittest.cc
@@ -376,4 +376,481 @@ } } +TEST_F(BubbleBorderTest, BubblePositionedCorrectlyWithVisibleArrow) { + views::BubbleBorder border(BubbleBorder::TOP_LEFT, + BubbleBorder::STANDARD_SHADOW, SK_ColorWHITE); + const gfx::Insets kInsets = border.GetInsets(); + border.set_visible_arrow(true); + + constexpr gfx::Size kContentSize(200, 150); + + // Anchor position. + constexpr gfx::Point kAnchorOrigin(100, 100); + + // Anchor smaller than contents. + constexpr gfx::Rect kAnchor1(kAnchorOrigin, gfx::Size(40, 50)); + + // Anchor larger than contents. + constexpr gfx::Rect kAnchor2(kAnchorOrigin, gfx::Size(400, 300)); + + // Anchor extremely small. + constexpr gfx::Rect kAnchor3(kAnchorOrigin, gfx::Size(10, 12)); + + // TODO(dfried): in all of these tests, the border is factored into the height + // of the bubble an extra time, because of the fact that the arrow doesn't + // properly overlap the border in the calculation (though it does visually). + // Please fix at some point. + + // TOP_LEFT: + + border.set_arrow(BubbleBorder::TOP_LEFT); + gfx::Rect bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor1.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_EQ(kAnchor1.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip, + bounds.x()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor2.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_EQ(kAnchor2.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip, + bounds.x()); + + // Too small of an anchor view will shift the bubble to make sure the arrow + // is not too close to the edge of the bubble. + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor3.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_GT(kAnchor3.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip, + bounds.x()); + + // TOP_CENTER: + + border.set_arrow(BubbleBorder::TOP_CENTER); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor1.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_EQ(kAnchor1.bottom_center().x() - bounds.width() / 2, bounds.x()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor2.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_EQ(kAnchor2.bottom_center().x() - bounds.width() / 2, bounds.x()); + + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor3.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_EQ(kAnchor3.bottom_center().x() - bounds.width() / 2, bounds.x()); + + // TOP_RIGHT: + + border.set_arrow(BubbleBorder::TOP_RIGHT); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor1.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_EQ( + kAnchor1.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip, + bounds.right()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor2.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_EQ( + kAnchor2.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip, + bounds.right()); + + // Too small of an anchor view will shift the bubble to make sure the arrow + // is not too close to the edge of the bubble. + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.bottom() + + BubbleBorder::kVisibleArrowLength, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor3.bottom() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.y()); + EXPECT_LT( + kAnchor3.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip, + bounds.right()); + + // BOTTOM_LEFT: + + border.set_arrow(BubbleBorder::BOTTOM_LEFT); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor1.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_EQ(kAnchor1.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip, + bounds.x()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor2.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_EQ(kAnchor2.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip, + bounds.x()); + + // Too small of an anchor view will shift the bubble to make sure the arrow + // is not too close to the edge of the bubble. + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor3.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_GT(kAnchor3.x() - kInsets.left() + BubbleBorder::kBorderThicknessDip, + bounds.x()); + + // BOTTOM_CENTER: + + border.set_arrow(BubbleBorder::BOTTOM_CENTER); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor1.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_EQ(kAnchor1.bottom_center().x() - bounds.width() / 2, bounds.x()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor2.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_EQ(kAnchor2.bottom_center().x() - bounds.width() / 2, bounds.x()); + + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor3.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_EQ(kAnchor3.bottom_center().x() - bounds.width() / 2, bounds.x()); + + // BOTTOM_RIGHT: + + border.set_arrow(BubbleBorder::BOTTOM_RIGHT); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor1.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_EQ( + kAnchor1.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip, + bounds.right()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor2.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_EQ( + kAnchor2.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip, + bounds.right()); + + // Too small of an anchor view will shift the bubble to make sure the arrow + // is not too close to the edge of the bubble. + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.height() + kInsets.top() + + BubbleBorder::kVisibleArrowLength + + BubbleBorder::kBorderThicknessDip, + bounds.height()); + EXPECT_EQ(kContentSize.width() + kInsets.width(), bounds.width()); + EXPECT_EQ(kAnchor3.y() - BubbleBorder::kVisibleArrowGap, bounds.bottom()); + EXPECT_LT( + kAnchor3.right() + kInsets.right() - BubbleBorder::kBorderThicknessDip, + bounds.right()); + + // LEFT_TOP: + + border.set_arrow(BubbleBorder::LEFT_TOP); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor1.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_EQ(kAnchor1.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip, + bounds.y()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor2.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_EQ(kAnchor2.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip, + bounds.y()); + + // Too small of an anchor view will shift the bubble to make sure the arrow + // is not too close to the edge of the bubble. + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor3.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_GT(kAnchor3.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip, + bounds.y()); + + // LEFT_CENTER: + + // Because the shadow counts as part of the bounds, the shadow offset (which + // is applied vertically) will affect the vertical positioning of a bubble + // which is placed next to the anchor by a similar amount. + border.set_arrow(BubbleBorder::LEFT_CENTER); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor1.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_NEAR(kAnchor1.right_center().y() - bounds.height() / 2, bounds.y(), + BubbleBorder::kShadowVerticalOffset); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor2.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_NEAR(kAnchor2.right_center().y() - bounds.height() / 2, bounds.y(), + BubbleBorder::kShadowVerticalOffset); + + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor3.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_NEAR(kAnchor3.right_center().y() - bounds.height() / 2, bounds.y(), + BubbleBorder::kShadowVerticalOffset); + + // LEFT_BOTTOM: + + border.set_arrow(BubbleBorder::LEFT_BOTTOM); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor1.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_EQ( + kAnchor1.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip, + bounds.bottom()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor2.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_EQ( + kAnchor2.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip, + bounds.bottom()); + + // Too small of an anchor view will shift the bubble to make sure the arrow + // is not too close to the edge of the bubble. + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor3.right() + BubbleBorder::kVisibleArrowGap + + BubbleBorder::kBorderThicknessDip, + bounds.x()); + EXPECT_LT( + kAnchor3.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip, + bounds.bottom()); + + // RIGHT_TOP: + + border.set_arrow(BubbleBorder::RIGHT_TOP); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor1.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_EQ(kAnchor1.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip, + bounds.y()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor2.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_EQ(kAnchor2.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip, + bounds.y()); + + // Too small of an anchor view will shift the bubble to make sure the arrow + // is not too close to the edge of the bubble. + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor3.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_GT(kAnchor3.y() - kInsets.top() + BubbleBorder::kBorderThicknessDip, + bounds.y()); + + // // RIGHT_CENTER: + + // Because the shadow counts as part of the bounds, the shadow offset (which + // is applied vertically) will affect the vertical positioning of a bubble + // which is placed next to the anchor by a similar amount. + border.set_arrow(BubbleBorder::RIGHT_CENTER); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor1.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_NEAR(kAnchor1.right_center().y() - bounds.height() / 2, bounds.y(), + BubbleBorder::kShadowVerticalOffset); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor2.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_NEAR(kAnchor2.right_center().y() - bounds.height() / 2, bounds.y(), + BubbleBorder::kShadowVerticalOffset); + + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor3.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_NEAR(kAnchor3.right_center().y() - bounds.height() / 2, bounds.y(), + BubbleBorder::kShadowVerticalOffset); + + // RIGHT_BOTTOM: + + border.set_arrow(BubbleBorder::RIGHT_BOTTOM); + bounds = border.GetBounds(kAnchor1, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor1.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_EQ( + kAnchor1.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip, + bounds.bottom()); + + bounds = border.GetBounds(kAnchor2, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor2.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_EQ( + kAnchor2.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip, + bounds.bottom()); + + // Too small of an anchor view will shift the bubble to make sure the arrow + // is not too close to the edge of the bubble. + bounds = border.GetBounds(kAnchor3, kContentSize); + EXPECT_EQ(kContentSize.width() + kInsets.right() + + BubbleBorder::kVisibleArrowLength, + bounds.width()); + EXPECT_EQ(kContentSize.height() + kInsets.height(), bounds.height()); + EXPECT_EQ(kAnchor3.x() - BubbleBorder::kVisibleArrowGap - + BubbleBorder::kBorderThicknessDip, + bounds.right()); + EXPECT_LT( + kAnchor3.bottom() + kInsets.bottom() - BubbleBorder::kBorderThicknessDip, + bounds.bottom()); +} + } // namespace views
diff --git a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc index 6e1b3c0..dcc060f 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -18,6 +18,7 @@ #include "ui/display/test/scoped_screen_override.h" #include "ui/display/test/test_screen.h" #include "ui/events/event_utils.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/animation/test/test_ink_drop.h" #include "ui/views/bubble/bubble_frame_view.h" @@ -564,7 +565,7 @@ anchor_widget->SetContentsView(std::make_unique<LabelButton>( Button::PressedCallback(), std::u16string())); TestInkDrop* ink_drop = new TestInkDrop(); - test::InkDropHostTestApi(button->ink_drop()) + test::InkDropHostTestApi(InkDrop::Get(button)) .SetInkDrop(base::WrapUnique(ink_drop)); TestBubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(nullptr); @@ -594,7 +595,7 @@ anchor_widget->SetContentsView(std::make_unique<LabelButton>( Button::PressedCallback(), std::u16string())); TestInkDrop* ink_drop = new TestInkDrop(); - test::InkDropHostTestApi(button->ink_drop()) + test::InkDropHostTestApi(InkDrop::Get(button)) .SetInkDrop(base::WrapUnique(ink_drop)); TestBubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(nullptr);
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc index a6672c5b..fbccbd544 100644 --- a/ui/views/bubble/bubble_frame_view.cc +++ b/ui/views/bubble/bubble_frame_view.cc
@@ -33,6 +33,7 @@ #include "ui/views/controls/button/image_button_factory.h" #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/controls/image_view.h" +#include "ui/views/image_model_utils.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/layout_provider.h" #include "ui/views/paint_info.h" @@ -289,9 +290,12 @@ } void BubbleFrameView::UpdateWindowIcon() { + DCHECK(GetWidget()); gfx::ImageSkia image; - if (GetWidget()->widget_delegate()->ShouldShowWindowIcon()) - image = GetWidget()->widget_delegate()->GetWindowIcon(); + if (GetWidget()->widget_delegate()->ShouldShowWindowIcon()) { + image = GetImageSkiaFromImageModel( + GetWidget()->widget_delegate()->GetWindowIcon(), GetNativeTheme()); + } title_icon_->SetImage(&image); }
diff --git a/ui/views/controls/button/button.cc b/ui/views/controls/button/button.cc index 8d07de7..7f9f6a7 100644 --- a/ui/views/controls/button/button.cc +++ b/ui/views/controls/button/button.cc
@@ -19,6 +19,7 @@ #include "ui/gfx/animation/throb_animation.h" #include "ui/gfx/color_palette.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/controls/button/button_controller.h" @@ -84,7 +85,7 @@ } InkDrop* Button::DefaultButtonControllerDelegate::GetInkDrop() { - return button()->ink_drop()->GetInkDrop(); + return InkDrop::Get(button())->GetInkDrop(); } int Button::DefaultButtonControllerDelegate::GetDragOperations( @@ -320,9 +321,10 @@ if (state_ != STATE_DISABLED) { SetState(is_hot_tracked ? STATE_HOVERED : STATE_NORMAL); if (show_ink_drop_when_hot_tracked_) { - ink_drop()->AnimateToState(is_hot_tracked ? views::InkDropState::ACTIVATED - : views::InkDropState::HIDDEN, - nullptr); + InkDrop::Get(this)->AnimateToState(is_hot_tracked + ? views::InkDropState::ACTIVATED + : views::InkDropState::HIDDEN, + nullptr); } } @@ -339,9 +341,10 @@ } void Button::SetHighlighted(bool bubble_visible) { - ink_drop()->AnimateToState(bubble_visible ? views::InkDropState::ACTIVATED - : views::InkDropState::DEACTIVATED, - nullptr); + InkDrop::Get(this)->AnimateToState(bubble_visible + ? views::InkDropState::ACTIVATED + : views::InkDropState::DEACTIVATED, + nullptr); } base::CallbackListSubscription Button::AddStateChangedCallback( @@ -409,16 +412,17 @@ if (HitTestPoint(event.location())) { SetState(should_enter_pushed ? STATE_PRESSED : STATE_HOVERED); if (should_show_pending && - ink_drop()->GetInkDrop()->GetTargetInkDropState() == + InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == views::InkDropState::HIDDEN) { - ink_drop()->AnimateToState(views::InkDropState::ACTION_PENDING, &event); + InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTION_PENDING, + &event); } } else { SetState(STATE_NORMAL); if (should_show_pending && - ink_drop()->GetInkDrop()->GetTargetInkDropState() == + InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == views::InkDropState::ACTION_PENDING) { - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, &event); + InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, &event); } } } @@ -435,8 +439,9 @@ // applies everywhere so gather any feedback and update. if (state_ != STATE_DISABLED) SetState(STATE_NORMAL); - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, nullptr /* event */); - ink_drop()->GetInkDrop()->SetHovered(false); + InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, + nullptr /* event */); + InkDrop::Get(this)->GetInkDrop()->SetHovered(false); View::OnMouseCaptureLost(); } @@ -491,8 +496,9 @@ if (state_ != STATE_DISABLED) SetState(STATE_NORMAL); if (hide_ink_drop_when_showing_context_menu_) { - ink_drop()->GetInkDrop()->SetHovered(false); - ink_drop()->AnimateToState(InkDropState::HIDDEN, nullptr /* event */); + InkDrop::Get(this)->GetInkDrop()->SetHovered(false); + InkDrop::Get(this)->AnimateToState(InkDropState::HIDDEN, + nullptr /* event */); } View::ShowContextMenu(p, source_type); } @@ -502,7 +508,7 @@ // (since disabled buttons may still be able to be dragged). if (state_ != STATE_DISABLED) SetState(STATE_NORMAL); - ink_drop()->AnimateToState(InkDropState::HIDDEN, nullptr /* event */); + InkDrop::Get(this)->AnimateToState(InkDropState::HIDDEN, nullptr /* event */); } void Button::OnPaint(gfx::Canvas* canvas) { @@ -561,10 +567,10 @@ View::OnBlur(); if (IsHotTracked() || state_ == STATE_PRESSED) { SetState(STATE_NORMAL); - if (ink_drop()->GetInkDrop()->GetTargetInkDropState() != + if (InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() != views::InkDropState::HIDDEN) - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, - nullptr /* event */); + InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, + nullptr /* event */); // TODO(bruthig) : Fix Buttons to work well when multiple input // methods are interacting with a button. e.g. By animating to HIDDEN here // it is possible for a Mouse Release to trigger an action however there @@ -580,23 +586,25 @@ Button::Button(PressedCallback callback) : AnimationDelegateViews(this), callback_(std::move(callback)) { + InkDrop::Install(this, std::make_unique<InkDropHost>(this)); + SetFocusBehavior(PlatformStyle::kDefaultFocusBehavior); SetProperty(kIsButtonProperty, true); hover_animation_.SetSlideDuration(base::TimeDelta::FromMilliseconds(150)); SetInstallFocusRingOnFocus(true); button_controller_ = std::make_unique<ButtonController>( this, std::make_unique<DefaultButtonControllerDelegate>(this)); - ink_drop()->SetCreateInkDropCallback(base::BindRepeating( + InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating( [](Button* button) { std::unique_ptr<InkDrop> ink_drop = - views::InkDrop::CreateInkDropForFloodFillRipple(button->ink_drop()); + InkDrop::CreateInkDropForFloodFillRipple(InkDrop::Get(button)); ink_drop->SetShowHighlightOnFocus(!button->focus_ring()); return ink_drop; }, base::Unretained(this))); // TODO(pbos): Investigate not setting a default color so that we can DCHECK // if one hasn't been set. - ink_drop()->SetBaseColor(gfx::kPlaceholderColor); + InkDrop::Get(this)->SetBaseColor(gfx::kPlaceholderColor); } void Button::RequestFocusFromEvent() { @@ -606,8 +614,8 @@ void Button::NotifyClick(const ui::Event& event) { if (has_ink_drop_action_on_click_) { - ink_drop()->AnimateToState(InkDropState::ACTION_TRIGGERED, - ui::LocatedEvent::FromIfValid(&event)); + InkDrop::Get(this)->AnimateToState(InkDropState::ACTION_TRIGGERED, + ui::LocatedEvent::FromIfValid(&event)); } // If we have an associated help context ID, notify that system that we have @@ -624,12 +632,12 @@ void Button::OnClickCanceled(const ui::Event& event) { if (ShouldUpdateInkDropOnClickCanceled()) { - if (ink_drop()->GetInkDrop()->GetTargetInkDropState() == + if (InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == views::InkDropState::ACTION_PENDING || - ink_drop()->GetInkDrop()->GetTargetInkDropState() == + InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == views::InkDropState::ALTERNATE_ACTION_PENDING) { - ink_drop()->AnimateToState(views::InkDropState::HIDDEN, - ui::LocatedEvent::FromIfValid(&event)); + InkDrop::Get(this)->AnimateToState(views::InkDropState::HIDDEN, + ui::LocatedEvent::FromIfValid(&event)); } } } @@ -683,10 +691,10 @@ if (GetEnabled()) { bool should_enter_hover_state = ShouldEnterHoveredState(); SetState(should_enter_hover_state ? STATE_HOVERED : STATE_NORMAL); - ink_drop()->GetInkDrop()->SetHovered(should_enter_hover_state); + InkDrop::Get(this)->GetInkDrop()->SetHovered(should_enter_hover_state); } else { SetState(STATE_DISABLED); - ink_drop()->GetInkDrop()->SetHovered(false); + InkDrop::Get(this)->GetInkDrop()->SetHovered(false); } }
diff --git a/ui/views/controls/button/button.h b/ui/views/controls/button/button.h index 8fabab8..69bc508 100644 --- a/ui/views/controls/button/button.h +++ b/ui/views/controls/button/button.h
@@ -182,9 +182,6 @@ base::CallbackListSubscription AddStateChangedCallback( PropertyChangedCallback callback); - InkDropHost* ink_drop() { return ink_drop_.get(); } - const InkDropHost* ink_drop() const { return ink_drop_.get(); } - // Overridden from View: bool OnMousePressed(const ui::MouseEvent& event) override; bool OnMouseDragged(const ui::MouseEvent& event) override; @@ -337,9 +334,6 @@ // tracked with SetHotTracked(). bool show_ink_drop_when_hot_tracked_ = false; - // The InkDrop for this Button. - std::unique_ptr<InkDropHost> ink_drop_{std::make_unique<InkDropHost>(this)}; - // The focus ring for this Button. FocusRing* focus_ring_ = nullptr;
diff --git a/ui/views/controls/button/button_controller.cc b/ui/views/controls/button/button_controller.cc index 77c71e4..9c5afcc 100644 --- a/ui/views/controls/button/button_controller.cc +++ b/ui/views/controls/button/button_controller.cc
@@ -27,8 +27,8 @@ button_controller_delegate_->ShouldEnterPushedState(event) && button_->HitTestPoint(event.location())) { button_->SetState(Button::STATE_PRESSED); - button_->ink_drop()->AnimateToState(views::InkDropState::ACTION_PENDING, - &event); + InkDrop::Get(button_)->AnimateToState(views::InkDropState::ACTION_PENDING, + &event); } button_controller_delegate_->RequestFocusFromEvent(); if (button_controller_delegate_->IsTriggerableEvent(event) && @@ -88,8 +88,8 @@ button_->SetState(Button::STATE_PRESSED); if (button_controller_delegate_->GetInkDrop()->GetTargetInkDropState() != InkDropState::ACTION_PENDING) { - button_->ink_drop()->AnimateToState(InkDropState::ACTION_PENDING, - nullptr /* event */); + InkDrop::Get(button_)->AnimateToState(InkDropState::ACTION_PENDING, + nullptr /* event */); } return true; case Button::KeyClickAction::kOnKeyPress:
diff --git a/ui/views/controls/button/button_unittest.cc b/ui/views/controls/button/button_unittest.cc index b26e873d..04befa8 100644 --- a/ui/views/controls/button/button_unittest.cc +++ b/ui/views/controls/button/button_unittest.cc
@@ -116,7 +116,7 @@ public: explicit TestButtonObserver(Button* button) { highlighted_changed_subscription_ = - button->ink_drop()->AddHighlightedChangedCallback(base::BindRepeating( + InkDrop::Get(button)->AddHighlightedChangedCallback(base::BindRepeating( [](TestButtonObserver* obs) { obs->highlighted_changed_ = true; }, base::Unretained(this))); state_changed_subscription_ = @@ -147,8 +147,9 @@ TestInkDrop* AddTestInkDrop(TestButton* button) { auto owned_ink_drop = std::make_unique<TestInkDrop>(); TestInkDrop* ink_drop = owned_ink_drop.get(); - button->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - InkDropHostTestApi(button->ink_drop()).SetInkDrop(std::move(owned_ink_drop)); + InkDrop::Get(button)->SetMode(views::InkDropHost::InkDropMode::ON); + InkDropHostTestApi(InkDrop::Get(button)) + .SetInkDrop(std::move(owned_ink_drop)); return ink_drop; } @@ -192,7 +193,7 @@ void CreateButtonWithObserver() { button_ = widget()->SetContentsView(std::make_unique<TestButton>(false)); - button_->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(button_)->SetMode(views::InkDropHost::InkDropMode::ON); button_observer_ = std::make_unique<TestButtonObserver>(button_); } @@ -846,19 +847,19 @@ TEST_F(ButtonTest, ChangingHighlightStateNotifiesCallback) { CreateButtonWithObserver(); EXPECT_FALSE(button_observer()->highlighted_changed()); - EXPECT_FALSE(button()->ink_drop()->GetHighlighted()); + EXPECT_FALSE(InkDrop::Get(button())->GetHighlighted()); button()->SetHighlighted(/*bubble_visible=*/true); EXPECT_TRUE(button_observer()->highlighted_changed()); - EXPECT_TRUE(button()->ink_drop()->GetHighlighted()); + EXPECT_TRUE(InkDrop::Get(button())->GetHighlighted()); button_observer()->Reset(); EXPECT_FALSE(button_observer()->highlighted_changed()); - EXPECT_TRUE(button()->ink_drop()->GetHighlighted()); + EXPECT_TRUE(InkDrop::Get(button())->GetHighlighted()); button()->SetHighlighted(/*bubble_visible=*/false); EXPECT_TRUE(button_observer()->highlighted_changed()); - EXPECT_FALSE(button()->ink_drop()->GetHighlighted()); + EXPECT_FALSE(InkDrop::Get(button())->GetHighlighted()); } // Verifies that button state changes trigger property change callbacks.
diff --git a/ui/views/controls/button/checkbox.cc b/ui/views/controls/button/checkbox.cc index 5bcf4f7..c07ddad 100644 --- a/ui/views/controls/button/checkbox.cc +++ b/ui/views/controls/button/checkbox.cc
@@ -20,6 +20,7 @@ #include "ui/gfx/skia_util.h" #include "ui/native_theme/native_theme.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/controls/button/label_button_border.h" @@ -52,19 +53,19 @@ SetHorizontalAlignment(gfx::ALIGN_LEFT); SetRequestFocusOnPress(false); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - views::InkDrop::UseInkDropWithoutAutoHighlight(ink_drop(), - /*highlight_on_hover=*/false); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + InkDrop::UseInkDropWithoutAutoHighlight(InkDrop::Get(this), + /*highlight_on_hover=*/false); + InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](Checkbox* host) { // The "small" size is 21dp, the large size is 1.33 * 21dp = 28dp. - return host->ink_drop()->CreateSquareRipple( + return InkDrop::Get(host)->CreateSquareRipple( host->image()->GetMirroredContentsBounds().CenterPoint(), gfx::Size(21, 21)); }, this)); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](Checkbox* host) { // Usually ink-drop ripples match the text color. Checkboxes use the // color of the unchecked, enabled icon.
diff --git a/ui/views/controls/button/image_button_factory.cc b/ui/views/controls/button/image_button_factory.cc index 0aa69638..b6793b6 100644 --- a/ui/views/controls/button/image_button_factory.cc +++ b/ui/views/controls/button/image_button_factory.cc
@@ -12,6 +12,7 @@ #include "ui/gfx/vector_icon_types.h" #include "ui/gfx/vector_icon_utils.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/border.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/layout/layout_provider.h" @@ -69,7 +70,7 @@ } void ConfigureVectorImageButton(ImageButton* button) { - button->ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(button)->SetMode(views::InkDropHost::InkDropMode::ON); button->SetHasInkDropActionOnClick(true); button->SetImageHorizontalAlignment(ImageButton::ALIGN_CENTER); button->SetImageVerticalAlignment(ImageButton::ALIGN_MIDDLE); @@ -113,7 +114,7 @@ button->SetImage(Button::STATE_NORMAL, normal_image); button->SetImage(Button::STATE_DISABLED, disabled_image); - button->ink_drop()->SetBaseColor(icon_color); + InkDrop::Get(button)->SetBaseColor(icon_color); } void SetToggledImageFromVectorIconWithColor(ToggleImageButton* button,
diff --git a/ui/views/controls/button/image_button_factory_unittest.cc b/ui/views/controls/button/image_button_factory_unittest.cc index 6dae681..175ae8e5 100644 --- a/ui/views/controls/button/image_button_factory_unittest.cc +++ b/ui/views/controls/button/image_button_factory_unittest.cc
@@ -11,6 +11,7 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/image_button.h" @@ -33,7 +34,7 @@ EXPECT_FALSE(button->GetImage(Button::STATE_NORMAL).isNull()); EXPECT_FALSE(button->GetImage(Button::STATE_DISABLED).isNull()); EXPECT_EQ(color_utils::DeriveDefaultIconColor(SK_ColorRED), - button->ink_drop()->GetBaseColor()); + InkDrop::Get(button.get())->GetBaseColor()); } class ImageButtonFactoryWidgetTest : public ViewsTestBase { @@ -81,7 +82,7 @@ Button::PressedCallback(), vector_icons::kCloseRoundedIcon)); EXPECT_EQ(button()->GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_DefaultIconColor), - button()->ink_drop()->GetBaseColor()); + InkDrop::Get(button())->GetBaseColor()); } TEST_F(ImageButtonFactoryWidgetTest,
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc index 86ddd3569..2ea2c26 100644 --- a/ui/views/controls/button/label_button.cc +++ b/ui/views/controls/button/label_button.cc
@@ -57,7 +57,12 @@ SetTextInternal(text); } -LabelButton::~LabelButton() = default; +LabelButton::~LabelButton() { + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); +} gfx::ImageSkia LabelButton::GetImage(ButtonState for_state) const { for_state = ImageStateForState(for_state);
diff --git a/ui/views/controls/button/label_button_unittest.cc b/ui/views/controls/button/label_button_unittest.cc index 187b0910..eed8f952 100644 --- a/ui/views/controls/button/label_button_unittest.cc +++ b/ui/views/controls/button/label_button_unittest.cc
@@ -26,6 +26,7 @@ #include "ui/native_theme/native_theme.h" #include "ui/native_theme/native_theme_base.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/animation/test/test_ink_drop.h" #include "ui/views/buildflags.h" @@ -794,7 +795,7 @@ Button::PressedCallback(), std::u16string())); test_ink_drop_ = new test::TestInkDrop(); - test::InkDropHostTestApi(button_->ink_drop()) + test::InkDropHostTestApi(InkDrop::Get(button_)) .SetInkDrop(base::WrapUnique(test_ink_drop_)); }
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc index 55345eb..6786e82 100644 --- a/ui/views/controls/button/md_text_button.cc +++ b/ui/views/controls/button/md_text_button.cc
@@ -18,6 +18,7 @@ #include "ui/gfx/color_utils.h" #include "ui/native_theme/native_theme.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_painted_layer_delegates.h" @@ -35,10 +36,10 @@ const std::u16string& text, int button_context) : LabelButton(std::move(callback), text, button_context) { - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); SetShowInkDropWhenHotTracked(true); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](MdTextButton* host) { return color_utils::DeriveDefaultIconColor( host->label()->GetEnabledColor()); @@ -96,8 +97,8 @@ if (corner_radius_ == radius) return; corner_radius_ = radius; - ink_drop()->SetSmallCornerRadius(corner_radius_); - ink_drop()->SetLargeCornerRadius(corner_radius_); + InkDrop::Get(this)->SetSmallCornerRadius(corner_radius_); + InkDrop::Get(this)->SetLargeCornerRadius(corner_radius_); OnPropertyChanged(&corner_radius_, kPropertyEffectsPaint); }
diff --git a/ui/views/controls/button/menu_button_controller.cc b/ui/views/controls/button/menu_button_controller.cc index 785bba4b..ac2d2a2e 100644 --- a/ui/views/controls/button/menu_button_controller.cc +++ b/ui/views/controls/button/menu_button_controller.cc
@@ -112,7 +112,7 @@ // If this is an unintentional trigger do not display the inkdrop. if (!is_intentional_menu_trigger_) - button()->ink_drop()->AnimateToState(InkDropState::HIDDEN, &event); + InkDrop::Get(button())->AnimateToState(InkDropState::HIDDEN, &event); return true; } @@ -123,7 +123,7 @@ Activate(&event); } else { if (button()->GetHideInkDropWhenShowingContextMenu()) - button()->ink_drop()->AnimateToState(InkDropState::HIDDEN, &event); + InkDrop::Get(button())->AnimateToState(InkDropState::HIDDEN, &event); ButtonController::OnMouseReleased(event); } } @@ -265,7 +265,7 @@ increment_pressed_lock_called_ = nullptr; if (!increment_pressed_lock_called && pressed_lock_count_ == 0) { - button()->ink_drop()->AnimateToState( + InkDrop::Get(button())->AnimateToState( InkDropState::ACTION_TRIGGERED, ui::LocatedEvent::FromIfValid(event)); } @@ -275,8 +275,8 @@ return false; } - button()->ink_drop()->AnimateToState(InkDropState::HIDDEN, - ui::LocatedEvent::FromIfValid(event)); + InkDrop::Get(button())->AnimateToState(InkDropState::HIDDEN, + ui::LocatedEvent::FromIfValid(event)); return true; } @@ -319,7 +319,7 @@ if (snap_ink_drop_to_activated) delegate()->GetInkDrop()->SnapToActivated(); else - button()->ink_drop()->AnimateToState(InkDropState::ACTIVATED, event); + InkDrop::Get(button())->AnimateToState(InkDropState::ACTIVATED, event); } button()->SetState(Button::STATE_PRESSED); delegate()->GetInkDrop()->SetHovered(false); @@ -347,8 +347,8 @@ // The widget may be null during shutdown. If so, it doesn't make sense to // try to add an ink drop effect. if (button()->GetWidget() && button()->GetState() != Button::STATE_PRESSED) - button()->ink_drop()->AnimateToState(InkDropState::DEACTIVATED, - nullptr /* event */); + InkDrop::Get(button())->AnimateToState(InkDropState::DEACTIVATED, + nullptr /* event */); } }
diff --git a/ui/views/controls/button/menu_button_unittest.cc b/ui/views/controls/button/menu_button_unittest.cc index 8e935658..5455f6c192 100644 --- a/ui/views/controls/button/menu_button_unittest.cc +++ b/ui/views/controls/button/menu_button_unittest.cc
@@ -14,6 +14,7 @@ #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/test/event_generator.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/animation/test/test_ink_drop.h" #include "ui/views/controls/button/button.h" @@ -117,7 +118,7 @@ auto ink_drop = std::make_unique<test::TestInkDrop>(); ink_drop_ = ink_drop.get(); - test::InkDropHostTestApi(button_->ink_drop()) + test::InkDropHostTestApi(InkDrop::Get(button_)) .SetInkDrop(std::move(ink_drop)); widget_->Show(); @@ -297,7 +298,7 @@ EXPECT_TRUE(button()->clicked()); gfx::Point inkdrop_center_point = - button()->ink_drop()->GetInkDropCenterBasedOnLastEvent(); + InkDrop::Get(button())->GetInkDropCenterBasedOnLastEvent(); View::ConvertPointToScreen(button(), &inkdrop_center_point); EXPECT_EQ(click_point, inkdrop_center_point); } @@ -314,7 +315,7 @@ EXPECT_EQ(Button::STATE_PRESSED, button()->GetState()); EXPECT_EQ(click_point, - button()->ink_drop()->GetInkDropCenterBasedOnLastEvent()); + InkDrop::Get(button())->GetInkDropCenterBasedOnLastEvent()); } // Test that the MenuButton stays pressed while there are any PressedLocks.
diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc index 98e6b3ba..797f26a7 100644 --- a/ui/views/controls/button/toggle_button.cc +++ b/ui/views/controls/button/toggle_button.cc
@@ -20,6 +20,7 @@ #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/shadow_value.h" #include "ui/gfx/skia_paint_util.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/border.h" @@ -131,21 +132,21 @@ slide_animation_.SetSlideDuration(base::TimeDelta::FromMilliseconds(80)); slide_animation_.SetTweenType(gfx::Tween::LINEAR); thumb_view_ = AddChildView(std::make_unique<ThumbView>()); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); // Do not set a clip, allow the ink drop to burst out. // TODO(pbos): Consider an explicit InkDrop API to not use a clip rect / mask. views::InstallEmptyHighlightPathGenerator(this); SetHasInkDropActionOnClick(true); - views::InkDrop::UseInkDropForSquareRipple(ink_drop(), - /*highlight_on_hover=*/false); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + InkDrop::UseInkDropForSquareRipple(InkDrop::Get(this), + /*highlight_on_hover=*/false); + InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](ToggleButton* host) { gfx::Rect rect = host->thumb_view_->GetLocalBounds(); rect.Inset(-ThumbView::GetShadowOutsets()); - return host->ink_drop()->CreateSquareRipple(rect.CenterPoint()); + return InkDrop::Get(host)->CreateSquareRipple(rect.CenterPoint()); }, this)); - ink_drop()->SetBaseColorCallback(base::BindRepeating( + InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( [](ToggleButton* host) { return host->GetTrackColor(host->GetIsOn() || host->HasFocus()); }, @@ -158,8 +159,10 @@ } ToggleButton::~ToggleButton() { - // Destroying ink drop early allows ink drop layer to be properly removed, - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); } void ToggleButton::AnimateIsOn(bool is_on) { @@ -309,7 +312,8 @@ void ToggleButton::OnFocus() { Button::OnFocus(); - ink_drop()->AnimateToState(views::InkDropState::ACTION_PENDING, nullptr); + InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTION_PENDING, + nullptr); SchedulePaint(); } @@ -317,9 +321,10 @@ Button::OnBlur(); // The ink drop may have already gone away if the user clicked after focusing. - if (ink_drop()->GetInkDrop()->GetTargetInkDropState() == + if (InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == views::InkDropState::ACTION_PENDING) { - ink_drop()->AnimateToState(views::InkDropState::ACTION_TRIGGERED, nullptr); + InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTION_TRIGGERED, + nullptr); } SchedulePaint(); } @@ -330,8 +335,8 @@ // Skip over Button::NotifyClick, to customize the ink drop animation. // Leave the ripple in place when the button is activated via the keyboard. if (!event.IsKeyEvent()) { - ink_drop()->AnimateToState(InkDropState::ACTION_TRIGGERED, - ui::LocatedEvent::FromIfValid(&event)); + InkDrop::Get(this)->AnimateToState(InkDropState::ACTION_TRIGGERED, + ui::LocatedEvent::FromIfValid(&event)); } Button::NotifyClick(event);
diff --git a/ui/views/controls/button/toggle_button_unittest.cc b/ui/views/controls/button/toggle_button_unittest.cc index 6f59963..0147dfc 100644 --- a/ui/views/controls/button/toggle_button_unittest.cc +++ b/ui/views/controls/button/toggle_button_unittest.cc
@@ -13,6 +13,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event_utils.h" #include "ui/events/test/event_generator.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/widget_utils.h" @@ -23,10 +24,10 @@ explicit TestToggleButton(int* counter) : counter_(counter) {} ~TestToggleButton() override { - // Calling ink_drop()->SetMode() in this subclass allows this class's - // implementation of RemoveLayerBeneathView() to be called. The same - // call is made in ~ToggleButton() so this is testing the general technique. - ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); + // TODO(pbos): Revisit explicit removal of InkDrop for classes that override + // Add/RemoveLayerBeneathView(). This is done so that the InkDrop doesn't + // access the non-override versions in ~View. + views::InkDrop::Remove(this); } void AddLayerBeneathView(ui::Layer* layer) override {
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc index 51770884..de31ba4 100644 --- a/ui/views/controls/combobox/combobox.cc +++ b/ui/views/controls/combobox/combobox.cc
@@ -27,6 +27,7 @@ #include "ui/native_theme/native_theme.h" #include "ui/native_theme/themed_vector_icon.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/background.h" #include "ui/views/controls/button/button.h" @@ -66,18 +67,18 @@ button_controller()->set_notify_action( ButtonController::NotifyAction::kOnPress); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - InkDrop::UseInkDropForSquareRipple(ink_drop(), + InkDrop::UseInkDropForSquareRipple(InkDrop::Get(this), /*highlight_on_hover=*/false); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](Button* host) -> std::unique_ptr<views::InkDropRipple> { return std::make_unique<views::FloodFillInkDropRipple>( host->size(), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), host->GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_LabelEnabledColor), - host->ink_drop()->GetVisibleOpacity()); + InkDrop::Get(host)->GetVisibleOpacity()); }, this)); }
diff --git a/ui/views/controls/editable_combobox/editable_combobox.cc b/ui/views/controls/editable_combobox/editable_combobox.cc index 6c67ac9e..5772b992 100644 --- a/ui/views/controls/editable_combobox/editable_combobox.cc +++ b/ui/views/controls/editable_combobox/editable_combobox.cc
@@ -76,18 +76,18 @@ // TODO(pbos): Share ink-drop configuration code between here and // Combobox's TransparentButton. // Similar to Combobox's TransparentButton. - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); SetHasInkDropActionOnClick(true); - InkDrop::UseInkDropForSquareRipple(ink_drop(), + InkDrop::UseInkDropForSquareRipple(InkDrop::Get(this), /*highlight_on_hover=*/false); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](Button* host) -> std::unique_ptr<views::InkDropRipple> { return std::make_unique<views::FloodFillInkDropRipple>( host->size(), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), + InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), style::GetColor(*host, style::CONTEXT_TEXTFIELD, style::STYLE_PRIMARY), - host->ink_drop()->GetVisibleOpacity()); + InkDrop::Get(host)->GetVisibleOpacity()); }, this)); }
diff --git a/ui/views/controls/focus_ring.cc b/ui/views/controls/focus_ring.cc index 699c15f..8045b01e 100644 --- a/ui/views/controls/focus_ring.cc +++ b/ui/views/controls/focus_ring.cc
@@ -17,6 +17,8 @@ #include "ui/compositor/layer.h" #include "ui/gfx/canvas.h" #include "ui/gfx/color_utils.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/skia_util.h" #include "ui/views/controls/focusable_border.h" #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/style/platform_style.h" @@ -115,6 +117,7 @@ void FocusRing::SetPathGenerator( std::unique_ptr<HighlightPathGenerator> generator) { path_generator_ = std::move(generator); + InvalidateLayout(); SchedulePaint(); } @@ -142,6 +145,16 @@ // The focus ring handles its own sizing, which is simply to fill the parent // and extend a little beyond its borders. gfx::Rect focus_bounds = parent()->GetLocalBounds(); + + // Make sure the focus-ring path fits. + // TODO(pbos): Chase down use cases where this path is not in a usable state + // by the time layout happens. This may be due to synchronous Layout() calls. + const SkPath path = GetPath(); + if (IsPathUsable(path)) { + focus_bounds.Union( + gfx::ToEnclosingRect(gfx::SkRectToRectF(path.getBounds()))); + } + focus_bounds.Inset(gfx::Insets(PlatformStyle::kFocusHaloInset)); SetBoundsRect(focus_bounds); @@ -183,14 +196,7 @@ paint.setStyle(cc::PaintFlags::kStroke_Style); paint.setStrokeWidth(PlatformStyle::kFocusHaloThickness); - SkPath path; - if (path_generator_) - path = path_generator_->GetHighlightPath(parent()); - - // If there's no path generator or the generated path is unusable, fall back - // to the default. - if (!IsPathUsable(path)) - path = GetHighlightPathInternal(parent()); + const SkPath path = GetPath(); DCHECK(IsPathUsable(path)); DCHECK_EQ(GetFlipCanvasOnPaintForRTLUI(), @@ -238,6 +244,19 @@ SetCanProcessEventsWithinSubtree(false); } +SkPath FocusRing::GetPath() const { + SkPath path; + if (path_generator_) { + path = path_generator_->GetHighlightPath(parent()); + if (IsPathUsable(path)) + return path; + } + + // If there's no path generator or the generated path is unusable, fall back + // to the default. + return GetHighlightPathInternal(parent()); +} + void FocusRing::RefreshLayer() { // TODO(pbos): This always keeps the layer alive if |has_focus_predicate_| is // set. This is done because we're not notified when the predicate might
diff --git a/ui/views/controls/focus_ring.h b/ui/views/controls/focus_ring.h index 3c50c76..f0c33a8 100644 --- a/ui/views/controls/focus_ring.h +++ b/ui/views/controls/focus_ring.h
@@ -92,6 +92,8 @@ private: FocusRing(); + SkPath GetPath() const; + void RefreshLayer(); // Translates the provided SkRect or SkRRect, which is in the parent's
diff --git a/ui/views/view.cc b/ui/views/view.cc index 75320647..831bb3c 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -239,6 +239,11 @@ if (!child->owned_by_client_) delete child; } + + // Clear `children_` to prevent UAFs from observers and properties that may + // end up looking at children(), directly or indirectly, before ~View() goes + // out of scope. + children_.clear(); } for (ViewObserver& observer : observers_)
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index f8d0cf3f..d62ee894 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -22,6 +22,7 @@ #include "ui/base/ime/input_method.h" #include "ui/base/l10n/l10n_font_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/color/color_provider_manager.h" #include "ui/compositor/compositor.h" @@ -35,6 +36,7 @@ #include "ui/views/focus/focus_manager.h" #include "ui/views/focus/focus_manager_factory.h" #include "ui/views/focus/widget_focus_manager.h" +#include "ui/views/image_model_utils.h" #include "ui/views/views_delegate.h" #include "ui/views/views_features.h" #include "ui/views/widget/any_widget_observer_singleton.h" @@ -935,8 +937,11 @@ void Widget::UpdateWindowIcon() { if (non_client_view_) non_client_view_->UpdateWindowIcon(); - native_widget_->SetWindowIcons(widget_delegate_->GetWindowIcon(), - widget_delegate_->GetWindowAppIcon()); + native_widget_->SetWindowIcons( + GetImageSkiaFromImageModel(widget_delegate_->GetWindowIcon(), + GetNativeTheme()), + GetImageSkiaFromImageModel(widget_delegate_->GetWindowAppIcon(), + GetNativeTheme())); } FocusTraversable* Widget::GetFocusTraversable() {
diff --git a/ui/views/widget/widget_delegate.cc b/ui/views/widget/widget_delegate.cc index b4fa10a85..89925f9 100644 --- a/ui/views/widget/widget_delegate.cc +++ b/ui/views/widget/widget_delegate.cc
@@ -12,6 +12,7 @@ #include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/gfx/image/image_skia.h" @@ -143,17 +144,17 @@ return params_.show_close_button; } -gfx::ImageSkia WidgetDelegate::GetWindowAppIcon() { +ui::ImageModel WidgetDelegate::GetWindowAppIcon() { // Prefer app icon if available. if (!params_.app_icon.isNull()) - return params_.app_icon; + return ui::ImageModel::FromImageSkia(params_.app_icon); // Fall back to the window icon. return GetWindowIcon(); } // Returns the icon to be displayed in the window. -gfx::ImageSkia WidgetDelegate::GetWindowIcon() { - return params_.icon; +ui::ImageModel WidgetDelegate::GetWindowIcon() { + return ui::ImageModel::FromImageSkia(params_.icon); } bool WidgetDelegate::ShouldShowWindowIcon() const {
diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h index f40543d..2ea519f 100644 --- a/ui/views/widget/widget_delegate.h +++ b/ui/views/widget/widget_delegate.h
@@ -22,6 +22,10 @@ class Rect; } // namespace gfx +namespace ui { +class ImageModel; +} // namespace ui + namespace views { class BubbleDialogDelegate; class ClientView; @@ -194,10 +198,10 @@ // Returns the app icon for the window. On Windows, this is the ICON_BIG used // in Alt-Tab list and Win7's taskbar. - virtual gfx::ImageSkia GetWindowAppIcon(); + virtual ui::ImageModel GetWindowAppIcon(); // Returns the icon to be displayed in the window. - virtual gfx::ImageSkia GetWindowIcon(); + virtual ui::ImageModel GetWindowIcon(); // Returns true if a window icon should be shown. bool ShouldShowWindowIcon() const;
diff --git a/ui/views/widget/widget_delegate_unittest.cc b/ui/views/widget/widget_delegate_unittest.cc index 80209ee..55d0d190 100644 --- a/ui/views/widget/widget_delegate_unittest.cc +++ b/ui/views/widget/widget_delegate_unittest.cc
@@ -7,8 +7,10 @@ #include <utility> #include "base/test/bind.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_unittest_util.h" +#include "ui/views/image_model_utils.h" #include "ui/views/test/views_test_base.h" #include "ui/views/view.h" #include "ui/views/view_tracker.h" @@ -122,8 +124,10 @@ delegate->SetIcon(window_icon); gfx::ImageSkia app_icon = gfx::test::CreateImageSkia(48, 48); delegate->SetAppIcon(app_icon); - EXPECT_TRUE(delegate->GetWindowIcon().BackedBySameObjectAs(window_icon)); - EXPECT_TRUE(delegate->GetWindowAppIcon().BackedBySameObjectAs(app_icon)); + EXPECT_TRUE(GetImageSkiaFromImageModel(delegate->GetWindowIcon(), nullptr) + .BackedBySameObjectAs(window_icon)); + EXPECT_TRUE(GetImageSkiaFromImageModel(delegate->GetWindowAppIcon(), nullptr) + .BackedBySameObjectAs(app_icon)); } TEST_F(WidgetDelegateTest, AppIconFallsBackToWindowIcon) { @@ -132,7 +136,8 @@ gfx::ImageSkia window_icon = gfx::test::CreateImageSkia(16, 16); delegate->SetIcon(window_icon); // Don't set an independent app icon. - EXPECT_TRUE(delegate->GetWindowAppIcon().BackedBySameObjectAs(window_icon)); + EXPECT_TRUE(GetImageSkiaFromImageModel(delegate->GetWindowAppIcon(), nullptr) + .BackedBySameObjectAs(window_icon)); } } // namespace
diff --git a/ui/views/window/frame_caption_button.cc b/ui/views/window/frame_caption_button.cc index 6c10aa98..1cd69f2 100644 --- a/ui/views/window/frame_caption_button.cc +++ b/ui/views/window/frame_caption_button.cc
@@ -17,6 +17,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/rrect_f.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" @@ -76,18 +77,18 @@ swap_images_animation_->Reset(1); SetHasInkDropActionOnClick(true); - ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); - ink_drop()->SetVisibleOpacity(kInkDropVisibleOpacity); + InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); + InkDrop::Get(this)->SetVisibleOpacity(kInkDropVisibleOpacity); UpdateInkDropBaseColor(); - views::InkDrop::UseInkDropWithoutAutoHighlight(ink_drop(), - /*highlight_on_hover=*/false); - ink_drop()->SetCreateRippleCallback(base::BindRepeating( + InkDrop::UseInkDropWithoutAutoHighlight(InkDrop::Get(this), + /*highlight_on_hover=*/false); + InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](FrameCaptionButton* host) -> std::unique_ptr<views::InkDropRipple> { return std::make_unique<views::FloodFillInkDropRipple>( host->size(), host->GetInkdropInsets(host->size()), - host->ink_drop()->GetInkDropCenterBasedOnLastEvent(), - host->ink_drop()->GetBaseColor(), - host->ink_drop()->GetVisibleOpacity()); + InkDrop::Get(host)->GetInkDropCenterBasedOnLastEvent(), + InkDrop::Get(host)->GetBaseColor(), + InkDrop::Get(host)->GetVisibleOpacity()); }, this)); @@ -279,7 +280,7 @@ // the window is moving as a result of the animation from normal to // maximized state or vice versa. https://crbug.com/840901. cc::PaintFlags flags; - flags.setColor(ink_drop()->GetBaseColor()); + flags.setColor(InkDrop::Get(this)->GetBaseColor()); flags.setAlpha(highlight_alpha); DrawHighlight(canvas, flags); } @@ -349,7 +350,7 @@ // TODO(pkasting): It would likely be better to make the button glyph always // be an alpha-blended version of GetColorWithMaxContrast(background_color_). const SkColor button_color = GetButtonColor(background_color_); - ink_drop()->SetBaseColor( + InkDrop::Get(this)->SetBaseColor( GetColorWithMaxContrast(GetColorWithMaxContrast(button_color))); }
diff --git a/weblayer/BUILD.gn b/weblayer/BUILD.gn index 3441291..3ab8558 100644 --- a/weblayer/BUILD.gn +++ b/weblayer/BUILD.gn
@@ -385,7 +385,6 @@ "//base/third_party/dynamic_annotations", "//build:chromeos_buildflags", "//cc", - "//components/android_autofill/browser", "//components/autofill/content/browser", "//components/autofill/content/renderer", "//components/autofill/core/browser", @@ -665,7 +664,8 @@ deps += [ "//android_webview:generate_aw_resources", "//android_webview:generate_aw_strings", - "//components/android_autofill/android", + "//components/android_autofill/browser", + "//components/android_autofill/browser:android", "//components/android_system_error_page", "//components/browser_ui/client_certificate/android", "//components/browser_ui/contacts_picker/android", @@ -863,7 +863,7 @@ deps = [ ":weblayer_lib_webview_test", "//base", - "//components/android_autofill/android/test_support:component_autofill_provider_native_test_support", + "//components/android_autofill/browser/test_support:component_autofill_provider_native_test_support", "//content/public/app", "//weblayer/browser/java:test_weblayer_jni_registration", ]
diff --git a/weblayer/app/DEPS b/weblayer/app/DEPS index 6b8b33a..88501335 100644 --- a/weblayer/app/DEPS +++ b/weblayer/app/DEPS
@@ -2,6 +2,7 @@ "+components/autofill/core/common", "+components/content_capture/common", "+components/startup_metric_utils", + "+components/variations", "+components/version_info", "+components/viz/common", "+content/public",
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc index 8e42fd27..b7da58b 100644 --- a/weblayer/app/content_main_delegate_impl.cc +++ b/weblayer/app/content_main_delegate_impl.cc
@@ -20,6 +20,7 @@ #include "build/chromeos_buildflags.h" #include "components/content_capture/common/content_capture_features.h" #include "components/startup_metric_utils/browser/startup_metric_utils.h" +#include "components/variations/variations_ids_provider.h" #include "content/public/browser/browser_main_runner.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" @@ -247,6 +248,14 @@ #endif } +variations::VariationsIdsProvider* +ContentMainDelegateImpl::CreateVariationsIdsProvider() { + // As the embedder supplies the set of ids, the signed-in state does not make + // sense and is ignored. + return variations::VariationsIdsProvider::Create( + variations::VariationsIdsProvider::Mode::kIgnoreSignedInState); +} + void ContentMainDelegateImpl::PreSandboxStartup() { // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is // complete.
diff --git a/weblayer/app/content_main_delegate_impl.h b/weblayer/app/content_main_delegate_impl.h index cab456a..51f9bc9 100644 --- a/weblayer/app/content_main_delegate_impl.h +++ b/weblayer/app/content_main_delegate_impl.h
@@ -27,6 +27,7 @@ // ContentMainDelegate implementation: bool BasicStartupComplete(int* exit_code) override; bool ShouldCreateFeatureList() override; + variations::VariationsIdsProvider* CreateVariationsIdsProvider() override; void PreSandboxStartup() override; void PostEarlyInitialization(bool is_running_tests) override; int RunProcess(
diff --git a/weblayer/browser/DEPS b/weblayer/browser/DEPS index 10cd2933..20a4e5a 100644 --- a/weblayer/browser/DEPS +++ b/weblayer/browser/DEPS
@@ -1,6 +1,5 @@ include_rules = [ "+cc", - "+components/android_autofill/android", "+components/android_autofill/browser", "+components/autofill/content/browser", "+components/autofill/content/common",
diff --git a/weblayer/browser/browser_context_impl.cc b/weblayer/browser/browser_context_impl.cc index 4a933a9..0c91e66 100644 --- a/weblayer/browser/browser_context_impl.cc +++ b/weblayer/browser/browser_context_impl.cc
@@ -316,19 +316,17 @@ variations::mojom::VariationsHeadersPtr GetVariationsHeaders() const override { + // As the embedder supplies the set of ids, the signed-in state should be + // ignored. The value supplied (`is_signed_in`) doesn't matter as + // VariationsIdsProvider is configured to ignore the signed in state. + const bool is_signed_in = true; + DCHECK_EQ(variations::VariationsIdsProvider::Mode::kIgnoreSignedInState, + variations::VariationsIdsProvider::GetInstance()->mode()); return variations::VariationsIdsProvider::GetInstance() - ->GetClientDataHeaders(IsSignedIn()); + ->GetClientDataHeaders(is_signed_in); } private: - // Signed-in state shouldn't control the set of variations for WebLayer, - // so this always returns true. This is particularly experiment for - // registering external experiment ids, which are registered assuming - // signed-in. - // TODO(sky): this is rather misleading, and needs to be resolved. Figure - // out right long term solution. - bool IsSignedIn() const { return true; } - content::BrowserContext* browser_context_; };
diff --git a/weblayer/browser/java/BUILD.gn b/weblayer/browser/java/BUILD.gn index 689cc797..7778ccc 100644 --- a/weblayer/browser/java/BUILD.gn +++ b/weblayer/browser/java/BUILD.gn
@@ -199,7 +199,7 @@ ":weblayer_resources", "//base:base_java", "//cc:cc_java", - "//components/android_autofill/android:java", + "//components/android_autofill/browser:java", "//components/browser_ui/banners/android:java", "//components/browser_ui/bottomsheet/android:factory_java", "//components/browser_ui/bottomsheet/android:java", @@ -344,8 +344,8 @@ ":test_interfaces_java", ":weblayer_test_resources", "//base:base_java", - "//components/android_autofill/android:java", - "//components/android_autofill/android/test_support:component_autofill_provider_java_test_support", + "//components/android_autofill/browser:java", + "//components/android_autofill/browser/test_support:component_autofill_provider_java_test_support", "//components/content_capture/android:java", "//components/infobars/android:java", "//components/location/android:location_java",
diff --git a/weblayer/browser/tab_impl.cc b/weblayer/browser/tab_impl.cc index cfe0d8c..d6d1340 100644 --- a/weblayer/browser/tab_impl.cc +++ b/weblayer/browser/tab_impl.cc
@@ -15,8 +15,6 @@ #include "base/task/thread_pool.h" #include "base/time/default_tick_clock.h" #include "cc/layers/layer.h" -#include "components/android_autofill/browser/android_autofill_manager.h" -#include "components/android_autofill/browser/autofill_provider.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/common/autofill_features.h" #include "components/blocked_content/popup_blocker.h" @@ -103,7 +101,9 @@ #include "base/android/jni_string.h" #include "base/json/json_writer.h" #include "base/trace_event/trace_event.h" -#include "components/android_autofill/android/autofill_provider_android.h" +#include "components/android_autofill/browser/android_autofill_manager.h" +#include "components/android_autofill/browser/autofill_provider.h" +#include "components/android_autofill/browser/autofill_provider_android.h" #include "components/browser_ui/sms/android/sms_infobar.h" #include "components/download/content/public/context_menu_download.h" #include "components/embedder_support/android/contextmenu/context_menu_builder.h" @@ -1358,7 +1358,6 @@ base::android::AttachCurrentThread(), java_impl_, static_cast<int>(reason), static_cast<int>(constraint)); } -#endif void TabImpl::InitializeAutofillForTests() { InitializeAutofillDriver(); @@ -1375,7 +1374,6 @@ autofill::AutofillManager::AutofillDownloadManagerState enable_autofill_download_manager = autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER; -#if defined(OS_ANDROID) if (base::FeatureList::IsEnabled( autofill::features::kAndroidAutofillQueryServerFieldTypes) && (!autofill::AutofillProvider:: @@ -1383,7 +1381,6 @@ enable_autofill_download_manager = autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER; } -#endif // OS_ANDROID autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( web_contents, AutofillClientImpl::FromWebContents(web_contents), @@ -1391,6 +1388,8 @@ base::BindRepeating(&autofill::AndroidAutofillManager::Create)); } +#endif // defined(OS_ANDROID) + find_in_page::FindTabHelper* TabImpl::GetFindTabHelper() { return find_in_page::FindTabHelper::FromWebContents(web_contents_.get()); }
diff --git a/weblayer/browser/tab_impl.h b/weblayer/browser/tab_impl.h index 9fcca6a..0d203d6 100644 --- a/weblayer/browser/tab_impl.h +++ b/weblayer/browser/tab_impl.h
@@ -31,10 +31,6 @@ class JsCommunicationHost; } -namespace autofill { -class AutofillProvider; -} // namespace autofill - namespace blink { namespace web_pref { struct WebPreferences; @@ -240,8 +236,10 @@ // Executes |script| with a user gesture. void ExecuteScriptWithUserGestureForTests(const std::u16string& script); +#if defined(OS_ANDROID) // Initializes the autofill system for tests. void InitializeAutofillForTests(); +#endif // defined(OS_ANDROID) private: // content::WebContentsDelegate: @@ -343,8 +341,6 @@ void UpdateRendererPrefs(bool should_sync_prefs); - void InitializeAutofillDriver(); - // Returns the FindTabHelper for the page, or null if none exists. find_in_page::FindTabHelper* GetFindTabHelper(); @@ -352,6 +348,7 @@ content::WebContents* web_contents); #if defined(OS_ANDROID) + void InitializeAutofillDriver(); void SetBrowserControlsConstraint(ControlsVisibilityReason reason, cc::BrowserControlsState constraint); #endif
diff --git a/weblayer/public/browser_observer.h b/weblayer/public/browser_observer.h index 80e6dfea..ffa2188 100644 --- a/weblayer/public/browser_observer.h +++ b/weblayer/public/browser_observer.h
@@ -5,7 +5,7 @@ #ifndef WEBLAYER_PUBLIC_BROWSER_OBSERVER_H_ #define WEBLAYER_PUBLIC_BROWSER_OBSERVER_H_ -#include "base/observer_list.h" +#include "base/observer_list_types.h" namespace weblayer {
diff --git a/weblayer/public/browser_restore_observer.h b/weblayer/public/browser_restore_observer.h index 8f85de8..aeea62e 100644 --- a/weblayer/public/browser_restore_observer.h +++ b/weblayer/public/browser_restore_observer.h
@@ -5,7 +5,7 @@ #ifndef WEBLAYER_PUBLIC_BROWSER_RESTORE_OBSERVER_H_ #define WEBLAYER_PUBLIC_BROWSER_RESTORE_OBSERVER_H_ -#include "base/observer_list.h" +#include "base/observer_list_types.h" namespace weblayer {
diff --git a/weblayer/public/favicon_fetcher_delegate.h b/weblayer/public/favicon_fetcher_delegate.h index e5da5d3..35ce42d 100644 --- a/weblayer/public/favicon_fetcher_delegate.h +++ b/weblayer/public/favicon_fetcher_delegate.h
@@ -5,7 +5,7 @@ #ifndef WEBLAYER_PUBLIC_FAVICON_FETCHER_DELEGATE_H_ #define WEBLAYER_PUBLIC_FAVICON_FETCHER_DELEGATE_H_ -#include "base/observer_list.h" +#include "base/observer_list_types.h" namespace gfx { class Image;
diff --git a/weblayer/test/BUILD.gn b/weblayer/test/BUILD.gn index ce19220..de30e40e 100644 --- a/weblayer/test/BUILD.gn +++ b/weblayer/test/BUILD.gn
@@ -106,7 +106,6 @@ deps = [ "//base", "//base/test:test_support", - "//components/android_autofill/browser:test_support", "//components/autofill/core/browser", "//components/autofill/core/common", "//components/background_sync", @@ -159,7 +158,6 @@ sources = [ "../browser/ad_tagging_browsertest.cc", "../browser/ads_page_load_metrics_observer_browsertest.cc", - "../browser/autofill_browsertest.cc", "../browser/background_sync/background_sync_browsertest.cc", "../browser/client_hints_browsertest.cc", "../browser/clipboard_browsertest.cc", @@ -197,8 +195,6 @@ "interstitial_utils.h", "load_completion_observer.cc", "load_completion_observer.h", - "stub_autofill_provider.cc", - "stub_autofill_provider.h", "subresource_filter_browser_test_harness.cc", "subresource_filter_browser_test_harness.h", "test_launcher_delegate_impl.cc", @@ -220,6 +216,7 @@ "../browser/android/metrics/metrics_test_helper.cc", "../browser/android/metrics/metrics_test_helper.h", "../browser/android/metrics/ukm_browsertest.cc", + "../browser/autofill_browsertest.cc", "../browser/safe_browsing/client_side_detection_service_browsertest.cc", "../browser/safe_browsing/client_side_detection_service_factory_browsertest.cc", "../browser/safe_browsing/safe_browsing_browsertest.cc", @@ -227,6 +224,8 @@ "../shell/android/browsertests_apk/translate_test_bridge.cc", "../shell/android/browsertests_apk/translate_test_bridge.h", "../shell/android/browsertests_apk/weblayer_browser_tests_jni_onload.cc", + "stub_autofill_provider.cc", + "stub_autofill_provider.h", ] deps += [ ":weblayer_browsertests_java", @@ -235,6 +234,7 @@ "//android_webview:generate_aw_strings_grit", "//android_webview:locale_pak_assets", "//android_webview:pak_file_assets", + "//components/android_autofill/browser:test_support", "//components/infobars/core", "//components/metrics", "//components/page_info",
diff --git a/weblayer/test/weblayer_browser_test_utils.cc b/weblayer/test/weblayer_browser_test_utils.cc index 742107d4..60aa36c 100644 --- a/weblayer/test/weblayer_browser_test_utils.cc +++ b/weblayer/test/weblayer_browser_test_utils.cc
@@ -15,9 +15,12 @@ #include "weblayer/public/navigation_controller.h" #include "weblayer/public/tab.h" #include "weblayer/shell/browser/shell.h" -#include "weblayer/test/stub_autofill_provider.h" #include "weblayer/test/test_navigation_observer.h" +#if defined(OS_ANDROID) +#include "weblayer/test/stub_autofill_provider.h" +#endif // defined(OS_ANDROID) + namespace weblayer { namespace { @@ -89,6 +92,7 @@ return tab_impl->web_contents()->GetTitle(); } +#if defined(OS_ANDROID) void InitializeAutofillWithEventForwarding( Shell* shell, const base::RepeatingCallback<void(const autofill::FormData&)>& @@ -97,6 +101,7 @@ new StubAutofillProvider(tab_impl->web_contents(), on_received_form_data); tab_impl->InitializeAutofillForTests(); } +#endif // defined(OS_ANDROID) void ActivateSubresourceFilterInWebContentsForURL( content::WebContents* web_contents,
diff --git a/weblayer/test/weblayer_browser_test_utils.h b/weblayer/test/weblayer_browser_test_utils.h index a40f9330..08db0325 100644 --- a/weblayer/test/weblayer_browser_test_utils.h +++ b/weblayer/test/weblayer_browser_test_utils.h
@@ -10,6 +10,7 @@ #include "base/callback_forward.h" #include "base/run_loop.h" #include "base/values.h" +#include "build/build_config.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "weblayer/public/navigation.h" #include "weblayer/public/navigation_observer.h" @@ -62,12 +63,14 @@ /// Gets the title of the current webpage in |shell|. const std::u16string& GetTitle(Shell* shell); +#if defined(OS_ANDROID) // Sets up the autofill system to be one that simply forwards detected forms to // the passed-in callback. void InitializeAutofillWithEventForwarding( Shell* shell, const base::RepeatingCallback<void(const autofill::FormData&)>& on_received_form_data); +#endif // defined(OS_ANDROID) // Configures the subresource filter to activate on |url| in |web_contents|. void ActivateSubresourceFilterInWebContentsForURL(