diff --git a/DEPS b/DEPS index 6098ecd..b7b4065 100644 --- a/DEPS +++ b/DEPS
@@ -199,11 +199,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': 'd1b593f446d3ed532937dc3a3b39a8cf083d1f4d', + 'skia_revision': '6d4577bc520866b97ef3f03b1abe91fee1232ce0', # 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': 'bcfb0a5ada22d472155e73725ec23568f3bc9526', + 'v8_revision': 'ef6c61213b14d3cf31e97bbd314e1dda24794a0d', # 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. @@ -211,11 +211,11 @@ # 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': '220642a93da1a6e98b6e6c94f1c7767eb267bf58', + 'angle_revision': '938399865e720c2e37616cdad64109ef331bb035', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '1cc5b3357d2ff3c81ef7ec0b07a6660796bde5cd', + 'swiftshader_revision': 'ff29e249d3179766a40c9486183559fe3e5c1456', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -250,7 +250,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. - 'freetype_revision': '768022b98e45d343b540f83816fb65f549eac041', + 'freetype_revision': 'c6ff2556c8e6f3bb8370cf3f6113bf73a6d5d9a3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -274,7 +274,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': 'b5f42f1dedcae42fd546655c52fe4db8eef6765b', + 'devtools_frontend_revision': '88ae79312726562abb495497c6c6b44d883b7e37', # 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. @@ -314,11 +314,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. - 'dawn_revision': '0eb61724c8f115bc5f26bd9850f14a1dfcae4216', + 'dawn_revision': '86980018b3f2786aeb5ded1220ec94bc927fa6b2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': 'cfb206c8b38663bf10ec1ada85a3a4db2a7da632', + 'quiche_revision': '528c36b3cfd0110e56b1158f8f58d833817991e0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -411,7 +411,7 @@ 'src/buildtools/mac': { 'packages': [ { - 'package': 'gn/gn/mac-amd64', + 'package': 'gn/gn/mac-${{arch}}', 'version': Var('gn_version'), } ], @@ -553,7 +553,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '8bd8b295e227310a8c835ec9d3f58ca3b651319a', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '3bc7339b7a8e834a661de78fe3ae9805468f5259', 'condition': 'checkout_ios', }, @@ -873,7 +873,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' + '@' + '2813dd74be3425790790e5dcfddca5fe05f43fe1', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '650c95ac2394b19dfab665a7d32cd16cd4685f02', 'condition': 'checkout_chromeos', }, @@ -893,7 +893,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3b39cefc6195f782b655e2c73ac2a73313c28879', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '364205c70ed16c00802b1c264e88d8e03a0b37ae', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1262,7 +1262,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '6005f1179a65bd5e6c63b224a6aaa6ed7b18deeb', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'ecce47e1955f9dd366f9d18b7759de225d54fae6', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1433,7 +1433,7 @@ Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + 'ea368c2f07de5f31146a10214f27d15091b09771', 'src/third_party/sqlite/src': - Var('chromium_git') + '/chromium/deps/sqlite.git' + '@' + '0324bd3ef1af08b478c9e9f82722d7e1e565d6bc', + Var('chromium_git') + '/chromium/deps/sqlite.git' + '@' + 'd9581878fcf81ec8beda15b079726edaddd775bb', 'src/third_party/sqlite4java': { 'packages': [ @@ -1514,7 +1514,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3c2fe3888658d82b47ca831d59a2e07579619c2d', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '1f0df96659aeb6447d5d8959c114f3212fc1ca04', + Var('webrtc_git') + '/src.git' + '@' + '5d2bf19be865c19ae09b21b32771ccda3c95eda0', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1552,7 +1552,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': 'Ac-h0vLh65FkA8CAYh5B6yg9X0l3cJFf5XCZkVByG1AC', + 'version': 'h8KxWs4p5Ox0HAM1_xkOEZT6ctPb1Rfi3qeXr_mmL2YC', }, ], 'dep_type': 'cipd', @@ -1562,7 +1562,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': 'HHMFtoVyIQfQIhJgSOb5RkIHwzApVNZXRtDNjBCx3tEC', + 'version': 'uyDrAODdxxnyC-OmE4swqMJGVNnO4tK6XpC4VfbZf-gC', }, ], 'dep_type': 'cipd', @@ -1572,7 +1572,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': 'NYEeKAWq6p8n1jHl0h3emCE3hdfWkaYbeoEPrnFO5dEC', + 'version': 'LNZgcy3MnDuxTfNU14P35CMe60eSA5owlqW81AdRROIC', }, ], 'dep_type': 'cipd', @@ -1586,7 +1586,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@41dde25e96c533f6065ea31f405c021a8ea739c1', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@11c7d845479b0470bdc4bae1f39f8f87d696371b', 'condition': 'checkout_src_internal', }, @@ -1594,7 +1594,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'nmFhO5_ZTTtPNJGhEylXtJ4sG_lvSsW7CgsI4mn7xzoC', + 'version': 'lS1l7jMzRb6bzoO6vbP1ZMBpvEEYJKB60YS3L7IJrb8C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1605,7 +1605,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'KIiRm3KFqXZdpUq3U-M9LOzTpV0pmYVBi7D66Yc6yhwC', + 'version': 'gYicacAmlNBTfmj5bqOqzRfHBhSEG6KBAY2UtDyAakQC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1909,7 +1909,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/androidx_documentfile_documentfile', - 'version': 'version:1.0.0-cr0', + 'version': 'version:1.1.0-SNAPSHOT-cr0', }, ], 'condition': 'checkout_android', @@ -2019,7 +2019,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils', - 'version': 'version:1.0.0-cr0', + 'version': 'version:1.1.0-SNAPSHOT-cr0', }, ], 'condition': 'checkout_android', @@ -2118,7 +2118,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/androidx_loader_loader', - 'version': 'version:1.0.0-cr0', + 'version': 'version:1.2.0-SNAPSHOT-cr0', }, ], 'condition': 'checkout_android', @@ -2195,7 +2195,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/androidx_print_print', - 'version': 'version:1.0.0-cr0', + 'version': 'version:1.1.0-SNAPSHOT-cr0', }, ], 'condition': 'checkout_android',
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index e8ef0b8f..3ac4c6e 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1217,7 +1217,13 @@ <message name="IDS_ASH_PHONE_HUB_SILENCE_BUTTON_NOT_AVAILABLE_TOOLTIP" desc="Tooltip message that indicates to the user that the Silence Phone feature is disabled because their phone is on a work profile."> Silence phone is not available on work profile </message> - + <message name="IDS_ASH_PHONE_HUB_LOCATE_BUTTON_NOT_AVAILABLE_TOOLTIP" desc="Tooltip message that indicates to the user that Phone Hub's 'Locate phone' feature is not available because the user disabled alarms that make sounds on their phone."> + Locate phone is not available when alarm sounds are disabled + </message> + <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_STYLUS_BATTERY_LOW_LABEL"> Low </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_NO_RECEPTION_STATE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_NO_RECEPTION_STATE_TOOLTIP.png.sha1 new file mode 100644 index 0000000..065b09f --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_NO_RECEPTION_STATE_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +fdb1d2ad6dd867d78bbd82b81cfd20cf7da69ac6 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_LOCATE_BUTTON_NOT_AVAILABLE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_LOCATE_BUTTON_NOT_AVAILABLE_TOOLTIP.png.sha1 new file mode 100644 index 0000000..834b4364 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_LOCATE_BUTTON_NOT_AVAILABLE_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +d7fa90d6f286617baaaef959c781bab2d64f43ad \ No newline at end of file
diff --git a/ash/login/ui/login_auth_user_view_unittest.cc b/ash/login/ui/login_auth_user_view_unittest.cc index ccbf363..5d31f342 100644 --- a/ash/login/ui/login_auth_user_view_unittest.cc +++ b/ash/login/ui/login_auth_user_view_unittest.cc
@@ -56,17 +56,14 @@ } // namespace -class LoginAuthUserViewUnittest - : public LoginTestBase, - /*<autosubmit_feature, display_password_feature>*/ - public ::testing::WithParamInterface<std::tuple<bool, bool>> { +class LoginAuthUserViewUnittest : public LoginTestBase, + /*autosubmit_feature*/ + public ::testing::WithParamInterface<bool> { public: static std::string ParamInfoToString( testing::TestParamInfo<LoginAuthUserViewUnittest::ParamType> info) { return base::StrCat( - {std::get<0>(info.param) ? "AutosubmitEnabled" : "AutosubmitDisabled", - std::get<1>(info.param) ? "DisplayPasswordEnabled" - : "DisplayPasswordDisabled"}); + {info.param ? "AutosubmitEnabled" : "AutosubmitDisabled"}); } protected: @@ -98,18 +95,14 @@ } void SetUpFeatures() { - auto param = GetParam(); - autosubmit_feature_enabled_ = std::get<0>(param); - display_password_feature_enabled_ = std::get<1>(param); - std::vector<base::Feature> enabled; - std::vector<base::Feature> disabled; - autosubmit_feature_enabled_ - ? enabled.push_back(chromeos::features::kQuickUnlockPinAutosubmit) - : disabled.push_back(chromeos::features::kQuickUnlockPinAutosubmit); - display_password_feature_enabled_ - ? enabled.push_back(chromeos::features::kLoginDisplayPasswordButton) - : disabled.push_back(chromeos::features::kLoginDisplayPasswordButton); - feature_list_.InitWithFeatures(enabled, disabled); + autosubmit_feature_enabled_ = GetParam(); + if (autosubmit_feature_enabled_) { + feature_list_.InitWithFeatures( + {chromeos::features::kQuickUnlockPinAutosubmit}, {}); + } else { + feature_list_.InitWithFeatures( + {}, {chromeos::features::kQuickUnlockPinAutosubmit}); + } } void SetAuthMethods(uint32_t auth_methods, @@ -144,9 +137,8 @@ EXPECT_EQ(test.pin_password_toggle()->GetVisible(), visibility.toggle); } - // Initialized by test parameters in `SetUpFeatures` + // Initialized by test parameter in `SetUpFeatures` bool autosubmit_feature_enabled_ = false; - bool display_password_feature_enabled_ = false; base::test::ScopedFeatureList feature_list_; LoginUserInfo user_; @@ -315,16 +307,14 @@ view_->UpdateForUser(another_user); EXPECT_TRUE(password_test.textfield()->GetText().empty()); - if (display_password_feature_enabled_) { - password_test.textfield()->SetTextInputType(ui::TEXT_INPUT_TYPE_NULL); - EXPECT_EQ(password_test.textfield()->GetTextInputType(), - ui::TEXT_INPUT_TYPE_NULL); + password_test.textfield()->SetTextInputType(ui::TEXT_INPUT_TYPE_NULL); + EXPECT_EQ(password_test.textfield()->GetTextInputType(), + ui::TEXT_INPUT_TYPE_NULL); - // Updating user should make the textfield as a password again. - view_->UpdateForUser(user_); - EXPECT_EQ(password_test.textfield()->GetTextInputType(), - ui::TEXT_INPUT_TYPE_PASSWORD); - } + // Updating user should make the textfield as a password again. + view_->UpdateForUser(user_); + EXPECT_EQ(password_test.textfield()->GetTextInputType(), + ui::TEXT_INPUT_TYPE_PASSWORD); } // Tests the correctness of InputFieldMode::NONE @@ -457,11 +447,9 @@ } } -INSTANTIATE_TEST_SUITE_P( - LoginAuthUserViewTests, - LoginAuthUserViewUnittest, - testing::Combine(testing::Bool(), // Display password feature - testing::Bool()), // PIN autosubmit feature - LoginAuthUserViewUnittest::ParamInfoToString); +INSTANTIATE_TEST_SUITE_P(LoginAuthUserViewTests, + LoginAuthUserViewUnittest, + testing::Bool(), // PIN autosubmit feature + LoginAuthUserViewUnittest::ParamInfoToString); } // namespace ash
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc index ee4dc321d..d00bfe98 100644 --- a/ash/login/ui/login_password_view.cc +++ b/ash/login/ui/login_password_view.cc
@@ -21,7 +21,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/timer/timer.h" -#include "chromeos/constants/chromeos_features.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" @@ -111,12 +110,13 @@ constexpr const int kPasswordRowFocusRingRadiusDp = 6; -// Clears the password after some time if no action has been done and the -// display password feature is enabled, for security reasons. +// Delay after which the password gets cleared if nothing has been typed. It is +// only effective if the display password button is shown, as there is no +// potential security threat otherwise. constexpr base::TimeDelta kClearPasswordAfterDelay = base::TimeDelta::FromSeconds(30); -// Hides the password after a short delay for security reasons. +// Delay after which the password gets back to hidden state, for security. constexpr base::TimeDelta kHidePasswordAfterDelay = base::TimeDelta::FromSeconds(5); @@ -532,9 +532,7 @@ } LoginPasswordView::LoginPasswordView(const LoginPalette& palette) - : is_display_password_feature_enabled_( - chromeos::features::IsLoginDisplayPasswordButtonEnabled()), - clear_password_timer_(std::make_unique<base::RetainingOneShotTimer>()), + : clear_password_timer_(std::make_unique<base::RetainingOneShotTimer>()), hide_password_timer_(std::make_unique<base::RetainingOneShotTimer>()), palette_(palette) { Shell::Get()->ime_controller()->AddObserver(this); @@ -590,16 +588,13 @@ // OnCapsLockChanged with the actual caps lock state. capslock_icon_->SetVisible(false); - if (is_display_password_feature_enabled_) { - display_password_button_ = - password_row_->AddChildView(std::make_unique<DisplayPasswordButton>( - palette_, base::BindRepeating( - [](LoginPasswordView* view) { - if (view->is_display_password_feature_enabled_) - view->InvertPasswordDisplayingState(); - }, - this))); - } + display_password_button_ = + password_row_->AddChildView(std::make_unique<DisplayPasswordButton>( + palette_, base::BindRepeating( + [](LoginPasswordView* view) { + view->InvertPasswordDisplayingState(); + }, + this))); submit_button_ = AddChildView(std::make_unique<ArrowButtonView>( base::BindRepeating(&LoginPasswordView::SubmitPassword, @@ -672,8 +667,6 @@ } void LoginPasswordView::SetDisplayPasswordButtonVisible(bool visible) { - if (!is_display_password_feature_enabled_) - return; display_password_button_->SetVisible(visible); // Only start the timer if the display password button is enabled. if (visible) { @@ -686,11 +679,9 @@ void LoginPasswordView::Reset() { Clear(); - if (is_display_password_feature_enabled_) { - // A user could hit the display button, then quickly switch account and - // type; we want the password to be hidden in such a case. - HidePassword(false /*chromevox_exception*/); - } + // A user could hit the display button, then quickly switch account and + // type; we want the password to be hidden in such a case. + HidePassword(false /*chromevox_exception*/); } void LoginPasswordView::Clear() { @@ -787,13 +778,11 @@ textfield_->UpdateFontListAndCursor(); on_password_text_changed_.Run(new_contents.empty() /*is_empty*/); - if (!is_display_password_feature_enabled_) - return; - // If the password is currently revealed. if (textfield_->GetTextInputType() == ui::TEXT_INPUT_TYPE_NULL) hide_password_timer_->Reset(); - // The feature could be enabled on the device but disabled for this user by policy. + + // The display password button could be hidden by user policy. if (display_password_button_->GetVisible()) clear_password_timer_->Reset(); } @@ -833,9 +822,6 @@ if (!enable_buttons && submit_button_->HasFocus()) RequestFocus(); submit_button_->SetEnabled(enable_buttons); - - if (!is_display_password_feature_enabled_) - return; display_password_button_->SetEnabled(enable_buttons); }
diff --git a/ash/login/ui/login_password_view.h b/ash/login/ui/login_password_view.h index 42d1060..770ba443 100644 --- a/ash/login/ui/login_password_view.h +++ b/ash/login/ui/login_password_view.h
@@ -28,21 +28,21 @@ enum class EasyUnlockIconId; // Contains a textfield and a submit button. When the display password button -// feature is enabled, the textfield contains a button in the form of an eye -// icon that the user can click on to reveal the password. Submitting a password -// will make it read only and prevent further submissions until the controller -// sets ReadOnly to false again. +// is visible, the textfield contains a button in the form of an eye icon that +// the user can click on to reveal the password. Submitting a password will +// make it read only and prevent further submissions until the controller sets +// ReadOnly to false again. // // This view is always rendered via layers. // // -// When the display password button feature is disabled, the password view looks +// When the display password button is hidden, the password view looks // like this: // // * * * * * * (=>) // ------------------ // -// When the display password button feature is enabled, the password view looks +// When the display password button is visible, the password view looks // like this by default: // // * * * * * * (\) (=>) @@ -86,8 +86,8 @@ explicit LoginPasswordView(const LoginPalette& palette); ~LoginPasswordView() override; - // |on_submit| is called when the user hits enter (or pressed the submit arrow - // when the display password button feature is disabled). + // |on_submit| is called when the user hits enter or has pressed the submit + // arrow. // |on_password_text_changed| is called when the text in the password field // changes. void Init(const OnPasswordSubmit& on_submit, @@ -105,9 +105,8 @@ // Set the textfield name used for accessibility. void SetAccessibleName(const base::string16& name); - // Enable or disable focus on the child elements (i.e.: password field, and - // submit button if the display password button feature is disabled, or - // display password button if the feature is enabled). + // Enable or disable focus on the child elements (i.e.: password field and + // submit button, or display password button if it is shown). void SetFocusEnabledForTextfield(bool enable); // Sets whether the display password button is visible. @@ -130,8 +129,7 @@ // itself because it doesn't know which auth methods are enabled. void SetPlaceholderText(const base::string16& placeholder_text); - // Makes the textfield read-only, and enables/disables submitting if the - // display password button feature is disabled. + // Makes the textfield read-only and enables/disables submitting. void SetReadOnly(bool read_only); // views::View: @@ -182,21 +180,18 @@ // textfield is not empty or if |enabled_on_empty_password| is true. bool IsPasswordSubmittable(); - // When the display password button feature is disabled, UpdateUiState - // enables/disables the submit button. + // UpdateUiState enables/disables the submit button, and the display password + // button when it is visible. void UpdateUiState(); OnPasswordSubmit on_submit_; OnPasswordTextChanged on_password_text_changed_; - // True if the display password button feature is enabled. - const bool is_display_password_feature_enabled_; - // Is the password field enabled when there is no text? bool enabled_on_empty_password_ = false; // Clears the password field after a time without action if the display - // password feature is enabled. + // password button is visible. std::unique_ptr<base::RetainingOneShotTimer> clear_password_timer_; // Hides the password after a short delay if the password is shown, except if
diff --git a/ash/login/ui/login_password_view_test.cc b/ash/login/ui/login_password_view_test.cc index c2abb185..6d9bbbd 100644 --- a/ash/login/ui/login_password_view_test.cc +++ b/ash/login/ui/login_password_view_test.cc
@@ -10,9 +10,7 @@ #include "ash/shell.h" #include "base/bind.h" #include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_feature_list.h" #include "base/timer/mock_timer.h" -#include "chromeos/constants/chromeos_features.h" #include "ui/base/ime/text_input_type.h" #include "ui/events/event_constants.h" #include "ui/events/test/event_generator.h" @@ -66,23 +64,6 @@ DISALLOW_COPY_AND_ASSIGN(LoginPasswordViewTest); }; -// LoginPasswordViewTest with display password button feature enabled. -class LoginPasswordViewTestFeatureEnabled : public LoginPasswordViewTest { - protected: - LoginPasswordViewTestFeatureEnabled() { - feature_list_.InitWithFeatures( - {chromeos::features::kLoginDisplayPasswordButton}, {}); - } - LoginPasswordViewTestFeatureEnabled( - const LoginPasswordViewTestFeatureEnabled&) = delete; - LoginPasswordViewTestFeatureEnabled& operator=( - const LoginPasswordViewTestFeatureEnabled&) = delete; - ~LoginPasswordViewTestFeatureEnabled() override = default; - - private: - base::test::ScopedFeatureList feature_list_; -}; - } // namespace // Verifies that the submit button updates its UI state. @@ -122,8 +103,7 @@ } // Verifies that the display password button updates its UI state. -TEST_F(LoginPasswordViewTestFeatureEnabled, - DisplayPasswordButtonUpdatesUiState) { +TEST_F(LoginPasswordViewTest, DisplayPasswordButtonUpdatesUiState) { LoginPasswordView::TestApi test_api(view_); ui::test::EventGenerator* generator = GetEventGenerator(); @@ -312,7 +292,7 @@ // Verifies that the password textfield clears after a delay when the display // password button is shown. -TEST_F(LoginPasswordViewTestFeatureEnabled, PasswordAutoClearsAndHides) { +TEST_F(LoginPasswordViewTest, PasswordAutoClearsAndHides) { LoginPasswordView::TestApi test_api(view_); ui::test::EventGenerator* generator = GetEventGenerator(); @@ -356,8 +336,7 @@ // Verifies that the password textfield remains in the same visibility state // when the content changes. -TEST_F(LoginPasswordViewTestFeatureEnabled, - ContentChangesDoNotImpactPasswordVisibility) { +TEST_F(LoginPasswordViewTest, ContentChangesDoNotImpactPasswordVisibility) { LoginPasswordView::TestApi test_api(view_); ui::test::EventGenerator* generator = GetEventGenerator(); @@ -398,7 +377,7 @@ // Checks that the display password button is disabled when the textfield is // empty and enabled when it is not. -TEST_F(LoginPasswordViewTestFeatureEnabled, +TEST_F(LoginPasswordViewTest, DisplayPasswordButonIsEnabledIFFTextfieldIsNotEmpty) { LoginPasswordView::TestApi test_api(view_); ui::test::EventGenerator* generator = GetEventGenerator(); @@ -432,7 +411,7 @@ } // Verifies that focus returned to the textfield after InsertNumber is called. -TEST_F(LoginPasswordViewTestFeatureEnabled, FocusReturn) { +TEST_F(LoginPasswordViewTest, FocusReturn) { LoginPasswordView::TestApi test_api(view_); ui::test::EventGenerator* generator = GetEventGenerator(); // Verify that focus is returned to view after the number insertion.
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 49ae3e60..5aed96a 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -362,6 +362,7 @@ "app_list/app_list_config_provider_unittest.cc", "default_scale_factor_retriever_unittest.cc", "file_icon_util_unittest.cc", + "holding_space/holding_space_image_unittest.cc", "holding_space/holding_space_item_unittest.cc", "metrics_util_unittest.cc", "pagination/pagination_model_unittest.cc",
diff --git a/ash/public/cpp/holding_space/holding_space_image.cc b/ash/public/cpp/holding_space/holding_space_image.cc index 5544851..40406339 100644 --- a/ash/public/cpp/holding_space/holding_space_image.cc +++ b/ash/public/cpp/holding_space/holding_space_image.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/location.h" #include "ui/gfx/image/image_skia_source.h" #include "ui/gfx/skia_util.h" @@ -17,12 +18,9 @@ class HoldingSpaceImage::ImageSkiaSource : public gfx::ImageSkiaSource { public: - ImageSkiaSource(const base::WeakPtr<HoldingSpaceImage>& owner, - const gfx::ImageSkia& placeholder, - AsyncBitmapResolver async_bitmap_resolver) - : owner_(owner), - placeholder_(placeholder), - async_bitmap_resolver_(async_bitmap_resolver) {} + ImageSkiaSource(const base::WeakPtr<HoldingSpaceImage>& host, + const gfx::ImageSkia& placeholder) + : host_(host), placeholder_(placeholder) {} ImageSkiaSource(const ImageSkiaSource&) = delete; ImageSkiaSource& operator=(const ImageSkiaSource&) = delete; @@ -31,45 +29,26 @@ private: // gfx::ImageSkiaSource: gfx::ImageSkiaRep GetImageForScale(float scale) override { - // Use a cached representation when possible. - if (base::Contains(cache_, scale)) - return cache_[scale].GetRepresentation(scale); - - // When missing the cache, asynchronously resolve the bitmap for `scale`. - async_bitmap_resolver_.Run( - gfx::ScaleToCeiledSize(placeholder_.size(), scale), scale, - base::BindOnce(&ImageSkiaSource::CacheImageForScale, - weak_factory_.GetWeakPtr(), scale)); + if (host_) + host_->LoadBitmap(scale); // Use `placeholder_` while we wait for the async bitmap to resolve. return placeholder_.GetRepresentation(scale); } - void CacheImageForScale(float scale, const SkBitmap* bitmap) { - if (bitmap) { - cache_[scale].AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale)); - if (owner_) - owner_->NotifyUpdated(scale); - } - } - - const base::WeakPtr<HoldingSpaceImage> owner_; + const base::WeakPtr<HoldingSpaceImage> host_; const gfx::ImageSkia placeholder_; - AsyncBitmapResolver async_bitmap_resolver_; - std::map<float, gfx::ImageSkia> cache_; - - base::WeakPtrFactory<ImageSkiaSource> weak_factory_{this}; }; // HoldingSpaceImage ----------------------------------------------------------- -HoldingSpaceImage::HoldingSpaceImage( - const gfx::ImageSkia& placeholder, - AsyncBitmapResolver async_bitmap_resolver) { - image_skia_ = gfx::ImageSkia( - std::make_unique<ImageSkiaSource>(/*owner=*/weak_factory_.GetWeakPtr(), - placeholder, async_bitmap_resolver), - placeholder.size()); +HoldingSpaceImage::HoldingSpaceImage(const base::FilePath& backing_file_path, + const gfx::ImageSkia& placeholder, + AsyncBitmapResolver async_bitmap_resolver) + : backing_file_path_(backing_file_path), + placeholder_(placeholder), + async_bitmap_resolver_(async_bitmap_resolver) { + CreateImageSkia(); } HoldingSpaceImage::~HoldingSpaceImage() = default; @@ -83,12 +62,82 @@ return callback_list_.Add(std::move(callback)); } -void HoldingSpaceImage::NotifyUpdated(float scale) { +void HoldingSpaceImage::LoadBitmap(float scale) { + async_bitmap_resolver_.Run( + backing_file_path_, gfx::ScaleToCeiledSize(image_skia_.size(), scale), + scale, + base::BindOnce(&HoldingSpaceImage::OnBitmapLoaded, + weak_factory_.GetWeakPtr(), backing_file_path_, scale)); +} + +void HoldingSpaceImage::OnBitmapLoaded(const base::FilePath& file_path, + float scale, + const SkBitmap* bitmap) { + if (!bitmap) { + // Retry load if the backing file path has changed while the image load was + // in progress. + if (backing_file_path_ != file_path) + LoadBitmap(scale); + return; + } + // Force invalidate `image_skia_` for `scale` so that it will request the // updated `gfx::ImageSkiaRep` at next access. image_skia_.RemoveRepresentation(scale); + image_skia_.AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale)); image_skia_.RemoveUnsupportedRepresentationsForScale(scale); + + // Update the placeholder image, so the newly loaded representation becomes + // the default for any `ImageSkia` instances created when the holding space + // image gets invalidated. + placeholder_.RemoveRepresentation(scale); + placeholder_.AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale)); + placeholder_.RemoveUnsupportedRepresentationsForScale(scale); + callback_list_.Notify(); } +void HoldingSpaceImage::Invalidate() { + if (invalidate_timer_.IsRunning()) + return; + + // Schedule an invalidation task with a delay to reduce number of image loads + // when multiple image invalidations are requested in quick succession. The + // delay is selected somewhat arbitrarily to be non trivial but still not + // easily noticable by the user. + invalidate_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(250), + base::BindOnce(&HoldingSpaceImage::OnInvalidateTimer, + base::Unretained(this))); +} + +void HoldingSpaceImage::UpdateBackingFilePath(const base::FilePath& file_path) { + backing_file_path_ = file_path; +} + +bool HoldingSpaceImage::FireInvalidateTimerForTesting() { + if (!invalidate_timer_.IsRunning()) + return false; + invalidate_timer_.FireNow(); + return true; +} + +void HoldingSpaceImage::OnInvalidateTimer() { + // Invalidate the existing pointers to: + // * Invalidate previous `image_skia_`'s host pointer, and prevent it from + // requesting bitmap loads. + // * Prevent pending bitmap request callbacks from running. + weak_factory_.InvalidateWeakPtrs(); + + CreateImageSkia(); + + callback_list_.Notify(); +} + +void HoldingSpaceImage::CreateImageSkia() { + image_skia_ = + gfx::ImageSkia(std::make_unique<ImageSkiaSource>( + /*host=*/weak_factory_.GetWeakPtr(), placeholder_), + placeholder_.size()); +} + } // namespace ash
diff --git a/ash/public/cpp/holding_space/holding_space_image.h b/ash/public/cpp/holding_space/holding_space_image.h index ceb2c1a..436372e9 100644 --- a/ash/public/cpp/holding_space/holding_space_image.h +++ b/ash/public/cpp/holding_space/holding_space_image.h
@@ -10,6 +10,7 @@ #include "ash/public/cpp/ash_public_export.h" #include "base/callback_forward.h" #include "base/callback_list.h" +#include "base/timer/timer.h" #include "ui/gfx/image/image_skia.h" namespace ash { @@ -23,10 +24,14 @@ using BitmapCallback = base::OnceCallback<void(const SkBitmap*)>; // Returns a bitmap asynchronously for a given size. - using AsyncBitmapResolver = base::RepeatingCallback< - void(const gfx::Size&, float scale_factor, BitmapCallback)>; + using AsyncBitmapResolver = + base::RepeatingCallback<void(const base::FilePath& file_path, + const gfx::Size&, + float scale_factor, + BitmapCallback)>; - HoldingSpaceImage(const gfx::ImageSkia& placeholder, + HoldingSpaceImage(const base::FilePath& backing_file_path, + const gfx::ImageSkia& placeholder, AsyncBitmapResolver async_bitmap_resolver); HoldingSpaceImage(const HoldingSpaceImage&) = delete; HoldingSpaceImage& operator=(const HoldingSpaceImage&) = delete; @@ -42,13 +47,48 @@ // dynamically updated, so UI classes should observe and react to updates. const gfx::ImageSkia& image_skia() const { return image_skia_; } + // Creates new image skia for the item, and thus invalidates currently loaded + // representation. When the image is requested next time, the image + // representations will be reloaded. + void Invalidate(); + + // Updates the backing file path that should be used to generate image + // representations for the item. The method will *not* invalidate previously + // loaded image representations - it assumes that the file contents remained + // the same, and old representations are thus still valid. + void UpdateBackingFilePath(const base::FilePath& file_path); + + bool FireInvalidateTimerForTesting(); + private: class ImageSkiaSource; - void NotifyUpdated(float scale); + // Requests a load for the image representation for the provided scale. + void LoadBitmap(float scale); + + // Response to an image representation load request. + void OnBitmapLoaded(const base::FilePath& file_path, + float scale, + const SkBitmap* bitmap); + + // Creates `image_skia_` to be used for the holding space image. + // If `image_skia_` already exists, it will be recreated with a fresh image + // source. + void CreateImageSkia(); + + // `Invalidate()` requests are handled with a delay to reduce number of image + // loads if the backing file gets updated multiple times in quick succession. + void OnInvalidateTimer(); + + base::FilePath backing_file_path_; + gfx::ImageSkia placeholder_; + AsyncBitmapResolver async_bitmap_resolver_; gfx::ImageSkia image_skia_; + // Timer used to throttle image invalidate requests. + base::OneShotTimer invalidate_timer_; + // Mutable to allow const access from `AddImageSkiaChangedCallback()`. mutable CallbackList callback_list_;
diff --git a/ash/public/cpp/holding_space/holding_space_image_unittest.cc b/ash/public/cpp/holding_space/holding_space_image_unittest.cc new file mode 100644 index 0000000..cb3487c --- /dev/null +++ b/ash/public/cpp/holding_space/holding_space_image_unittest.cc
@@ -0,0 +1,922 @@ +// 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 "ash/public/cpp/holding_space/holding_space_image.h" + +#include <memory> +#include <utility> +#include <vector> + +#include "ash/public/cpp/holding_space/holding_space_item.h" +#include "base/bind.h" +#include "base/memory/weak_ptr.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_unittest_util.h" + +namespace ash { + +namespace { + +SkBitmap CreateBitmap(int width, int height, SkColor color) { + SkBitmap bitmap; + bitmap.allocN32Pixels(width, height); + bitmap.eraseColor(color); + return bitmap; +} + +gfx::ImageSkia CreateImageSkia(int width, int height, SkColor color) { + return gfx::ImageSkia::CreateFrom1xBitmap(CreateBitmap(width, height, color)); +} + +// Helper class that provides a test implementation for the async bitmap +// resolver callback used to generate holding space image representations. +class ImageGenerator { + public: + ImageGenerator() = default; + ImageGenerator(const ImageGenerator&) = delete; + ImageGenerator& operator=(const ImageGenerator&) = delete; + ~ImageGenerator() = default; + + HoldingSpaceImage::AsyncBitmapResolver CreateResolverCallback() { + return base::BindRepeating(&ImageGenerator::GenerateImage, + weak_factory_.GetWeakPtr()); + } + + void GenerateImage(const base::FilePath& file_path, + const gfx::Size& size, + float scale, + HoldingSpaceImage::BitmapCallback callback) { + auto request = std::make_unique<PendingRequest>(); + request->file_path = file_path; + request->size = size; + request->callback = std::move(callback); + pending_requests_.push_back(std::move(request)); + } + + size_t NumberOfPendingRequests() const { return pending_requests_.size(); } + + const base::FilePath& GetPendingRequestFilePath(size_t index) const { + if (index >= pending_requests_.size()) { + ADD_FAILURE() << "Invalid index " << index; + static base::FilePath kEmptyPath; + return kEmptyPath; + } + return pending_requests_[index]->file_path; + } + + void FulfillRequest(size_t index, SkColor color) { + ASSERT_LT(index, pending_requests_.size()); + + auto it = pending_requests_.begin() + index; + SkBitmap result = + CreateBitmap((*it)->size.width(), (*it)->size.height(), color); + HoldingSpaceImage::BitmapCallback callback = std::move((*it)->callback); + + pending_requests_.erase(it); + + std::move(callback).Run(&result); + } + + void FailRequest(size_t index) { + ASSERT_LT(index, pending_requests_.size()); + + auto it = pending_requests_.begin() + index; + HoldingSpaceImage::BitmapCallback callback = std::move((*it)->callback); + pending_requests_.erase(it); + + std::move(callback).Run(nullptr); + } + + private: + struct PendingRequest { + base::FilePath file_path; + gfx::Size size; + HoldingSpaceImage::BitmapCallback callback; + }; + + std::vector<std::unique_ptr<PendingRequest>> pending_requests_; + + base::WeakPtrFactory<ImageGenerator> weak_factory_{this}; +}; + +// Helper class that keeps track of how many times an holding space image has +// been updated, and requests an image representation after each image update. +class TestImageClient { + public: + explicit TestImageClient(const HoldingSpaceImage* image) : image_(image) { + image_subscription_ = image_->AddImageSkiaChangedCallback( + base::BindRepeating(&TestImageClient::OnHoldingSpaceItemImageChanged, + base::Unretained(this))); + image_->image_skia().GetRepresentation(1.0f); + } + + void OnHoldingSpaceItemImageChanged() { + image_->image_skia().GetRepresentation(1.0f); + ++image_change_count_; + } + + size_t GetAndResetImageChangeCount() { + size_t result = image_change_count_; + image_change_count_ = 0; + return result; + } + + private: + const HoldingSpaceImage* const image_; + base::CallbackListSubscription image_subscription_; + size_t image_change_count_ = 0; +}; + +std::unique_ptr<HoldingSpaceItem> CreateTestItem( + const base::FilePath& file_path, + ImageGenerator* image_generator, + int image_size, + SkColor image_color) { + const GURL file_system_url("filesystem:file_system_url"); + gfx::ImageSkia placeholder( + CreateImageSkia(image_size, image_size, image_color)); + placeholder.AddRepresentation(gfx::ImageSkiaRep( + CreateBitmap(image_size * 2, image_size * 2, image_color), 2)); + + return HoldingSpaceItem::CreateFileBackedItem( + HoldingSpaceItem::Type::kPinnedFile, file_path, file_system_url, + base::BindLambdaForTesting([&](HoldingSpaceItem::Type type, + const base::FilePath& file_path) { + return std::make_unique<HoldingSpaceImage>( + file_path, placeholder, image_generator->CreateResolverCallback()); + })); +} + +} // namespace + +class HoldingSpaceImageTest : public ::testing::Test { + public: + HoldingSpaceImageTest() = default; + HoldingSpaceImageTest(const HoldingSpaceImageTest&) = delete; + HoldingSpaceImageTest& operator=(const HoldingSpaceImageTest&) = delete; + ~HoldingSpaceImageTest() override = default; + + private: + base::test::TaskEnvironment task_environment_; +}; + +// Tests the basic flow for generating holding space image bitmaps. +TEST_F(HoldingSpaceImageTest, ImageGeneration) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // The test client implementation requests an image on construction. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // The image should return the placeholder bitmap. + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + // Generate the holding space item image, and verify the icon has been + // updated. + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Tests the basic flow for generating holding space image bitmaps where 2x +// bitmap gets requested. +TEST_F(HoldingSpaceImageTest, ImageGenerationWith2xScale) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Request 2x bitmap. + const SkBitmap bitmap_2x = image.GetRepresentation(2.0f).GetBitmap(); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Use placeholder while the image request is in progress. + EXPECT_EQ(20, bitmap_2x.height()); + EXPECT_EQ(20, bitmap_2x.width()); + EXPECT_EQ(SK_ColorRED, bitmap_2x.getColor(5, 5)); + + // Verify that the image gets updated once the holding space image is + // generated. + image_generator.FulfillRequest(0, SK_ColorBLUE); + + image = holding_space_item->image().image_skia(); + const SkBitmap loaded_bitmap_2x = image.GetRepresentation(2.0f).GetBitmap(); + EXPECT_EQ(20, loaded_bitmap_2x.height()); + EXPECT_EQ(20, loaded_bitmap_2x.width()); + EXPECT_EQ(SK_ColorBLUE, loaded_bitmap_2x.getColor(5, 5)); +} + +// Verifies that the holding space image handles failed holding space image +// requests. +TEST_F(HoldingSpaceImageTest, ImageLoadFailure) { + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(base::FilePath("test_file.txt"), &image_generator, + /*image_size=*/10, /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Test image client requests an image representation durion construction. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Use placeholder while the image request is in progress. + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + // Simulate failed holding space item image request, and verify the icon keeps + // using the placeholder image. + image_generator.FailRequest(0); + + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); +} + +// Verifies that the holding space image can be updated using +// `HoldingSpaceItem::InvalidateImage()`. +TEST_F(HoldingSpaceImageTest, ImageRefresh) { + ImageGenerator image_generator; + const base::FilePath kTestFile("test_file.test"); + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + // Finish loading the initial image. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Request image refresh, and verify another image gets requested. + holding_space_item->InvalidateImage(); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + ASSERT_TRUE( + holding_space_item->image_for_testing().FireInvalidateTimerForTesting()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + + // While image load request is in progress, use the previously loaded icon. + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + // Verify that image gets updated once the image load request completes. + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + image_generator.FulfillRequest(0, SK_ColorGREEN); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorGREEN, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Verifies that image refresh requests issued in quick succession do not result +// in multiple image load requests. +TEST_F(HoldingSpaceImageTest, ImageRefreshThrottling) { + ImageGenerator image_generator; + const base::FilePath kTestFile("test_file.test"); + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + // Finish loading the initial image. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Request image refresh multiple times, and verify that image load gets + // requested only once. + holding_space_item->InvalidateImage(); + holding_space_item->InvalidateImage(); + holding_space_item->InvalidateImage(); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + ASSERT_TRUE( + holding_space_item->image_for_testing().FireInvalidateTimerForTesting()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + // Verify that image gets updated once the image load request completes. + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + image_generator.FulfillRequest(0, SK_ColorGREEN); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorGREEN, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Verifies that holding space image can be refreshed while the initial image +// load is in progress. +TEST_F(HoldingSpaceImageTest, ImageRefreshDuringInitialLoad) { + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(base::FilePath("test_file.txt"), &image_generator, + /*image_size=*/10, /*image_color=*/SK_ColorRED); + + // The test client implementation requests an image on construction. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Use placeholder while the image load is in progress. + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + holding_space_item->InvalidateImage(); + ASSERT_TRUE( + holding_space_item->image_for_testing().FireInvalidateTimerForTesting()); + + // Verify that placeholder image remains to be used. + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(2u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + // Fulfill the initial request - the load result should be ignored. + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + // Fulfill the later request, and verify the icon gets updated. + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + image_generator.FulfillRequest(0, SK_ColorGREEN); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorGREEN, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Verifies that holding space image can be refreshed while the initial image +// load is in progress - test the case where the initial load request finishes +// after the request for refreshed image. +TEST_F(HoldingSpaceImageTest, + ImageRefreshDuringInitialLoadWithOutOfOrderResponses) { + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(base::FilePath("test_file.txt"), &image_generator, + /*image_size=*/10, /*image_color=*/SK_ColorRED); + + // The test client implementation requests an image on construction. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Use placeholder while the image load is in progress. + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + holding_space_item->InvalidateImage(); + ASSERT_TRUE( + holding_space_item->image_for_testing().FireInvalidateTimerForTesting()); + EXPECT_EQ(2u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + // Fulfill the later request, and verify the icon gets updated. + image_generator.FulfillRequest(1, SK_ColorGREEN); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorGREEN, image.bitmap()->getColor(5, 5)); + + // Fulfill the initial request, and verify the result is ignored + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorGREEN, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Verifies that holding space image representation can be requested even after +// the holding space item gets deleted (in which case the image will continue +// using the image placeholder). +TEST_F(HoldingSpaceImageTest, ImageRequestsAfterItemDestruction) { + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(base::FilePath("test_file.txt"), &image_generator, + /*image_size=*/10, /*image_color=*/SK_ColorRED); + + // Finish the flow for loading 1x bitmap. + TestImageClient image_client(&holding_space_item->image()); + image_generator.FulfillRequest(0, SK_ColorBLUE); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + + // Reset the holding space item, and request 2x representation. + holding_space_item.reset(); + const SkBitmap bitmap_2x = image.GetRepresentation(2.0f).GetBitmap(); + + // Verify that image returns the placeholder bitmap, and that no image + // generation requests are actually issued. + EXPECT_EQ(20, bitmap_2x.height()); + EXPECT_EQ(20, bitmap_2x.width()); + EXPECT_EQ(SK_ColorRED, bitmap_2x.getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); +} + +// Tests that HoldingSpaceImage can handle holding space item destruction while +// image load is still in progress. +TEST_F(HoldingSpaceImageTest, ItemDestructionDuringImageLoad) { + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(base::FilePath("test_file.txt"), &image_generator, + /*image_size=*/10, /*image_color=*/SK_ColorRED); + + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + // Reset the item, and then simulate image request response. + holding_space_item.reset(); + image_generator.FulfillRequest(0, SK_ColorBLUE); + + // Verify that the image keeps using the placeholder bitmap. + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Tests that HoldingSpaceImage can handle holding space item destruction while +// image load is still in progress, in case the pending image load fails. +TEST_F(HoldingSpaceImageTest, ItemDestructionDuringFailedImageLoad) { + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(base::FilePath("test_file.txt"), &image_generator, + /*image_size=*/10, /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + TestImageClient image_client(&holding_space_item->image()); + + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + // Reset the item, and then simulate a failed image request response. + holding_space_item.reset(); + image_generator.FailRequest(0); + + // Verify that the image keeps using the placeholder bitmap. + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Verifies that HoldingSpaceImage can handle holding space item destruction +// while image refresh is in progress. +TEST_F(HoldingSpaceImageTest, ItemDestructionDuringImageRefresh) { + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(base::FilePath("test_file.txt"), &image_generator, + /*image_size=*/10, /*image_color=*/SK_ColorRED); + + // Run thr flow for loading the initial image version. + TestImageClient image_client(&holding_space_item->image()); + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + + holding_space_item->InvalidateImage(); + ASSERT_TRUE( + holding_space_item->image_for_testing().FireInvalidateTimerForTesting()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + // Reset the item before image load request completes. + holding_space_item.reset(); + image_generator.FulfillRequest(0, SK_ColorGREEN); + + // Verify that the image keeps using previously generated icon. + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Tests that image load requests use the new file path if the item's backing +// file path changes. +TEST_F(HoldingSpaceImageTest, HandleBackingFilePathChange) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Update the backing file path before any image representations are + // requested. + const base::FilePath kUpdatedTestFile("updated_test_file.test"); + holding_space_item->UpdateBackingFile( + kUpdatedTestFile, GURL("filesystem:updated_file_system_url")); + + // Create test image client to issue an image request. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kUpdatedTestFile, image_generator.GetPendingRequestFilePath(0)); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Refresh image, and verify the reload request also uses the upated file + // path. + holding_space_item->InvalidateImage(); + ASSERT_TRUE( + holding_space_item->image_for_testing().FireInvalidateTimerForTesting()); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kUpdatedTestFile, image_generator.GetPendingRequestFilePath(0)); + image_generator.FulfillRequest(0, SK_ColorGREEN); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorGREEN, image.bitmap()->getColor(5, 5)); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Tests that image load requests use the new file path if the item's backing +// file path changes. +TEST_F(HoldingSpaceImageTest, HandleBackingFilePathChangeFor2xBitmap) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Create test image client to issue an image request. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + image_generator.FulfillRequest(0, SK_ColorBLUE); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + // Update the backing file path, and verify requests for 2x bitmap will use + // the new file path. + const base::FilePath kUpdatedTestFile("updated_test_file.test"); + holding_space_item->UpdateBackingFile( + kUpdatedTestFile, GURL("filesystem:updated_file_system_url")); + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + image.GetRepresentation(2.0f); + + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kUpdatedTestFile, image_generator.GetPendingRequestFilePath(0)); + image_generator.FulfillRequest(0, SK_ColorBLUE); + + const SkBitmap bitmap_2x = image.GetRepresentation(2.0f).GetBitmap(); + EXPECT_EQ(20, bitmap_2x.height()); + EXPECT_EQ(20, bitmap_2x.width()); + EXPECT_EQ(SK_ColorBLUE, bitmap_2x.getColor(10, 10)); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); +} + +// Tests that failed image loads will be retried for requests issued before +// the path change. +TEST_F(HoldingSpaceImageTest, RetryFailedImageRequestsOnFilePathChange) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Create test image client to issue an image request. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + + // Update the backing file path, and simulate image load failure.. + const base::FilePath kUpdatedTestFile("updated_test_file.test"); + holding_space_item->UpdateBackingFile( + kUpdatedTestFile, GURL("filesystem:updated_file_system_url")); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + image_generator.FailRequest(0); + + // Verify that image load is retried using the new file path. + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kUpdatedTestFile, image_generator.GetPendingRequestFilePath(0)); + + image_generator.FulfillRequest(0, SK_ColorBLUE); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); +} + +// Tests that failed image loads will be not be retried for requests that failed +// before file path change. +TEST_F(HoldingSpaceImageTest, + DontRetryImageRequestsFailedBeforeFilePathChange) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Create test image client to issue an image request. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + // Simulate request failure before updating the backing file path. + image_generator.FailRequest(0); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + // Update the backing file path, and verify the failed request was not + // retried. + const base::FilePath kUpdatedTestFile("updated_test_file.test"); + holding_space_item->UpdateBackingFile( + kUpdatedTestFile, GURL("filesystem:updated_file_system_url")); + + // Verify that image load is retried using the new file path. + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Tests that failed image loads will be not be retried for requests issued +// after file path change. +TEST_F(HoldingSpaceImageTest, DontRetryImageRequestsFailedAfterPathChange) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Update the backing file path before creating a client that requests an + // image representation. + const base::FilePath kUpdatedTestFile("updated_test_file.test"); + holding_space_item->UpdateBackingFile( + kUpdatedTestFile, GURL("filesystem:updated_file_system_url")); + + // Create test image client, and simulate image load failure. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kUpdatedTestFile, image_generator.GetPendingRequestFilePath(0)); + image_generator.FailRequest(0); + + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Verify that the request is not retried. + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); +} + +// Tests that changing the backing file alone does not retry image loads. +TEST_F(HoldingSpaceImageTest, DontRetryImageLoadOnBackingFileChange) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Create test image client, and simulate a successfull image load. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + image_generator.FulfillRequest(0, SK_ColorBLUE); + + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + + // Update the backing file path, and verify the image load is not requested + // again. + const base::FilePath kUpdatedTestFile("updated_test_file.test"); + holding_space_item->UpdateBackingFile( + kUpdatedTestFile, GURL("filesystem:updated_file_system_url")); + + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + + // Verify that the request is not retried. + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +// Tests that changing the backing file alone does not retry image loads, even +// if the image load finishes after file path changes. +TEST_F(HoldingSpaceImageTest, + DontRetryImageLaodsThatSucceedDuringBackingFileChange) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Create test image client. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + + // Update the backing file path, and verify the image load is not requested + // again. + const base::FilePath kUpdatedTestFile("updated_test_file.test"); + holding_space_item->UpdateBackingFile( + kUpdatedTestFile, GURL("filesystem:updated_file_system_url")); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + + // Finish initial load request. + image_generator.FulfillRequest(0, SK_ColorBLUE); + + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorBLUE, image.bitmap()->getColor(5, 5)); + + // Verify that the request is not retried. + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + + // Image should still be reloaded if it gets refreshed. + holding_space_item->InvalidateImage(); + ASSERT_TRUE( + holding_space_item->image_for_testing().FireInvalidateTimerForTesting()); + + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + EXPECT_EQ(kUpdatedTestFile, image_generator.GetPendingRequestFilePath(0)); +} + +// Tests a scenario where the item backing file is moved and modified while the +// initial image load request is still in progress, +TEST_F(HoldingSpaceImageTest, ItemPathMovedAndModifiedDuringInitialLoad) { + const base::FilePath kTestFile("test_file.test"); + ImageGenerator image_generator; + std::unique_ptr<HoldingSpaceItem> holding_space_item = + CreateTestItem(kTestFile, &image_generator, /*image_size=*/10, + /*image_color=*/SK_ColorRED); + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + + // Create test image client to initiate image request. + TestImageClient image_client(&holding_space_item->image()); + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + + // Update the backing file path, and then invalidate the image. + const base::FilePath kUpdatedTestFile("updated_test_file.test"); + holding_space_item->UpdateBackingFile( + kUpdatedTestFile, GURL("filesystem:updated_file_system_url")); + holding_space_item->InvalidateImage(); + ASSERT_TRUE( + holding_space_item->image_for_testing().FireInvalidateTimerForTesting()); + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + + // Verify that a image reload gets requested. + EXPECT_EQ(2u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kTestFile, image_generator.GetPendingRequestFilePath(0)); + EXPECT_EQ(kUpdatedTestFile, image_generator.GetPendingRequestFilePath(1)); + + // Finish initial load request - the result should be ignored. + image_generator.FulfillRequest(0, SK_ColorBLUE); + + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); + gfx::ImageSkia image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorRED, image.bitmap()->getColor(5, 5)); + + // Finish the later request, and verify the image gets updated. + EXPECT_EQ(1u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(kUpdatedTestFile, image_generator.GetPendingRequestFilePath(0)); + image_generator.FulfillRequest(0, SK_ColorGREEN); + + EXPECT_EQ(1u, image_client.GetAndResetImageChangeCount()); + image = holding_space_item->image().image_skia(); + EXPECT_EQ(gfx::Size(10, 10), image.size()); + EXPECT_EQ(SK_ColorGREEN, image.bitmap()->getColor(5, 5)); + + EXPECT_EQ(0u, image_generator.NumberOfPendingRequests()); + EXPECT_EQ(0u, image_client.GetAndResetImageChangeCount()); +} + +} // namespace ash
diff --git a/ash/public/cpp/holding_space/holding_space_item.cc b/ash/public/cpp/holding_space/holding_space_item.cc index bdfae06..763664a 100644 --- a/ash/public/cpp/holding_space/holding_space_item.cc +++ b/ash/public/cpp/holding_space/holding_space_item.cc
@@ -43,14 +43,14 @@ Type type, const base::FilePath& file_path, const GURL& file_system_url, - std::unique_ptr<HoldingSpaceImage> image) { + ImageResolver image_resolver) { DCHECK(!file_system_url.is_empty()); // Note: std::make_unique does not work with private constructors. return base::WrapUnique(new HoldingSpaceItem( type, /*id=*/base::UnguessableToken::Create().ToString(), file_path, file_system_url, file_path.BaseName().LossyDisplayName(), - std::move(image))); + std::move(image_resolver).Run(type, file_path))); } // static @@ -128,6 +128,12 @@ file_path_ = file_path; file_system_url_ = file_system_url; text_ = file_path.BaseName().LossyDisplayName(); + image_->UpdateBackingFilePath(file_path); +} + +void HoldingSpaceItem::InvalidateImage() { + if (image_) + image_->Invalidate(); } HoldingSpaceItem::HoldingSpaceItem(Type type,
diff --git a/ash/public/cpp/holding_space/holding_space_item.h b/ash/public/cpp/holding_space/holding_space_item.h index d80e00f6..656a1d9 100644 --- a/ash/public/cpp/holding_space/holding_space_item.h +++ b/ash/public/cpp/holding_space/holding_space_item.h
@@ -45,17 +45,17 @@ bool operator==(const HoldingSpaceItem& rhs) const; + // Returns an image for a given type and file path. + using ImageResolver = base::OnceCallback< + std::unique_ptr<HoldingSpaceImage>(Type, const base::FilePath&)>; + // Creates a HoldingSpaceItem that's backed by a file system URL. // NOTE: `file_system_url` is expected to be non-empty. static std::unique_ptr<HoldingSpaceItem> CreateFileBackedItem( Type type, const base::FilePath& file_path, const GURL& file_system_url, - std::unique_ptr<HoldingSpaceImage> image); - - // Returns an image for a given type and file path. - using ImageResolver = base::OnceCallback< - std::unique_ptr<HoldingSpaceImage>(Type, const base::FilePath&)>; + ImageResolver image_resolver); // Deserializes from `base::DictionaryValue` to `HoldingSpaceItem`. // This creates a partially initialized item with an empty file system URL. @@ -86,6 +86,10 @@ void UpdateBackingFile(const base::FilePath& file_path, const GURL& file_system_url); + // Invalidates the current holding space image, so fresh image representations + // are loaded when the image is next needed. + void InvalidateImage(); + const std::string& id() const { return id_; } Type type() const { return type_; } @@ -98,6 +102,8 @@ const GURL& file_system_url() const { return file_system_url_; } + HoldingSpaceImage& image_for_testing() { return *image_; } + private: // Constructor for file backed items. HoldingSpaceItem(Type type,
diff --git a/ash/public/cpp/holding_space/holding_space_item_unittest.cc b/ash/public/cpp/holding_space/holding_space_item_unittest.cc index 549012f..6d8203e 100644 --- a/ash/public/cpp/holding_space/holding_space_item_unittest.cc +++ b/ash/public/cpp/holding_space/holding_space_item_unittest.cc
@@ -25,6 +25,14 @@ return types; } +std::unique_ptr<HoldingSpaceImage> CreateFakeHoldingSpaceImage( + HoldingSpaceItem::Type type, + const base::FilePath& file_path) { + return std::make_unique<HoldingSpaceImage>( + file_path, /*placeholder=*/gfx::test::CreateImageSkia(10, 10), + /*async_bitmap_resolver=*/base::DoNothing()); +} + } // namespace using HoldingSpaceItemTest = testing::TestWithParam<HoldingSpaceItem::Type>; @@ -37,20 +45,14 @@ const auto holding_space_item = HoldingSpaceItem::CreateFileBackedItem( /*type=*/GetParam(), file_path, file_system_url, - std::make_unique<HoldingSpaceImage>( - placeholder, /*async_bitmap_resolver=*/base::DoNothing())); + /*image_resolver=*/base::BindOnce(&CreateFakeHoldingSpaceImage)); const base::DictionaryValue serialized_holding_space_item = holding_space_item->Serialize(); const auto deserialized_holding_space_item = HoldingSpaceItem::Deserialize( serialized_holding_space_item, - /*image_resolver=*/ - base::BindLambdaForTesting([&](HoldingSpaceItem::Type type, - const base::FilePath& file_path) { - return std::make_unique<HoldingSpaceImage>( - placeholder, /*async_bitmap_resolver=*/base::DoNothing()); - })); + /*image_resolver=*/base::BindOnce(&CreateFakeHoldingSpaceImage)); EXPECT_FALSE(deserialized_holding_space_item->IsFinalized()); EXPECT_TRUE(deserialized_holding_space_item->file_system_url().is_empty()); @@ -65,9 +67,7 @@ const auto holding_space_item = HoldingSpaceItem::CreateFileBackedItem( /*type=*/GetParam(), base::FilePath("file_path"), GURL("filesystem:file_system_url"), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::test::CreateImageSkia(10, 10), - /*async_bitmap_resolver=*/base::DoNothing())); + /*image_resolver=*/base::BindOnce(&CreateFakeHoldingSpaceImage)); const base::DictionaryValue serialized_holding_space_item = holding_space_item->Serialize();
diff --git a/ash/public/cpp/holding_space/holding_space_model.cc b/ash/public/cpp/holding_space/holding_space_model.cc index 1cd11f2..15424ace 100644 --- a/ash/public/cpp/holding_space/holding_space_model.cc +++ b/ash/public/cpp/holding_space/holding_space_model.cc
@@ -27,6 +27,10 @@ std::vector<const HoldingSpaceItem*> item_ptrs; for (std::unique_ptr<HoldingSpaceItem>& item : items) { DCHECK(!GetItem(item->id())); + + if (item->IsFinalized()) + ++finalized_item_counts_by_type_[item->type()]; + item_ptrs.push_back(item.get()); items_.push_back(std::move(item)); } @@ -64,6 +68,8 @@ DCHECK(!item->IsFinalized()); item->Finalize(file_system_url); + ++finalized_item_counts_by_type_[item->type()]; + for (auto& observer : observers_) observer.OnHoldingSpaceItemFinalized(item); } @@ -99,6 +105,9 @@ item_ptrs.push_back(item.get()); items.push_back(std::move(item)); items_.erase(items_.begin() + i); + + if (item_ptrs.back()->IsFinalized()) + --finalized_item_counts_by_type_[item_ptrs.back()->type()]; } } @@ -116,6 +125,8 @@ ItemList items; items.swap(items_); + finalized_item_counts_by_type_.clear(); + std::vector<const HoldingSpaceItem*> item_ptrs; for (auto& item : items) item_ptrs.push_back(item.get()); @@ -156,6 +167,12 @@ return GetItem(type, file_path) != nullptr; } +bool HoldingSpaceModel::ContainsFinalizedItemOfType( + HoldingSpaceItem::Type type) const { + auto it = finalized_item_counts_by_type_.find(type); + return it != finalized_item_counts_by_type_.end() && it->second > 0u; +} + void HoldingSpaceModel::AddObserver(HoldingSpaceModelObserver* observer) { observers_.AddObserver(observer); }
diff --git a/ash/public/cpp/holding_space/holding_space_model.h b/ash/public/cpp/holding_space/holding_space_model.h index 9a78816..6598439 100644 --- a/ash/public/cpp/holding_space/holding_space_model.h +++ b/ash/public/cpp/holding_space/holding_space_model.h
@@ -5,6 +5,7 @@ #ifndef ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_H_ #define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_MODEL_H_ +#include <map> #include <memory> #include <set> #include <string> @@ -85,6 +86,10 @@ bool ContainsItem(HoldingSpaceItem::Type type, const base::FilePath& file_path) const; + // Returns true if the model contains any finalized items of the specified + // `type`, false otherwise. + bool ContainsFinalizedItemOfType(HoldingSpaceItem::Type type) const; + const ItemList& items() const { return items_; } void AddObserver(HoldingSpaceModelObserver* observer); @@ -95,6 +100,11 @@ // the model. ItemList items_; + // Caches the count of finalized items in the model for each holding space + // item type. Used to quickly look up whether the model contains any finalized + // items of a given type. + std::map<HoldingSpaceItem::Type, size_t> finalized_item_counts_by_type_; + base::ObserverList<HoldingSpaceModelObserver> observers_; };
diff --git a/ash/strings/ash_strings_eu.xtb b/ash/strings/ash_strings_eu.xtb index 808249eb..b0b25a18 100644 --- a/ash/strings/ash_strings_eu.xtb +++ b/ash/strings/ash_strings_eu.xtb
@@ -19,6 +19,7 @@ <translation id="1119348796022671382">Gaikako kolore moduak horma-paperetik ateratako koloreak erabiltzen ditu interfazea pixka bat koloreztatzeko.</translation> <translation id="112308213915226829">Ezkutatu apala automatikoki</translation> <translation id="1153356358378277386">Parekatutako gailuak</translation> +<translation id="1165712434476988950">Gailua berrabiarazi egin behar da eguneratzea aplikatzeko.</translation> <translation id="1175572348579024023">Egin gora edo behera</translation> <translation id="1178581264944972037">Pausatu</translation> <translation id="118532027333893379">Sakatu pantailako edozein puntu pantaila osoaren argazkia ateratzeko</translation> @@ -118,6 +119,7 @@ <translation id="1978498689038657292">Testu-idazketa</translation> <translation id="1993072747612765854">Lortu informazio gehiago <ph name="SYSTEM_APP_NAME" /> aplikazioaren azken eguneratzeari buruz</translation> <translation id="1995660704900986789">Itzali</translation> +<translation id="1998100899771863792">Uneko lan-eremua</translation> <translation id="2012624427112548395">Ktrl + Bilatu + H</translation> <translation id="2016340657076538683">Idatzi mezu bat</translation> <translation id="2018630726571919839">Kontatu txiste bat</translation> @@ -898,6 +900,7 @@ <translation id="9089416786594320554">Idazketa-metodoak</translation> <translation id="9091626656156419976">Kendu da <ph name="DISPLAY_NAME" /> pantaila</translation> <translation id="9098969848082897657">Isilarazi telefonoa</translation> +<translation id="9099154003160514616">Lacros-en eguneratze bat dago</translation> <translation id="9151726767154816831">Berrabiarazi eta berrezarri fabrikako ezarpenak eguneratzeko</translation> <translation id="9166331175924255663">Aldatu Nearby Share-ren ikusgaitasun handia.</translation> <translation id="9168436347345867845">Geroago</translation> @@ -908,6 +911,7 @@ <translation id="9198992156681343238"><ph name="DISPLAY_NAME" /> bereizmena honako bereizmen honetara aldatu da: <ph name="RESOLUTION" />. Sakatu "Berretsi" aldaketak gordetzeko. <ph name="TIMEOUT_SECONDS" /> barru aurreko ezarpenak leheneratuko dira.</translation> <translation id="9201374708878217446"><ph name="CONNECTION_STATUS" />. Administratzaileak kudeatua.</translation> <translation id="9210037371811586452">Mahaigain bateratuko modutik irteten</translation> +<translation id="9211490828691860325">Lan-eremu guztiak</translation> <translation id="9211681782751733685"><ph name="TIME_REMAINING" /> bateria guztiz kargatu arte.</translation> <translation id="9215934040295798075">Ezarri horma-papera</translation> <translation id="921989828232331238">Guraso batek gailua blokeatu dizu gaurkoz</translation>
diff --git a/ash/strings/ash_strings_pl.xtb b/ash/strings/ash_strings_pl.xtb index cb2f07bd..567b7f1 100644 --- a/ash/strings/ash_strings_pl.xtb +++ b/ash/strings/ash_strings_pl.xtb
@@ -55,7 +55,7 @@ <translation id="1351937230027495976">Zwiń menu</translation> <translation id="1383876407941801731">Szukaj</translation> <translation id="1391102559483454063">Włączono</translation> -<translation id="1407069428457324124">Tryb ciemny</translation> +<translation id="1407069428457324124">Ciemny motyw</translation> <translation id="1419738280318246476">Odblokuj urządzenie, by zareagować na powiadomienie</translation> <translation id="1420408895951708260">Włącz lub wyłącz Podświetlenie nocne. <ph name="STATE_TEXT" /></translation> <translation id="1420527829902822813">Utworzono zrzut ekranu i zapisano go w schowku</translation> @@ -268,7 +268,7 @@ <translation id="3375634426936648815">Połączono</translation> <translation id="3386978599540877378">Lupa pełnoekranowa</translation> <translation id="3400357268283240774">Ustawienia dodatkowe</translation> -<translation id="3410336247007142655">Pokaż ustawienia trybu ciemnego</translation> +<translation id="3410336247007142655">Pokaż ustawienia ciemnego motywu</translation> <translation id="3413817803639110246">Na razie nie ma nic do pokazania</translation> <translation id="3428447136709161042">Odłączyć od sieci <ph name="NETWORK_NAME" />?</translation> <translation id="3430396595145920809">Aby wrócić, przesuń palcem od prawej strony</translation> @@ -347,7 +347,7 @@ <translation id="4129129681837227511">Aby wyświetlać powiadomienia na ekranie blokady, odblokuj ekran i zmień ustawienie</translation> <translation id="4146833061457621061">Włącz muzykę</translation> <translation id="415719264485676252">Zrzut ekranu jest zablokowany</translation> -<translation id="4157822100366708405">Ustawienia trybu ciemnego</translation> +<translation id="4157822100366708405">Ustawienia ciemnego motywu</translation> <translation id="4181841719683918333">Języki</translation> <translation id="4195877955194704651">Automatyczne klikanie przycisku</translation> <translation id="4197790712631116042">Wyłączono</translation> @@ -405,7 +405,7 @@ <translation id="4577274620589681794">Czas minął · <ph name="LABEL" /></translation> <translation id="4577990005084629481">Pokaż podglądy</translation> <translation id="4585337515783392668">Zakończ przesyłanie do nieznanego odbiornika</translation> -<translation id="4596144739579517758">Tryb ciemny jest wyłączony</translation> +<translation id="4596144739579517758">Ciemny motyw jest wyłączony</translation> <translation id="4623167406982293031">Zweryfikuj konto</translation> <translation id="4628757576491864469">Urządzenia</translation> <translation id="4642092649622328492">Zrób zrzut części ekranu</translation> @@ -482,7 +482,7 @@ <translation id="5322611492012084517">Nie udało się znaleźć telefonu</translation> <translation id="5329548388331921293">Łączę…</translation> <translation id="5331975486040154427">Urządzenie USB-C (tylny port na lewym boku)</translation> -<translation id="5352250171825660495">Tryb ciemny jest włączony</translation> +<translation id="5352250171825660495">Ciemny motyw jest włączony</translation> <translation id="5379115545237091094">Zbyt wiele prób</translation> <translation id="5397578532367286026">Działania i historia tego użytkownika mogą być sprawdzane przez menedżera (<ph name="MANAGER_EMAIL" />) na chrome.com.</translation> <translation id="5400461572260843123">Szybkie ustawienia, naciśnij Wyszukaj + strzałka w lewo, by otworzyć centrum powiadomień.</translation> @@ -866,7 +866,7 @@ <translation id="8850991929411075241">Szukaj+Esc</translation> <translation id="8853703225951107899">Nadal nie udało się zweryfikować Twojego hasła ani kodu PIN. Uwaga: jeśli Twoje hasło zostało ostatnio zmienione, użyj starego hasła. Nowe hasło zacznie obowiązywać, gdy się wylogujesz.</translation> <translation id="8870509716567206129">Aplikacja nie obsługuje dzielonego ekranu.</translation> -<translation id="8871580645200179206">Przełącz tryb ciemny. <ph name="STATE_TEXT" /></translation> +<translation id="8871580645200179206">Przełącz ciemny motyw. <ph name="STATE_TEXT" /></translation> <translation id="8874184842967597500">Brak połączenia</translation> <translation id="8876661425082386199">Sprawdź połączenie</translation> <translation id="8877788021141246043">Ustaw przypomnienie</translation>
diff --git a/ash/strings/ash_strings_te.xtb b/ash/strings/ash_strings_te.xtb index fc7cc14..9c0249f 100644 --- a/ash/strings/ash_strings_te.xtb +++ b/ash/strings/ash_strings_te.xtb
@@ -19,6 +19,7 @@ <translation id="1119348796022671382">'రూపం ఉన్న రంగు మోడ్'లో ఇంటర్ఫేస్కు పలుచగా రంగులు అద్దడానికి మీ వాల్పేపర్లోని రంగులు సంగ్రహించి ఉపయోగించబడతాయి.</translation> <translation id="112308213915226829">అరను స్వయంచాలకంగా దాచు</translation> <translation id="1153356358378277386">జత చేసిన పరికరాలు</translation> +<translation id="1165712434476988950">అప్డేట్ను వర్తింపజేయడానికి పరికరాన్ని రీస్టార్ట్ చేయాలి.</translation> <translation id="1175572348579024023">స్క్రోల్ చేస్తుంది</translation> <translation id="1178581264944972037">పాజ్ చేయి</translation> <translation id="118532027333893379">ఫుల్ స్క్రీన్ను క్యాప్చర్ చేయడానికి ఎక్కడైనా ట్యాప్ చేయండి</translation> @@ -118,6 +119,7 @@ <translation id="1978498689038657292">వచన ఇన్పుట్</translation> <translation id="1993072747612765854">తాజా <ph name="SYSTEM_APP_NAME" /> అప్డేట్ గురించి మరింత తెలుసుకోండి</translation> <translation id="1995660704900986789">పవర్ ఆఫ్ చేయి</translation> +<translation id="1998100899771863792">ప్రస్తుత డెస్క్</translation> <translation id="2012624427112548395">Ctrl+Search+H</translation> <translation id="2016340657076538683">సందేశాన్ని టైప్ చేయండి</translation> <translation id="2018630726571919839">ఒక జోక్ చెప్పు</translation> @@ -898,6 +900,7 @@ <translation id="9089416786594320554">ఇన్పుట్ పద్ధతులు</translation> <translation id="9091626656156419976">డిస్ప్లే <ph name="DISPLAY_NAME" /> తీసివేయబడింది</translation> <translation id="9098969848082897657">ఫోన్ను సైలెంట్ చేయండి</translation> +<translation id="9099154003160514616">Lacros అప్డేట్ అందుబాటులో ఉంది</translation> <translation id="9151726767154816831">అప్డేట్ చేయడానికి పునఃప్రారంభించి, పవర్వాష్ చేయండి</translation> <translation id="9166331175924255663">సమీప షేరింగ్ అధిక విజిబిలిటీ మోడ్ను టోగుల్ చేయండి.</translation> <translation id="9168436347345867845">దీనిని తర్వాత చేయి</translation> @@ -908,6 +911,7 @@ <translation id="9198992156681343238"><ph name="DISPLAY_NAME" /> రిజల్యూషన్ <ph name="RESOLUTION" />కు మార్చబడింది. మార్పులను అలాగే ఉంచడానికి 'ధృవీకరించు'ను క్లిక్ చేయండి. మునుపటి సెట్టింగ్లు <ph name="TIMEOUT_SECONDS" />లో రీస్టోర్ చేయబడతాయి.</translation> <translation id="9201374708878217446"><ph name="CONNECTION_STATUS" />, మీ అడ్మినిస్ట్రేటర్ ద్వారా నిర్వహించబడుతోంది</translation> <translation id="9210037371811586452">ఏకీకృత డెస్క్టాప్ మోడ్ నుండి ఎగ్జిట్ అవుతోంది</translation> +<translation id="9211490828691860325">అన్ని డెస్క్లు</translation> <translation id="9211681782751733685">బ్యాటరీ పూర్తిగా ఛార్జ్ కావడానికి పట్టే సమయం, <ph name="TIME_REMAINING" />.</translation> <translation id="9215934040295798075">వాల్పేపర్ను సెట్ చేయండి</translation> <translation id="921989828232331238">మీ తల్లి/తండ్రి ఈ రోజుకి మీ పరికరాన్ని లాక్ చేసి ఉంచారు</translation>
diff --git a/ash/system/holding_space/holding_space_item_views_section.cc b/ash/system/holding_space/holding_space_item_views_section.cc index 6471365..fe337b2 100644 --- a/ash/system/holding_space/holding_space_item_views_section.cc +++ b/ash/system/holding_space/holding_space_item_views_section.cc
@@ -5,13 +5,14 @@ #include "ash/system/holding_space/holding_space_item_views_section.h" #include "ash/public/cpp/holding_space/holding_space_constants.h" +#include "ash/public/cpp/holding_space/holding_space_controller.h" +#include "ash/public/cpp/holding_space/holding_space_model.h" #include "ash/system/holding_space/holding_space_item_view.h" #include "ash/system/holding_space/holding_space_item_view_delegate.h" +#include "ash/system/holding_space/holding_space_util.h" #include "base/auto_reset.h" #include "ui/compositor/callback_layer_animation_observer.h" -#include "ui/compositor/layer_animation_element.h" #include "ui/compositor/layer_animation_observer.h" -#include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/layer_animator.h" #include "ui/views/controls/scroll_view.h" #include "ui/views/layout/box_layout.h" @@ -37,61 +38,6 @@ ui::LayerAnimator::PreemptionStrategy::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); } -// Creates a `ui::LayerAnimationSequence` for the specified `element` with -// optional `delay`, observed by the specified `observer`. -std::unique_ptr<ui::LayerAnimationSequence> CreateObservedSequence( - std::unique_ptr<ui::LayerAnimationElement> element, - base::TimeDelta delay, - ui::LayerAnimationObserver* observer) { - auto sequence = std::make_unique<ui::LayerAnimationSequence>(); - if (!delay.is_zero()) { - sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement( - element->properties(), delay)); - } - sequence->AddElement(std::move(element)); - sequence->AddObserver(observer); - return sequence; -} - -// Animates the specified `view` to a target `opacity` with the specified -// `duration` and optional `delay`, associating `observer` with the created -// animation sequences. -void DoAnimateTo(views::View* view, - float opacity, - base::TimeDelta duration, - base::TimeDelta delay, - ui::LayerAnimationObserver* observer) { - // Opacity animation. - auto opacity_element = - ui::LayerAnimationElement::CreateOpacityElement(opacity, duration); - opacity_element->set_tween_type(gfx::Tween::Type::LINEAR); - - // Note that the `ui::LayerAnimator` takes ownership of any animation - // sequences so they need to be released. - view->layer()->GetAnimator()->StartAnimation( - CreateObservedSequence(std::move(opacity_element), delay, observer) - .release()); -} - -// Animates in the specified `view` with the specified `duration` and optional -// `delay`, associating `observer` with the created animation sequences. -void DoAnimateIn(views::View* view, - base::TimeDelta duration, - base::TimeDelta delay, - ui::LayerAnimationObserver* observer) { - view->layer()->SetOpacity(0.f); - DoAnimateTo(view, /*opacity=*/1.f, duration, delay, observer); -} - -// Animates out the specified `view` with the specified `duration, associating -// `observer` with the created animation sequences. -void DoAnimateOut(views::View* view, - base::TimeDelta duration, - ui::LayerAnimationObserver* observer) { - DoAnimateTo(view, /*opacity=*/0.f, duration, /*delay=*/base::TimeDelta(), - observer); -} - // Returns a callback which deletes the associated animation observer after // running another `callback`. using AnimationCompletedCallback = @@ -171,13 +117,11 @@ HoldingSpaceItemViewsSection::HoldingSpaceItemViewsSection( HoldingSpaceItemViewDelegate* delegate, - std::vector<HoldingSpaceItem::Type> supported_types, + std::set<HoldingSpaceItem::Type> supported_types, const base::Optional<size_t>& max_count) : delegate_(delegate), supported_types_(std::move(supported_types)), - max_count_(max_count) { - controller_observer_.Observe(HoldingSpaceController::Get()); -} + max_count_(max_count) {} HoldingSpaceItemViewsSection::~HoldingSpaceItemViewsSection() = default; @@ -231,11 +175,15 @@ // Views. HoldingSpaceModel* model = HoldingSpaceController::Get()->model(); - if (model) { + if (model && !model->items().empty()) { + std::vector<const HoldingSpaceItem*> item_ptrs; + for (const auto& item : model->items()) + item_ptrs.push_back(item.get()); + // Sections are not animated during initialization as their respective // bubbles will be animated in instead. base::AutoReset<bool> scoped_disable_animations(&disable_animations_, true); - OnHoldingSpaceModelAttached(model); + OnHoldingSpaceItemsAdded(item_ptrs); } // Re-enable propagation of `PreferredSizeChanged()` after initializing. @@ -244,9 +192,6 @@ } void HoldingSpaceItemViewsSection::Reset() { - model_observer_.Reset(); - controller_observer_.Reset(); - // The holding space item views `delegate_` will be destroyed before this view // when asynchronously closing the holding space bubble. To prevent accessing // `delegate_` after deletion, prevent animation callbacks from being run. @@ -307,25 +252,6 @@ PreferredSizeChanged(); } -void HoldingSpaceItemViewsSection::OnHoldingSpaceModelAttached( - HoldingSpaceModel* model) { - model_observer_.Observe(model); - - std::vector<const HoldingSpaceItem*> item_ptrs; - for (const auto& item : model->items()) - item_ptrs.push_back(item.get()); - - if (!item_ptrs.empty()) - OnHoldingSpaceItemsAdded(item_ptrs); -} - -void HoldingSpaceItemViewsSection::OnHoldingSpaceModelDetached( - HoldingSpaceModel* model) { - model_observer_.Reset(); - if (!container_->children().empty()) - MaybeAnimateOut(); -} - void HoldingSpaceItemViewsSection::OnHoldingSpaceItemsAdded( const std::vector<const HoldingSpaceItem*>& items) { const bool needs_update = std::any_of( @@ -353,6 +279,15 @@ MaybeAnimateOut(); } +void HoldingSpaceItemViewsSection::RemoveAllHoldingSpaceItemViews() { + // Holding space item views should only be removed when the `container_` is + // not visible to the user. + DCHECK(!IsDrawn() || !container_->IsDrawn() || + container_->layer()->opacity() == 0.f); + container_->RemoveAllChildViews(/*delete_children=*/true); + views_by_item_id_.clear(); +} + std::unique_ptr<views::View> HoldingSpaceItemViewsSection::CreatePlaceholder() { return nullptr; } @@ -426,15 +361,19 @@ // If the `header_` is not opaque, this section was not previously visible // to the user so the `header_` needs to be animated in alongside any content. const bool animate_in_header = header_->layer()->GetTargetOpacity() != 1.f; - if (animate_in_header) - DoAnimateIn(header_, animation_duration, animation_delay, observer); + if (animate_in_header) { + holding_space_util::AnimateIn(header_, animation_duration, animation_delay, + observer); + } if (views_by_item_id_.empty() && placeholder_) { - DoAnimateIn(placeholder_, animation_duration, animation_delay, observer); + holding_space_util::AnimateIn(placeholder_, animation_duration, + animation_delay, observer); return; } - DoAnimateIn(container_, animation_duration, animation_delay, observer); + holding_space_util::AnimateIn(container_, animation_duration, animation_delay, + observer); } void HoldingSpaceItemViewsSection::AnimateOut( @@ -452,25 +391,24 @@ if (animate_out_header) { HoldingSpaceModel* model = HoldingSpaceController::Get()->model(); if (model) { - animate_out_header = - std::none_of(model->items().begin(), model->items().end(), - [this](const auto& item) { - return item->IsFinalized() && - base::Contains(supported_types_, item->type()); - }); + animate_out_header = std::none_of( + supported_types_.begin(), supported_types_.end(), + [&model](HoldingSpaceItem::Type supported_type) { + return model->ContainsFinalizedItemOfType(supported_type); + }); } } if (animate_out_header) - DoAnimateOut(header_, animation_duration, observer); + holding_space_util::AnimateOut(header_, animation_duration, observer); if (placeholder_ && placeholder_->GetVisible()) { DCHECK(views_by_item_id_.empty()); - DoAnimateOut(placeholder_, animation_duration, observer); + holding_space_util::AnimateOut(placeholder_, animation_duration, observer); return; } - DoAnimateOut(container_, animation_duration, observer); + holding_space_util::AnimateOut(container_, animation_duration, observer); } void HoldingSpaceItemViewsSection::OnAnimateInCompleted( @@ -520,11 +458,7 @@ }, base::Unretained(this))); - if (!container_->children().empty()) { - container_->RemoveAllChildViews(/*delete_children=*/true); - views_by_item_id_.clear(); - } - + RemoveAllHoldingSpaceItemViews(); DCHECK(views_by_item_id_.empty()); HoldingSpaceModel* model = HoldingSpaceController::Get()->model();
diff --git a/ash/system/holding_space/holding_space_item_views_section.h b/ash/system/holding_space/holding_space_item_views_section.h index ed53d19..9a5f1d6 100644 --- a/ash/system/holding_space/holding_space_item_views_section.h +++ b/ash/system/holding_space/holding_space_item_views_section.h
@@ -10,13 +10,8 @@ #include <string> #include <vector> -#include "ash/public/cpp/holding_space/holding_space_controller.h" -#include "ash/public/cpp/holding_space/holding_space_controller_observer.h" #include "ash/public/cpp/holding_space/holding_space_item.h" -#include "ash/public/cpp/holding_space/holding_space_model.h" -#include "ash/public/cpp/holding_space/holding_space_model_observer.h" #include "base/optional.h" -#include "base/scoped_observation.h" #include "ui/views/view.h" namespace ui { @@ -34,14 +29,11 @@ class HoldingSpaceItemViewDelegate; // A section of holding space item views in a `HoldingSpaceTrayChildBubble`. -class HoldingSpaceItemViewsSection : public views::View, - public HoldingSpaceControllerObserver, - public HoldingSpaceModelObserver { +class HoldingSpaceItemViewsSection : public views::View { public: - HoldingSpaceItemViewsSection( - HoldingSpaceItemViewDelegate* delegate, - std::vector<HoldingSpaceItem::Type> supported_types, - const base::Optional<size_t>& max_count); + HoldingSpaceItemViewsSection(HoldingSpaceItemViewDelegate* delegate, + std::set<HoldingSpaceItem::Type> supported_types, + const base::Optional<size_t>& max_count); HoldingSpaceItemViewsSection(const HoldingSpaceItemViewsSection& other) = delete; HoldingSpaceItemViewsSection& operator=( @@ -51,9 +43,9 @@ // Initializes the section. void Init(); - // Resets the section. Called when the tray bubble starts closing to stop - // observing the holding space controller/model to ensure that no new items - // are created while the bubble widget is being asynchronously closed. + // Resets the section. Called when the tray bubble starts closing to ensure + // that no new items are created while the bubble widget is being + // asynchronously closed. void Reset(); // views::View: @@ -62,16 +54,28 @@ void PreferredSizeChanged() override; void ViewHierarchyChanged(const views::ViewHierarchyChangedDetails&) override; - // HoldingSpaceControllerObserver: - void OnHoldingSpaceModelAttached(HoldingSpaceModel* model) override; - void OnHoldingSpaceModelDetached(HoldingSpaceModel* model) override; + // `HoldingSpaceModelObserver` events forwarded from the parent + // `HoldingSpaceTrayChildBubble`. Note that events may be withheld from this + // view if, for example, its parent is animating out. + void OnHoldingSpaceItemsAdded(const std::vector<const HoldingSpaceItem*>&); + void OnHoldingSpaceItemsRemoved(const std::vector<const HoldingSpaceItem*>&); + void OnHoldingSpaceItemFinalized(const HoldingSpaceItem* item); - // HoldingSpaceModelObserver: - void OnHoldingSpaceItemsAdded( - const std::vector<const HoldingSpaceItem*>& items) override; - void OnHoldingSpaceItemsRemoved( - const std::vector<const HoldingSpaceItem*>& items) override; - void OnHoldingSpaceItemFinalized(const HoldingSpaceItem* item) override; + // Removes all holding space item views from this section. This method is + // expected to only be called: + // * from the parent `HoldingSpaceTrayChildBubble` when this view is hidden. + // * internally after having animated out the `container_` just prior to + // swapping in new contents. + void RemoveAllHoldingSpaceItemViews(); + + // Returns whether this section has a placeholder to show in lieu of item + // views when the model contains no finalized items of supported types. + bool has_placeholder() const { return !!placeholder_; } + + // Returns the types of holding space items supported by this section. + const std::set<HoldingSpaceItem::Type>& supported_types() const { + return supported_types_; + } protected: // Invoked to create the `header_` for this section. @@ -125,7 +129,7 @@ void OnAnimateOutCompleted(const ui::CallbackLayerAnimationObserver&); HoldingSpaceItemViewDelegate* const delegate_; - const std::vector<HoldingSpaceItem::Type> supported_types_; + const std::set<HoldingSpaceItem::Type> supported_types_; const base::Optional<size_t> max_count_; // Owned by view hierarchy. @@ -149,13 +153,6 @@ // and visibility change operations to reduce the number of layout events. bool disable_preferred_size_changed_ = false; - base::ScopedObservation<HoldingSpaceController, - HoldingSpaceControllerObserver> - controller_observer_{this}; - - base::ScopedObservation<HoldingSpaceModel, HoldingSpaceModelObserver> - model_observer_{this}; - base::WeakPtrFactory<HoldingSpaceItemViewsSection> weak_factory_{this}; };
diff --git a/ash/system/holding_space/holding_space_tray_child_bubble.cc b/ash/system/holding_space/holding_space_tray_child_bubble.cc index 4c10767..ebade24 100644 --- a/ash/system/holding_space/holding_space_tray_child_bubble.cc +++ b/ash/system/holding_space/holding_space_tray_child_bubble.cc
@@ -4,16 +4,58 @@ #include "ash/system/holding_space/holding_space_tray_child_bubble.h" +#include <set> + #include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/style/ash_color_provider.h" #include "ash/system/holding_space/holding_space_item_views_section.h" +#include "ash/system/holding_space/holding_space_util.h" #include "ash/system/tray/tray_constants.h" +#include "ui/compositor/callback_layer_animation_observer.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/layer_animator.h" #include "ui/views/layout/box_layout.h" namespace ash { namespace { +// Animation. +constexpr base::TimeDelta kAnimationDuration = + base::TimeDelta::FromMilliseconds(167); + +// Helpers --------------------------------------------------------------------- + +// Returns a callback which deletes the associated animation observer after +// running another `callback`. +using AnimationCompletedCallback = base::OnceCallback<void(bool aborted)>; +base::RepeatingCallback<bool(const ui::CallbackLayerAnimationObserver&)> +DeleteObserverAfterRunning(AnimationCompletedCallback callback) { + return base::BindRepeating( + [](AnimationCompletedCallback callback, + const ui::CallbackLayerAnimationObserver& observer) { + // NOTE: It's safe to move `callback` since this code will only run + // once due to deletion of the associated `observer`. The `observer` is + // deleted by returning `true`. + std::move(callback).Run(/*aborted=*/observer.aborted_count() > 0); + return true; + }, + base::Passed(std::move(callback))); +} + +// Returns whether the given holding space `model` contains any finalized items +// which are supported by the specified holding space item views `section`. +bool ModelContainsFinalizedItemsForSection( + const HoldingSpaceModel* model, + const HoldingSpaceItemViewsSection* section) { + const auto& supported_types = section->supported_types(); + return std::any_of( + supported_types.begin(), supported_types.end(), + [&model](HoldingSpaceItem::Type supported_type) { + return model->ContainsFinalizedItemOfType(supported_type); + }); +} + // TopAlignedBoxLayout --------------------------------------------------------- // A vertical `views::BoxLayout` which overrides layout behavior when there is @@ -68,7 +110,11 @@ HoldingSpaceTrayChildBubble::HoldingSpaceTrayChildBubble( HoldingSpaceItemViewDelegate* delegate) - : delegate_(delegate) {} + : delegate_(delegate) { + controller_observer_.Observe(HoldingSpaceController::Get()); + if (HoldingSpaceController::Get()->model()) + model_observer_.Observe(HoldingSpaceController::Get()->model()); +} HoldingSpaceTrayChildBubble::~HoldingSpaceTrayChildBubble() = default; @@ -79,11 +125,14 @@ // Layer. SetPaintToLayer(ui::LAYER_SOLID_COLOR); + layer()->GetAnimator()->set_preemption_strategy( + ui::LayerAnimator::PreemptionStrategy::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); layer()->SetBackgroundBlur(kUnifiedMenuBackgroundBlur); layer()->SetColor(AshColorProvider::Get()->GetBaseLayerColor( AshColorProvider::BaseLayerType::kTransparent80)); layer()->SetFillsBoundsOpaquely(false); layer()->SetIsFastRoundedCorner(true); + layer()->SetOpacity(0.f); layer()->SetRoundedCornerRadius( gfx::RoundedCornersF{kUnifiedTrayCornerRadius}); @@ -95,10 +144,83 @@ } void HoldingSpaceTrayChildBubble::Reset() { + // Prevent animation callbacks from running when the holding space bubble is + // being asynchronously closed. This view will be imminently deleted. + weak_factory_.InvalidateWeakPtrs(); + + model_observer_.Reset(); + controller_observer_.Reset(); + for (HoldingSpaceItemViewsSection* section : sections_) section->Reset(); } +void HoldingSpaceTrayChildBubble::OnHoldingSpaceModelAttached( + HoldingSpaceModel* model) { + model_observer_.Observe(model); + + // New model contents, if available, will be populated and animated in after + // the out animation completes. + MaybeAnimateOut(); +} + +void HoldingSpaceTrayChildBubble::OnHoldingSpaceModelDetached( + HoldingSpaceModel* model) { + model_observer_.Reset(); + MaybeAnimateOut(); +} + +void HoldingSpaceTrayChildBubble::OnHoldingSpaceItemsAdded( + const std::vector<const HoldingSpaceItem*>& items) { + // Ignore new items while the bubble is animating out. The bubble content will + // be updated to match the model after the out animation completes. + if (!is_animating_out_) { + for (HoldingSpaceItemViewsSection* section : sections_) + section->OnHoldingSpaceItemsAdded(items); + } +} + +void HoldingSpaceTrayChildBubble::OnHoldingSpaceItemsRemoved( + const std::vector<const HoldingSpaceItem*>& items) { + // Ignore item removal while the bubble is animating out. The bubble content + // will be updated to match the model after the out animation completes. + if (is_animating_out_) + return; + + HoldingSpaceModel* model = HoldingSpaceController::Get()->model(); + DCHECK(model); + + // This child bubble should animate out if the attached model does not + // contain finalized items supported by any of its sections. The exception is + // if a section has a placeholder to show in lieu of holding space items. If + // a placeholder exists, the child bubble should persist. + const bool animate_out = std::none_of( + sections_.begin(), sections_.end(), + [&model](const HoldingSpaceItemViewsSection* section) { + return section->has_placeholder() || + ModelContainsFinalizedItemsForSection(model, section); + }); + + if (animate_out) { + MaybeAnimateOut(); + return; + } + + for (HoldingSpaceItemViewsSection* section : sections_) + section->OnHoldingSpaceItemsRemoved(items); +} + +void HoldingSpaceTrayChildBubble::OnHoldingSpaceItemFinalized( + const HoldingSpaceItem* item) { + // Ignore item finalization while the bubble is animating out. The bubble + // content will be updated to match the model after the out animation + // completes. + if (!is_animating_out_) { + for (HoldingSpaceItemViewsSection* section : sections_) + section->OnHoldingSpaceItemFinalized(item); + } +} + const char* HoldingSpaceTrayChildBubble::GetClassName() const { return "HoldingSpaceTrayChildBubble"; } @@ -118,10 +240,122 @@ } } - if (visible != GetVisible()) + if (visible != GetVisible()) { SetVisible(visible); + // When the child bubble becomes visible, its due to one of its sections + // becoming visible. In this case, the child bubble should animate in. + if (GetVisible()) + MaybeAnimateIn(); + } + PreferredSizeChanged(); } +void HoldingSpaceTrayChildBubble::MaybeAnimateIn() { + // Don't preempt an out animation as new content will populate and be animated + // in, if any exists, once the out animation completes. + if (is_animating_out_) + return; + + // Don't attempt to animate in this bubble unnecessarily as it will cause + // opacity to revert to zero before proceeding to animate in. Ensure that + // event processing is enabled as it may have been disabled while animating + // this bubble out. + if (layer()->GetTargetOpacity() == 1.f) { + SetCanProcessEventsWithinSubtree(true); + return; + } + + // NOTE: `animate_in_observer` is deleted after `OnAnimateInCompleted()`. + ui::CallbackLayerAnimationObserver* animate_in_observer = + new ui::CallbackLayerAnimationObserver(DeleteObserverAfterRunning( + base::BindOnce(&HoldingSpaceTrayChildBubble::OnAnimateInCompleted, + weak_factory_.GetWeakPtr()))); + + AnimateIn(animate_in_observer); + animate_in_observer->SetActive(); +} + +void HoldingSpaceTrayChildBubble::MaybeAnimateOut() { + if (is_animating_out_) + return; + + // Child bubbles should not process events when being animated as the model + // objects backing their views may no longer exist. Event processing will be + // re-enabled on animation completion. + SetCanProcessEventsWithinSubtree(false); + + // NOTE: `animate_out_observer` is deleted after `OnAnimateOutCompleted()`. + ui::CallbackLayerAnimationObserver* animate_out_observer = + new ui::CallbackLayerAnimationObserver(DeleteObserverAfterRunning( + base::BindOnce(&HoldingSpaceTrayChildBubble::OnAnimateOutCompleted, + weak_factory_.GetWeakPtr()))); + + AnimateOut(animate_out_observer); + animate_out_observer->SetActive(); +} + +void HoldingSpaceTrayChildBubble::AnimateIn( + ui::LayerAnimationObserver* observer) { + DCHECK(!is_animating_out_); + + // Delay in animations to give the holding space bubble time to animate its + // layout changes. This ensures that there is sufficient space to display the + // child bubble before it is displayed to the user. + const base::TimeDelta animation_delay = kAnimationDuration; + holding_space_util::AnimateIn(this, kAnimationDuration, animation_delay, + observer); +} + +void HoldingSpaceTrayChildBubble::AnimateOut( + ui::LayerAnimationObserver* observer) { + DCHECK(!is_animating_out_); + is_animating_out_ = true; + + // Animation is only necessary if this view is visible to the user. + const base::TimeDelta animation_duration = + IsDrawn() ? kAnimationDuration : base::TimeDelta(); + holding_space_util::AnimateOut(this, animation_duration, observer); +} + +void HoldingSpaceTrayChildBubble::OnAnimateInCompleted(bool aborted) { + // Restore event processing once the child bubble has fully animated in. Its + // contents are guaranteed to exist in the model and can be acted upon by the + // user. + if (!aborted) + SetCanProcessEventsWithinSubtree(true); +} + +void HoldingSpaceTrayChildBubble::OnAnimateOutCompleted(bool aborted) { + DCHECK(is_animating_out_); + is_animating_out_ = false; + + if (aborted) + return; + + // Once the child bubble has animated out it is transparent but still + // "visible" as far as the views framework is concerned and so takes up layout + // space. Hide the view so that the holding space bubble will animate the + // re-layout of its view hierarchy with this child bubble taking no space. + SetVisible(false); + + for (HoldingSpaceItemViewsSection* section : sections_) + section->RemoveAllHoldingSpaceItemViews(); + + HoldingSpaceModel* model = HoldingSpaceController::Get()->model(); + if (!model || model->items().empty()) + return; + + std::vector<const HoldingSpaceItem*> item_ptrs; + for (const auto& item : model->items()) + item_ptrs.push_back(item.get()); + + // Populating a `section` may cause it's visibility to change if the `model` + // contains finalized items of types which it supports. This, in turn, will + // cause visibility of this child bubble to update and animate in if needed. + for (HoldingSpaceItemViewsSection* section : sections_) + section->OnHoldingSpaceItemsAdded(item_ptrs); +} + } // namespace ash
diff --git a/ash/system/holding_space/holding_space_tray_child_bubble.h b/ash/system/holding_space/holding_space_tray_child_bubble.h index efadc83..d7e0362b 100644 --- a/ash/system/holding_space/holding_space_tray_child_bubble.h +++ b/ash/system/holding_space/holding_space_tray_child_bubble.h
@@ -8,15 +8,26 @@ #include <memory> #include <vector> +#include "ash/public/cpp/holding_space/holding_space_controller.h" +#include "ash/public/cpp/holding_space/holding_space_controller_observer.h" +#include "ash/public/cpp/holding_space/holding_space_model.h" +#include "ash/public/cpp/holding_space/holding_space_model_observer.h" +#include "base/scoped_observation.h" #include "ui/views/view.h" +namespace ui { +class LayerAnimationObserver; +} // namespace ui + namespace ash { class HoldingSpaceItemViewDelegate; class HoldingSpaceItemViewsSection; // Child bubble of the `HoldingSpaceTrayBubble`. -class HoldingSpaceTrayChildBubble : public views::View { +class HoldingSpaceTrayChildBubble : public views::View, + public HoldingSpaceControllerObserver, + public HoldingSpaceModelObserver { public: explicit HoldingSpaceTrayChildBubble(HoldingSpaceItemViewDelegate* delegate); HoldingSpaceTrayChildBubble(const HoldingSpaceTrayChildBubble& other) = @@ -33,6 +44,17 @@ // are created while the bubble widget is begin asynchronously closed. void Reset(); + // HoldingSpaceControllerObserver: + void OnHoldingSpaceModelAttached(HoldingSpaceModel* model) override; + void OnHoldingSpaceModelDetached(HoldingSpaceModel* model) override; + + // HoldingSpaceModelObserver: + void OnHoldingSpaceItemsAdded( + const std::vector<const HoldingSpaceItem*>& items) override; + void OnHoldingSpaceItemsRemoved( + const std::vector<const HoldingSpaceItem*>& items) override; + void OnHoldingSpaceItemFinalized(const HoldingSpaceItem* item) override; + protected: // Invoked to create the `sections_` for this child bubble. virtual std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>> @@ -46,10 +68,37 @@ void ChildPreferredSizeChanged(views::View* child) override; void ChildVisibilityChanged(views::View* child) override; + // Invoked to animate in/out this view if necessary. + void MaybeAnimateIn(); + void MaybeAnimateOut(); + + // Invoked to animate in/out this view. These methods should only be called + // from `MaybeAnimateIn()`/`MaybeAnimateOut()` respectively as those methods + // contain gating criteria for when these methods may be invoked. + void AnimateIn(ui::LayerAnimationObserver* observer); + void AnimateOut(ui::LayerAnimationObserver* observer); + + // Invoked when an in/out animation has completed. If `aborted` is true, + // the animation was cancelled and did not animation to target end values. + void OnAnimateInCompleted(bool aborted); + void OnAnimateOutCompleted(bool aborted); + HoldingSpaceItemViewDelegate* const delegate_; // Views owned by view hierarchy. std::vector<HoldingSpaceItemViewsSection*> sections_; + + // Whether or not this view is currently being animated out. + bool is_animating_out_ = false; + + base::ScopedObservation<HoldingSpaceController, + HoldingSpaceControllerObserver> + controller_observer_{this}; + + base::ScopedObservation<HoldingSpaceModel, HoldingSpaceModelObserver> + model_observer_{this}; + + base::WeakPtrFactory<HoldingSpaceTrayChildBubble> weak_factory_{this}; }; } // namespace ash
diff --git a/ash/system/holding_space/holding_space_tray_icon_preview.cc b/ash/system/holding_space/holding_space_tray_icon_preview.cc index d121f3d0..5266e7b 100644 --- a/ash/system/holding_space/holding_space_tray_icon_preview.cc +++ b/ash/system/holding_space/holding_space_tray_icon_preview.cc
@@ -113,40 +113,6 @@ const gfx::ImageSkia item_image_; }; -// ContentsImage --------------------------------------------------------------- - -class ContentsImage : public gfx::ImageSkia { - public: - ContentsImage(const HoldingSpaceItem* item, - base::RepeatingClosure image_invalidated_closure) - : gfx::ImageSkia( - std::make_unique<ContentsImageSource>(item->image().image_skia()), - GetPreviewSize()), - image_invalidated_closure_(image_invalidated_closure) { - image_subscription_ = item->image().AddImageSkiaChangedCallback( - base::BindRepeating(&ContentsImage::OnHoldingSpaceItemImageChanged, - base::Unretained(this))); - } - - ContentsImage(const ContentsImage&) = delete; - ContentsImage& operator=(const ContentsImage&) = delete; - ~ContentsImage() = default; - - private: - void OnHoldingSpaceItemImageChanged() { - // Invalidate cached image reps. - for (const gfx::ImageSkiaRep& image_rep : image_reps()) { - RemoveRepresentation(image_rep.scale()); - RemoveUnsupportedRepresentationsForScale(image_rep.scale()); - } - // Notify closure of invalidation. - image_invalidated_closure_.Run(); - } - - base::RepeatingClosure image_invalidated_closure_; - base::CallbackListSubscription image_subscription_; -}; - } // namespace // HoldingSpaceTrayIconPreview ------------------------------------------------- @@ -156,9 +122,13 @@ views::View* container, const HoldingSpaceItem* item) : shelf_(shelf), container_(container), item_(item) { - contents_image_ = std::make_unique<ContentsImage>( - item_, base::BindRepeating(&HoldingSpaceTrayIconPreview::InvalidateLayer, - base::Unretained(this))); + contents_image_ = gfx::ImageSkia( + std::make_unique<ContentsImageSource>(item->image().image_skia()), + GetPreviewSize()); + image_subscription_ = + item->image().AddImageSkiaChangedCallback(base::BindRepeating( + &HoldingSpaceTrayIconPreview::OnHoldingSpaceItemImageChanged, + base::Unretained(this))); container_observer_.Observe(container_); } @@ -351,9 +321,8 @@ std::min(contents_bounds.width(), contents_bounds.height()) / 2, flags); // Contents. - DCHECK(contents_image_); - if (!contents_image_->isNull()) { - canvas->DrawImageInt(*contents_image_, contents_bounds.x(), + if (!contents_image_.isNull()) { + canvas->DrawImageInt(contents_image_, contents_bounds.x(), contents_bounds.y()); } } @@ -386,6 +355,13 @@ container_observer_.Reset(); } +void HoldingSpaceTrayIconPreview::OnHoldingSpaceItemImageChanged() { + contents_image_ = gfx::ImageSkia( + std::make_unique<ContentsImageSource>(item_->image().image_skia()), + GetPreviewSize()); + InvalidateLayer(); +} + void HoldingSpaceTrayIconPreview::CreateLayer( const gfx::Transform& initial_transform) { DCHECK(!layer_);
diff --git a/ash/system/holding_space/holding_space_tray_icon_preview.h b/ash/system/holding_space/holding_space_tray_icon_preview.h index 9482189..6814491 100644 --- a/ash/system/holding_space/holding_space_tray_icon_preview.h +++ b/ash/system/holding_space/holding_space_tray_icon_preview.h
@@ -92,6 +92,10 @@ void OnViewBoundsChanged(views::View* observed_view) override; void OnViewIsDeleting(views::View* observed_view) override; + // Subscription callback for `item_` image changes. Called when the icon + // representation gets updated. + void OnHoldingSpaceItemImageChanged(); + // Creates the `layer_` for this preview. Note that `layer_` may be created // multiple times throughout this preview's lifetime as `layer_` will only // exist while in the viewport for the holding space tray `container_`. @@ -128,7 +132,7 @@ // A cached representation of the associated holding space `item_`'s image // which has been cropped, resized, and clipped to a circle to be painted at // `layer_`'s contents bounds. - std::unique_ptr<gfx::ImageSkia> contents_image_; + gfx::ImageSkia contents_image_; // This is a proxy for `layer_`'s transform and represents the target // position of this preview. Because `layer_` only exists while in @@ -154,6 +158,10 @@ // is about to move. Set while the holding space tray icon is updating. base::Optional<size_t> pending_index_; + // Subscription for changes to the holding space image backing + // `contents_image_`. + base::CallbackListSubscription image_subscription_; + // The `layer_` for this preview is parented by `container_`'s layer. It is // necessary to observe and react to bounds changes in `container_` to keep // `layer_`'s bounds in sync.
diff --git a/ash/system/holding_space/holding_space_tray_unittest.cc b/ash/system/holding_space/holding_space_tray_unittest.cc index c5f4e3cc..bc8a0f5 100644 --- a/ash/system/holding_space/holding_space_tray_unittest.cc +++ b/ash/system/holding_space/holding_space_tray_unittest.cc
@@ -49,9 +49,12 @@ event_generator.PressKey(key_code, flags); } -std::unique_ptr<HoldingSpaceImage> CreateStubHoldingSpaceImage() { +std::unique_ptr<HoldingSpaceImage> CreateStubHoldingSpaceImage( + HoldingSpaceItem::Type type, + const base::FilePath& file_path) { return std::make_unique<HoldingSpaceImage>( - gfx::ImageSkia(), /*async_bitmap_resolver=*/base::DoNothing()); + file_path, /*placeholder=*/gfx::ImageSkia(), + /*async_bitmap_resolver=*/base::DoNothing()); } // Mocks ----------------------------------------------------------------------- @@ -137,8 +140,9 @@ GURL file_system_url( base::StrCat({"filesystem:", path.BaseName().value()})); std::unique_ptr<HoldingSpaceItem> item = - HoldingSpaceItem::CreateFileBackedItem(type, path, file_system_url, - CreateStubHoldingSpaceImage()); + HoldingSpaceItem::CreateFileBackedItem( + type, path, file_system_url, + base::BindOnce(&CreateStubHoldingSpaceImage)); HoldingSpaceItem* item_ptr = item.get(); model()->AddItem(std::move(item)); return item_ptr; @@ -149,19 +153,16 @@ // Create a holding space item, and use it to create a serialized item // dictionary. std::unique_ptr<HoldingSpaceItem> item = - HoldingSpaceItem::CreateFileBackedItem(type, path, - GURL("filesystem:ignored"), - CreateStubHoldingSpaceImage()); + HoldingSpaceItem::CreateFileBackedItem( + type, path, GURL("filesystem:ignored"), + base::BindOnce(&CreateStubHoldingSpaceImage)); const base::DictionaryValue serialized_holding_space_item = item->Serialize(); std::unique_ptr<HoldingSpaceItem> deserialized_item = HoldingSpaceItem::Deserialize( serialized_holding_space_item, /*image_resolver=*/ - base::BindLambdaForTesting([&](HoldingSpaceItem::Type type, - const base::FilePath& file_path) { - return CreateStubHoldingSpaceImage(); - })); + base::BindOnce(&CreateStubHoldingSpaceImage)); HoldingSpaceItem* deserialized_item_ptr = deserialized_item.get(); model()->AddItem(std::move(deserialized_item));
diff --git a/ash/system/holding_space/holding_space_util.cc b/ash/system/holding_space/holding_space_util.cc index 03d3353..f2eec46 100644 --- a/ash/system/holding_space/holding_space_util.cc +++ b/ash/system/holding_space/holding_space_util.cc
@@ -5,11 +5,76 @@ #include "ash/system/holding_space/holding_space_util.h" #include "ash/style/ash_color_provider.h" +#include "ui/compositor/layer_animation_element.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/layer_animation_sequence.h" +#include "ui/compositor/layer_animator.h" #include "ui/views/controls/label.h" namespace ash { namespace holding_space_util { +namespace { + +// Helpers --------------------------------------------------------------------- + +// Creates a `ui::LayerAnimationSequence` for the specified `element` with +// optional `delay`, observed by the specified `observer`. +std::unique_ptr<ui::LayerAnimationSequence> CreateObservedSequence( + std::unique_ptr<ui::LayerAnimationElement> element, + base::TimeDelta delay, + ui::LayerAnimationObserver* observer) { + auto sequence = std::make_unique<ui::LayerAnimationSequence>(); + if (!delay.is_zero()) { + sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement( + element->properties(), delay)); + } + sequence->AddElement(std::move(element)); + sequence->AddObserver(observer); + return sequence; +} + +// Animates the specified `view` to a target `opacity` with the specified +// `duration` and optional `delay`, associating `observer` with the created +// animation sequences. +void AnimateTo(views::View* view, + float opacity, + base::TimeDelta duration, + base::TimeDelta delay, + ui::LayerAnimationObserver* observer) { + // Opacity animation. + auto opacity_element = + ui::LayerAnimationElement::CreateOpacityElement(opacity, duration); + opacity_element->set_tween_type(gfx::Tween::Type::LINEAR); + + // Note that the `ui::LayerAnimator` takes ownership of any animation + // sequences so they need to be released. + view->layer()->GetAnimator()->StartAnimation( + CreateObservedSequence(std::move(opacity_element), delay, observer) + .release()); +} + +} // namespace + +// Animates in the specified `view` with the specified `duration` and optional +// `delay`, associating `observer` with the created animation sequences. +void AnimateIn(views::View* view, + base::TimeDelta duration, + base::TimeDelta delay, + ui::LayerAnimationObserver* observer) { + view->layer()->SetOpacity(0.f); + AnimateTo(view, /*opacity=*/1.f, duration, delay, observer); +} + +// Animates out the specified `view` with the specified `duration, associating +// `observer` with the created animation sequences. +void AnimateOut(views::View* view, + base::TimeDelta duration, + ui::LayerAnimationObserver* observer) { + AnimateTo(view, /*opacity=*/0.f, duration, /*delay=*/base::TimeDelta(), + observer); +} + std::unique_ptr<views::Label> CreateLabel(LabelStyle style, const base::string16& text) { auto label = std::make_unique<views::Label>(text);
diff --git a/ash/system/holding_space/holding_space_util.h b/ash/system/holding_space/holding_space_util.h index 9cf6680..f8e1fa8 100644 --- a/ash/system/holding_space/holding_space_util.h +++ b/ash/system/holding_space/holding_space_util.h
@@ -6,14 +6,33 @@ #define ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_UTIL_H_ #include "base/strings/string16.h" +#include "base/time/time.h" + +namespace ui { +class LayerAnimationObserver; +} // namespace ui namespace views { class Label; +class View; } // namespace views namespace ash { namespace holding_space_util { +// Animates in the specified `view` with the specified `duration` and optional +// `delay`, associating `observer` with the created animation sequences. +void AnimateIn(views::View* view, + base::TimeDelta duration, + base::TimeDelta delay, + ui::LayerAnimationObserver* observer); + +// Animates out the specified `view` with the specified `duration, associating +// `observer` with the created animation sequences. +void AnimateOut(views::View* view, + base::TimeDelta duration, + ui::LayerAnimationObserver* observer); + // Enumeration of supported label styles. enum class LabelStyle { kBadge,
diff --git a/ash/system/phonehub/bluetooth_disabled_view.cc b/ash/system/phonehub/bluetooth_disabled_view.cc index 654cf3a..45dd1285 100644 --- a/ash/system/phonehub/bluetooth_disabled_view.cc +++ b/ash/system/phonehub/bluetooth_disabled_view.cc
@@ -17,6 +17,7 @@ #include "ash/system/phonehub/phone_hub_view_ids.h" #include "ash/system/phonehub/ui_constants.h" #include "ash/system/status_area_widget.h" +#include "chromeos/components/phonehub/url_constants.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/chromeos/devicetype_utils.h" @@ -71,7 +72,8 @@ void BluetoothDisabledView::LearnMoreButtonPressed() { LogInterstitialScreenEvent(InterstitialScreenEvent::kLearnMore); NewWindowDelegate::GetInstance()->NewTabWithUrl( - GURL(kLearnMoreUrl), /*from_user_interaction=*/true); + GURL(chromeos::phonehub::kPhoneHubLearnMoreLink), + /*from_user_interaction=*/true); } BEGIN_METADATA(BluetoothDisabledView, views::View)
diff --git a/ash/system/phonehub/enable_hotspot_quick_action_controller.cc b/ash/system/phonehub/enable_hotspot_quick_action_controller.cc index 7934da2..033718d 100644 --- a/ash/system/phonehub/enable_hotspot_quick_action_controller.cc +++ b/ash/system/phonehub/enable_hotspot_quick_action_controller.cc
@@ -65,6 +65,9 @@ case Status::kConnected: SetState(ActionState::kConnected); break; + case Status::kNoReception: + SetState(ActionState::kNoReception); + break; } item_->SetVisible(true); } @@ -73,12 +76,14 @@ item_->SetEnabled(true); bool icon_enabled; + bool button_enabled; int state_text_id; int sub_label_text; SkColor sub_label_color; switch (state) { case ActionState::kOff: icon_enabled = false; + button_enabled = true; state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_DISABLED_STATE_TOOLTIP; sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_OFF_STATE; sub_label_color = AshColorProvider::Get()->GetContentLayerColor( @@ -86,6 +91,7 @@ break; case ActionState::kConnecting: icon_enabled = true; + button_enabled = true; state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTING_STATE_TOOLTIP; sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTING_STATE; sub_label_color = AshColorProvider::Get()->GetContentLayerColor( @@ -93,21 +99,37 @@ break; case ActionState::kConnected: icon_enabled = true; + button_enabled = true; state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTED_STATE_TOOLTIP; sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTED_STATE; sub_label_color = AshColorProvider::Get()->GetContentLayerColor( AshColorProvider::ContentLayerType::kTextColorPositive); break; + case ActionState::kNoReception: + icon_enabled = false; + button_enabled = false; + state_text_id = + IDS_ASH_PHONE_HUB_ENABLE_HOTSPOT_NO_RECEPTION_STATE_TOOLTIP; + sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_NOT_AVAILABLE_STATE; + sub_label_color = AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kTextColorSecondary); + break; } item_->SetToggled(icon_enabled); + item_->SetEnabled(button_enabled); item_->SetSubLabel(l10n_util::GetStringUTF16(sub_label_text)); item_->SetSubLabelColor(sub_label_color); - base::string16 tooltip_state = - l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel()); - item_->SetIconTooltip( - l10n_util::GetStringFUTF16(IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, - item_->GetItemLabel(), tooltip_state)); + + if (state == ActionState::kNoReception) { + item_->SetIconTooltip(l10n_util::GetStringUTF16(state_text_id)); + } else { + base::string16 tooltip_state = + l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel()); + item_->SetIconTooltip(l10n_util::GetStringFUTF16( + IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, item_->GetItemLabel(), + tooltip_state)); + } } } // namespace ash
diff --git a/ash/system/phonehub/enable_hotspot_quick_action_controller.h b/ash/system/phonehub/enable_hotspot_quick_action_controller.h index feacf054..19c87e4 100644 --- a/ash/system/phonehub/enable_hotspot_quick_action_controller.h +++ b/ash/system/phonehub/enable_hotspot_quick_action_controller.h
@@ -33,7 +33,7 @@ private: // All the possible states that the enable hotspot button can be viewed. Each // state has a corresponding icon, labels and tooltip view. - enum class ActionState { kOff, kConnecting, kConnected }; + enum class ActionState { kOff, kConnecting, kConnected, kNoReception }; // Set the item (including icon, label and tooltips) to a certain state. void SetState(ActionState state);
diff --git a/ash/system/phonehub/locate_phone_quick_action_controller.cc b/ash/system/phonehub/locate_phone_quick_action_controller.cc index 4ebf57b..81b67a5 100644 --- a/ash/system/phonehub/locate_phone_quick_action_controller.cc +++ b/ash/system/phonehub/locate_phone_quick_action_controller.cc
@@ -8,7 +8,6 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/system/phonehub/phone_hub_metrics.h" #include "ash/system/phonehub/quick_action_item.h" -#include "ash/system/phonehub/silence_phone_quick_action_controller.h" #include "base/timer/timer.h" #include "ui/base/l10n/l10n_util.h" @@ -29,19 +28,14 @@ using Status = chromeos::phonehub::FindMyDeviceController::Status; LocatePhoneQuickActionController::LocatePhoneQuickActionController( - chromeos::phonehub::FindMyDeviceController* find_my_device_controller, - SilencePhoneQuickActionController* silence_phone_controller) - : find_my_device_controller_(find_my_device_controller), - silence_phone_controller_(silence_phone_controller) { + chromeos::phonehub::FindMyDeviceController* find_my_device_controller) + : find_my_device_controller_(find_my_device_controller) { DCHECK(find_my_device_controller_); - DCHECK(silence_phone_controller_); find_my_device_controller_->AddObserver(this); - silence_phone_controller_->AddObserver(this); } LocatePhoneQuickActionController::~LocatePhoneQuickActionController() { find_my_device_controller_->RemoveObserver(this); - silence_phone_controller_->RemoveObserver(this); } QuickActionItem* LocatePhoneQuickActionController::CreateItem() { @@ -69,11 +63,6 @@ find_my_device_controller_->RequestNewPhoneRingingState(!is_now_enabled); } -void LocatePhoneQuickActionController::OnSilencePhoneItemStateChanged() { - is_silence_enabled_ = silence_phone_controller_->IsItemEnabled(); - UpdateState(); -} - void LocatePhoneQuickActionController::OnPhoneRingingStateChanged() { UpdateState(); } @@ -81,20 +70,16 @@ void LocatePhoneQuickActionController::UpdateState() { // Disable Locate Phone if Silence Phone is on, otherwise change accordingly // based on status from FindMyDeviceController. - if (is_silence_enabled_) { - state_ = ActionState::kNotAvailable; - } else { - switch (find_my_device_controller_->GetPhoneRingingStatus()) { - case Status::kRingingOff: - state_ = ActionState::kOff; - break; - case Status::kRingingOn: - state_ = ActionState::kOn; - break; - case Status::kRingingNotAvailable: - state_ = ActionState::kNotAvailable; - break; - } + switch (find_my_device_controller_->GetPhoneRingingStatus()) { + case Status::kRingingOff: + state_ = ActionState::kOff; + break; + case Status::kRingingOn: + state_ = ActionState::kOn; + break; + case Status::kRingingNotAvailable: + state_ = ActionState::kNotAvailable; + break; } SetItemState(state_); @@ -109,32 +94,42 @@ void LocatePhoneQuickActionController::SetItemState(ActionState state) { bool icon_enabled; + bool button_enabled; int state_text_id; int sub_label_text; switch (state) { case ActionState::kNotAvailable: - item_->SetEnabled(false); - return; + icon_enabled = false; + button_enabled = false; + state_text_id = IDS_ASH_PHONE_HUB_LOCATE_BUTTON_NOT_AVAILABLE_TOOLTIP; + sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_NOT_AVAILABLE_STATE; + break; case ActionState::kOff: icon_enabled = false; + button_enabled = true; state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_DISABLED_STATE_TOOLTIP; sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_OFF_STATE; break; case ActionState::kOn: icon_enabled = true; + button_enabled = true; state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_ENABLED_STATE_TOOLTIP; sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_ON_STATE; break; } - item_->SetEnabled(true); + item_->SetEnabled(button_enabled); item_->SetToggled(icon_enabled); item_->SetSubLabel(l10n_util::GetStringUTF16(sub_label_text)); - base::string16 tooltip_state = - l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel()); - item_->SetIconTooltip( - l10n_util::GetStringFUTF16(IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, - item_->GetItemLabel(), tooltip_state)); + if (state == ActionState::kNotAvailable) { + item_->SetIconTooltip(l10n_util::GetStringUTF16(state_text_id)); + } else { + base::string16 tooltip_state = + l10n_util::GetStringFUTF16(state_text_id, item_->GetItemLabel()); + item_->SetIconTooltip(l10n_util::GetStringFUTF16( + IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, item_->GetItemLabel(), + tooltip_state)); + } } void LocatePhoneQuickActionController::CheckRequestedState() {
diff --git a/ash/system/phonehub/locate_phone_quick_action_controller.h b/ash/system/phonehub/locate_phone_quick_action_controller.h index 0c0402e..9ec016c 100644 --- a/ash/system/phonehub/locate_phone_quick_action_controller.h +++ b/ash/system/phonehub/locate_phone_quick_action_controller.h
@@ -5,7 +5,7 @@ #ifndef ASH_SYSTEM_PHONEHUB_LOCATE_PHONE_QUICK_ACTION_CONTROLLER_H_ #define ASH_SYSTEM_PHONEHUB_LOCATE_PHONE_QUICK_ACTION_CONTROLLER_H_ -#include "ash/system/phonehub/silence_phone_quick_action_controller.h" +#include "ash/system/phonehub/quick_action_controller_base.h" #include "chromeos/components/phonehub/find_my_device_controller.h" namespace base { @@ -17,12 +17,10 @@ // Controller of a quick action item that toggles Locate phone mode. class LocatePhoneQuickActionController : public QuickActionControllerBase, - public SilencePhoneQuickActionController::Observer, public chromeos::phonehub::FindMyDeviceController::Observer { public: LocatePhoneQuickActionController( - chromeos::phonehub::FindMyDeviceController* find_my_device_controller, - SilencePhoneQuickActionController* silence_phone_controller); + chromeos::phonehub::FindMyDeviceController* find_my_device_controller); ~LocatePhoneQuickActionController() override; LocatePhoneQuickActionController(LocatePhoneQuickActionController&) = delete; LocatePhoneQuickActionController operator=( @@ -32,9 +30,6 @@ QuickActionItem* CreateItem() override; void OnButtonPressed(bool is_now_enabled) override; - // SilencePhoneQuickActionController::Observer: - void OnSilencePhoneItemStateChanged() override; - // chromeos::phonehub::FindMyDeviceController::Observer: void OnPhoneRingingStateChanged() override; @@ -43,8 +38,8 @@ // state has a corresponding icon, labels and tooltip view. enum class ActionState { kNotAvailable, kOff, kOn }; - // Compute and update the state of the item according to Silence Phone item - // and FindMyDeviceController. + // Compute and update the state of the item according to + // FindMyDeviceController. void UpdateState(); // Set the item (including icon, label and tooltips) to a certain state. @@ -56,15 +51,11 @@ chromeos::phonehub::FindMyDeviceController* find_my_device_controller_ = nullptr; - SilencePhoneQuickActionController* silence_phone_controller_ = nullptr; QuickActionItem* item_ = nullptr; // Keep track the current state of the item. ActionState state_ = ActionState::kOff; - // Keep track the state of Silence Phone item. - bool is_silence_enabled_ = false; - // State that user requests when clicking the button. base::Optional<ActionState> requested_state_;
diff --git a/ash/system/phonehub/phone_disconnected_view.cc b/ash/system/phonehub/phone_disconnected_view.cc index d275ea2..3b455d4 100644 --- a/ash/system/phonehub/phone_disconnected_view.cc +++ b/ash/system/phonehub/phone_disconnected_view.cc
@@ -16,6 +16,7 @@ #include "ash/system/phonehub/phone_hub_view_ids.h" #include "ash/system/phonehub/ui_constants.h" #include "chromeos/components/phonehub/connection_scheduler.h" +#include "chromeos/components/phonehub/url_constants.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/views/layout/fill_layout.h" @@ -53,7 +54,8 @@ base::BindRepeating( &NewWindowDelegate::NewTabWithUrl, base::Unretained(NewWindowDelegate::GetInstance()), - GURL(kLearnMoreUrl), /*from_user_interaction=*/true)), + GURL(chromeos::phonehub::kPhoneHubLearnMoreLink), + /*from_user_interaction=*/true)), l10n_util::GetStringUTF16( IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_LEARN_MORE_BUTTON), /*paint_background=*/false);
diff --git a/ash/system/phonehub/phone_hub_notification_controller.cc b/ash/system/phonehub/phone_hub_notification_controller.cc index 2cf2351..e04276c 100644 --- a/ash/system/phonehub/phone_hub_notification_controller.cc +++ b/ash/system/phonehub/phone_hub_notification_controller.cc
@@ -286,7 +286,8 @@ void PhoneHubNotificationController::OnNotificationsAdded( const base::flat_set<int64_t>& notification_ids) { for (int64_t id : notification_ids) { - CreateOrUpdateNotification(manager_->GetNotification(id)); + SetNotification(manager_->GetNotification(id), + /*is_update=*/false); } LogNotificationCount(); @@ -295,7 +296,8 @@ void PhoneHubNotificationController::OnNotificationsUpdated( const base::flat_set<int64_t>& notification_ids) { for (int64_t id : notification_ids) { - CreateOrUpdateNotification(manager_->GetNotification(id)); + SetNotification(manager_->GetNotification(id), + /*is_update=*/true); } } @@ -375,8 +377,9 @@ phone_hub_metrics::LogNotificationCount(count); } -void PhoneHubNotificationController::CreateOrUpdateNotification( - const chromeos::phonehub::Notification* notification) { +void PhoneHubNotificationController::SetNotification( + const chromeos::phonehub::Notification* notification, + bool is_update) { int64_t phone_hub_id = notification->id(); std::string cros_id = base::StrCat( {kNotifierId, kNotifierIdSeparator, base::NumberToString(phone_hub_id)}); @@ -389,7 +392,8 @@ } NotificationDelegate* delegate = notification_map_[phone_hub_id].get(); - auto cros_notification = CreateNotification(notification, cros_id, delegate); + auto cros_notification = + CreateNotification(notification, cros_id, delegate, is_update); cros_notification->set_custom_view_type(kNotificationCustomViewType); shown_notification_ids_.insert(phone_hub_id); @@ -404,7 +408,8 @@ PhoneHubNotificationController::CreateNotification( const chromeos::phonehub::Notification* notification, const std::string& cros_id, - NotificationDelegate* delegate) { + NotificationDelegate* delegate, + bool is_update) { message_center::NotifierId notifier_id( message_center::NotifierType::PHONE_HUB, kNotifierId); @@ -428,28 +433,14 @@ const gfx::Image& icon = notification->contact_image().value_or(gfx::Image()); - switch (notification->importance()) { - case chromeos::phonehub::Notification::Importance::kNone: - FALLTHROUGH; - case chromeos::phonehub::Notification::Importance::kLow: - optional_fields.priority = message_center::MIN_PRIORITY; - break; - case chromeos::phonehub::Notification::Importance::kUnspecified: - FALLTHROUGH; - case chromeos::phonehub::Notification::Importance::kMin: - FALLTHROUGH; - case chromeos::phonehub::Notification::Importance::kDefault: - optional_fields.priority = message_center::LOW_PRIORITY; - break; - case chromeos::phonehub::Notification::Importance::kHigh: - // If the notification has already been shown in the past (even across - // disconnects), then downgrade the priority so it's not a pop-up. - if (base::Contains(shown_notification_ids_, notification->id())) - optional_fields.priority = message_center::LOW_PRIORITY; - else - optional_fields.priority = message_center::MAX_PRIORITY; - break; - } + optional_fields.priority = + GetSystemPriorityForNotification(notification, is_update); + + // If the notification was updated, set renotify to true so that the + // notification pops up again and is visible to the user. See + // https://crbug.com/1159063. + if (is_update) + optional_fields.renotify = true; message_center::ButtonInfo reply_button; reply_button.title = l10n_util::GetStringUTF16( @@ -468,6 +459,39 @@ delegate->AsScopedRefPtr()); } +int PhoneHubNotificationController::GetSystemPriorityForNotification( + const chromeos::phonehub::Notification* notification, + bool is_update) { + switch (notification->importance()) { + case chromeos::phonehub::Notification::Importance::kNone: + FALLTHROUGH; + case chromeos::phonehub::Notification::Importance::kMin: + return message_center::MIN_PRIORITY; + + case chromeos::phonehub::Notification::Importance::kUnspecified: + FALLTHROUGH; + case chromeos::phonehub::Notification::Importance::kLow: + FALLTHROUGH; + case chromeos::phonehub::Notification::Importance::kDefault: + FALLTHROUGH; + case chromeos::phonehub::Notification::Importance::kHigh: + bool has_notification_been_shown = + base::Contains(shown_notification_ids_, notification->id()); + + // If the same notification was already shown and has not been updated, + // use LOW_PRIORITY so that the notification is silently added to the + // notification shade. This ensures that we don't spam users with the same + // information multiple times. + if (has_notification_been_shown && !is_update) + return message_center::LOW_PRIORITY; + + // Use MAX_PRIORITY, which causes the notification to be shown in a popup + // so that users can see new messages come in as they are chatting. See + // https://crbug.com/1159063. + return message_center::MAX_PRIORITY; + } +} + // static std::unique_ptr<message_center::MessageView> PhoneHubNotificationController::CreateCustomNotificationView(
diff --git a/ash/system/phonehub/phone_hub_notification_controller.h b/ash/system/phonehub/phone_hub_notification_controller.h index e7bf8f5..6dd8c9e 100644 --- a/ash/system/phonehub/phone_hub_notification_controller.h +++ b/ash/system/phonehub/phone_hub_notification_controller.h
@@ -79,16 +79,21 @@ // Logs the number of PhoneHub notifications. void LogNotificationCount(); - // Creates or updates a ChromeOS notification for the given PhoneHub - // notification data. - void CreateOrUpdateNotification( - const chromeos::phonehub::Notification* notification); + // Shows a Chrome OS notification for the provided phonehub::Notification. + // If |is_update| is true, this function updates an existing notification; + // otherwise, a new notification is created. + void SetNotification(const chromeos::phonehub::Notification* notification, + bool is_update); // Creates a message_center::Notification from the PhoneHub notification data. std::unique_ptr<message_center::Notification> CreateNotification( const chromeos::phonehub::Notification* notification, const std::string& cros_id, - NotificationDelegate* delegate); + NotificationDelegate* delegate, + bool is_update); + int GetSystemPriorityForNotification( + const chromeos::phonehub::Notification* notification, + bool is_update); static std::unique_ptr<message_center::MessageView> CreateCustomNotificationView(
diff --git a/ash/system/phonehub/phone_hub_notification_controller_unittest.cc b/ash/system/phonehub/phone_hub_notification_controller_unittest.cc index e4725c63..f3394d4 100644 --- a/ash/system/phonehub/phone_hub_notification_controller_unittest.cc +++ b/ash/system/phonehub/phone_hub_notification_controller_unittest.cc
@@ -327,7 +327,7 @@ ASSERT_TRUE(cros_notification); EXPECT_EQ(message_center::LOW_PRIORITY, cros_notification->priority()); - // Disable the feature.. + // Disable the feature. feature_status_provider_->SetStatus( chromeos::phonehub::FeatureStatus::kDisabled); notification_manager_->RemoveNotification(kPhoneHubNotificationId0); @@ -340,6 +340,25 @@ cros_notification = FindNotification(kCrOSNotificationId0); ASSERT_TRUE(cros_notification); EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority()); + + // Update the notification with some new text, but keep the notification ID + // the same. + chromeos::phonehub::Notification modified_fake_notification( + kPhoneHubNotificationId0, + chromeos::phonehub::Notification::AppMetadata(base::UTF8ToUTF16(kAppName), + kPackageName, + /*icon=*/gfx::Image()), + base::Time::Now(), chromeos::phonehub::Notification::Importance::kHigh, + /*inline_reply_id=*/0, base::UTF8ToUTF16(kTitle), + base::UTF8ToUTF16("New text")); + + // Update the existingt notification; the priority should be MAX_PRIORITY, and + // renotify should be true. + notification_manager_->SetNotification(modified_fake_notification); + cros_notification = FindNotification(kCrOSNotificationId0); + ASSERT_TRUE(cros_notification); + EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority()); + EXPECT_TRUE(cros_notification->renotify()); } } // namespace ash
diff --git a/ash/system/phonehub/phone_hub_tray_unittest.cc b/ash/system/phonehub/phone_hub_tray_unittest.cc index 982d0a0..6f9dba7 100644 --- a/ash/system/phonehub/phone_hub_tray_unittest.cc +++ b/ash/system/phonehub/phone_hub_tray_unittest.cc
@@ -417,7 +417,7 @@ // article in a browser tab. EXPECT_CALL(new_window_delegate(), NewTabWithUrl) .WillOnce([](const GURL& url, bool from_user_interaction) { - EXPECT_EQ(GURL("https://support.google.com/chromebook/?p=multi_device"), + EXPECT_EQ(GURL("https://support.google.com/chromebook?p=phone_hub"), url); EXPECT_TRUE(from_user_interaction); }); @@ -438,7 +438,7 @@ // article in a browser tab. EXPECT_CALL(new_window_delegate(), NewTabWithUrl) .WillOnce([](const GURL& url, bool from_user_interaction) { - EXPECT_EQ(GURL("https://support.google.com/chromebook/?p=multi_device"), + EXPECT_EQ(GURL("https://support.google.com/chromebook?p=phone_hub"), url); EXPECT_TRUE(from_user_interaction); });
diff --git a/ash/system/phonehub/quick_actions_view.cc b/ash/system/phonehub/quick_actions_view.cc index c8a5badc..745ab12 100644 --- a/ash/system/phonehub/quick_actions_view.cc +++ b/ash/system/phonehub/quick_actions_view.cc
@@ -49,8 +49,7 @@ auto locate_phone_controller = std::make_unique<LocatePhoneQuickActionController>( - phone_hub_manager_->GetFindMyDeviceController(), - silence_phone_controller.get()); + phone_hub_manager_->GetFindMyDeviceController()); locate_phone_ = AddChildView(locate_phone_controller->CreateItem()); quick_action_controllers_.push_back(std::move(silence_phone_controller));
diff --git a/ash/system/phonehub/quick_actions_view_unittest.cc b/ash/system/phonehub/quick_actions_view_unittest.cc index fe594cd..b92bcd1f 100644 --- a/ash/system/phonehub/quick_actions_view_unittest.cc +++ b/ash/system/phonehub/quick_actions_view_unittest.cc
@@ -112,13 +112,9 @@ test_api.NotifyClick(DummyEvent()); EXPECT_TRUE(dnd_controller()->IsDndEnabled()); - // Locate phone should be disabled when do not disturb is enabled. - EXPECT_FALSE(actions_view()->locate_phone_for_testing()->GetEnabled()); - // Toggle again to disable. test_api.NotifyClick(DummyEvent()); EXPECT_FALSE(dnd_controller()->IsDndEnabled()); - EXPECT_TRUE(actions_view()->locate_phone_for_testing()->GetEnabled()); // Test the error state. dnd_controller()->SetShouldRequestFail(true);
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller.cc b/ash/system/phonehub/silence_phone_quick_action_controller.cc index a3eef773..49c0823 100644 --- a/ash/system/phonehub/silence_phone_quick_action_controller.cc +++ b/ash/system/phonehub/silence_phone_quick_action_controller.cc
@@ -36,14 +36,6 @@ dnd_controller_->RemoveObserver(this); } -void SilencePhoneQuickActionController::AddObserver(Observer* observer) { - observer_list_.AddObserver(observer); -} - -void SilencePhoneQuickActionController::RemoveObserver(Observer* observer) { - observer_list_.RemoveObserver(observer); -} - bool SilencePhoneQuickActionController::IsItemEnabled() { return item_->IsToggled(); } @@ -133,8 +125,6 @@ IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP, item_->GetItemLabel(), tooltip_state)); } - for (auto& observer : observer_list_) - observer.OnSilencePhoneItemStateChanged(); } void SilencePhoneQuickActionController::CheckRequestedState() {
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller.h b/ash/system/phonehub/silence_phone_quick_action_controller.h index 7ded968..4305b53 100644 --- a/ash/system/phonehub/silence_phone_quick_action_controller.h +++ b/ash/system/phonehub/silence_phone_quick_action_controller.h
@@ -6,8 +6,6 @@ #define ASH_SYSTEM_PHONEHUB_SILENCE_PHONE_QUICK_ACTION_CONTROLLER_H_ #include "ash/system/phonehub/quick_action_controller_base.h" -#include "base/observer_list.h" -#include "base/observer_list_types.h" #include "chromeos/components/phonehub/do_not_disturb_controller.h" namespace base { @@ -21,14 +19,6 @@ : public QuickActionControllerBase, public chromeos::phonehub::DoNotDisturbController::Observer { public: - class Observer : public base::CheckedObserver { - public: - ~Observer() override = default; - - // Called when the state of the item has changed. - virtual void OnSilencePhoneItemStateChanged() = 0; - }; - explicit SilencePhoneQuickActionController( chromeos::phonehub::DoNotDisturbController* dnd_controller); ~SilencePhoneQuickActionController() override; @@ -37,9 +27,6 @@ SilencePhoneQuickActionController operator=( SilencePhoneQuickActionController&) = delete; - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - // Return true if the item is enabled/toggled. bool IsItemEnabled(); @@ -80,9 +67,6 @@ // if the requested state is similar to the current state after the button is // pressed for a certain time. std::unique_ptr<base::OneShotTimer> check_requested_state_timer_; - - // Registered observers. - base::ObserverList<Observer> observer_list_; }; } // namespace ash
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller_unittest.cc b/ash/system/phonehub/silence_phone_quick_action_controller_unittest.cc index ca9a58a..db9aa76 100644 --- a/ash/system/phonehub/silence_phone_quick_action_controller_unittest.cc +++ b/ash/system/phonehub/silence_phone_quick_action_controller_unittest.cc
@@ -9,9 +9,7 @@ namespace ash { -class SilencePhoneQuickActionControllerTest - : public AshTestBase, - public SilencePhoneQuickActionController::Observer { +class SilencePhoneQuickActionControllerTest : public AshTestBase { public: SilencePhoneQuickActionControllerTest() = default; @@ -26,21 +24,16 @@ controller_ = std::make_unique<SilencePhoneQuickActionController>( dnd_controller_.get()); - controller_->AddObserver(this); controller_->CreateItem(); } void TearDown() override { - controller_->RemoveObserver(this); controller_.reset(); dnd_controller_.reset(); AshTestBase::TearDown(); } protected: - // SilencePhoneQuickActionController::Observer: - void OnSilencePhoneItemStateChanged() override { ++num_calls_; } - SilencePhoneQuickActionController* controller() { return controller_.get(); } chromeos::phonehub::FakeDoNotDisturbController* dnd_controller() { @@ -52,37 +45,28 @@ controller_->GetItemState(); } - size_t GetNumObserverCalls() { return num_calls_; } - private: std::unique_ptr<SilencePhoneQuickActionController> controller_; std::unique_ptr<chromeos::phonehub::FakeDoNotDisturbController> dnd_controller_; - size_t num_calls_ = 0; }; TEST_F(SilencePhoneQuickActionControllerTest, ItemStateChanged) { // Set request to fail to avoid triggering state's changes by the model. dnd_controller()->SetShouldRequestFail(true); - // Initially, there's one observer call during initiation. - EXPECT_EQ(1u, GetNumObserverCalls()); - // Allow the button to be enabled. dnd_controller()->SetDoNotDisturbStateInternal( /*is_dnd_enabled=*/false, /*can_request_new_dnd_state=*/true); - EXPECT_EQ(2u, GetNumObserverCalls()); // Press the button to enabled state will trigger observer. controller()->OnButtonPressed(false /* is_now_enabled */); - EXPECT_EQ(3u, GetNumObserverCalls()); // Item state changed to enabled. EXPECT_TRUE(controller()->IsItemEnabled()); // Press the button to disabled state will trigger observer. controller()->OnButtonPressed(true /* is_now_enabled */); - EXPECT_EQ(4u, GetNumObserverCalls()); // Item state changed to disabled. EXPECT_FALSE(controller()->IsItemEnabled()); @@ -94,7 +78,7 @@ // Set DoNotDisturbState to not allow any new request. dnd_controller()->SetDoNotDisturbStateInternal( /*is_dnd_enabled=*/false, /*can_request_new_dnd_state=*/false); - EXPECT_EQ(1u, GetNumObserverCalls()); + // Since no new state requests are allowed, expect the button to be disabled. EXPECT_FALSE(controller()->IsItemEnabled()); EXPECT_TRUE(IsButtonDisabled()); @@ -103,7 +87,7 @@ // work profile. dnd_controller()->SetDoNotDisturbStateInternal( /*is_dnd_enabled=*/true, /*can_request_new_dnd_state=*/false); - EXPECT_EQ(2u, GetNumObserverCalls()); + // The button should still be disabled despite the phone has DoNotDisturb mode // enabled. However, the underlying toggle has been flipped to enabled. EXPECT_TRUE(controller()->IsItemEnabled()); @@ -112,7 +96,6 @@ // Flip toggle state back to enabled, but still in a work profile. dnd_controller()->SetDoNotDisturbStateInternal( /*is_dnd_enabled=*/false, /*can_request_new_dnd_state=*/false); - EXPECT_EQ(3u, GetNumObserverCalls()); EXPECT_FALSE(controller()->IsItemEnabled()); EXPECT_TRUE(IsButtonDisabled()); }
diff --git a/ash/system/phonehub/ui_constants.h b/ash/system/phonehub/ui_constants.h index 0eb8b46..33f9d19 100644 --- a/ash/system/phonehub/ui_constants.h +++ b/ash/system/phonehub/ui_constants.h
@@ -11,11 +11,6 @@ constexpr int kBubbleHorizontalSidePaddingDip = 16; constexpr int kBubbleBottomPaddingDip = 16; -// URLs. -// TODO(meilinw): replace it with the real one. -constexpr char kLearnMoreUrl[] = - "https://support.google.com/chromebook/?p=multi_device"; - } // namespace ash #endif // ASH_SYSTEM_PHONEHUB_UI_CONSTANTS_H_
diff --git a/base/files/file_descriptor_watcher_posix.cc b/base/files/file_descriptor_watcher_posix.cc index 0da1c78..8d2ab70 100644 --- a/base/files/file_descriptor_watcher_posix.cc +++ b/base/files/file_descriptor_watcher_posix.cc
@@ -234,7 +234,11 @@ WeakPtr<Controller> weak_this = weak_factory_.GetWeakPtr(); - callback_.Run(); + // Run a copy of the callback in case this Controller is deleted by the + // callback. This would cause the callback itself to be deleted while it is + // being run. + RepeatingClosure callback_copy = callback_; + callback_copy.Run(); // If |this| wasn't deleted, re-enable the watch. if (weak_this)
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc index 43ff1654..a4de2af9 100644 --- a/base/files/important_file_writer.cc +++ b/base/files/important_file_writer.cc
@@ -42,6 +42,15 @@ namespace { constexpr auto kDefaultCommitInterval = TimeDelta::FromSeconds(10); +#if defined(OS_WIN) +// This is how many times we will retry ReplaceFile on Windows. +constexpr int kReplaceRetries = 5; +// This is the result code recorded if ReplaceFile still fails. +// It should stay constant even if we change kReplaceRetries. +constexpr int kReplaceRetryFailure = 10; +static_assert(kReplaceRetryFailure > kReplaceRetries, "No overlap allowed"); +constexpr auto kReplacePauseInterval = TimeDelta::FromMilliseconds(100); +#endif // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. @@ -285,21 +294,41 @@ PlatformThread::SetCurrentThreadPriority(ThreadPriority::DISPLAY); #endif // defined(OS_WIN) tmp_file.Close(); - const bool result = ReplaceFile(tmp_file_path, path, &replace_file_error); + bool result = ReplaceFile(tmp_file_path, path, &replace_file_error); #if defined(OS_WIN) // Save and restore the last error code so that it's not polluted by the // thread priority change. - const auto last_error = ::GetLastError(); + auto last_error = ::GetLastError(); + int retry_count = 0; + for (/**/; !result && retry_count < kReplaceRetries; ++retry_count) { + // The race condition between closing the temporary file and moving it gets + // hit on a regular basis on some systems (https://crbug.com/1099284), so + // we retry a few times before giving up. + PlatformThread::Sleep(kReplacePauseInterval); + result = ReplaceFile(tmp_file_path, path, &replace_file_error); + last_error = ::GetLastError(); + } if (reset_priority) PlatformThread::SetCurrentThreadPriority(previous_priority); + + // Log how many times we had to retry the ReplaceFile operation before it + // succeeded. If we never succeeded then return a special value. if (!result) - ::SetLastError(last_error); + retry_count = kReplaceRetryFailure; + UmaHistogramExactLinear("ImportantFile.FileReplaceRetryCount", retry_count, + kReplaceRetryFailure); #endif // defined(OS_WIN) if (!result) { UmaHistogramExactLinearWithSuffix("ImportantFile.FileRenameError", histogram_suffix, -replace_file_error, -File::FILE_ERROR_MAX); +#if defined(OS_WIN) + // Restore the error code from ReplaceFile so that it will be available for + // LogFailure, otherwise failures in SetCurrrentThreadPriority may be + // reported instead. + ::SetLastError(last_error); +#endif LogFailure(path, histogram_suffix, FAILED_RENAMING, "could not rename temporary file"); DeleteTmpFileWithRetry(File(), tmp_file_path, histogram_suffix);
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index 45bc2a3..e4ad791 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -298,10 +298,6 @@ List of all resource zip files belonging to all transitive resource dependencies of this target. Excludes resources owned by non-chromium code. -* `deps_info['owned_resource_srcjars']`: -List of all .srcjar files belonging to all *direct* resource dependencies (i.e. -without another java_library in the dependency path) for this target. - * `deps_info['javac']`: A dictionary containing information about the way the sources in this library are compiled. Appears also on other Java-related targets. See the [dedicated @@ -1428,33 +1424,16 @@ if options.res_sources_path: deps_info['res_sources_path'] = options.res_sources_path - if options.requires_android and is_java_target: - owned_resource_srcjars = set() - for c in all_resources_deps: - srcjar = c.get('srcjar') - if srcjar: - owned_resource_srcjars.add(srcjar) - for c in all_library_deps: - if c['requires_android'] and not c['is_prebuilt']: - # Many .aar files include R.class files in them, as it makes it easier - # for IDEs to resolve symbols. However, including them is not required - # and not all prebuilts do. Rather than try to detect their presense, - # just assume they are not there. The only consequence is redundant - # compilation of the R.class. - owned_resource_srcjars.difference_update(c['owned_resource_srcjars']) - deps_info['owned_resource_srcjars'] = sorted(owned_resource_srcjars) - - if options.type == 'java_library': - # Used to strip out R.class for android_prebuilt()s. - config['javac']['resource_packages'] = [ - c['package_name'] for c in all_resources_deps if 'package_name' in c - ] - if options.package_name: - deps_info['package_name'] = options.package_name + if options.requires_android and options.type == 'java_library': + # Used to strip out R.class for android_prebuilt()s. + config['javac']['resource_packages'] = [ + c['package_name'] for c in all_resources_deps if 'package_name' in c + ] + if options.package_name: + deps_info['package_name'] = options.package_name if options.type in ('android_resources', 'android_apk', 'junit_binary', 'dist_aar', 'android_app_bundle_module', 'java_library'): - dependency_zips = [] dependency_zip_overlays = [] for c in all_resources_deps:
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 64fe0cec..3446420 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -3088,7 +3088,6 @@ # java_files: Optional list of Java source file paths. # srcjar_deps: Optional list of .srcjar dependencies (not file paths). # The corresponding source files they contain will be compiled too. - # srcjar_filearg: Optional @FileArg for additional srcjars. # java_sources_file: Optional path to file containing list of Java source # file paths. This must always be provided if java_files is not empty # and must match it exactly. @@ -3254,9 +3253,6 @@ if (enable_kythe_annotations && !invoker.enable_errorprone) { args += [ "--enable-kythe-annotations" ] } - if (defined(invoker.srcjar_filearg)) { - args += [ "--java-srcjars=${invoker.srcjar_filearg}" ] - } if (invoker.requires_android) { args += [ "--bootclasspath=@FileArg($_rebased_build_config:android:sdk_interface_jars)" ] } @@ -3839,10 +3835,6 @@ _uses_fake_rjava = _type == "java_library" && _requires_android - # android_apk and junit_binary pass real R.java srcjars via - # srcjar_deps. Other targets, that do not define resources_package, - # will use the owned_resource_srcjars of their android_resources - # dependencies instead. if (_uses_fake_rjava && defined(_resources_package)) { # has _resources at the end so it looks like a resources pattern, since # it does act like one (and other resources patterns need to depend on @@ -3889,15 +3881,6 @@ deps = [] } deps += _classpath_deps - - # android_apk and junit_binary pass real R.java srcjars via - # srcjar_deps. Other targets that do not define resources_package - # will use the owned_resource_srcjars of their android_resources - # dependencies instead. - if (_uses_fake_rjava && !defined(_resources_package)) { - _rebased_build_config = rebase_path(_build_config, root_build_dir) - srcjar_filearg = "@FileArg($_rebased_build_config:deps_info:owned_resource_srcjars)" - } } } _compile_java_forward_variables = [
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index e498a04..5b632be 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20201228.3.1 +0.20201230.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index e498a04..5b632be 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20201228.3.1 +0.20201230.2.1
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn index 835cd36..96b1695 100644 --- a/build/toolchain/mac/BUILD.gn +++ b/build/toolchain/mac/BUILD.gn
@@ -444,10 +444,7 @@ # Instead use clonefile to copy the files which is as efficient as # hardlink but ensure the file have distinct metadata (thus avoid the # error with ditto, see https://crbug.com/1042182). - command = - "rm -rf {{output}} && cp -fRc {{source}} {{output}} 2>/dev/null " + - "|| (rm -rf {{output}} && cp -fR {{source}} {{output}})" - + command = "rm -rf {{output}} && cp -Rc {{source}} {{output}}" description = "COPY_BUNDLE_DATA {{source}} {{output}}" pool = ":bundle_pool($default_toolchain)" }
diff --git a/cc/layers/heads_up_display_layer.cc b/cc/layers/heads_up_display_layer.cc index cd1128d..09dbbd9e 100644 --- a/cc/layers/heads_up_display_layer.cc +++ b/cc/layers/heads_up_display_layer.cc
@@ -91,7 +91,7 @@ layer_impl->SetHUDTypeface(typeface_); layer_impl->SetLayoutShiftRects(layout_shift_rects_); layout_shift_rects_.clear(); - if (web_vital_metrics_) + if (web_vital_metrics_ && web_vital_metrics_->HasValue()) layer_impl->SetWebVitalMetrics(std::move(web_vital_metrics_)); }
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc index 1cb7a619..01534350 100644 --- a/cc/layers/heads_up_display_layer_impl.cc +++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -567,7 +567,8 @@ layer_impl->SetHUDTypeface(typeface_); layer_impl->SetLayoutShiftRects(layout_shift_rects_); layout_shift_rects_.clear(); - layer_impl->SetWebVitalMetrics(std::move(web_vital_metrics_)); + if (web_vital_metrics_ && web_vital_metrics_->HasValue()) + layer_impl->SetWebVitalMetrics(std::move(web_vital_metrics_)); } void HeadsUpDisplayLayerImpl::UpdateHudContents() {
diff --git a/cc/paint/paint_filter.h b/cc/paint/paint_filter.h index 556ab9a9..532aca4 100644 --- a/cc/paint/paint_filter.h +++ b/cc/paint/paint_filter.h
@@ -33,7 +33,7 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt { public: - enum class Type : uint32_t { + enum class Type { // For serialization purposes, we reserve one enum to indicate that there // was no PaintFilter, ie the filter is "null". kNullFilter, @@ -60,13 +60,13 @@ kLightingPoint, kLightingSpot, // Update the following if kLightingSpot is not the max anymore. - kMaxFilterType = kLightingSpot + kMaxValue = kLightingSpot }; - enum class LightingType : uint32_t { + enum class LightingType { kDiffuse, kSpecular, // Update the following if kSpecular is not the max anymore. - kMaxLightingType = kSpecular + kMaxValue = kSpecular }; using MapDirection = SkImageFilter::MapDirection; @@ -554,7 +554,7 @@ class CC_PAINT_EXPORT MorphologyPaintFilter final : public PaintFilter { public: - enum class MorphType : uint32_t { kDilate, kErode, kMaxMorphType = kErode }; + enum class MorphType { kDilate, kErode, kMaxValue = kErode }; static constexpr Type kType = Type::kMorphology; MorphologyPaintFilter(MorphType morph_type, float radius_x, @@ -636,10 +636,10 @@ class CC_PAINT_EXPORT TurbulencePaintFilter final : public PaintFilter { public: static constexpr Type kType = Type::kTurbulence; - enum class TurbulenceType : uint32_t { + enum class TurbulenceType { kTurbulence, kFractalNoise, - kMaxTurbulenceType = kFractalNoise + kMaxValue = kFractalNoise }; TurbulencePaintFilter(TurbulenceType turbulence_type, SkScalar base_frequency_x,
diff --git a/cc/paint/paint_filter_unittest.cc b/cc/paint/paint_filter_unittest.cc index 9e56256..df029b8 100644 --- a/cc/paint/paint_filter_unittest.cc +++ b/cc/paint/paint_filter_unittest.cc
@@ -153,7 +153,7 @@ P, PaintFilterTest, ::testing::Range(static_cast<uint8_t>(PaintFilter::Type::kColorFilter), - static_cast<uint8_t>(PaintFilter::Type::kMaxFilterType))); + static_cast<uint8_t>(PaintFilter::Type::kMaxValue))); TEST_P(PaintFilterTest, HasDiscardableImagesYes) { // TurbulencePaintFilter can not embed images.
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc index 10e5201..5012427 100644 --- a/cc/paint/paint_op_buffer_unittest.cc +++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -2536,7 +2536,10 @@ buffer.push<ClipRectOp>(test_rects[0], bad_clip, true); buffer.push<ClipRRectOp>(test_rrects[0], bad_clip, false); - SkClipOp bad_clip_max = static_cast<SkClipOp>(~static_cast<uint32_t>(0)); + // SkClipOp is serialized to uint8_t (see WriteEnum). Values outside uint8_t + // would crash the serialization, so this is the max value that passes checked + // cast but will still fail validation during deserialization. + SkClipOp bad_clip_max = static_cast<SkClipOp>(static_cast<uint8_t>(~0)); buffer.push<ClipRectOp>(test_rects[1], bad_clip_max, false); TestOptionsProvider options_provider; @@ -2598,15 +2601,15 @@ SkBlendMode::kSaturation, SkBlendMode::kColor, SkBlendMode::kLuminosity, - static_cast<SkBlendMode>(static_cast<uint32_t>(SkBlendMode::kLastMode) + + static_cast<SkBlendMode>(static_cast<uint8_t>(SkBlendMode::kLastMode) + 1), - static_cast<SkBlendMode>(static_cast<uint32_t>(~0)), + static_cast<SkBlendMode>(static_cast<uint8_t>(~0)), }; SkBlendMode bad_modes_for_flags[] = { - static_cast<SkBlendMode>(static_cast<uint32_t>(SkBlendMode::kLastMode) + + static_cast<SkBlendMode>(static_cast<uint8_t>(SkBlendMode::kLastMode) + 1), - static_cast<SkBlendMode>(static_cast<uint32_t>(~0)), + static_cast<SkBlendMode>(static_cast<uint8_t>(~0)), }; for (size_t i = 0; i < base::size(bad_modes_for_draw_color); ++i) {
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc index 48394f53..ef65cf7 100644 --- a/cc/paint/paint_op_reader.cc +++ b/cc/paint/paint_op_reader.cc
@@ -41,18 +41,6 @@ static_cast<uint8_t>(PaintShader::Type::kShaderCount); } -// SkTileMode has no defined backing type, so read/write int32_t's. -// If read_mode is a valid tile mode, this returns true and updates mode to the -// equivalent enum value. Otherwise false is returned and mode is not modified. -bool ValidateAndGetSkShaderTileMode(int32_t read_mode, SkTileMode* mode) { - if (read_mode < 0 || read_mode >= kSkTileModeCount) { - return false; - } - - *mode = static_cast<SkTileMode>(read_mode); - return true; -} - bool IsValidPaintShaderScalingBehavior(PaintShader::ScalingBehavior behavior) { return behavior == PaintShader::ScalingBehavior::kRasterAtScale || behavior == PaintShader::ScalingBehavior::kFixedScale; @@ -266,11 +254,7 @@ Read(&flags->width_); Read(&flags->miter_limit_); - ReadSimple(&flags->blend_mode_); - if (flags->blend_mode_ > static_cast<uint32_t>(SkBlendMode::kLastMode)) { - SetInvalid(); - return; - } + Read(&flags->blend_mode_); ReadSimple(&flags->bitfields_uint_); @@ -523,16 +507,8 @@ ReadSimple(&ref.flags_); ReadSimple(&ref.end_radius_); ReadSimple(&ref.start_radius_); - - // See ValidateAndGetSkShaderTileMode - int32_t tx = 0; - int32_t ty = 0; - Read(&tx); - Read(&ty); - if (!ValidateAndGetSkShaderTileMode(tx, &ref.tx_) || - !ValidateAndGetSkShaderTileMode(ty, &ref.ty_)) { - SetInvalid(); - } + Read(&ref.tx_); + Read(&ref.ty_); ReadSimple(&ref.fallback_color_); ReadSimple(&ref.scaling_behavior_); if (!IsValidPaintShaderScalingBehavior(ref.scaling_behavior_)) @@ -650,18 +626,6 @@ ReadSimple(matrix); } -void PaintOpReader::Read(SkColorType* color_type) { - uint32_t raw_color_type = kUnknown_SkColorType; - ReadSimple(&raw_color_type); - - if (raw_color_type > kLastEnum_SkColorType) { - SetInvalid(); - return; - } - - *color_type = static_cast<SkColorType>(raw_color_type); -} - void PaintOpReader::Read(SkYUVColorSpace* yuv_color_space) { uint32_t raw_yuv_color_space = kIdentity_SkYUVColorSpace; ReadSimple(&raw_yuv_color_space); @@ -773,14 +737,11 @@ } void PaintOpReader::Read(sk_sp<PaintFilter>* filter) { - uint32_t type_int = 0; - ReadSimple(&type_int); - if (type_int > static_cast<uint32_t>(PaintFilter::Type::kMaxFilterType)) - SetInvalid(); + PaintFilter::Type type; + ReadEnum(&type); if (!valid_) return; - auto type = static_cast<PaintFilter::Type>(type_int); if (type == PaintFilter::Type::kNullFilter) { *filter = nullptr; return; @@ -910,13 +871,13 @@ void PaintOpReader::ReadDropShadowPaintFilter( sk_sp<PaintFilter>* filter, const base::Optional<PaintFilter::CropRect>& crop_rect) { + using ShadowMode = DropShadowPaintFilter::ShadowMode; SkScalar dx = 0.f; SkScalar dy = 0.f; SkScalar sigma_x = 0.f; SkScalar sigma_y = 0.f; SkColor color = SK_ColorBLACK; - DropShadowPaintFilter::ShadowMode shadow_mode = - SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode; + ShadowMode shadow_mode; sk_sp<PaintFilter> input; Read(&dx); @@ -924,11 +885,9 @@ Read(&sigma_x); Read(&sigma_y); Read(&color); - ReadSimple(&shadow_mode); + ReadEnum<ShadowMode, ShadowMode::kLast_ShadowMode>(&shadow_mode); Read(&input); - if (shadow_mode > SkDropShadowImageFilter::kLast_ShadowMode) - SetInvalid(); if (!valid_) return; filter->reset(new DropShadowPaintFilter(dx, dy, sigma_x, sigma_y, color, @@ -987,19 +946,15 @@ void PaintOpReader::ReadXfermodePaintFilter( sk_sp<PaintFilter>* filter, const base::Optional<PaintFilter::CropRect>& crop_rect) { - uint32_t blend_mode_int = 0; + SkBlendMode blend_mode; sk_sp<PaintFilter> background; sk_sp<PaintFilter> foreground; - Read(&blend_mode_int); + Read(&blend_mode); Read(&background); Read(&foreground); - SkBlendMode blend_mode = SkBlendMode::kClear; - if (blend_mode_int > static_cast<uint32_t>(SkBlendMode::kLastMode)) - SetInvalid(); if (!valid_) return; - blend_mode = static_cast<SkBlendMode>(blend_mode_int); filter->reset(new XfermodePaintFilter(blend_mode, std::move(background), std::move(foreground), @@ -1073,33 +1028,25 @@ void PaintOpReader::ReadDisplacementMapEffectPaintFilter( sk_sp<PaintFilter>* filter, const base::Optional<PaintFilter::CropRect>& crop_rect) { - // Unknown, R, G, B, A: max type is 4. - static const int kMaxChannelSelectorType = 4; + using ChannelSelectorType = + DisplacementMapEffectPaintFilter::ChannelSelectorType; - uint32_t channel_x_int = 0; - uint32_t channel_y_int = 0; + ChannelSelectorType channel_x; + ChannelSelectorType channel_y; SkScalar scale = 0.f; sk_sp<PaintFilter> displacement; sk_sp<PaintFilter> color; - Read(&channel_x_int); - Read(&channel_y_int); + ReadEnum<ChannelSelectorType, ChannelSelectorType::kLast_ChannelSelectorType>( + &channel_x); + ReadEnum<ChannelSelectorType, ChannelSelectorType::kLast_ChannelSelectorType>( + &channel_y); Read(&scale); Read(&displacement); Read(&color); - if (channel_x_int > kMaxChannelSelectorType || - channel_y_int > kMaxChannelSelectorType) { - SetInvalid(); - } if (!valid_) return; - DisplacementMapEffectPaintFilter::ChannelSelectorType channel_x = - static_cast<DisplacementMapEffectPaintFilter::ChannelSelectorType>( - channel_x_int); - DisplacementMapEffectPaintFilter::ChannelSelectorType channel_y = - static_cast<DisplacementMapEffectPaintFilter::ChannelSelectorType>( - channel_y_int); filter->reset(new DisplacementMapEffectPaintFilter( channel_x, channel_y, scale, std::move(displacement), std::move(color), base::OptionalOrNullptr(crop_rect))); @@ -1167,22 +1114,16 @@ void PaintOpReader::ReadMorphologyPaintFilter( sk_sp<PaintFilter>* filter, const base::Optional<PaintFilter::CropRect>& crop_rect) { - uint32_t morph_type_int = 0; + MorphologyPaintFilter::MorphType morph_type; float radius_x = 0; float radius_y = 0; sk_sp<PaintFilter> input; - Read(&morph_type_int); + ReadEnum(&morph_type); Read(&radius_x); Read(&radius_y); Read(&input); - if (morph_type_int > - static_cast<uint32_t>(MorphologyPaintFilter::MorphType::kMaxMorphType)) { - SetInvalid(); - } if (!valid_) return; - MorphologyPaintFilter::MorphType morph_type = - static_cast<MorphologyPaintFilter::MorphType>(morph_type_int); filter->reset(new MorphologyPaintFilter(morph_type, radius_x, radius_y, std::move(input), base::OptionalOrNullptr(crop_rect))); @@ -1222,28 +1163,21 @@ void PaintOpReader::ReadTurbulencePaintFilter( sk_sp<PaintFilter>* filter, const base::Optional<PaintFilter::CropRect>& crop_rect) { - uint32_t turbulence_type_int = 0; + TurbulencePaintFilter::TurbulenceType turbulence_type; SkScalar base_frequency_x = 0.f; SkScalar base_frequency_y = 0.f; int num_octaves = 0; SkScalar seed = 0.f; SkISize tile_size = SkISize::MakeEmpty(); - Read(&turbulence_type_int); + ReadEnum(&turbulence_type); Read(&base_frequency_x); Read(&base_frequency_y); Read(&num_octaves); Read(&seed); ReadSimple(&tile_size); - if (turbulence_type_int > - static_cast<uint32_t>( - TurbulencePaintFilter::TurbulenceType::kMaxTurbulenceType)) { - SetInvalid(); - } if (!valid_) return; - TurbulencePaintFilter::TurbulenceType turbulence_type = - static_cast<TurbulencePaintFilter::TurbulenceType>(turbulence_type_int); filter->reset(new TurbulencePaintFilter( turbulence_type, base_frequency_x, base_frequency_y, num_octaves, seed, &tile_size, base::OptionalOrNullptr(crop_rect))); @@ -1269,10 +1203,8 @@ sk_sp<PaintFilter> input; Read(&matrix); - ReadSimple(&filter_quality); + Read(&filter_quality); Read(&input); - if (filter_quality > kLast_SkFilterQuality) - SetInvalid(); if (!valid_) return; filter->reset( @@ -1282,7 +1214,7 @@ void PaintOpReader::ReadLightingDistantPaintFilter( sk_sp<PaintFilter>* filter, const base::Optional<PaintFilter::CropRect>& crop_rect) { - uint32_t lighting_type_int = 0; + PaintFilter::LightingType lighting_type; SkPoint3 direction = SkPoint3::Make(0.f, 0.f, 0.f); SkColor light_color = SK_ColorBLACK; SkScalar surface_scale = 0.f; @@ -1290,21 +1222,15 @@ SkScalar shininess = 0.f; sk_sp<PaintFilter> input; - Read(&lighting_type_int); + ReadEnum(&lighting_type); ReadSimple(&direction); Read(&light_color); Read(&surface_scale); Read(&kconstant); Read(&shininess); Read(&input); - if (lighting_type_int > - static_cast<uint32_t>(PaintFilter::LightingType::kMaxLightingType)) { - SetInvalid(); - } if (!valid_) return; - PaintFilter::LightingType lighting_type = - static_cast<PaintFilter::LightingType>(lighting_type_int); filter->reset(new LightingDistantPaintFilter( lighting_type, direction, light_color, surface_scale, kconstant, shininess, std::move(input), base::OptionalOrNullptr(crop_rect))); @@ -1313,7 +1239,7 @@ void PaintOpReader::ReadLightingPointPaintFilter( sk_sp<PaintFilter>* filter, const base::Optional<PaintFilter::CropRect>& crop_rect) { - uint32_t lighting_type_int = 0; + PaintFilter::LightingType lighting_type; SkPoint3 location = SkPoint3::Make(0.f, 0.f, 0.f); SkColor light_color = SK_ColorBLACK; SkScalar surface_scale = 0.f; @@ -1321,21 +1247,15 @@ SkScalar shininess = 0.f; sk_sp<PaintFilter> input; - Read(&lighting_type_int); + ReadEnum(&lighting_type); ReadSimple(&location); Read(&light_color); Read(&surface_scale); Read(&kconstant); Read(&shininess); Read(&input); - if (lighting_type_int > - static_cast<uint32_t>(PaintFilter::LightingType::kMaxLightingType)) { - SetInvalid(); - } if (!valid_) return; - PaintFilter::LightingType lighting_type = - static_cast<PaintFilter::LightingType>(lighting_type_int); filter->reset(new LightingPointPaintFilter( lighting_type, location, light_color, surface_scale, kconstant, shininess, std::move(input), base::OptionalOrNullptr(crop_rect))); @@ -1344,7 +1264,7 @@ void PaintOpReader::ReadLightingSpotPaintFilter( sk_sp<PaintFilter>* filter, const base::Optional<PaintFilter::CropRect>& crop_rect) { - uint32_t lighting_type_int = 0; + PaintFilter::LightingType lighting_type; SkPoint3 location = SkPoint3::Make(0.f, 0.f, 0.f); SkPoint3 target = SkPoint3::Make(0.f, 0.f, 0.f); SkScalar specular_exponent = 0.f; @@ -1355,7 +1275,7 @@ SkScalar shininess = 0.f; sk_sp<PaintFilter> input; - Read(&lighting_type_int); + ReadEnum(&lighting_type); ReadSimple(&location); ReadSimple(&target); Read(&specular_exponent); @@ -1366,14 +1286,8 @@ Read(&shininess); Read(&input); - if (lighting_type_int > - static_cast<uint32_t>(PaintFilter::LightingType::kMaxLightingType)) { - SetInvalid(); - } if (!valid_) return; - PaintFilter::LightingType lighting_type = - static_cast<PaintFilter::LightingType>(lighting_type_int); filter->reset(new LightingSpotPaintFilter( lighting_type, location, target, specular_exponent, cutoff_angle, light_color, surface_scale, kconstant, shininess, std::move(input),
diff --git a/cc/paint/paint_op_reader.h b/cc/paint/paint_op_reader.h index ce03f47a..bbbdb16d 100644 --- a/cc/paint/paint_op_reader.h +++ b/cc/paint/paint_op_reader.h
@@ -72,7 +72,6 @@ void Read(sk_sp<PaintShader>* shader); void Read(SkMatrix* matrix); void Read(SkM44* matrix); - void Read(SkColorType* color_type); void Read(SkImageInfo* info); void Read(sk_sp<SkColorSpace>* color_space); void Read(SkYUVColorSpace* yuv_color_space); @@ -84,39 +83,28 @@ void Read(scoped_refptr<SkottieWrapper>* skottie); #endif - void Read(SkClipOp* op) { - uint8_t value = 0u; - Read(&value); - *op = static_cast<SkClipOp>(value); - } + void Read(SkClipOp* op) { ReadEnum<SkClipOp, SkClipOp::kMax_EnumValue>(op); } void Read(PaintCanvas::AnnotationType* type) { - uint8_t value = 0u; - Read(&value); - *type = static_cast<PaintCanvas::AnnotationType>(value); + ReadEnum<PaintCanvas::AnnotationType, + PaintCanvas::AnnotationType::LINK_TO_DESTINATION>(type); } void Read(SkCanvas::SrcRectConstraint* constraint) { - uint8_t value = 0u; - Read(&value); - *constraint = static_cast<SkCanvas::SrcRectConstraint>(value); + ReadEnum<SkCanvas::SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint>( + constraint); + } + void Read(SkColorType* color_type) { + ReadEnum<SkColorType, kLastEnum_SkColorType>(color_type); } void Read(SkFilterQuality* quality) { - uint8_t value = 0u; - Read(&value); - if (value > static_cast<uint8_t>(kLast_SkFilterQuality)) { - SetInvalid(); - return; - } - *quality = static_cast<SkFilterQuality>(value); + ReadEnum<SkFilterQuality, kLast_SkFilterQuality>(quality); } void Read(SkBlendMode* blend_mode) { - uint8_t value = 0u; - Read(&value); - if (value > static_cast<uint8_t>(SkBlendMode::kLastMode)) { - SetInvalid(); - return; - } - *blend_mode = static_cast<SkBlendMode>(value); + ReadEnum<SkBlendMode, SkBlendMode::kLastMode>(blend_mode); } + void Read(SkTileMode* tile_mode) { + ReadEnum<SkTileMode, SkTileMode::kLastTileMode>(tile_mode); + } + void Read(bool* data) { uint8_t value = 0u; Read(&value); @@ -138,6 +126,19 @@ template <typename T> void ReadFlattenable(sk_sp<T>* val); + template <typename Enum, Enum kMaxValue = Enum::kMaxValue> + void ReadEnum(Enum* enum_value) { + static_assert(static_cast<unsigned>(kMaxValue) <= 255, + "Max value must fit in uint8_t"); + uint8_t value = 0u; + Read(&value); + if (value > static_cast<uint8_t>(kMaxValue)) { + SetInvalid(); + return; + } + *enum_value = static_cast<Enum>(value); + } + void SetInvalid(bool skip_crash_dump = false); // The main entry point is Read(sk_sp<PaintFilter>* filter) which calls one of
diff --git a/cc/paint/paint_op_writer.cc b/cc/paint/paint_op_writer.cc index e7affb7..7c032e80 100644 --- a/cc/paint/paint_op_writer.cc +++ b/cc/paint/paint_op_writer.cc
@@ -210,7 +210,7 @@ WriteSimple(flags.color_); Write(flags.width_); Write(flags.miter_limit_); - WriteSimple(flags.blend_mode_); + Write(flags.blend_mode_); WriteSimple(flags.bitfields_uint_); WriteFlattenable(flags.path_effect_.get()); @@ -480,10 +480,8 @@ WriteSimple(shader->flags_); WriteSimple(shader->end_radius_); WriteSimple(shader->start_radius_); - // SkTileMode does not have an explicitly defined backing type, so - // write a consistently sized value. - Write(static_cast<int32_t>(shader->tx_)); - Write(static_cast<int32_t>(shader->ty_)); + Write(shader->tx_); + Write(shader->ty_); WriteSimple(shader->fallback_color_); WriteSimple(shader->scaling_behavior_); if (shader->local_matrix_) { @@ -538,10 +536,6 @@ // using other fields. } -void PaintOpWriter::Write(SkColorType color_type) { - WriteSimple(static_cast<uint32_t>(color_type)); -} - void PaintOpWriter::Write(SkYUVColorSpace yuv_color_space) { WriteSimple(static_cast<uint32_t>(yuv_color_space)); } @@ -587,10 +581,10 @@ void PaintOpWriter::Write(const PaintFilter* filter) { if (!filter) { - WriteSimple(static_cast<uint32_t>(PaintFilter::Type::kNullFilter)); + WriteEnum(PaintFilter::Type::kNullFilter); return; } - WriteSimple(static_cast<uint32_t>(filter->type())); + WriteEnum(filter->type()); auto* crop_rect = filter->crop_rect(); WriteSimple(static_cast<uint32_t>(!!crop_rect)); if (crop_rect) { @@ -693,7 +687,7 @@ WriteSimple(filter.sigma_x()); WriteSimple(filter.sigma_y()); WriteSimple(filter.color()); - WriteSimple(filter.shadow_mode()); + WriteEnum(filter.shadow_mode()); Write(filter.input().get()); } @@ -716,7 +710,7 @@ } void PaintOpWriter::Write(const XfermodePaintFilter& filter) { - WriteSimple(static_cast<uint32_t>(filter.blend_mode())); + Write(filter.blend_mode()); Write(filter.background().get()); Write(filter.foreground().get()); } @@ -746,8 +740,8 @@ } void PaintOpWriter::Write(const DisplacementMapEffectPaintFilter& filter) { - WriteSimple(static_cast<uint32_t>(filter.channel_x())); - WriteSimple(static_cast<uint32_t>(filter.channel_y())); + WriteEnum(filter.channel_x()); + WriteEnum(filter.channel_y()); WriteSimple(filter.scale()); Write(filter.displacement().get()); Write(filter.color().get()); @@ -795,7 +789,7 @@ } void PaintOpWriter::Write(const MorphologyPaintFilter& filter) { - WriteSimple(filter.morph_type()); + WriteEnum(filter.morph_type()); WriteSimple(filter.radius_x()); WriteSimple(filter.radius_y()); Write(filter.input().get()); @@ -814,7 +808,7 @@ } void PaintOpWriter::Write(const TurbulencePaintFilter& filter) { - WriteSimple(filter.turbulence_type()); + WriteEnum(filter.turbulence_type()); WriteSimple(filter.base_frequency_x()); WriteSimple(filter.base_frequency_y()); WriteSimple(filter.num_octaves()); @@ -828,12 +822,12 @@ void PaintOpWriter::Write(const MatrixPaintFilter& filter) { Write(filter.matrix()); - WriteSimple(filter.filter_quality()); + Write(filter.filter_quality()); Write(filter.input().get()); } void PaintOpWriter::Write(const LightingDistantPaintFilter& filter) { - WriteSimple(filter.lighting_type()); + WriteEnum(filter.lighting_type()); WriteSimple(filter.direction()); WriteSimple(filter.light_color()); WriteSimple(filter.surface_scale()); @@ -843,7 +837,7 @@ } void PaintOpWriter::Write(const LightingPointPaintFilter& filter) { - WriteSimple(filter.lighting_type()); + WriteEnum(filter.lighting_type()); WriteSimple(filter.location()); WriteSimple(filter.light_color()); WriteSimple(filter.surface_scale()); @@ -853,7 +847,7 @@ } void PaintOpWriter::Write(const LightingSpotPaintFilter& filter) { - WriteSimple(filter.lighting_type()); + WriteEnum(filter.lighting_type()); WriteSimple(filter.location()); WriteSimple(filter.target()); WriteSimple(filter.specular_exponent());
diff --git a/cc/paint/paint_op_writer.h b/cc/paint/paint_op_writer.h index 660d8f8..a00c002 100644 --- a/cc/paint/paint_op_writer.h +++ b/cc/paint/paint_op_writer.h
@@ -69,25 +69,19 @@ void Write(const PaintShader* shader, SkFilterQuality quality); void Write(const PaintFilter* filter); void Write(const sk_sp<SkTextBlob>& blob); - void Write(SkColorType color_type); void Write(SkYUVColorSpace yuv_color_space); void Write(SkYUVAInfo::PlaneConfig plane_config); void Write(SkYUVAInfo::Subsampling subsampling); void Write(const gpu::Mailbox& mailbox); - void Write(SkClipOp op) { Write(static_cast<uint8_t>(op)); } - void Write(PaintCanvas::AnnotationType type) { - Write(static_cast<uint8_t>(type)); - } - void Write(SkCanvas::SrcRectConstraint constraint) { - Write(static_cast<uint8_t>(constraint)); - } - void Write(SkFilterQuality filter_quality) { - Write(static_cast<uint8_t>(filter_quality)); - } - void Write(SkBlendMode blend_mode) { - Write(static_cast<uint8_t>(blend_mode)); - } + void Write(SkClipOp op) { WriteEnum(op); } + void Write(PaintCanvas::AnnotationType type) { WriteEnum(type); } + void Write(SkCanvas::SrcRectConstraint constraint) { WriteEnum(constraint); } + void Write(SkColorType color_type) { WriteEnum(color_type); } + void Write(SkFilterQuality filter_quality) { WriteEnum(filter_quality); } + void Write(SkBlendMode blend_mode) { WriteEnum(blend_mode); } + void Write(SkTileMode tile_mode) { WriteEnum(tile_mode); } + void Write(bool data) { Write(static_cast<uint8_t>(data)); } // Aligns the memory to the given alignment. @@ -127,6 +121,11 @@ void WriteFlattenable(const SkFlattenable* val); + template <typename Enum> + void WriteEnum(Enum value) { + Write(base::checked_cast<uint8_t>(value)); + } + // The main entry point is Write(const PaintFilter* filter) which casts the // filter and calls one of the following functions. void Write(const ColorFilterPaintFilter& filter);
diff --git a/chrome/VERSION b/chrome/VERSION index 01a3209..2c1b088a 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=89 MINOR=0 -BUILD=4372 +BUILD=4374 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 66c3513..d429ea3c 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -2146,6 +2146,7 @@ "java/src/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java", "java/src/org/chromium/chrome/browser/ChromeBackgroundService.java", "java/src/org/chromium/chrome/browser/ChromeBackupAgent.java", + "java/src/org/chromium/chrome/browser/DeferredStartupHandler.java", "java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java", "java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java", "java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 729ff2da..d06c0a3 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -29,7 +29,6 @@ "java/src/org/chromium/chrome/browser/ChromeWindow.java", "java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java", "java/src/org/chromium/chrome/browser/DefaultBrowserInfo2.java", - "java/src/org/chromium/chrome/browser/DeferredStartupHandler.java", "java/src/org/chromium/chrome/browser/DelayedScreenLockIntentHandler.java", "java/src/org/chromium/chrome/browser/DevToolsServer.java", "java/src/org/chromium/chrome/browser/FileProviderHelper.java",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java index d674032f..235735c 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
@@ -223,7 +223,8 @@ if (model.get(TabProperties.SHOPPING_PERSISTED_TAB_DATA_FETCHER) != null) { model.get(TabProperties.SHOPPING_PERSISTED_TAB_DATA_FETCHER) .fetch((shoppingPersistedTabData) -> { - if (shoppingPersistedTabData.getPriceDrop() == null) { + if (shoppingPersistedTabData == null + || shoppingPersistedTabData.getPriceDrop() == null) { priceCardView.setVisibility(View.GONE); model.set(TabProperties.PRICE_DROP, null); } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java index b2936e2..07938ee 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
@@ -6,6 +6,7 @@ import static org.chromium.chrome.browser.base.SplitCompatUtils.CHROME_SPLIT_NAME; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; @@ -25,10 +26,10 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; +import org.chromium.chrome.browser.DeferredStartupHandler; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.version.ChromeVersionInfo; -import org.chromium.content_public.browser.BrowserStartupController; import java.lang.reflect.Field; @@ -42,8 +43,11 @@ */ public class SplitChromeApplication extends SplitCompatApplication { private static final String TAG = "SplitChromeApp"; + + @SuppressLint("StaticFieldLeak") + private static SplitPreloader sSplitPreloader; + private String mChromeApplicationClassName; - private SplitPreloader mSplitPreloader; public SplitChromeApplication() { this(SplitCompatUtils.getIdentifierName( @@ -56,9 +60,7 @@ @Override public void onCreate() { - if (mSplitPreloader != null) { - mSplitPreloader.wait(CHROME_SPLIT_NAME); - } + finishPreload(CHROME_SPLIT_NAME); super.onCreate(); } @@ -81,11 +83,9 @@ @Override public Context createContextForSplit(String name) throws PackageManager.NameNotFoundException { try (TraceEvent te = TraceEvent.scoped("SplitChromeApplication.createContextForSplit")) { - if (mSplitPreloader != null) { - // Wait for any splits that are preloading so we don't have a race to update the - // class loader cache (b/172602571). - mSplitPreloader.wait(name); - } + // Wait for any splits that are preloading so we don't have a race to update the + // class loader cache (b/172602571). + finishPreload(name); long startTime = SystemClock.uptimeMillis(); Context context = super.createContextForSplit(name); RecordHistogram.recordTimesHistogram("Android.IsolatedSplits.ContextCreateTime." + name, @@ -99,13 +99,13 @@ // The chrome split has a large amount of code, which can slow down startup. Loading // this in the background allows us to do this in parallel with startup tasks which do // not depend on code in the chrome split. - mSplitPreloader = new SplitPreloader(context); + sSplitPreloader = new SplitPreloader(context); // If the chrome module is not enabled or isolated splits are not supported (e.g. in Android // N), the onComplete function will run immediately so it must handle the case where the // base context of the application has not been set yet. - mSplitPreloader.preload(CHROME_SPLIT_NAME, (chromeContext) -> { + sSplitPreloader.preload(CHROME_SPLIT_NAME, (chromeContext) -> { // When installed, the vr module is always loaded on startup, so preload here. - mSplitPreloader.preload("vr", null); + sSplitPreloader.preload("vr", null); // If the chrome module is not enabled or isolated splits are not supported, // chromeContext will have the same ClassLoader as the base context, so no need to // replace the ClassLoaders here. @@ -120,6 +120,12 @@ return new Impl(); } + /* package */ static void finishPreload(String name) { + if (sSplitPreloader != null) { + sSplitPreloader.wait(name); + } + } + /** * Fixes Activity ClassLoader if necessary. Isolated splits can cause a ClassLoader mismatch * between the Application and Activity ClassLoaders. We have a workaround in @@ -164,53 +170,41 @@ || ChromeVersionInfo.isLocalBuild()) { return; } - // Wait until startup completes so this doesn't slow down early startup or mess with // compiled dex files before they get loaded initially. - // TODO(crbug.com/1159608): Determine if this works good enough, or if more needs to be done - // to avoid slowing startup. - BrowserStartupController.getInstance().addStartupCompletedObserver( - new BrowserStartupController.StartupCallback() { - @Override - public void onSuccess() { - // BEST_EFFORT will only affect when the task runs, the dexopt will run with - // normal priority (but in a separate process, due to using Runtime.exec()). - PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> { - try { - // If the app has just been updated, it will be compiled with - // quicken. The next time bg-dexopt-job runs it will break the - // optimized dex for splits. If we force compile now, then - // bg-dexopt-job won't mess up the splits, and we save the user a - // slow startup. - if (needsDexCompileAfterUpdate()) { - performDexCompile(); - return; - } - - // Make sure all splits are compiled correclty, and if not force a - // compile. - String[] splitNames = - ApiHelperForO.getSplitNames(getApplicationInfo()); - for (int i = 0; i < splitNames.length; i++) { - // Ignore config splits like "config.en". - if (splitNames[i].contains(".")) { - continue; - } - if (DexFile.isDexOptNeeded( - getApplicationInfo().splitSourceDirs[i])) { - performDexCompile(); - return; - } - } - } catch (Exception e) { - Log.e(TAG, "Error compiling dex.", e); - } - }); + DeferredStartupHandler.getInstance().addDeferredTask(() -> { + // BEST_EFFORT will only affect when the task runs, the dexopt will run with + // normal priority (but in a separate process, due to using Runtime.exec()). + PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> { + try { + // If the app has just been updated, it will be compiled with + // quicken. The next time bg-dexopt-job runs it will break the + // optimized dex for splits. If we force compile now, then + // bg-dexopt-job won't mess up the splits, and we save the user a + // slow startup. + if (needsDexCompileAfterUpdate()) { + performDexCompile(); + return; } - @Override - public void onFailure() {} - }); + // Make sure all splits are compiled correclty, and if not force a + // compile. + String[] splitNames = ApiHelperForO.getSplitNames(getApplicationInfo()); + for (int i = 0; i < splitNames.length; i++) { + // Ignore config splits like "config.en". + if (splitNames[i].contains(".")) { + continue; + } + if (DexFile.isDexOptNeeded(getApplicationInfo().splitSourceDirs[i])) { + performDexCompile(); + return; + } + } + } catch (Exception e) { + Log.e(TAG, "Error compiling dex.", e); + } + }); + }); } /** Returns whether the dex has been compiled since the last app update. */ @@ -222,14 +216,8 @@ /** Compiles dex for the app, and sets the pref key tracking the latest compiled version. */ private void performDexCompile() throws Exception { - Class<?> c = Class.forName("android.os.SystemProperties"); - java.lang.reflect.Method get = c.getMethod("get", String.class, String.class); - // Use the shared compile mode, and if we can't find that, default to speed. The shared - // compile mode will be quicken on Android Go. - String compileMode = (String) get.invoke(null, "pm.dexopt.shared", "speed"); - - Runtime.getRuntime().exec(new String[] { - "cmd", "package", "compile", "-m", compileMode, "-f", getPackageName()}); + Runtime.getRuntime().exec( + new String[] {"cmd", "package", "compile", "-r", "shared", getPackageName()}); SharedPreferencesManager.getInstance().writeInt( ChromePreferenceKeys.ISOLATED_SPLITS_DEX_COMPILE_VERSION, PackageUtils.getPackageVersion(this, getPackageName()));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java index d2f284d..ea05b17 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.base; +import static org.chromium.chrome.browser.base.SplitCompatUtils.CHROME_SPLIT_NAME; + import android.annotation.TargetApi; import android.app.Activity; import android.app.AppComponentFactory; @@ -32,6 +34,9 @@ @Override public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + // Activities will not call createContextForSplit() which will normally ensure the preload + // is finished, so we have to manually ensure that here. + SplitChromeApplication.finishPreload(CHROME_SPLIT_NAME); return super.instantiateActivity(getComponentClassLoader(cl, className), className, intent); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java index 9adc6217..b2f5c811 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -25,7 +25,6 @@ import org.chromium.chrome.browser.datareduction.DataReductionProxyUma; import org.chromium.chrome.browser.metrics.UmaUtils; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; -import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl; import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory; import org.chromium.chrome.browser.searchwidget.SearchWidgetProvider; import org.chromium.ui.base.LocalizationUtils; @@ -453,13 +452,6 @@ // intent. The re-launched intent will still need to know to avoid the FRE. FirstRunStatus.setFirstRunSkippedByPolicy(true); - // This pref is written to have a value of true during the FRE's startup. If the user - // presses the accept ToS button, this pref's value is overridden with their choice. - // However, when the FRE is skipped, that initial value is the opposite of what we want, so - // manually set it to false here. - // TODO(https://crbug.com/1128955): Remove this once the default is not written on startup. - PrivacyPreferencesManagerImpl.getInstance().setUsageAndCrashReporting(false); - launchPendingIntentAndFinish(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java index cef25723..1114264 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -25,7 +25,6 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.locale.LocaleManager; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; -import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.services.AndroidChildAccountHelper; import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; @@ -140,12 +139,6 @@ } @VisibleForTesting - protected void setDefaultMetricsAndCrashReporting() { - PrivacyPreferencesManagerImpl.getInstance().setUsageAndCrashReporting( - FirstRunActivity.DEFAULT_METRICS_AND_CRASH_REPORTING); - } - - @VisibleForTesting protected void setFirstRunFlowSignInComplete() { FirstRunSignInProcessor.setFirstRunFlowSignInComplete(true); } @@ -169,10 +162,6 @@ Bundle freProperties = new Bundle(); freProperties.putInt(SigninFirstRunFragment.CHILD_ACCOUNT_STATUS, mChildAccountStatus); - // Initialize usage and crash reporting according to the default value. - // The user can explicitly enable or disable the reporting on the Welcome page. - setDefaultMetricsAndCrashReporting(); - onFlowIsKnown(freProperties); if (ChildAccountStatus.isChild(mChildAccountStatus)) { setFirstRunFlowSignInComplete();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunUtils.java index 09e7399e..6fc4156 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunUtils.java
@@ -26,6 +26,8 @@ private static final int DEFAULT_SKIP_TOS_EXIT_DELAY_MS = 1000; private static final int A11Y_DELAY_FACTOR = 2; + private static boolean sDisableDelayOnExitFreForTest; + /** * Synchronizes first run native and Java preferences. * Must be called after native initialization. @@ -132,6 +134,8 @@ * @return The number of ms delay before exiting FRE with policy. */ public static int getSkipTosExitDelayMs() { + if (sDisableDelayOnExitFreForTest) return 0; + int durationMs = DEFAULT_SKIP_TOS_EXIT_DELAY_MS; if (ChromeAccessibilityUtil.get().isTouchExplorationEnabled()) { durationMs *= A11Y_DELAY_FACTOR; @@ -139,6 +143,11 @@ return durationMs; } + @VisibleForTesting + public static void setDisableDelayOnExitFreForTest(boolean isDisable) { + sDisableDelayOnExitFreForTest = isDisable; + } + @NativeMethods public interface Natives { boolean getFirstRunEulaAccepted();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java index 916d6f6..17a870e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java
@@ -81,7 +81,6 @@ }); mSendReportCheckBox.setChecked(FirstRunActivity.DEFAULT_METRICS_AND_CRASH_REPORTING); - if (!canShowUmaCheckBox()) { mSendReportCheckBox.setVisibility(View.GONE); } @@ -177,8 +176,7 @@ } mTriggerAcceptAfterNativeInit = false; - boolean allowCrashUpload = (mSendReportCheckBox.getVisibility() == View.VISIBLE) - && mSendReportCheckBox.isChecked(); + boolean allowCrashUpload = canShowUmaCheckBox() && mSendReportCheckBox.isChecked(); getPageDelegate().acceptTermsOfService(allowCrashUpload); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java index 5abec3ca..0dcc50a9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java
@@ -77,7 +77,6 @@ new OneshotSupplierImpl<>(); private Handler mHandler; - private Runnable mExitFreRunnable; /** The {@link SystemClock} timestamp when onViewCreated is called. */ private long mViewCreatedTimeMs; @@ -92,8 +91,9 @@ mSkipTosDialogPolicyListener.destroy(); mSkipTosDialogPolicyListener = null; } - if (mHandler != null && mExitFreRunnable != null) { - mHandler.removeCallbacks(mExitFreRunnable); + if (mHandler != null) { + // Remove all callback associated. + mHandler.removeCallbacksAndMessages(null); mHandler = null; } super.onDestroy(); @@ -192,17 +192,13 @@ mPrivacyDisclaimer.announceForAccessibility(mPrivacyDisclaimer.getText()); } - if (sOverridenOnExitFreRunnableForTest != null) { - mExitFreRunnable = sOverridenOnExitFreRunnableForTest; - } else { - mExitFreRunnable = () -> { - getPageDelegate().exitFirstRun(); - mExitFreRunnable = null; - }; - } - + // Make sure this function is called at most once by asserting no handler is created yet. + assert mHandler == null; + Runnable exitFreRunnable = sOverridenOnExitFreRunnableForTest != null + ? sOverridenOnExitFreRunnableForTest + : () -> getPageDelegate().exitFirstRun(); mHandler = new Handler(ThreadUtils.getUiThreadLooper()); - mHandler.postDelayed(mExitFreRunnable, FirstRunUtils.getSkipTosExitDelayMs()); + mHandler.postDelayed(exitFreRunnable, FirstRunUtils.getSkipTosExitDelayMs()); } @VisibleForTesting
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java index 971ddcb..c38a65e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
@@ -94,6 +94,7 @@ public void setUp() { MockitoAnnotations.initMocks(this); FirstRunStatus.setFirstRunSkippedByPolicy(false); + FirstRunUtils.setDisableDelayOnExitFreForTest(true); FirstRunActivity.setObserverForTest(mTestObserver); ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(true); @@ -109,6 +110,7 @@ @After public void tearDown() { FirstRunStatus.setFirstRunSkippedByPolicy(false); + FirstRunUtils.setDisableDelayOnExitFreForTest(false); FirstRunAppRestrictionInfo.setInitializedInstanceForTest(null); ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(false); EnterpriseInfo.setInstanceForTest(null);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java index edea25f..ede8bab 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunUtilsTest.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.firstrun; -import android.accounts.Account; import android.accounts.AuthenticatorDescription; import android.support.test.InstrumentationRegistry; @@ -33,11 +32,6 @@ public class FirstRunUtilsTest { private FakeAuthenticationAccountManager mAccountManager; private AdvancedMockContext mAccountTestingContext; - private Account mTestAccount; - - public FirstRunUtilsTest() { - mTestAccount = AccountUtils.createAccountFromName("Dummy"); - } @Before public void setUp() { @@ -73,7 +67,7 @@ private void addTestAccount() { mAccountManager.addAccountHolderBlocking( - AccountHolder.builder(mTestAccount).alwaysAccept(true).build()); + AccountHolder.builder("dummy@gmail.com").alwaysAccept(true).build()); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java index 2edff56a..6e2cac63 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java
@@ -7,6 +7,8 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; import android.app.Activity; import android.app.Instrumentation; @@ -31,9 +33,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import org.chromium.base.Callback; import org.chromium.base.CommandLine; @@ -45,6 +50,8 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.init.BrowserParts; +import org.chromium.chrome.browser.init.ChromeBrowserInitializer; import org.chromium.chrome.browser.policy.EnterpriseInfo; import org.chromium.chrome.browser.policy.PolicyServiceFactory; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; @@ -68,12 +75,14 @@ */ @RunWith(ChromeJUnit4ClassRunner.class) public class TosAndUmaFirstRunFragmentWithEnterpriseSupportTest { - @IntDef({FragmentState.LOADING, FragmentState.NO_POLICY, FragmentState.HAS_POLICY}) + @IntDef({FragmentState.LOADING, FragmentState.NO_POLICY, FragmentState.HAS_POLICY, + FragmentState.WAITING_UNTIL_NEXT_PAGE}) @Retention(RetentionPolicy.SOURCE) @interface FragmentState { int LOADING = 0; int NO_POLICY = 1; int HAS_POLICY = 2; + int WAITING_UNTIL_NEXT_PAGE = 3; } @IntDef({SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.FASTER, @@ -101,6 +110,11 @@ @Mock public EnterpriseInfo mMockEnterpriseInfo; + @Spy + public ChromeBrowserInitializer mInitializer; + @Captor + public ArgumentCaptor<BrowserParts> mBrowserParts; + private FirstRunActivity mActivity; private final List<PolicyService.Observer> mPolicyServiceObservers = new ArrayList<>(); private final List<Callback<Boolean>> mAppRestrictionsCallbacks = new ArrayList<>(); @@ -112,7 +126,8 @@ private View mTosText; private View mAcceptButton; - private View mLargeSpinner; + private View mLowerSpinner; + private View mCenterSpinner; private View mPrivacyDisclaimer; private CheckBox mUmaCheckBox; @@ -123,9 +138,15 @@ Assert.assertFalse( CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)); + Mockito.doNothing() + .when(mInitializer) + .handlePostNativeStartup(anyBoolean(), any(BrowserParts.class)); + ChromeBrowserInitializer.setForTesting(mInitializer); + FirstRunAppRestrictionInfo.setInitializedInstanceForTest(mMockAppRestrictionInfo); ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(true); PolicyServiceFactory.setPolicyServiceForTest(mPolicyService); + FirstRunUtils.setDisableDelayOnExitFreForTest(true); FirstRunUtilsJni.TEST_HOOKS.setInstanceForTesting(mFirstRunUtils); EnterpriseInfo.setInstanceForTest(mMockEnterpriseInfo); @@ -167,6 +188,7 @@ ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(false); TosAndUmaFirstRunFragmentWithEnterpriseSupport.setOverrideOnExitFreRunnableForTest(null); PolicyServiceFactory.setPolicyServiceForTest(null); + FirstRunUtils.setDisableDelayOnExitFreForTest(false); FirstRunUtilsJni.TEST_HOOKS.setInstanceForTesting(mFirstRunUtils); EnterpriseInfo.setInstanceForTest(null); SharedPreferencesManager.getInstance().writeBoolean( @@ -186,6 +208,12 @@ assertHistograms(true, SpeedComparedToInflation.SLOWER, SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.NOT_RECORDED); + SharedPreferencesManager.getInstance().writeBoolean( + ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, false); + Assert.assertFalse("Crash report should be disabled by shared preference.", + PrivacyPreferencesManagerImpl.getInstance() + .isUsageAndCrashReportingPermittedByUser()); + // Try to accept ToS. TestThreadUtils.runOnUiThreadBlocking((Runnable) mAcceptButton::performClick); Assert.assertTrue("Crash report should be enabled.", @@ -195,6 +223,38 @@ @Test @SmallTest + public void testNoRestriction_AcceptBeforeNative() { + launchFirstRunThroughCustomTabPreNative(); + assertUIState(FragmentState.LOADING); + + setAppRestrictionsMockInitialized(false); + assertUIState(FragmentState.NO_POLICY); + + assertHistograms(true, SpeedComparedToInflation.SLOWER, + SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.NOT_RECORDED); + + SharedPreferencesManager.getInstance().writeBoolean( + ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, false); + Assert.assertFalse("Crash report should be disabled by shared preference.", + PrivacyPreferencesManagerImpl.getInstance() + .isUsageAndCrashReportingPermittedByUser()); + + // Try to accept ToS. + TestThreadUtils.runOnUiThreadBlocking((Runnable) mAcceptButton::performClick); + assertUIState(FragmentState.WAITING_UNTIL_NEXT_PAGE); + Assert.assertFalse("Crash report should not be enabled before native initialized.", + PrivacyPreferencesManagerImpl.getInstance() + .isUsageAndCrashReportingPermittedByUser()); + + // ToS should be accepted when native is initialized. + startNativeInitializationAndWait(); + Assert.assertTrue("Crash report should be enabled.", + PrivacyPreferencesManagerImpl.getInstance() + .isUsageAndCrashReportingPermittedByUser()); + } + + @Test + @SmallTest public void testNoRestriction_BeforeInflation() { setAppRestrictionsMockInitialized(false); launchFirstRunThroughCustomTab(); @@ -454,10 +514,15 @@ renderWithPortraitAndLandscape(tosAndUmaFragment, "fre_tosanduma_withpolicy"); } + private void launchFirstRunThroughCustomTab() { + launchFirstRunThroughCustomTabPreNative(); + startNativeInitializationAndWait(); + } + /** * Launch chrome through custom tab and trigger first run. */ - private void launchFirstRunThroughCustomTab() { + private void launchFirstRunThroughCustomTabPreNative() { final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); final Context context = instrumentation.getTargetContext(); @@ -483,14 +548,11 @@ CriteriaHelper.pollUiThread( () -> mActivity.getSupportFragmentManager().getFragments().size() > 0); - // Force this to happen now to try to make the tests more deterministic. Ideally the tests - // could control when this happens and test for difference sequences. - waitUntilNativeLoaded(); - mTosText = mActivity.findViewById(R.id.tos_and_privacy); mUmaCheckBox = mActivity.findViewById(R.id.send_report_checkbox); mAcceptButton = mActivity.findViewById(R.id.terms_accept); - mLargeSpinner = mActivity.findViewById(R.id.progress_spinner_large); + mLowerSpinner = mActivity.findViewById(R.id.progress_spinner); + mCenterSpinner = mActivity.findViewById(R.id.progress_spinner_large); mPrivacyDisclaimer = mActivity.findViewById(R.id.privacy_disclaimer); } @@ -499,12 +561,14 @@ int spinnerVisibility = (fragmentState == FragmentState.LOADING) ? View.VISIBLE : View.GONE; int privacyVisibility = (fragmentState == FragmentState.HAS_POLICY) ? View.VISIBLE : View.GONE; + int lowerSpinnerVisibility = + (fragmentState == FragmentState.WAITING_UNTIL_NEXT_PAGE) ? View.VISIBLE : View.GONE; CriteriaHelper.pollUiThread( () -> Criteria.checkThat( "Visibility of Loading spinner never reached test setting.", - mLargeSpinner.getVisibility(), Matchers.is(spinnerVisibility))); + mCenterSpinner.getVisibility(), Matchers.is(spinnerVisibility))); Assert.assertEquals("Visibility of ToS text is different than the test setting.", tosVisibility, mTosText.getVisibility()); @@ -512,6 +576,8 @@ tosVisibility, mUmaCheckBox.getVisibility()); Assert.assertEquals("Visibility of accept button is different than the test setting.", tosVisibility, mAcceptButton.getVisibility()); + Assert.assertEquals("Visibility of lower spinner is different than the test setting.", + lowerSpinnerVisibility, mLowerSpinner.getVisibility()); Assert.assertEquals("Visibility of privacy disclaimer is different than the test setting.", privacyVisibility, mPrivacyDisclaimer.getVisibility()); @@ -522,6 +588,21 @@ () -> Criteria.checkThat(mExitCount, Matchers.is(expectedExitCount))); } + private void startNativeInitializationAndWait() { + Mockito.verify(mInitializer, Mockito.timeout(3000L)) + .handlePostNativeStartup(eq(true), mBrowserParts.capture()); + Mockito.doCallRealMethod() + .when(mInitializer) + .handlePostNativeStartup(anyBoolean(), any(BrowserParts.class)); + + TestThreadUtils.runOnUiThreadBlocking( + () + -> mInitializer.handlePostNativeStartup( + /*isAsync*/ false, mBrowserParts.getValue())); + CriteriaHelper.pollUiThread( + (() -> mActivity.isNativeSideIsInitializedForTest()), "native never initialized."); + } + /** * Asserts the speed histograms related to FirstRunAppRestrictions and TosAndUmaFirstRunFragment * are recorded correctly. Noting that with the current test setup, it is possible that the @@ -566,11 +647,6 @@ recorded ? 1 : 0, RecordHistogram.getHistogramTotalCountForTesting(histogram)); } - private void waitUntilNativeLoaded() { - CriteriaHelper.pollUiThread( - (() -> mActivity.isNativeSideIsInitializedForTest()), "native never initialized."); - } - private void setAppRestrictionsMockNotInitialized() { Mockito.doAnswer(invocation -> { Callback<Boolean> callback = invocation.getArgument(0);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/PersistedTabDataTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/PersistedTabDataTest.java index 6e772f7a2..97c3d6205 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/PersistedTabDataTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/PersistedTabDataTest.java
@@ -59,6 +59,36 @@ }); } + @SmallTest + @UiThreadTest + @Test + public void testSerializeAndLogOutOfMemoryError() { + Tab tab = MockTab.createAndInitialize(1, false); + OutOfMemoryMockPersistedTabData outOfMemoryMockPersistedTabData = + new OutOfMemoryMockPersistedTabData(tab); + Assert.assertNull(outOfMemoryMockPersistedTabData.serializeAndLog()); + } + + @SmallTest + @UiThreadTest + @Test(expected = OutOfMemoryError.class) + public void testSerializeOutOfMemoryError() { + Tab tab = MockTab.createAndInitialize(1, false); + OutOfMemoryMockPersistedTabData outOfMemoryMockPersistedTabData = + new OutOfMemoryMockPersistedTabData(tab); + outOfMemoryMockPersistedTabData.serialize(); + } + + static class OutOfMemoryMockPersistedTabData extends MockPersistedTabData { + OutOfMemoryMockPersistedTabData(Tab tab) { + super(tab, 0 /** unused in OutOfMemoryMockPersistedTabData */); + } + @Override + public byte[] serialize() { + throw new OutOfMemoryError("Out of memory error"); + } + } + private static void registerObserverSupplier(MockPersistedTabData mockPersistedTabData) { ObservableSupplierImpl<Boolean> supplier = new ObservableSupplierImpl<>(); supplier.set(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArAnchorsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArAnchorsTest.java index f69887bf..12d35a4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArAnchorsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArAnchorsTest.java
@@ -68,6 +68,7 @@ */ @Test @MediumTest + @DisabledTest(message = "https://crbug.com/1153305") @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) @ArPlaybackFile("chrome/test/data/xr/ar_playback_datasets/floor_session_12s_30fps.mp4") public void testHitTestAnchorSucceedsWithPlane() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java index 0797402..2f53498 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
@@ -52,7 +52,6 @@ public static class TestFirstRunFlowSequencer extends FirstRunFlowSequencer { public Bundle returnedBundle; public boolean calledOnFlowIsKnown; - public boolean calledSetDefaultMetricsAndCrashReporting; public boolean calledSetFirstRunFlowSignInComplete; public boolean isFirstRunFlowComplete; @@ -116,11 +115,6 @@ } @Override - public void setDefaultMetricsAndCrashReporting() { - calledSetDefaultMetricsAndCrashReporting = true; - } - - @Override protected void setFirstRunFlowSignInComplete() { calledSetFirstRunFlowSignInComplete = true; } @@ -155,7 +149,6 @@ mSequencer.processFreEnvironmentPreNative(); assertTrue(mSequencer.calledOnFlowIsKnown); assertNull(mSequencer.returnedBundle); - assertFalse(mSequencer.calledSetDefaultMetricsAndCrashReporting); } @Test @@ -171,7 +164,6 @@ mSequencer.processFreEnvironmentPreNative(); assertTrue(mSequencer.calledOnFlowIsKnown); - assertTrue(mSequencer.calledSetDefaultMetricsAndCrashReporting); assertFalse(mSequencer.calledSetFirstRunFlowSignInComplete); Bundle bundle = mSequencer.returnedBundle; @@ -197,7 +189,6 @@ mSequencer.processFreEnvironmentPreNative(); assertTrue(mSequencer.calledOnFlowIsKnown); - assertTrue(mSequencer.calledSetDefaultMetricsAndCrashReporting); assertTrue(mSequencer.calledSetFirstRunFlowSignInComplete); Bundle bundle = mSequencer.returnedBundle; @@ -225,7 +216,6 @@ mSequencer.processFreEnvironmentPreNative(); assertTrue(mSequencer.calledOnFlowIsKnown); - assertTrue(mSequencer.calledSetDefaultMetricsAndCrashReporting); assertFalse(mSequencer.calledSetFirstRunFlowSignInComplete); Bundle bundle = mSequencer.returnedBundle; @@ -251,7 +241,6 @@ mSequencer.processFreEnvironmentPreNative(); assertTrue(mSequencer.calledOnFlowIsKnown); - assertTrue(mSequencer.calledSetDefaultMetricsAndCrashReporting); assertFalse(mSequencer.calledSetFirstRunFlowSignInComplete); Bundle bundle = mSequencer.returnedBundle;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index bdc8afa..5370e57 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -3118,7 +3118,7 @@ <!-- Platform verification UI --> <message name="IDS_PLATFORM_VERIFICATION_DIALOG_HEADLINE" desc="The label to describe what the dialog wants to confirm."> - <ph name="DOMAIN">$1<ex>example.com</ex></ph> wants your device's identity to be verified, by Google, to determine eligibility for enhanced playback of protected content. + <ph name="DOMAIN">$1<ex>example.com</ex></ph> wants to identify your device so it can play the highest quality protected video and audio. </message> <!-- Network portal notification -->
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PLATFORM_VERIFICATION_DIALOG_HEADLINE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PLATFORM_VERIFICATION_DIALOG_HEADLINE.png.sha1 new file mode 100644 index 0000000..2ccb3bc --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_PLATFORM_VERIFICATION_DIALOG_HEADLINE.png.sha1
@@ -0,0 +1 @@ +54bdbaf785801685067b449ddca9515557b00bb9 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index f370d5ec..606aa240 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -20,11 +20,11 @@ </message> <message name="IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS" desc="Banner displayed in OS settings page in case update is required by policy, but the device has reached end-of-life and the number of days remaining to return the device back to the manager is less than seven. MANAGER can be a domain or an email address."> {NUM_DAYS, plural, - =1 {<ph name="MANAGER">{1}<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">{2}<ex>Chromebook</ex></ph> today.<ph name="LINK_BEGIN"><a target="_blank" href="{3}<ex>https://google.com/</ex>"></ph>See details<ph name="LINK_END"></a></ph>} - other {<ph name="MANAGER">{1}<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">{2}<ex>Chromebook</ex></ph> within {NUM_DAYS} days.<ph name="LINK_BEGIN"><a target="_blank" href="{3}<ex>https://google.com/</ex>"></ph>See details<ph name="LINK_END"></a></ph>}} + =1 {<ph name="MANAGER">{1}<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">{2}<ex>Chromebook</ex></ph> today. <ph name="LINK_BEGIN"><a target="_blank" href="{3}<ex>https://google.com/</ex>"></ph>See details<ph name="LINK_END"></a></ph>} + other {<ph name="MANAGER">{1}<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">{2}<ex>Chromebook</ex></ph> within {NUM_DAYS} days. <ph name="LINK_BEGIN"><a target="_blank" href="{3}<ex>https://google.com/</ex>"></ph>See details<ph name="LINK_END"></a></ph>}} </message> <message name="IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK" desc="Banner displayed in OS settings page in case update is required by policy, but the device has reached end-of-life and the number of days remaining to return the device back to the manager is equal to seven. MANAGER can be a domain or an email address."> - <ph name="MANAGER">$1<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> within 1 week.<ph name="LINK_BEGIN"><a target="_blank" href="$3<ex>https://google.com/</ex>"></ph>See details<ph name="LINK_END"></a></ph> + <ph name="MANAGER">$1<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> within 1 week. <ph name="LINK_BEGIN"><a target="_blank" href="$3<ex>https://google.com/</ex>"></ph>See details<ph name="LINK_END"></a></ph> </message> <!-- Settings Search Box --> @@ -212,7 +212,7 @@ Turn off </message> <message name="IDS_OS_SETTINGS_SYNC_FEATURE_LABEL" desc="Label describing the OS sync feature."> - Your apps and settings will sync across all Chrome OS devices where you are signed in with your Google account. For browser sync options, go to<ph name="LINK_BEGIN"><a></ph>Chrome settings<ph name="LINK_END"></a></ph>. + Your apps and settings will sync across all Chrome OS devices where you are signed in with your Google account. For browser sync options, go to <ph name="LINK_BEGIN"><a></ph>Chrome settings<ph name="LINK_END"></a></ph>. </message> <message name="IDS_OS_SETTINGS_SYNC_APPS_CHECKBOX_LABEL" desc="Label for the checkbox which enables syncing of apps across devices."> Apps @@ -638,10 +638,10 @@ Select <ph name="TOPIC_SOURCE">$1<ex>Google Photos</ex></ph> albums </message> <message name="IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_TITLE" desc="Label for the subpage to select albums of Google Photos in ambient mode."> - Relive your favorite memories. To add or edit albums, go to<ph name="LINK_BEGIN"><a target="_blank" href="$1<ex>https://google.com/</ex>"></ph>Google Photos<ph name="LINK_END"></a></ph>. + Relive your favorite memories. To add or edit albums, go to <ph name="LINK_BEGIN"><a target="_blank" href="$1<ex>https://google.com/</ex>"></ph>Google Photos<ph name="LINK_END"></a></ph>. </message> <message name="IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_NO_ALBUM" desc="Text for the subpage to select albums of Google Photos when there is no album in ambient mode."> - No albums. Create an album in<ph name="LINK_BEGIN"><a target="_blank" href="$1<ex>https://google.com/</ex>"></ph>Google Photos<ph name="LINK_END"></a></ph>. + No albums. Create an album in <ph name="LINK_BEGIN"><a target="_blank" href="$1<ex>https://google.com/</ex>"></ph>Google Photos<ph name="LINK_END"></a></ph>. </message> <message name="IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_RECENT_DESC" desc="Description for the Recent highlights album in ambient mode."> Your best photos, selected automatically @@ -999,8 +999,8 @@ <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_TITLE" desc="A title for a dialog to assign a switch key to an action. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> Assign switch: <ph name="action">$1<ex>Select</ex></ph> </message> - <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WAIT_FOR_KEY_PROMPT_NO_SWITCHES" desc="A message shown to ask a user to press a new key to be assigned to an action. No switches are currently assigned to this action. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> - Press a new switch to start assignment. + <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WAIT_FOR_KEY_PROMPT_NO_SWITCHES" desc="A message shown to ask a user to press a new key to be assigned to an action. No switches are currently assigned to this action. The user can assign multiple switches to this action. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> + Press a switch to assign “<ph name="action">$1<ex>Select</ex></ph>”. You can assign multiple switches to this action. </message> <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WAIT_FOR_KEY_PROMPT_AT_LEAST_ONE_SWITCH" desc="A message shown to ask a user to press a key to be assigned to an action, or press an assigned switch to remove assignment. One or more switches are currently assigned to this action. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> Press a new switch to start assignment. @@ -1013,10 +1013,10 @@ Press “<ph name="currentKey">$1<ex>backspace</ex></ph>” again to remove assignment and exit. </message> <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_NOT_CONFIRMED_PROMPT" desc="A message warning the user that the switch key pressed during confirmation did not match the initial switch key pressed. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> - Keys do not match. “<ph name="unexpectedKey">$1<ex>enter</ex></ph>” was pressed. “<ph name="currentKey">$2<ex>backspace</ex></ph>” was pressed before. Press any key to exit. + Keys do not match. Press any key to exit. </message> <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH" desc="A message warning the user that they cannot remove the last switch for the Select action. The text for the 'Select' action should be the same as the text from IDS_SETTINGS_ASSIGN_SELECT_SWITCH_LABEL. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> - Couldn't remove the only switch assigned to Select. Press any key to exit. + Can’t remove the only switch assigned to Select. Press any key to exit. </message> <message name="IDS_SETTINGS_ASSIGN_SWITCH_SUB_LABEL_0_SWITCHES" desc="A sub-label for the link that brings up a dialog to assign a switch key to an action. Mentions zero switches assigned. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> 0 switches assigned @@ -1048,6 +1048,18 @@ <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_EXIT" desc="The label of the button to exit the switch access action assignment dialog without making any changes. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> Exit </message> + <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ASSIGNED_ICON_LABEL" desc="A label for an icon indicating a switch is assigned to an action. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> + Assigned + </message> + <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ADD_ASSIGNMENT_ICON_LABEL" desc="A label for an icon indicating a switch is ready to add as an assignment to an action. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> + Add assignment + </message> + <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_REMOVE_ASSIGNMENT_ICON_LABEL" desc="A label for an icon indicating a switch is ready to remove as an assignment from an action. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> + Remove assignment + </message> + <message name="IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ERROR_ICON_LABEL" desc="The label for an icon indicating that there was an error adding or removing a switch assignment. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> + Error + </message> <message name="IDS_SETTINGS_ACCESSIBILITY_TEXT_TO_SPEECH_HEADING" desc="In the settings tab, the heading for accessibility features that enable the computer to speak text from the computer screen."> Text-to-Speech </message> @@ -1174,7 +1186,7 @@ Adding a school account enables easy sign-in to websites, extensions, and apps as a student while still operating under parental controls. </message> <message name="IDS_SETTINGS_ACCOUNT_MANAGER_PRIMARY_ACCOUNT_DESCRIPTION" desc="Description of the Account Manager Settings page for primary account. Shown above primary account picture."> - Your apps and OS settings will sync across Chromebooks where you're signed in with this account.<ph name="LINK_BEGIN"><a href="#"></ph>Sync Settings<ph name="LINK_END"></a></ph> + Your apps and OS settings will sync across Chromebooks where you're signed in with this account. <ph name="LINK_BEGIN"><a href="#"></ph>Sync Settings<ph name="LINK_END"></a></ph> </message> <message name="IDS_SETTINGS_ACCOUNT_MANAGER_SECONDARY_ACCOUNTS_DESCRIPTION" desc="Description of secondary accounts usage, shown on Account Manager Settings page."> When you add a secondary account here, you may browse the web, download apps, check your Gmail and other Google services using that account. @@ -2489,7 +2501,7 @@ View recent Chrome tabs from your phone </message> <message name="IDS_SETTINGS_MULTIDEVICE_PHONE_HUB_TASK_CONTINUATION_DISABLED_SUMMARY" desc="Description of for the 'Phone Hub Task Continuation' setting when Chrome sync is not enabled. This feature lets users resume in-app actions and chrome tabs that are open on a connected Android phone from Chrome OS devices."> - Turn on<ph name="LINK1_BEGIN"><a id="chromeSyncLink"></ph>Chrome Sync<ph name="LINK1_END"></a></ph> to view recent Chrome tabs.<ph name="LINK2_BEGIN"><a target="_blank" id="learnMoreLink" href="$1<ex>https://google.com/</ex>"></ph>Learn More<ph name="LINK2_END"></a></ph> + Turn on <ph name="LINK1_BEGIN"><a id="chromeSyncLink"></ph>Chrome Sync<ph name="LINK1_END"></a></ph> to view recent Chrome tabs. <ph name="LINK2_BEGIN"><a target="_blank" id="learnMoreLink" href="$1<ex>https://google.com/</ex>"></ph>Learn More<ph name="LINK2_END"></a></ph> </message> <message name="IDS_SETTINGS_MULTIDEVICE_PHONE_HUB_TASK_CONTINUATION_SYNC_LABEL" desc="Accessibility label (used by screen readers, not shown in UI) for a link that leads to the Chrome Sync toggle that needs to be enabled as a prerequisite for the 'Phone Hub Task Continuation' feature to be enabled. This feature lets users resume chrome tabs that are open on a connected Android phone from Chrome OS devices."> Turn on Chrome Sync to view recent Chrome tabs from your phone
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_NO_ALBUM.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_NO_ALBUM.png.sha1 index c17b600..a0c1af0 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_NO_ALBUM.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_NO_ALBUM.png.sha1
@@ -1 +1 @@ -2951dee8302a35c689bfad352d75db0e1b01174a \ No newline at end of file +7dcbd4a4328842824274744e61cd1603ccb9527d \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_TITLE.png.sha1 index c17b600..ea9f1d0 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_TITLE.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_GOOGLE_PHOTOS_TITLE.png.sha1
@@ -1 +1 @@ -2951dee8302a35c689bfad352d75db0e1b01174a \ No newline at end of file +3189d6652a8a75d43b44f9e52a1af6c7505cd2ba \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYNC_FEATURE_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYNC_FEATURE_LABEL.png.sha1 index e01fe7d..25d69d4 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYNC_FEATURE_LABEL.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYNC_FEATURE_LABEL.png.sha1
@@ -1 +1 @@ -b408bd6da5e3360cd76f954d1ad558549358da4b \ No newline at end of file +1b35d0d9ea4cf6511693dd7d3688fa8838d4cb1e \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_PRIMARY_ACCOUNT_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_PRIMARY_ACCOUNT_DESCRIPTION.png.sha1 index 2e71f1f..5ba713c 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_PRIMARY_ACCOUNT_DESCRIPTION.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_PRIMARY_ACCOUNT_DESCRIPTION.png.sha1
@@ -1 +1 @@ -ff945af9a4d7096af626d1e6131cac6f73115976 \ No newline at end of file +12082215b3390cbcb51953244fbc44b9dfb0da65 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_PHONE_HUB_TASK_CONTINUATION_DISABLED_SUMMARY.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_PHONE_HUB_TASK_CONTINUATION_DISABLED_SUMMARY.png.sha1 index 4d363653..a1de0b2 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_PHONE_HUB_TASK_CONTINUATION_DISABLED_SUMMARY.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_MULTIDEVICE_PHONE_HUB_TASK_CONTINUATION_DISABLED_SUMMARY.png.sha1
@@ -1 +1 @@ -2720eadd205fbd423bcf77978c03da7c5e99bb14 \ No newline at end of file +24fcb0ae1e6364842ce282da05195cced932e7d3 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ADD_ASSIGNMENT_ICON_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ADD_ASSIGNMENT_ICON_LABEL.png.sha1 new file mode 100644 index 0000000..f9c7051 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ADD_ASSIGNMENT_ICON_LABEL.png.sha1
@@ -0,0 +1 @@ +c07d6bd772300f3e72b2863b460c9ce792703063 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ASSIGNED_ICON_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ASSIGNED_ICON_LABEL.png.sha1 new file mode 100644 index 0000000..b74396d0 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ASSIGNED_ICON_LABEL.png.sha1
@@ -0,0 +1 @@ +0681088d0f58ecbe94da381d000c5f1ecc062635 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ERROR_ICON_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ERROR_ICON_LABEL.png.sha1 new file mode 100644 index 0000000..f6f1a9e --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ERROR_ICON_LABEL.png.sha1
@@ -0,0 +1 @@ +ed6d9dac1110bb5a8f5107c166a7ec50bd5077ce \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_REMOVE_ASSIGNMENT_ICON_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_REMOVE_ASSIGNMENT_ICON_LABEL.png.sha1 new file mode 100644 index 0000000..32805f09 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_REMOVE_ASSIGNMENT_ICON_LABEL.png.sha1
@@ -0,0 +1 @@ +6b3ece88d02c845dce97bd99324b6526fdd119d3 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WAIT_FOR_KEY_PROMPT_NO_SWITCHES.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WAIT_FOR_KEY_PROMPT_NO_SWITCHES.png.sha1 index 8cabbacb..c5405d346 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WAIT_FOR_KEY_PROMPT_NO_SWITCHES.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WAIT_FOR_KEY_PROMPT_NO_SWITCHES.png.sha1
@@ -1 +1 @@ -b14090832131315ecb83e68967b8c2a3f1daac9a \ No newline at end of file +15ee6bb5dc6f28957f3927ca92d46d8dab694a8c \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH.png.sha1 index e9346da..783c81fa 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH.png.sha1
@@ -1 +1 @@ -b6f7099a92f1ae4de9e58c63994179379018902e \ No newline at end of file +bdf360c94294cf0f89939e3aed405ae28aec1bcb \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_NOT_CONFIRMED_PROMPT.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_NOT_CONFIRMED_PROMPT.png.sha1 index d335a87..e24897e 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_NOT_CONFIRMED_PROMPT.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_WARN_NOT_CONFIRMED_PROMPT.png.sha1
@@ -1 +1 @@ -50399f24500516b7cb529f26af2b0fd1893065c3 \ No newline at end of file +9fc79913e1446ecd43c53cb00fec04c981ae5235 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS.png.sha1 index c94f944f..4c96e11 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS.png.sha1
@@ -1 +1 @@ -ac20dd522d48d3b3ec5595bb7ec9875856d36d7b \ No newline at end of file +85905f6cc44a8b0b1b8b91cb0fc551d77941e51c \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK.png.sha1 index c94f944f..1434f3f 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK.png.sha1
@@ -1 +1 @@ -ac20dd522d48d3b3ec5595bb7ec9875856d36d7b \ No newline at end of file +cf183ea776c3b9180835632fa4e3deec4f3ccc17 \ No newline at end of file
diff --git a/chrome/app/resources/generated_resources_af.xtb b/chrome/app/resources/generated_resources_af.xtb index 2329a94..126d60ca 100644 --- a/chrome/app/resources/generated_resources_af.xtb +++ b/chrome/app/resources/generated_resources_af.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Wys stelselteks in hierdie taal</translation> <translation id="2367972762794486313">Wys programme</translation> <translation id="2371076942591664043">Maak oop wanneer klaar is</translation> +<translation id="23721837607121582">Laai mobiele profiel af, netwerk <ph name="NETWORK_INDEX" /> van <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Pas op papier</translation> <translation id="2375406435414127095">Koppel aan jou foon</translation> <translation id="2377588536920405462">Jy kan ligging afskakel deur die hoofligginginstelling op jou toestel af te skakel. Jy kan ook die gebruik van Wi-Fi, selnetwerke en sensors vir ligging in ligginginstellings afskakel.</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">Swiep op om te begin</translation> <translation id="2603115962224169880">Maak rekenaar skoon</translation> <translation id="2603463522847370204">Maak in incognitovenster oop</translation> -<translation id="2603656971249947488">Oortjiestrook</translation> <translation id="2604255671529671813">Netwerkverbinding-fout</translation> <translation id="2606246518223360146">Koppel data</translation> <translation id="2606454609872547359">Nee, gaan voort sonder ChromeVox</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">Aan, swerf</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Bereken tans …</translation> +<translation id="3971140002794351170">Laai mobiele profiel af, netwerk <ph name="NETWORK_INDEX" /> van <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Vingerafdrukke op hierdie sekuriteitsleutel</translation> <translation id="3973660817924297510">Gaan tans wagwoorde na (<ph name="CHECKED_PASSWORDS" /> van <ph name="TOTAL_PASSWORDS" />) …</translation> <translation id="3975565978598857337">Kon nie bediener vir domein kontak nie</translation> @@ -6467,6 +6468,7 @@ <translation id="8398877366907290961">Gaan nogtans voort</translation> <translation id="8400146488506985033">Bestuur mense</translation> <translation id="8401432541486058167">Verskaf die PIN wat met jou slimkaart geassosieer word.</translation> +<translation id="8403562727702715619">Onlangs uit Google Drive</translation> <translation id="8407199357649073301">Loglêervlak:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" />-netwerk; koppel tans</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6907,6 +6909,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> kan die volgende lêers en vouers wysig</translation> <translation id="8890170499370378450">Kan mobiele dataheffings aangaan</translation> <translation id="8890516388109605451">Bronne</translation> +<translation id="8890529496706615641">Profiel kon nie hernoem word nie. Probeer weer of kontak jou diensverskaffer vir tegniese steundiens.</translation> <translation id="8892168913673237979">Gereed!</translation> <translation id="8893801527741465188">Deïnstallering is voltooi</translation> <translation id="8893928184421379330">Jammer, die toestel <ph name="DEVICE_LABEL" /> kon nie herken word nie.</translation>
diff --git a/chrome/app/resources/generated_resources_am.xtb b/chrome/app/resources/generated_resources_am.xtb index aee09f1..3b9aff08 100644 --- a/chrome/app/resources/generated_resources_am.xtb +++ b/chrome/app/resources/generated_resources_am.xtb
@@ -1249,6 +1249,7 @@ <translation id="2366260648632264559">በዚህ ቋንቋ የሥርዓት ጽሑፍን አሳይ</translation> <translation id="2367972762794486313">መተግበሪያዎችን አሳይ</translation> <translation id="2371076942591664043">&ሲጠናቀቅ ክፈት</translation> +<translation id="23721837607121582">የሞባይል መገለጫን ያውርዱ፣ አውታረ መረብ <ph name="NETWORK_INDEX" /> ከ<ph name="NETWORK_COUNT" />፣ <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">ከወረቀት ጋር አመጣጥን</translation> <translation id="2375406435414127095">ከእርስዎ ስልክ ጋር ይገናኙ</translation> <translation id="2377588536920405462">በመሣሪያዎ ላይ ዋናውን የአካባቢ ቅንብር በማጥፋት አካባቢን ማጥፋት ይችላሉ። እንዲሁም በአካባቢ ቅንብሮች ውስጥ Wi-Fiን፣ የተንቀሳቃሽ ስልክ አውታረ መረቦችን እና ዳሳሾችን መጠቀም ለአካባቢ ማጥፋት ይችላሉ።</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">ለመጀመር በጣት ይጥረጉ</translation> <translation id="2603115962224169880">ኮምፒውተርን አጽዳ</translation> <translation id="2603463522847370204">በ&ማንነትን የማያሳውቅ መስኮት ክፈት</translation> -<translation id="2603656971249947488">የትር ድርድር</translation> <translation id="2604255671529671813">የአውታረ መረብ ግንኙነት ስህተት</translation> <translation id="2606246518223360146">ውሂብ አገናኝ</translation> <translation id="2606454609872547359">አይ፣ ያለChromeVox ቀጥል</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">በርቷል፣ በማንዣበብ ላይ</translation> <translation id="3970114302595058915">መታወቂያ</translation> <translation id="397105322502079400">በማስላት ላይ...</translation> +<translation id="3971140002794351170">የሞባይል መገለጫን ያውርዱ፣ አውታረ መረብ <ph name="NETWORK_INDEX" /> ከ<ph name="NETWORK_COUNT" />፣ <ph name="NETWORK_NAME" />፣ <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">በዚህ የደህንነት ቁልፍ ላይ ያሉ የጣት አሻራዎች</translation> <translation id="3973660817924297510">የይለፍ ቃላትን (<ph name="CHECKED_PASSWORDS" /> ከ<ph name="TOTAL_PASSWORDS" />) በመፈተሽ ላይ…</translation> <translation id="3975565978598857337">ለማከማቸት አገልጋይን ማግኘት አልተሳካም</translation> @@ -6470,6 +6471,7 @@ <translation id="8398877366907290961">ለማንኛውም ቀጥል</translation> <translation id="8400146488506985033">ሰዎችን አቀናብር</translation> <translation id="8401432541486058167">ከእርስዎ ዘመናዊ ካርድ ጋር የተቆራኘውን ፒን ይስጡ።</translation> +<translation id="8403562727702715619">በቅርቡ ከGoogle Drive</translation> <translation id="8407199357649073301">የምዝግብ ማስታወሻ ደረጃ፦</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> አውታረ መረብ፣ በመገናኘት ላይ</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6911,6 +6913,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> የሚከተሉትን ፋይሎች እና አቃፊዎች ማርትዕ ይችላል</translation> <translation id="8890170499370378450">የተንቀሳቃሽ ስልክ ውሂብ ክፍያዎችን ሊያስከትል ይችላል</translation> <translation id="8890516388109605451">ምንጮች</translation> +<translation id="8890529496706615641">መገለጫን እንደገና መሰየም አልተቻለም። እባክዎ እንደገና ይሞክሩ ወይም ለቴክኒካዊ ድጋፍ አገልግሎት አቅራቢዎን ያነጋግሩ።</translation> <translation id="8892168913673237979">ሁሉም ዝግጁ!</translation> <translation id="8893801527741465188">ማራገፍ ተጠናቅቋል</translation> <translation id="8893928184421379330">ይቅርታ፣ መሣሪያ <ph name="DEVICE_LABEL" /> ሊታወቅ አልቻለም።</translation>
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb index 932d1252..8963d69 100644 --- a/chrome/app/resources/generated_resources_ar.xtb +++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -1252,6 +1252,7 @@ <translation id="2366260648632264559">عرض نص النظام بهذه اللغة</translation> <translation id="2367972762794486313">إظهار التطبيقات</translation> <translation id="2371076942591664043">فتح الملفّ عند &انتهاء التحميل</translation> +<translation id="23721837607121582">تنزيل الملف الشخصي لشريحة eSIM على الجهاز الجوّال، الشبكة رقم <ph name="NETWORK_INDEX" /> من أصل <ph name="NETWORK_COUNT" />، <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">ملاءمة حجم الورقة</translation> <translation id="2375406435414127095">الاتصال بهاتفك</translation> <translation id="2377588536920405462">يمكنك إيقاف "الموقع الجغرافي" من خلال إيقاف إعداد الموقع الجغرافي الرئيسي على جهازك. ويمكنك أيضًا إيقاف استخدام شبكة Wi-Fi وشبكات الجوّال وأجهزة الاستشعار للموقع الجغرافي في إعدادات الموقع الجغرافي.</translation> @@ -1445,7 +1446,6 @@ <translation id="2602501489742255173">مرِّر سريعًا للأعلى للبدء.</translation> <translation id="2603115962224169880">إزالة البرامج الضارة من جهاز الكمبيوتر</translation> <translation id="2603463522847370204">فتح في نافذة &التصفح المتخفي</translation> -<translation id="2603656971249947488">شريط علامات التبويب</translation> <translation id="2604255671529671813">خطأ في اتصال الشبكة</translation> <translation id="2606246518223360146">ربط البيانات</translation> <translation id="2606454609872547359">لا، المتابعة بدون ChromeVox</translation> @@ -1625,7 +1625,7 @@ <translation id="2791529110887957050">إزالة نظام التشغيل Linux</translation> <translation id="2791952154587244007">حدث خطأ. لن يمكن تشغيل تطبيق الكشك تلقائيًا على هذا الجهاز.</translation> <translation id="2792290659606763004">هل تريد إزالة تطبيقات Android؟</translation> -<translation id="2792465461386711506">يمكنك تفعيل ميزة مزامنة "Chrome" لعرض علامات تبويب Chrome الأخيرة من هاتفك.</translation> +<translation id="2792465461386711506">يمكنك تفعيل ميزة "مزامنة Chrome" لعرض علامات تبويب Chrome الأخيرة من هاتفك.</translation> <translation id="2794233252405721443">تم حظر الموقع</translation> <translation id="2795716239552913152">تستخدم المواقع الإلكترونية عادةً موقعك الجغرافي لتتيح ميزات أو معلومات ذات صلة مثل الأخبار المحلية أو المتاجر القريبة.</translation> <translation id="2796424461616874739">انتهت مهلة المصادقة أثناء الاتصال بالجهاز "<ph name="DEVICE_NAME" />".</translation> @@ -2681,6 +2681,7 @@ <translation id="3969092967100188979">مفعَّل، تجوال</translation> <translation id="3970114302595058915">رقم التعريف</translation> <translation id="397105322502079400">جارٍ الحساب...</translation> +<translation id="3971140002794351170">تنزيل الملف الشخصي لشريحة eSIM على الجهاز الجوّال، الشبكة رقم <ph name="NETWORK_INDEX" /> من أصل <ph name="NETWORK_COUNT" />، <ph name="NETWORK_NAME" />، <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">بصمات الأصابع المُسجلة في مفتاح الأمان هذا</translation> <translation id="3973660817924297510">جارٍ التحقّق من كلمات المرور (<ph name="CHECKED_PASSWORDS" /> من <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">تعذّر الاتصال بخادم النطاق</translation> @@ -6473,6 +6474,7 @@ <translation id="8398877366907290961">المتابعة على كلّ حال</translation> <translation id="8400146488506985033">إدارة الأشخاص</translation> <translation id="8401432541486058167">عليك تقديم رقم التعريف الشخصي المرتبط بالبطاقة الذكية التابعة لك.</translation> +<translation id="8403562727702715619">مؤخرًا من Google Drive</translation> <translation id="8407199357649073301">مستوى السجلّ:</translation> <translation id="8408068190360279472">شبكة <ph name="NETWORK_TYPE" />، جارٍ الاتصال</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6917,6 +6919,7 @@ <translation id="8889651696183044030">بإمكان <ph name="ORIGIN" /> تعديل الملفات والمجلدات التالية:</translation> <translation id="8890170499370378450">قد يتم تحصيل رسوم منك مقابل استخدام بيانات الجوّال.</translation> <translation id="8890516388109605451">المصادر</translation> +<translation id="8890529496706615641">تعذّرت إعادة تسمية الملف الشخصي. يُرجى إعادة المحاولة أو التواصل مع فريق الدعم الفني لدى مشغّل شبكة الجوّال.</translation> <translation id="8892168913673237979">كل شيء جاهز!</translation> <translation id="8893801527741465188">اكتملت عملية إلغاء التثبيت</translation> <translation id="8893928184421379330">عذرًا، تعذر التعرف على الجهاز <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_as.xtb b/chrome/app/resources/generated_resources_as.xtb index ddd7fd1..90f5e20 100644 --- a/chrome/app/resources/generated_resources_as.xtb +++ b/chrome/app/resources/generated_resources_as.xtb
@@ -1439,7 +1439,6 @@ <translation id="2602501489742255173">আৰম্ভ কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক</translation> <translation id="2603115962224169880">কম্পিউটাৰৰ ডেটা মচক</translation> <translation id="2603463522847370204">&ইনক’গনিট’ ৱিণ্ড’ত খোলক</translation> -<translation id="2603656971249947488">টেবৰ ষ্ট্ৰিপ</translation> <translation id="2604255671529671813">নেটৱৰ্ক সংযোগ সম্পর্কীয় আসোঁৱাহ</translation> <translation id="2606246518223360146">ডেটা লিংক কৰক</translation> <translation id="2606454609872547359">নহয়, ChromeVoxৰ অবিহনে অব্যাহত ৰাখক</translation>
diff --git a/chrome/app/resources/generated_resources_az.xtb b/chrome/app/resources/generated_resources_az.xtb index 6dd425c..989c613 100644 --- a/chrome/app/resources/generated_resources_az.xtb +++ b/chrome/app/resources/generated_resources_az.xtb
@@ -1436,7 +1436,6 @@ <translation id="2602501489742255173">Başlamaq üçün yuxarı sürüşdürün</translation> <translation id="2603115962224169880">Kompüteri təmizləyin</translation> <translation id="2603463522847370204">İnkoqnito pəncərəsində açın</translation> -<translation id="2603656971249947488">Tab zolağı</translation> <translation id="2604255671529671813">Şəbəkə bağlantı xətası</translation> <translation id="2606246518223360146">Link Datası</translation> <translation id="2606454609872547359">Xeyr, ChromeVox olmadan davam edin</translation>
diff --git a/chrome/app/resources/generated_resources_be.xtb b/chrome/app/resources/generated_resources_be.xtb index d31cf0a7..dfbea99 100644 --- a/chrome/app/resources/generated_resources_be.xtb +++ b/chrome/app/resources/generated_resources_be.xtb
@@ -1444,7 +1444,6 @@ <translation id="2602501489742255173">Каб пачаць, правядзіце пальцам уверх</translation> <translation id="2603115962224169880">Ачыстка камп'ютара</translation> <translation id="2603463522847370204">Адкрыць у &акне ў рэжыме інкогніта</translation> -<translation id="2603656971249947488">Панэль укладак</translation> <translation id="2604255671529671813">Памылка падключэння да сеткі</translation> <translation id="2606246518223360146">Звязаць даныя</translation> <translation id="2606454609872547359">Не, працягнуць без ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_bg.xtb b/chrome/app/resources/generated_resources_bg.xtb index c4502ac..e6cac0a 100644 --- a/chrome/app/resources/generated_resources_bg.xtb +++ b/chrome/app/resources/generated_resources_bg.xtb
@@ -1245,6 +1245,7 @@ <translation id="2366260648632264559">Показване на системния текст на този език</translation> <translation id="2367972762794486313">Показване на приложенията</translation> <translation id="2371076942591664043">Отваряне &след изтегляне</translation> +<translation id="23721837607121582">Изтегляне на мобилния потребителски профил, мрежа <ph name="NETWORK_INDEX" /> от <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Уеднаквяване с размера на хартията</translation> <translation id="2375406435414127095">Свързване с телефона ви</translation> <translation id="2377588536920405462">Можете да изключите местоположението, като деактивирате главната настройка за него на устройството си. Също така от настройките за местоположението сте в състояние да изключите определянето му чрез Wi-Fi, мобилни мрежи и сензори.</translation> @@ -1438,7 +1439,6 @@ <translation id="2602501489742255173">Прекарайте пръст нагоре, за да започнете</translation> <translation id="2603115962224169880">Почистване на компютъра</translation> <translation id="2603463522847370204">Отваряне на прозорец в режим „&инкогнито“</translation> -<translation id="2603656971249947488">Лента с раздели</translation> <translation id="2604255671529671813">Грешка при свързване с мрежата</translation> <translation id="2606246518223360146">Свързване на данните</translation> <translation id="2606454609872547359">Не, продължаване без ChromeVox</translation> @@ -2676,6 +2676,7 @@ <translation id="3969092967100188979">Включено, използва се роуминг</translation> <translation id="3970114302595058915">Идентификатор</translation> <translation id="397105322502079400">Изчислява се...</translation> +<translation id="3971140002794351170">Изтегляне на мобилния потребителски профил, мрежа <ph name="NETWORK_INDEX" /> от <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Отпечатъци, регистрирани на този ключ за сигурност</translation> <translation id="3973660817924297510">Паролите се проверяват (<ph name="CHECKED_PASSWORDS" /> от <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Свързването със сървъра за областта не бе успешно</translation> @@ -6467,6 +6468,7 @@ <translation id="8398877366907290961">Продължаване напред въпреки това</translation> <translation id="8400146488506985033">Управление на хората</translation> <translation id="8401432541486058167">Въведете ПИН, свързан със смарткартата ви</translation> +<translation id="8403562727702715619">Наскоро от Google Диск</translation> <translation id="8407199357649073301">Ниво на запис в регистрационния файл:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> мрежа – установява се връзка</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6907,6 +6909,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> може да редактира следните файлове и папки</translation> <translation id="8890170499370378450">Може да доведе до таксуване за мобилни данни</translation> <translation id="8890516388109605451">Източници</translation> +<translation id="8890529496706615641">Потребителският профил не бе преименуван. Моля, опитайте отново или се обърнете към оператора си за техническа поддръжка.</translation> <translation id="8892168913673237979">Готово!</translation> <translation id="8893801527741465188">Деинсталирането завърши</translation> <translation id="8893928184421379330">За съжаление устройството <ph name="DEVICE_LABEL" /> не можа да бъде разпознато.</translation>
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb index 9e60154..2586e100a 100644 --- a/chrome/app/resources/generated_resources_bn.xtb +++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">শুরু করতে স্ক্রিনের উপরের দিকে সোয়াইপ করুন</translation> <translation id="2603115962224169880">কম্পিউটার সাফ করুন</translation> <translation id="2603463522847370204">ছদ্মবেশী উইন্ডোতে খুলু&ন</translation> -<translation id="2603656971249947488">ট্যাব বার</translation> <translation id="2604255671529671813">নেটওয়ার্ক সংযোগে সমস্যা</translation> <translation id="2606246518223360146">ডেটা লিঙ্ক করুন</translation> <translation id="2606454609872547359">না, ChromeVox ছাড়াই চালিয়ে যান</translation>
diff --git a/chrome/app/resources/generated_resources_bs.xtb b/chrome/app/resources/generated_resources_bs.xtb index 57d101b..c213bafa 100644 --- a/chrome/app/resources/generated_resources_bs.xtb +++ b/chrome/app/resources/generated_resources_bs.xtb
@@ -1250,6 +1250,7 @@ <translation id="2366260648632264559">Prikaži tekst na ovom jeziku</translation> <translation id="2367972762794486313">Prikaži aplikacije</translation> <translation id="2371076942591664043">Otvori kad bude &gotovo</translation> +<translation id="23721837607121582">Preuzimanje profila mobilnog uređaja, mreža <ph name="NETWORK_INDEX" /> od <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Prilagodi veličini papira</translation> <translation id="2375406435414127095">Povežite na telefon</translation> <translation id="2377588536920405462">Lokaciju možete isključiti ako na uređaju isključite glavnu postavku lokacije. U postavkama lokacije možete isključiti i korištenje WiFi-ja, mobilnih mreža i senzora za lokaciju.</translation> @@ -1443,7 +1444,6 @@ <translation id="2602501489742255173">Prevucite prema gore da počnete</translation> <translation id="2603115962224169880">Očisti računar</translation> <translation id="2603463522847370204">Otvaranje u &anonimnom prozoru</translation> -<translation id="2603656971249947488">Traka kartice</translation> <translation id="2604255671529671813">Greška mrežne veze</translation> <translation id="2606246518223360146">Poveži podatke</translation> <translation id="2606454609872547359">Ne, nastavi bez ChromeVoxa</translation> @@ -2680,6 +2680,7 @@ <translation id="3969092967100188979">Uključeno, u romingu</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Računanje…</translation> +<translation id="3971140002794351170">Preuzimanje profila mobilnog uređaja, mreža <ph name="NETWORK_INDEX" /> od <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Otisci prsta na ovom sigurnosnom ključu</translation> <translation id="3973660817924297510">Provjeravanje lozinki (<ph name="CHECKED_PASSWORDS" /> od <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Povezivanje servera za okruženje nije uspjelo</translation> @@ -6470,6 +6471,7 @@ <translation id="8398877366907290961">Svejedno nastavi</translation> <translation id="8400146488506985033">Upravljaj osobama</translation> <translation id="8401432541486058167">Unesite PIN koji je povezan s vašom pametnom karticom.</translation> +<translation id="8403562727702715619">Nedavno s Google diska</translation> <translation id="8407199357649073301">Nivo zapisa:</translation> <translation id="8408068190360279472">Mreža <ph name="NETWORK_TYPE" />, povezivanje</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6912,6 +6914,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> može uređivati sljedeće fajlove i foldere</translation> <translation id="8890170499370378450">Mogu nastati troškovi prijenosa podataka na mobilnoj mreži</translation> <translation id="8890516388109605451">Izvori</translation> +<translation id="8890529496706615641">Promjena naziva profila nije uspjela. Pokušajte ponovo ili kontaktirajte svog mobilnog operatora za tehničku podršku.</translation> <translation id="8892168913673237979">Sve je spremno!</translation> <translation id="8893801527741465188">Deinstalacija je završena</translation> <translation id="8893928184421379330">Žao nam je, ali prepoznavanje uređaja <ph name="DEVICE_LABEL" /> nije uspjelo.</translation>
diff --git a/chrome/app/resources/generated_resources_ca.xtb b/chrome/app/resources/generated_resources_ca.xtb index f465525..53341e4 100644 --- a/chrome/app/resources/generated_resources_ca.xtb +++ b/chrome/app/resources/generated_resources_ca.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Mostra el text del sistema en aquest idioma</translation> <translation id="2367972762794486313">Mostra les aplicacions</translation> <translation id="2371076942591664043">Obre quan &acabi</translation> +<translation id="23721837607121582">Baixa el perfil mòbil, xarxa <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Ajusta al paper</translation> <translation id="2375406435414127095">Connecta't al telèfon</translation> <translation id="2377588536920405462">Pots desactivar la ubicació desactivant la configuració d'ubicació principal del dispositiu. A la configuració d'ubicació també pots desactivar l'ús de sensors, xarxes mòbils i Wi-Fi per calcular la ubicació.</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">Llisca cap amunt per començar</translation> <translation id="2603115962224169880">Neteja l'ordinador</translation> <translation id="2603463522847370204">Obre-ho en una &finestra d'incògnit</translation> -<translation id="2603656971249947488">Barra de pestanyes</translation> <translation id="2604255671529671813">Error de connexió a la xarxa</translation> <translation id="2606246518223360146">Enllaça les dades</translation> <translation id="2606454609872547359">No, continua sense ChromeVox</translation> @@ -2676,6 +2676,7 @@ <translation id="3969092967100188979">Activat, en itinerància</translation> <translation id="3970114302595058915">Identificador</translation> <translation id="397105322502079400">S’està calculant...</translation> +<translation id="3971140002794351170">Baixa el perfil mòbil, xarxa <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Empremtes digitals d'aquesta clau de seguretat</translation> <translation id="3973660817924297510">S'estan comprovant les contrasenyes (<ph name="CHECKED_PASSWORDS" /> de <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">No s'ha pogut contactar amb el servidor del domini</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">Continua igualment</translation> <translation id="8400146488506985033">Gestiona persones</translation> <translation id="8401432541486058167">Proporciona el PIN que està associat a la teva targeta intel·ligent.</translation> +<translation id="8403562727702715619">Recentment des de Google Drive</translation> <translation id="8407199357649073301">Nivell de registre:</translation> <translation id="8408068190360279472">Xarxa <ph name="NETWORK_TYPE" /> (connectant)</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> pot editar els fitxers i les carpetes següents</translation> <translation id="8890170499370378450">És possible que s'apliquin càrrecs per ús de dades mòbils</translation> <translation id="8890516388109605451">Fonts</translation> +<translation id="8890529496706615641">No s'ha pogut canviar el nom del perfil. Torna-ho a provar o contacta amb el teu operador per rebre assistència tècnica.</translation> <translation id="8892168913673237979">Tot a punt</translation> <translation id="8893801527741465188">S'ha completat la desinstal·lació</translation> <translation id="8893928184421379330">El dispositiu <ph name="DEVICE_LABEL" /> no s'ha pogut reconèixer.</translation>
diff --git a/chrome/app/resources/generated_resources_cs.xtb b/chrome/app/resources/generated_resources_cs.xtb index 9384674..80bb590 100644 --- a/chrome/app/resources/generated_resources_cs.xtb +++ b/chrome/app/resources/generated_resources_cs.xtb
@@ -1250,6 +1250,7 @@ <translation id="2366260648632264559">Text systému zobrazit v tomto jazyce</translation> <translation id="2367972762794486313">Zobrazit aplikace</translation> <translation id="2371076942591664043">Po dokončení otevřít</translation> +<translation id="23721837607121582">Stáhněte si mobilní profil, síť <ph name="NETWORK_INDEX" /> z <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Přizpůsobit papíru</translation> <translation id="2375406435414127095">Připojte se k telefonu</translation> <translation id="2377588536920405462">Určování polohy můžete vypnout tím, že v zařízení deaktivujete hlavní nastavení polohy. V nastavení polohy můžete také vypnout používání sítí Wi-Fi, mobilních sítí a senzorů k určování polohy.</translation> @@ -1442,7 +1443,6 @@ <translation id="2602501489742255173">Začněte přejetím nahoru</translation> <translation id="2603115962224169880">Vyčištění počítače</translation> <translation id="2603463522847370204">Otevřít v &anonymním okně</translation> -<translation id="2603656971249947488">Lišta karet</translation> <translation id="2604255671529671813">Chyba připojení k síti</translation> <translation id="2606246518223360146">Propojit data</translation> <translation id="2606454609872547359">Ne, pokračovat bez čtečky ChromeVox</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">Roaming je povolen, ale neprobíhá</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Probíhá výpočet…</translation> +<translation id="3971140002794351170">Stáhněte si mobilní profil, síť <ph name="NETWORK_INDEX" /> z <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Otisky prstů na tomto bezpečnostním klíči</translation> <translation id="3973660817924297510">Probíhá kontrola hesel (<ph name="CHECKED_PASSWORDS" /> z <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Kontaktování serveru pro sféru se nezdařilo</translation> @@ -6467,6 +6468,7 @@ <translation id="8398877366907290961">Přesto pokračovat</translation> <translation id="8400146488506985033">Správa uživatelů</translation> <translation id="8401432541486058167">Zadejte kód PIN přidružený k vaší chytré kartě.</translation> +<translation id="8403562727702715619">Nedávný obsah z Disku Google</translation> <translation id="8407199357649073301">Úroveň protokolu:</translation> <translation id="8408068190360279472">Síť: <ph name="NETWORK_TYPE" />, připojování</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6909,6 +6911,7 @@ <translation id="8889651696183044030">Web <ph name="ORIGIN" /> může upravovat následující soubory a složky</translation> <translation id="8890170499370378450">Mohou být účtovány poplatky za mobilní data</translation> <translation id="8890516388109605451">Zdroje</translation> +<translation id="8890529496706615641">Profil se nepodařilo přejmenovat. Zkuste to znovu nebo požádejte o technickou podporu operátora.</translation> <translation id="8892168913673237979">Vše je nastaveno!</translation> <translation id="8893801527741465188">Odinstalace byla dokončena</translation> <translation id="8893928184421379330">Je nám líto, zařízení <ph name="DEVICE_LABEL" /> nelze rozpoznat.</translation>
diff --git a/chrome/app/resources/generated_resources_da.xtb b/chrome/app/resources/generated_resources_da.xtb index e4312b2..959dde9a 100644 --- a/chrome/app/resources/generated_resources_da.xtb +++ b/chrome/app/resources/generated_resources_da.xtb
@@ -1249,6 +1249,7 @@ <translation id="2366260648632264559">Vis systemtekst på dette sprog</translation> <translation id="2367972762794486313">Vis apps</translation> <translation id="2371076942591664043">Åbn når &færdigt</translation> +<translation id="23721837607121582">Download mobilprofil. Netværk <ph name="NETWORK_INDEX" /> af <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Tilpas til papiret</translation> <translation id="2375406435414127095">Opret forbindelse til din telefon</translation> <translation id="2377588536920405462">Du kan deaktivere Placering ved at deaktivere den overordnede placeringsindstilling på din enhed. Du kan også deaktivere brugen af Wi-Fi, mobilnetværk og sensorer ifm. placering i placeringsindstillingerne.</translation> @@ -1442,7 +1443,6 @@ <translation id="2602501489742255173">Stryg opad for at komme i gang</translation> <translation id="2603115962224169880">Ryd op på computeren</translation> <translation id="2603463522847370204">Åbn i &inkognitovindue</translation> -<translation id="2603656971249947488">Fanelinje</translation> <translation id="2604255671529671813">Fejl i netværksforbindelsen</translation> <translation id="2606246518223360146">Tilknyt data</translation> <translation id="2606454609872547359">Nej, fortsæt uden ChromeVox</translation> @@ -2679,6 +2679,7 @@ <translation id="3969092967100188979">Til, roamer</translation> <translation id="3970114302595058915">Id</translation> <translation id="397105322502079400">Beregner...</translation> +<translation id="3971140002794351170">Download mobilprofil. Netværk <ph name="NETWORK_INDEX" /> af <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Fingeraftryk på denne sikkerhedsnøgle</translation> <translation id="3973660817924297510">Tjekker adgangskoder (<ph name="CHECKED_PASSWORDS" /> af <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Det var ikke muligt at kontakte serveren for domænet</translation> @@ -6323,7 +6324,7 @@ <translation id="8227119283605456246">Vedhæft fil</translation> <translation id="8230134520748321204">Vil du gemme adgangskoden til <ph name="ORIGIN" />?</translation> <translation id="8234795456569844941">Hjælp vores softwareudviklere med at løse dette problem. Fortæl os, hvad der skete, lige før du fik fejlmeddelelsen for profilen:</translation> -<translation id="8235605354099176425">Aktivér <ph name="LINK1_BEGIN" />Chrome-synkronisering<ph name="LINK1_END" /> for at se de seneste Chrome-faner. <ph name="LINK2_BEGIN" />Få flere oplysninger<ph name="LINK2_END" /></translation> +<translation id="8235605354099176425">Aktivér<ph name="LINK1_BEGIN" />Chrome-synkronisering<ph name="LINK1_END" /> for at se de seneste Chrome-faner.<ph name="LINK2_BEGIN" />Få flere oplysninger<ph name="LINK2_END" /></translation> <translation id="8236917170563564587">Del denne fane i stedet</translation> <translation id="8237647586961940482">Mørk pink og rød</translation> <translation id="8239032431519548577">Tilmelding af virksomhed er gennemført</translation> @@ -6469,6 +6470,7 @@ <translation id="8398877366907290961">Fortsæt alligevel</translation> <translation id="8400146488506985033">Administrer personer</translation> <translation id="8401432541486058167">Brug den pinkode, der hører til dit chipkort.</translation> +<translation id="8403562727702715619">For nyligt fra Google Drive</translation> <translation id="8407199357649073301">Logfilsniveau:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" />-netværk, opretter forbindelse</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6911,6 +6913,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> kan redigere følgende filer og mapper</translation> <translation id="8890170499370378450">Der opkræves muligvis mobildatagebyrer</translation> <translation id="8890516388109605451">Kilder</translation> +<translation id="8890529496706615641">Navnet på profilen kunne ikke ændres. Prøv igen, eller kontakt dit mobilselskab for at få teknisk support.</translation> <translation id="8892168913673237979">Fuldført</translation> <translation id="8893801527741465188">Afinstallationen er fuldført</translation> <translation id="8893928184421379330">Vi beklager, men <ph name="DEVICE_LABEL" />-enheden kunne ikke genkendes.</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb index 7adc7c8..630e51e50 100644 --- a/chrome/app/resources/generated_resources_de.xtb +++ b/chrome/app/resources/generated_resources_de.xtb
@@ -1437,7 +1437,6 @@ <translation id="2602501489742255173">Zum Starten nach oben wischen</translation> <translation id="2603115962224169880">Computer bereinigen</translation> <translation id="2603463522847370204">In &Inkognito-Fenster öffnen</translation> -<translation id="2603656971249947488">Tableiste</translation> <translation id="2604255671529671813">Fehler bei der Netzwerkverbindung</translation> <translation id="2606246518223360146">Daten verknüpfen</translation> <translation id="2606454609872547359">Nein, ohne ChromeVox fortfahren</translation>
diff --git a/chrome/app/resources/generated_resources_el.xtb b/chrome/app/resources/generated_resources_el.xtb index 5d11368a9..a52f527 100644 --- a/chrome/app/resources/generated_resources_el.xtb +++ b/chrome/app/resources/generated_resources_el.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Εμφάνιση κειμένου συστήματος σε αυτήν τη γλώσσα</translation> <translation id="2367972762794486313">Εμφάνιση εφαρμογών</translation> <translation id="2371076942591664043">Άνοιγμα κατά την &ολοκλήρωση</translation> +<translation id="23721837607121582">Λήψη προφίλ κινητού, Δίκτυο <ph name="NETWORK_INDEX" /> από <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Προσαρμογή στο χαρτί</translation> <translation id="2375406435414127095">Συνδεθείτε στο τηλέφωνό σας</translation> <translation id="2377588536920405462">Μπορείτε να απενεργοποιήσετε την Τοποθεσία απενεργοποιώντας τη βασική ρύθμιση τοποθεσίας στη συσκευή σας. Μπορείτε επίσης να απενεργοποιήσετε τη χρήση δικτύων Wi-Fi και κινητής τηλεφωνίας και των αισθητήρων για την τοποθεσία στις ρυθμίσεις τοποθεσίας.</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">Σύρετε προς τα επάνω για να ξεκινήσετε</translation> <translation id="2603115962224169880">Εκκαθάριση υπολογιστή</translation> <translation id="2603463522847370204">Άνοιγμα σε παράθυρο για ανών&υμη περιήγηση</translation> -<translation id="2603656971249947488">Γραμμή καρτελών</translation> <translation id="2604255671529671813">Σφάλμα σύνδεσης δικτύου</translation> <translation id="2606246518223360146">Σύνδεση δεδομένων</translation> <translation id="2606454609872547359">Όχι, συνέχεια χωρίς το ChromeVox</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">Ενεργό, με περιαγωγή</translation> <translation id="3970114302595058915">Αναγνωριστικό</translation> <translation id="397105322502079400">Υπολογισμός…</translation> +<translation id="3971140002794351170">Λήψη προφίλ κινητού, Δίκτυο <ph name="NETWORK_INDEX" /> από <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Δακτυλικά αποτυπώματα σε αυτό το κλειδί ασφαλείας</translation> <translation id="3973660817924297510">Γίνεται έλεγχος κωδικών πρόσβασης (<ph name="CHECKED_PASSWORDS" /> από <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Η επικοινωνία με τον διακομιστή για realm απέτυχε</translation> @@ -6469,6 +6470,7 @@ <translation id="8398877366907290961">Συνέχεια</translation> <translation id="8400146488506985033">Διαχείριση ατόμων</translation> <translation id="8401432541486058167">Καταχωρίστε το PIN που συσχετίζεται με την έξυπνη κάρτα σας.</translation> +<translation id="8403562727702715619">Πρόσφατα από το Google Drive</translation> <translation id="8407199357649073301">Επίπεδο καταγραφής:</translation> <translation id="8408068190360279472">Δίκτυο <ph name="NETWORK_TYPE" />, σύνδεση σε εξέλιξη</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6907,6 +6909,7 @@ <translation id="8889651696183044030">Ο ιστότοπος <ph name="ORIGIN" /> μπορεί να επεξεργαστεί τα παρακάτω αρχεία και φακέλους</translation> <translation id="8890170499370378450">Μπορεί να επιφέρει χρεώσεις δεδομένων κινητής τηλεφωνίας.</translation> <translation id="8890516388109605451">Πηγές</translation> +<translation id="8890529496706615641">Δεν ήταν δυνατή η μετονομασία του προφίλ. Δοκιμάστε ξανά ή επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για τεχνική υποστήριξη.</translation> <translation id="8892168913673237979">Έτοιμο!</translation> <translation id="8893801527741465188">Η απεγκατάσταση ολοκληρώθηκε</translation> <translation id="8893928184421379330">Λυπούμαστε, δεν ήταν δυνατή η αναγνώριση της συσκευής <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_en-GB.xtb b/chrome/app/resources/generated_resources_en-GB.xtb index 4052a81c..3f66d7b 100644 --- a/chrome/app/resources/generated_resources_en-GB.xtb +++ b/chrome/app/resources/generated_resources_en-GB.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Show system text in this language</translation> <translation id="2367972762794486313">Show apps</translation> <translation id="2371076942591664043">Open when &done</translation> +<translation id="23721837607121582">Download mobile profile, network <ph name="NETWORK_INDEX" /> of <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Fit to paper</translation> <translation id="2375406435414127095">Connect to your phone</translation> <translation id="2377588536920405462">You can turn off location by turning off the main location setting on your device. You can also turn off the use of Wi-Fi, mobile networks and sensors for location in location settings.</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">Swipe up to get started</translation> <translation id="2603115962224169880">Clean up computer</translation> <translation id="2603463522847370204">Open in &Incognito window</translation> -<translation id="2603656971249947488">Tab strip</translation> <translation id="2604255671529671813">Network connection error</translation> <translation id="2606246518223360146">Link Data</translation> <translation id="2606454609872547359">No, continue without ChromeVox</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">On, roaming</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Calculating...</translation> +<translation id="3971140002794351170">Download mobile profile, network <ph name="NETWORK_INDEX" /> of <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Fingerprints on this security key</translation> <translation id="3973660817924297510">Checking passwords (<ph name="CHECKED_PASSWORDS" /> of <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Contacting server for realm failed</translation> @@ -6337,7 +6338,7 @@ <translation id="8246776524656196770">Protect your security key with a PIN (Personal Identification Number)</translation> <translation id="8248050856337841185">&Paste</translation> <translation id="8249048954461686687">OEM folder</translation> -<translation id="8249615410597138718">Send to Your Devices</translation> +<translation id="8249615410597138718">Send to your devices</translation> <translation id="8249672078237421304">Offer to translate pages that aren't in a language you read</translation> <translation id="8251441930213048644">Refresh now</translation> <translation id="8251578425305135684">Thumbnail removed.</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">Proceed anyway</translation> <translation id="8400146488506985033">Manage people</translation> <translation id="8401432541486058167">Provide the PIN that’s associated with your smart card.</translation> +<translation id="8403562727702715619">Recently from Google Drive</translation> <translation id="8407199357649073301">Log level:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> network, connecting</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> can edit the following files and folders</translation> <translation id="8890170499370378450">May incur mobile data charges</translation> <translation id="8890516388109605451">Sources</translation> +<translation id="8890529496706615641">Profile could not be renamed. Please try again or contact your operator for technical support.</translation> <translation id="8892168913673237979">Ready!</translation> <translation id="8893801527741465188">Uninstall complete</translation> <translation id="8893928184421379330">Sorry, the device <ph name="DEVICE_LABEL" /> could not be recognised.</translation>
diff --git a/chrome/app/resources/generated_resources_es-419.xtb b/chrome/app/resources/generated_resources_es-419.xtb index 22ec843..0377761 100644 --- a/chrome/app/resources/generated_resources_es-419.xtb +++ b/chrome/app/resources/generated_resources_es-419.xtb
@@ -1245,6 +1245,7 @@ <translation id="2366260648632264559">Mostrar el texto del sistema en este idioma</translation> <translation id="2367972762794486313">Mostrar aplicaciones</translation> <translation id="2371076942591664043">Abrir al &finalizar</translation> +<translation id="23721837607121582">Descarga un perfil de dispositivo móvil, red <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Ajustar a la hoja</translation> <translation id="2375406435414127095">Conéctate a tu teléfono</translation> <translation id="2377588536920405462">Para inhabilitar la Ubicación, desactiva la configuración de la ubicación principal en el dispositivo. También puedes desactivar el uso de Wi-Fi, redes móviles y sensores para obtener la ubicación en la configuración de la ubicación.</translation> @@ -1438,7 +1439,6 @@ <translation id="2602501489742255173">Desliza hacia arriba para comenzar</translation> <translation id="2603115962224169880">Limpiar la computadora</translation> <translation id="2603463522847370204">Abrir en una ventana de &incógnito</translation> -<translation id="2603656971249947488">Barra de pestañas</translation> <translation id="2604255671529671813">Error de conexión de red</translation> <translation id="2606246518223360146">Vincular datos</translation> <translation id="2606454609872547359">No, continuar sin ChromeVox</translation> @@ -2675,6 +2675,7 @@ <translation id="3969092967100188979">Activado (sin uso de roaming)</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Calculando...</translation> +<translation id="3971140002794351170">Descarga un perfil de dispositivo móvil, red <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Huellas digitales en esta llave de seguridad</translation> <translation id="3973660817924297510">Verificando contraseñas (<ph name="CHECKED_PASSWORDS" /> de <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Comunicándose con el servidor debido a un error en el dominio</translation> @@ -6465,6 +6466,7 @@ <translation id="8398877366907290961">Continuar de todos modos</translation> <translation id="8400146488506985033">Administrar personas</translation> <translation id="8401432541486058167">Proporciona el PIN asociado a tu tarjeta inteligente.</translation> +<translation id="8403562727702715619">Recientemente desde Google Drive</translation> <translation id="8407199357649073301">Nivel de registro:</translation> <translation id="8408068190360279472">Red <ph name="NETWORK_TYPE" />, conectando</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6905,6 +6907,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> puede editar los siguientes archivos y carpetas</translation> <translation id="8890170499370378450">Es posible que incurras en cargos por el uso de datos móviles.</translation> <translation id="8890516388109605451">Fuentes</translation> +<translation id="8890529496706615641">No se pudo cambiar el nombre del perfil. Vuelve a intentarlo o comunícate con tu proveedor para solicitarle asistencia técnica.</translation> <translation id="8892168913673237979">¡Listo!</translation> <translation id="8893801527741465188">Se completó la desinstalación</translation> <translation id="8893928184421379330">Lo sentimos, no se reconoció el dispositivo <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_es.xtb b/chrome/app/resources/generated_resources_es.xtb index 4773b02..dd387fa 100644 --- a/chrome/app/resources/generated_resources_es.xtb +++ b/chrome/app/resources/generated_resources_es.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Mostrar el texto del sistema en este idioma</translation> <translation id="2367972762794486313">Mostrar aplicaciones</translation> <translation id="2371076942591664043">Abrir al &finalizar</translation> +<translation id="23721837607121582">Descargar perfil móvil, red <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Ajustar al tamaño del papel</translation> <translation id="2375406435414127095">Conecta tu teléfono</translation> <translation id="2377588536920405462">Para inhabilitar la ubicación, desactiva el ajuste de ubicación principal en el dispositivo. También puedes desactivar el uso de sensores y redes Wi‑Fi o móviles para determinar la ubicación en los ajustes de ubicación.</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">Desliza el dedo hacia arriba para empezar</translation> <translation id="2603115962224169880">Limpiar ordenador</translation> <translation id="2603463522847370204">Abrir en una ventana de &incógnito</translation> -<translation id="2603656971249947488">Barra de pestañas</translation> <translation id="2604255671529671813">No se ha podido establecer conexión con la red</translation> <translation id="2606246518223360146">Vincular datos</translation> <translation id="2606454609872547359">No, continuar sin ChromeVox</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">Activado, con itinerancia</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Calculando...</translation> +<translation id="3971140002794351170">Descargar perfil móvil, red <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Huellas digitales de esta llave de seguridad</translation> <translation id="3973660817924297510">Comprobando contraseñas (<ph name="CHECKED_PASSWORDS" /> de <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Se ha producido un error al contactar con el servidor del dominio</translation> @@ -6467,6 +6468,7 @@ <translation id="8398877366907290961">Continuar de todos modos</translation> <translation id="8400146488506985033">Gestionar usuarios</translation> <translation id="8401432541486058167">Introduce el PIN asociado a tu tarjeta inteligente.</translation> +<translation id="8403562727702715619">Recientemente desde Google Drive</translation> <translation id="8407199357649073301">Nivel de registro:</translation> <translation id="8408068190360279472">Red <ph name="NETWORK_TYPE" />, conectando</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6907,6 +6909,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> puede editar los siguientes archivos y carpetas</translation> <translation id="8890170499370378450">Es posible que se apliquen cargos por el uso de datos móviles</translation> <translation id="8890516388109605451">Fuentes</translation> +<translation id="8890529496706615641">No se ha podido cambiar el nombre del perfil. Inténtalo de nuevo o ponte en contacto con tu operador para obtener asistencia técnica.</translation> <translation id="8892168913673237979">¡Todo listo!</translation> <translation id="8893801527741465188">Desinstalación completada</translation> <translation id="8893928184421379330">No se ha podido reconocer el dispositivo <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_et.xtb b/chrome/app/resources/generated_resources_et.xtb index 6525353..d3a86049 100644 --- a/chrome/app/resources/generated_resources_et.xtb +++ b/chrome/app/resources/generated_resources_et.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Kuva süsteemitekst selles keeles</translation> <translation id="2367972762794486313">Rakenduste kuvamine</translation> <translation id="2371076942591664043">Ava, kui on &valmis</translation> +<translation id="23721837607121582">Mobiiliprofiili allalaadimine, võrk <ph name="NETWORK_INDEX" />/<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Sobita paberilehele</translation> <translation id="2375406435414127095">Looge ühendus telefoniga</translation> <translation id="2377588536920405462">Võite funktsiooni Asukoht välja lülitada, lülitades oma seadmes välja peamise asukohaseade. Peale selle saab asukohaseadetes välja lülitada ka WiFi, mobiilsidevõrkude ja andurite kasutamise asukoha tuvastamiseks.</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">Alustamiseks pühkige üles</translation> <translation id="2603115962224169880">Puhasta arvuti</translation> <translation id="2603463522847370204">Ava &inkognito aknas</translation> -<translation id="2603656971249947488">Vahelehtede riba</translation> <translation id="2604255671529671813">Võrguühenduse viga</translation> <translation id="2606246518223360146">Lingi andmed</translation> <translation id="2606454609872547359">Ei, jätka ilma ChromeVoxita</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">Sees, rändlus toimib</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Arvutamine ...</translation> +<translation id="3971140002794351170">Mobiiliprofiili allalaadimine, võrk <ph name="NETWORK_INDEX" />/<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Sellel turvavõtmel olevad sõrmejäljed</translation> <translation id="3973660817924297510">Paroolide kontrollimine (<ph name="CHECKED_PASSWORDS" />/<ph name="TOTAL_PASSWORDS" />) …</translation> <translation id="3975565978598857337">Valduse jaoks serveriga ühenduse loomine nurjus</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">Jätka ikkagi</translation> <translation id="8400146488506985033">Halda inimesi</translation> <translation id="8401432541486058167">Sisestage oma kiipkaardi PIN-kood.</translation> +<translation id="8403562727702715619">Hiljuti Google Drive'ist</translation> <translation id="8407199357649073301">Logimistase:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" />-võrk, ühendamine</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> saab muuta järgmisi faile ja kaustu</translation> <translation id="8890170499370378450">Võib põhjustada mobiilse andmeside tasusid</translation> <translation id="8890516388109605451">Allikad</translation> +<translation id="8890529496706615641">Profiili nime ei saanud muuta. Proovige uuesti või võtke tehnilise toe saamiseks ühendust operaatoriga.</translation> <translation id="8892168913673237979">Kõik on valmis!</translation> <translation id="8893801527741465188">Desinstallimine jõudis lõpule</translation> <translation id="8893928184421379330">Kahjuks ei õnnestu seadet <ph name="DEVICE_LABEL" /> ära tunda.</translation>
diff --git a/chrome/app/resources/generated_resources_eu.xtb b/chrome/app/resources/generated_resources_eu.xtb index 19ade0a..e74f360a 100644 --- a/chrome/app/resources/generated_resources_eu.xtb +++ b/chrome/app/resources/generated_resources_eu.xtb
@@ -1110,7 +1110,7 @@ <translation id="2221261048068091179"><ph name="FIRST_SWITCH" />, <ph name="SECOND_SWITCH" /></translation> <translation id="2224337661447660594">Ez dago Interneteko konexiorik</translation> <translation id="2224444042887712269">Ezarpen hau <ph name="OWNER_EMAIL" /> erabiltzailearena da.</translation> -<translation id="222447520299472966">Arte-galeria moduko album bat gutxienez hautatu behar da</translation> +<translation id="222447520299472966">Arte-galeria kategoriako album bat gutxienez hautatu behar da</translation> <translation id="2224551243087462610">Editatu karpetaren izena</translation> <translation id="2225864335125757863">Aldatu honako pasahitz hauek ahal bezain laster kontua babestuta mantentzeko:</translation> <translation id="2226204716217107988">Beste profil batera aldatu nahi duzu?</translation> @@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">Hasteko, pasatu hatza gorantz</translation> <translation id="2603115962224169880">Garbitu ordenagailua</translation> <translation id="2603463522847370204">Ireki &ezkutuko nabigazio-leihoan</translation> -<translation id="2603656971249947488">Fitxen zinta</translation> <translation id="2604255671529671813">Sareko konexioaren errorea</translation> <translation id="2606246518223360146">Lotu datuak</translation> <translation id="2606454609872547359">Ez, egin aurrera ChromeVox gabe</translation>
diff --git a/chrome/app/resources/generated_resources_fa.xtb b/chrome/app/resources/generated_resources_fa.xtb index ae78007f..173551a 100644 --- a/chrome/app/resources/generated_resources_fa.xtb +++ b/chrome/app/resources/generated_resources_fa.xtb
@@ -1246,6 +1246,7 @@ <translation id="2366260648632264559">نمایش نوشتار سیستم به این زبان</translation> <translation id="2367972762794486313">نمایش برنامهها</translation> <translation id="2371076942591664043">پس از &تکمیل باز شود</translation> +<translation id="23721837607121582">بارگیری نمایه تلفن همراه، شبکه <ph name="NETWORK_INDEX" /> از <ph name="NETWORK_COUNT" />، <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">متناسب با اندازه کاغذ</translation> <translation id="2375406435414127095">اتصال به تلفن</translation> <translation id="2377588536920405462">میتوانید با خاموش کردن تنظیم اصلی «مکان» در دستگاهتان، «مکان» را خاموش کنید. میتوانید در تنظیمات مکان، استفاده از Wi-Fi، شبکه تلفن همراه، و حسگر را هم برای مکان خاموش کنید.</translation> @@ -1439,7 +1440,6 @@ <translation id="2602501489742255173">برای شروعبهکار تند بکشید</translation> <translation id="2603115962224169880">پاک کردن رایانه</translation> <translation id="2603463522847370204">باز کردن در پنجره &ناشناس</translation> -<translation id="2603656971249947488">نوار برگه</translation> <translation id="2604255671529671813">خطای اتصال شبکه</translation> <translation id="2606246518223360146">دادههای پیوند</translation> <translation id="2606454609872547359">نه، بدون ChromeVox ادامه داده شود</translation> @@ -2676,6 +2676,7 @@ <translation id="3969092967100188979">روشن، فراگردی</translation> <translation id="3970114302595058915">شناسه</translation> <translation id="397105322502079400">در حال محاسبه…</translation> +<translation id="3971140002794351170">بارگیری نمایه تلفن همراه، شبکه <ph name="NETWORK_INDEX" /> از <ph name="NETWORK_COUNT" />، <ph name="NETWORK_NAME" />، <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">اثر انگشتها در این کلید امنیتی</translation> <translation id="3973660817924297510">درحال بررسی کردن گذرواژهها (<ph name="CHECKED_PASSWORDS" /> از <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">برقراری ارتباط با سرور برای گستره ناموفق بود</translation> @@ -5225,7 +5226,7 @@ <translation id="6992554835374084304">روشن کردن غلطگیر املای بهبودیافته</translation> <translation id="6993000214273684335">برگه از گروه بینام برداشته شد - <ph name="GROUP_CONTENTS" /></translation> <translation id="6994069045767983299">رنگهای معکوس</translation> -<translation id="6995899638241819463">اگر گذرواژهها به دلیل نقض داده لو رفته باشد، هشدار میدهد</translation> +<translation id="6995899638241819463">اگر گذرواژهها دراثر سرقت اطلاعات شبکه لورفته باشند، به شما اطلاع داده شود</translation> <translation id="6997642619627518301"><ph name="NAME_PH" /> - گزارش فعالیت</translation> <translation id="6997707937646349884">در دستگاههای شما:</translation> <translation id="6998793565256476099">ثبتنام دستگاه برای برگزاری کنفرانس ویدیویی</translation> @@ -6466,6 +6467,7 @@ <translation id="8398877366907290961">در هر حال ادامه داده شود</translation> <translation id="8400146488506985033">مدیریت افراد</translation> <translation id="8401432541486058167">پین مرتبط با کارت هوشمندتان را ارائه کنید.</translation> +<translation id="8403562727702715619">اخیراً از Google Drive</translation> <translation id="8407199357649073301">سطح گزارش:</translation> <translation id="8408068190360279472">شبکه <ph name="NETWORK_TYPE" />، درحال اتصال</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6907,6 +6909,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> میتواند این فایلها و پوشهها را ویرایش کند:</translation> <translation id="8890170499370378450">ممکن است هزینه داده تلفن همراه اعمال شود</translation> <translation id="8890516388109605451">منابع</translation> +<translation id="8890529496706615641">نام نمایه تغییر نکرد. لطفاً دوباره امتحان کنید یا برای دریافت پشتیبانی فنی، با شرکت مخابراتی خود تماس بگیرید.</translation> <translation id="8892168913673237979">همه چیز آماده است!</translation> <translation id="8893801527741465188">حذف نصب تکمیل شد</translation> <translation id="8893928184421379330">متأسفیم، دستگاه <ph name="DEVICE_LABEL" /> شناسایی نشد.</translation>
diff --git a/chrome/app/resources/generated_resources_fi.xtb b/chrome/app/resources/generated_resources_fi.xtb index b7bba01..ba95200 100644 --- a/chrome/app/resources/generated_resources_fi.xtb +++ b/chrome/app/resources/generated_resources_fi.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">Aloita pyyhkäisemällä ylös</translation> <translation id="2603115962224169880">Puhdista tietokone</translation> <translation id="2603463522847370204">Avaa incognito-ikkunassa</translation> -<translation id="2603656971249947488">Välilehtirivi</translation> <translation id="2604255671529671813">Verkkoyhteysvirhe</translation> <translation id="2606246518223360146">Yhdistä tiedot</translation> <translation id="2606454609872547359">En, jatka ilman ChromeVoxia</translation>
diff --git a/chrome/app/resources/generated_resources_fil.xtb b/chrome/app/resources/generated_resources_fil.xtb index 76459cfb..785ade51e 100644 --- a/chrome/app/resources/generated_resources_fil.xtb +++ b/chrome/app/resources/generated_resources_fil.xtb
@@ -1249,6 +1249,7 @@ <translation id="2366260648632264559">Ipakita ang system text sa wikang ito</translation> <translation id="2367972762794486313">Ipakita ang apps</translation> <translation id="2371076942591664043">Buksan kapag &tapos na</translation> +<translation id="23721837607121582">I-download ang mobile profile, Network <ph name="NETWORK_INDEX" /> ng <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Pagkasyahin sa papel</translation> <translation id="2375406435414127095">Kumonekta sa iyong telepono</translation> <translation id="2377588536920405462">Puwede mong i-off ang Lokasyon sa pamamagitan ng pag-off sa pangunahing setting ng Lokasyon sa iyong device. Puwede mo ring i-off ang paggamit ng Wi-Fi, mga mobile network, at mga sensor para sa lokasyon sa mga setting ng lokasyon.</translation> @@ -1442,7 +1443,6 @@ <translation id="2602501489742255173">Mag-swipe pataas para makapagsimula</translation> <translation id="2603115962224169880">Linisin ang computer</translation> <translation id="2603463522847370204">Buksan sa &incognito window</translation> -<translation id="2603656971249947488">Tab strip</translation> <translation id="2604255671529671813">Error sa koneksyon ng network</translation> <translation id="2606246518223360146">I-link ang Data</translation> <translation id="2606454609872547359">Hindi, magpatuloy nang walang ChromeVox</translation> @@ -2679,6 +2679,7 @@ <translation id="3969092967100188979">Naka-on, roaming</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Kinakalkula...</translation> +<translation id="3971140002794351170">I-download ang mobile profile, Network <ph name="NETWORK_INDEX" /> ng <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Mga fingerprint sa security key na ito</translation> <translation id="3973660817924297510">Sinusuri ang mga password (<ph name="CHECKED_PASSWORDS" /> sa <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Hindi nagawang makipag-ugnayan sa server para sa realm</translation> @@ -6469,6 +6470,7 @@ <translation id="8398877366907290961">Magpatuloy</translation> <translation id="8400146488506985033">Pamahalaan ang mga tao</translation> <translation id="8401432541486058167">Ibigay ang PIN na nauugnay sa iyong smart card.</translation> +<translation id="8403562727702715619">Kamakailan mula sa Google Drive</translation> <translation id="8407199357649073301">Antas ng Log:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> network, kumokonekta</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6912,6 +6914,7 @@ <translation id="8889651696183044030">Puwedeng i-edit ng <ph name="ORIGIN" /> ang mga sumusunod na file at folder</translation> <translation id="8890170499370378450">Puwedeng magkaroon ng mga singil sa mobile data</translation> <translation id="8890516388109605451">Mga Source</translation> +<translation id="8890529496706615641">Hindi puwedeng i-rename ang profile. Pakisubukan ulit o makipag-ugnayan sa iyong carrier para sa technical support.</translation> <translation id="8892168913673237979">Handa na ang lahat!</translation> <translation id="8893801527741465188">Tapos nang mag-uninstall</translation> <translation id="8893928184421379330">Paumanhin, hindi makilala ang device na <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_fr-CA.xtb b/chrome/app/resources/generated_resources_fr-CA.xtb index 8e3a43eb..630f536 100644 --- a/chrome/app/resources/generated_resources_fr-CA.xtb +++ b/chrome/app/resources/generated_resources_fr-CA.xtb
@@ -1443,7 +1443,6 @@ <translation id="2602501489742255173">Glissez votre doigt vers le haut pour commencer</translation> <translation id="2603115962224169880">Nettoyer l'ordinateur</translation> <translation id="2603463522847370204">Ouvrir dans une fenêtre de &navigation privée</translation> -<translation id="2603656971249947488">Bande d'onglets</translation> <translation id="2604255671529671813">Erreur de connexion réseau</translation> <translation id="2606246518223360146">Associer les données</translation> <translation id="2606454609872547359">Non, continuer sans ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb index f9d53e1b..1d198de 100644 --- a/chrome/app/resources/generated_resources_fr.xtb +++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -1442,7 +1442,6 @@ <translation id="2602501489742255173">Balayez l'écran vers le haut pour démarrer</translation> <translation id="2603115962224169880">Nettoyer l'ordinateur</translation> <translation id="2603463522847370204">Ouvrir dans une fenêtre de &navigation privée</translation> -<translation id="2603656971249947488">Barre d'onglets</translation> <translation id="2604255671529671813">Erreur de connexion réseau</translation> <translation id="2606246518223360146">Associer les données</translation> <translation id="2606454609872547359">Non, continuer sans ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_gl.xtb b/chrome/app/resources/generated_resources_gl.xtb index 14864e6..3bd0d93 100644 --- a/chrome/app/resources/generated_resources_gl.xtb +++ b/chrome/app/resources/generated_resources_gl.xtb
@@ -1247,6 +1247,7 @@ <translation id="2366260648632264559">Mostrar o texto do sistema neste idioma</translation> <translation id="2367972762794486313">Mostrar aplicacións</translation> <translation id="2371076942591664043">Abrir ao fi&nalizar</translation> +<translation id="23721837607121582">Descargar perfil para móbiles, rede <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Axustar ao papel</translation> <translation id="2375406435414127095">Conectarse ao teléfono</translation> <translation id="2377588536920405462">Para desactivar a localización, desactiva a opción principal de localización do dispositivo. Tamén podes desactivar o uso de sensores e redes wifi ou de telefonía móbil para determinar a localización na configuración da localización.</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">Pasa o dedo cara arriba para comezar</translation> <translation id="2603115962224169880">Fai limpeza no ordenador</translation> <translation id="2603463522847370204">Abrir nunha ventá de &incógnito</translation> -<translation id="2603656971249947488">Franxa de pestanas</translation> <translation id="2604255671529671813">Produciuse un erro de conexión de rede</translation> <translation id="2606246518223360146">Ligar datos</translation> <translation id="2606454609872547359">Non, continuar sen ChromeVox</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">A itinerancia está activada e en uso</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Calculando...</translation> +<translation id="3971140002794351170">Descargar perfil para móbiles, rede <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Impresións dixitais nesta chave de seguranza</translation> <translation id="3973660817924297510">Comprobando contrasinais (<ph name="CHECKED_PASSWORDS" /> de <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Produciuse un erro durante o contacto co servidor do dominio</translation> @@ -6465,6 +6466,7 @@ <translation id="8398877366907290961">Continuar igualmente</translation> <translation id="8400146488506985033">Xestionar persoas</translation> <translation id="8401432541486058167">Introduce o PIN asociado á túa tarxeta intelixente.</translation> +<translation id="8403562727702715619">Recentemente desde Google Drive</translation> <translation id="8407199357649073301">Nivel de rexistro:</translation> <translation id="8408068190360279472">Rede de tipo <ph name="NETWORK_TYPE" />, conectando</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6905,6 +6907,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> pode editar os seguintes ficheiros e cartafoles</translation> <translation id="8890170499370378450">É posible que se apliquen cargos polo uso de datos móbiles</translation> <translation id="8890516388109605451">Fontes</translation> +<translation id="8890529496706615641">Non se puido cambiar o nome do perfil. Téntao de novo ou ponte en contacto co teu operador para obter asistencia técnica.</translation> <translation id="8892168913673237979">Todo listo!</translation> <translation id="8893801527741465188">Desinstalación completa</translation> <translation id="8893928184421379330">Non se puido recoñecer o dispositivo <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_gu.xtb b/chrome/app/resources/generated_resources_gu.xtb index 4eb1f49..3c62481 100644 --- a/chrome/app/resources/generated_resources_gu.xtb +++ b/chrome/app/resources/generated_resources_gu.xtb
@@ -1245,6 +1245,7 @@ <translation id="2366260648632264559">સિસ્ટમની ટેક્સ્ટ આ ભાષામાં બતાવો</translation> <translation id="2367972762794486313">ઍપ્લિકેશનો બતાવો</translation> <translation id="2371076942591664043">&પૂર્ણ થાય ત્યારે ખોલો</translation> +<translation id="23721837607121582"><ph name="NETWORK_NAME" />ના નેટવર્ક <ph name="NETWORK_COUNT" />માંથી <ph name="NETWORK_INDEX" /> મોબાઇલ પ્રોફાઇલ ડાઉનલોડ કરો</translation> <translation id="2373666622366160481">પેપરના કદ મુજબ પ્રિન્ટ કરો</translation> <translation id="2375406435414127095">તમારા ફોન સાથે કનેક્ટ કરો</translation> <translation id="2377588536920405462">તમે તમારા ડિવાઇસ પરનાં મુખ્ય સ્થાન સેટિંગને બંધ કરીને સ્થાન સેવાને બંધ કરી શકો છો. તમે સ્થાન સેટિંગમાં સ્થાન સેવા માટે વાઇ-ફાઇ, મોબાઇલ નેટવર્ક અને સેન્સરનો ઉપયોગ પણ બંધ કરી શકો છો.</translation> @@ -1438,7 +1439,6 @@ <translation id="2602501489742255173">શરૂ કરવા માટે ઉપર સ્વાઇપ કરો</translation> <translation id="2603115962224169880">કમ્પ્યુટર સાફ કરો</translation> <translation id="2603463522847370204">&છુપી વિંડોમાં ખોલો</translation> -<translation id="2603656971249947488">ટૅબ સ્ટ્રિપ</translation> <translation id="2604255671529671813">નેટવર્ક કનેક્શનમાં ભૂલ</translation> <translation id="2606246518223360146">ડેટાને લિંક કરો</translation> <translation id="2606454609872547359">ના, ChromeVox વગર આગળ વધો</translation> @@ -2675,6 +2675,7 @@ <translation id="3969092967100188979">ચાલુ, રોમિંગમાં</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">ગણના કરી રહ્યું છે...</translation> +<translation id="3971140002794351170"><ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" />ના નેટવર્ક <ph name="NETWORK_COUNT" />માંથી <ph name="NETWORK_INDEX" /> મોબાઇલ પ્રોફાઇલ ડાઉનલોડ કરો</translation> <translation id="3971764089670057203">આ સિક્યુરિટી કીમાંના ફિંગરપ્રિન્ટ</translation> <translation id="3973660817924297510">પાસવર્ડ ચેક કરી રહ્યાં છીએ (<ph name="TOTAL_PASSWORDS" />માંથી <ph name="CHECKED_PASSWORDS" />)…</translation> <translation id="3975565978598857337">ક્ષેત્ર માટે સર્વરનો સંપર્ક કરવામાં નિષ્ફળ થયાં</translation> @@ -6461,6 +6462,7 @@ <translation id="8398877366907290961">કોઈપણ રીતે આગળ વધારો</translation> <translation id="8400146488506985033">લોકોને મેનેજ કરો</translation> <translation id="8401432541486058167">તમારા સ્માર્ટ કાર્ડ સાથે સંકળાયેલો હોય તે પિન પ્રદાન કરો.</translation> +<translation id="8403562727702715619">તાજેતરમાં Google Driveમાંથી</translation> <translation id="8407199357649073301">લૉગ લેવલ:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> નેટવર્ક, કનેક્ટ કરી રહ્યું છે</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6902,6 +6904,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> નીચે આપેલી ફાઇલો અને ફોલ્ડરોમાં ફેરફાર કરી શકે છે</translation> <translation id="8890170499370378450">મોબાઇલ ડેટા શુલ્ક લાગુ થઈ શકે</translation> <translation id="8890516388109605451">સ્રોતો</translation> +<translation id="8890529496706615641">પ્રોફાઇલનું નામ બદલી શકાયું નથી. કૃપા કરીને ફરીથી પ્રયાસ કરો અથવા ટેક્નિકલ સપોર્ટ માટે તમારા મોબાઇલ ઑપરેટરનો સંપર્ક કરો.</translation> <translation id="8892168913673237979">બધું સેટ છે!</translation> <translation id="8893801527741465188">અનઇન્સ્ટૉલ કરવું પૂર્ણ</translation> <translation id="8893928184421379330">માફ કરશો, ઉપકરણ <ph name="DEVICE_LABEL" /> ઓળખી શકાયું નથી.</translation>
diff --git a/chrome/app/resources/generated_resources_hi.xtb b/chrome/app/resources/generated_resources_hi.xtb index a1345aa5..ef6a86a 100644 --- a/chrome/app/resources/generated_resources_hi.xtb +++ b/chrome/app/resources/generated_resources_hi.xtb
@@ -1442,7 +1442,6 @@ <translation id="2602501489742255173">शुरू करने के लिए ऊपर की ओर स्वाइप करें</translation> <translation id="2603115962224169880">कंप्यूटर साफ़ करें</translation> <translation id="2603463522847370204">&गुप्त विंडो में खोलें</translation> -<translation id="2603656971249947488">टैब बार</translation> <translation id="2604255671529671813">नेटवर्क कनेक्शन गड़बड़ी</translation> <translation id="2606246518223360146">डेटा लिंक करें</translation> <translation id="2606454609872547359">नहीं, ChromeVox के बिना जारी रखें</translation>
diff --git a/chrome/app/resources/generated_resources_hr.xtb b/chrome/app/resources/generated_resources_hr.xtb index ca2baa6..51ec16e3 100644 --- a/chrome/app/resources/generated_resources_hr.xtb +++ b/chrome/app/resources/generated_resources_hr.xtb
@@ -1249,6 +1249,7 @@ <translation id="2366260648632264559">Prikaži tekst sustava na ovom jeziku</translation> <translation id="2367972762794486313">Prikaz aplikacija</translation> <translation id="2371076942591664043">Otvori nakon &dovršetka</translation> +<translation id="23721837607121582">Preuzmi mobilni profil, mreža <ph name="NETWORK_INDEX" /> od <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Prilagodi papiru</translation> <translation id="2375406435414127095">Povežite se s telefonom</translation> <translation id="2377588536920405462">Lokaciju možete isključiti tako što ćete isključiti glavnu postavku lokacije na svojem uređaju. U postavkama lokacije također možete isključiti upotrebu Wi‑Fija, mobilnih mreža i senzora za lokaciju.</translation> @@ -1442,7 +1443,6 @@ <translation id="2602501489742255173">Prijeđite prstom prema gore za početak</translation> <translation id="2603115962224169880">Očistite računalo</translation> <translation id="2603463522847370204">Otvaranje u &anonimnom prozoru</translation> -<translation id="2603656971249947488">Vrpca kartica</translation> <translation id="2604255671529671813">Pogreška mrežne veze</translation> <translation id="2606246518223360146">Poveži podatke</translation> <translation id="2606454609872547359">Ne, nastavi bez ChromeVoxa</translation> @@ -2679,6 +2679,7 @@ <translation id="3969092967100188979">Uključeno, uz roaming</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Izračun u tijeku…</translation> +<translation id="3971140002794351170">Preuzmi mobilni profil, mreža <ph name="NETWORK_INDEX" /> od <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Otisci prsta na ovom sigurnosnom ključu</translation> <translation id="3973660817924297510">Provjera zaporki (<ph name="CHECKED_PASSWORDS" /> od <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Kontaktiranje poslužitelja za domenu nije uspjelo</translation> @@ -6467,6 +6468,7 @@ <translation id="8398877366907290961">Svejedno nastavi</translation> <translation id="8400146488506985033">Upravljaj korisnicima</translation> <translation id="8401432541486058167">Unesite PIN za pametnu karticu.</translation> +<translation id="8403562727702715619">Nedavno s Google diska</translation> <translation id="8407199357649073301">Razina zapisnika:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> mreža, povezivanje</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030">Web-lokacija <ph name="ORIGIN" /> može uređivati sljedeće datoteke i mape</translation> <translation id="8890170499370378450">Možda će se naplatiti mobilni podatkovni promet</translation> <translation id="8890516388109605451">Izvori</translation> +<translation id="8890529496706615641">Preimenovanje profila nije uspjelo. Pokušajte ponovo ili se obratite mobilnom operateru za tehničku podršku.</translation> <translation id="8892168913673237979">Sve je spremno!</translation> <translation id="8893801527741465188">Deinstalacija je dovršena</translation> <translation id="8893928184421379330">Žao nam je, nije bilo moguće prepoznati uređaj <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_hu.xtb b/chrome/app/resources/generated_resources_hu.xtb index cc53197..9e0f9a0 100644 --- a/chrome/app/resources/generated_resources_hu.xtb +++ b/chrome/app/resources/generated_resources_hu.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Rendszerszöveg megjelenítése ezen a nyelven</translation> <translation id="2367972762794486313">Alkalmazások megjelenítése</translation> <translation id="2371076942591664043">Megnyitás, amikor &kész</translation> +<translation id="23721837607121582">Mobilprofil letöltése, <ph name="NETWORK_COUNT" />/<ph name="NETWORK_INDEX" />. hálózat, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Igazítás a papírhoz</translation> <translation id="2375406435414127095">Kapcsolódjon telefonjához</translation> <translation id="2377588536920405462">A helyszolgáltatást kikapcsolhatja az eszközén a fő Hely beállítás kikapcsolásával. Ezenkívül a helybeállításokban letilthatja a Wi-Fi- és mobilhálózatoknak, valamint az érzékelőknek a hely meghatározására való felhasználását.</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">Az indításhoz csúsztasson felfelé</translation> <translation id="2603115962224169880">A számítógép megtisztítása</translation> <translation id="2603463522847370204">Megnyitás &inkognitóablakban</translation> -<translation id="2603656971249947488">Lapsor</translation> <translation id="2604255671529671813">Hálózati kapcsolati hiba</translation> <translation id="2606246518223360146">Adatok összekapcsolása</translation> <translation id="2606454609872547359">Nem, a ChromeVox nélkül folytatom</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">Bekapcsolva, a roaming aktív</translation> <translation id="3970114302595058915">Azonosító</translation> <translation id="397105322502079400">Számítás…</translation> +<translation id="3971140002794351170">Mobilprofil letöltése, <ph name="NETWORK_COUNT" />/<ph name="NETWORK_INDEX" />. hálózat, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">A biztonsági kulcson található ujjlenyomatok</translation> <translation id="3973660817924297510">Jelszavak ellenőrzése (<ph name="TOTAL_PASSWORDS" />/<ph name="CHECKED_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Nem sikerült kapcsolódni a tartomány szerveréhez</translation> @@ -6469,6 +6470,7 @@ <translation id="8398877366907290961">Továbblépés</translation> <translation id="8400146488506985033">Személyek kezelése</translation> <translation id="8401432541486058167">Adja meg az intelligens kártyájához tartozó PIN-kódot.</translation> +<translation id="8403562727702715619">Nemrégiben innen: Google Drive</translation> <translation id="8407199357649073301">Naplózási szint:</translation> <translation id="8408068190360279472">Hálózat: <ph name="NETWORK_TYPE" />. Csatlakozás…</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6909,6 +6911,7 @@ <translation id="8889651696183044030">A(z) <ph name="ORIGIN" /> szerkesztheti a következő fájlokat és mappákat:</translation> <translation id="8890170499370378450">Mobiladat-forgalmi díjjal járhat</translation> <translation id="8890516388109605451">Források</translation> +<translation id="8890529496706615641">Nem sikerült átnevezni a profilt. Próbálja újra, vagy technikai segítségért forduljon a szolgáltatójához.</translation> <translation id="8892168913673237979">Kész is van!</translation> <translation id="8893801527741465188">Az eltávolítás befejeződött</translation> <translation id="8893928184421379330">Elnézést kérünk, de a(z) <ph name="DEVICE_LABEL" /> eszköz nem ismerhető fel.</translation>
diff --git a/chrome/app/resources/generated_resources_hy.xtb b/chrome/app/resources/generated_resources_hy.xtb index ffb7463..47b2d69 100644 --- a/chrome/app/resources/generated_resources_hy.xtb +++ b/chrome/app/resources/generated_resources_hy.xtb
@@ -1421,7 +1421,7 @@ <translation id="2562743677925229011">Մուտք գործած չեք <ph name="SHORT_PRODUCT_NAME" /></translation> <translation id="2564520396658920462">AppleScript-ի միջոցով JavaScript-ի օգտագործումն անջատած է: Միացնելու համար ցանկագոտուց անցեք Դիտում > Մշակող > Թույլատրել JavaScript-ը Apple-ի իրադարձություններից: Լրացուցիչ տեղեկությունների համար անցեք https://support.google.com/chrome/?p=applescript</translation> <translation id="2564653188463346023">Ուղղագրության ընդլայնված ստուգում</translation> -<translation id="2568774940984945469">Տեղեկագոտու զետեղարան</translation> +<translation id="2568774940984945469">Տեղեկագոտու կոնտեյներ</translation> <translation id="2571655996835834626">Փոխել կարգավորումները, որոնք կառավարում քուքիների, JavaScript-ի, փլագինների, տեղադրության տվյալների, խոսափողի, ֆոտոխցիկի և այլ գործառույթների հասանելիությունը կայքերի համար։</translation> <translation id="2572032849266859634"><ph name="VOLUME_NAME" />-ին միայն կարդալու հնարավորություն է շնորհվել:</translation> <translation id="2575247648642144396">Այս պատկերակը կցուցադրվի, եթե ընդլայնումը կարող է աշխատել բեռնված էջում: Օգտագործեք այս ընդլայնումը՝ սեղմելով պատկերակի կամ <ph name="EXTENSION_SHORTCUT" />:</translation> @@ -1443,7 +1443,6 @@ <translation id="2602501489742255173">Սկսելու համար մատը սահեցրեք վերև</translation> <translation id="2603115962224169880">Մաքրեք համակարգիչը</translation> <translation id="2603463522847370204">Բացել &ինկոգնիտո պատուհանում</translation> -<translation id="2603656971249947488">Ներդիրների հատված</translation> <translation id="2604255671529671813">Ցանցի միացման սխալ</translation> <translation id="2606246518223360146">Կցել տվյալները</translation> <translation id="2606454609872547359">Ոչ, շարունակել առանց ChromeVox-ի</translation>
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb index bfa0870..323421f 100644 --- a/chrome/app/resources/generated_resources_id.xtb +++ b/chrome/app/resources/generated_resources_id.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">Geser ke atas untuk memulai</translation> <translation id="2603115962224169880">Bersihkan komputer</translation> <translation id="2603463522847370204">Buka di &jendela samaran</translation> -<translation id="2603656971249947488">Tab setrip</translation> <translation id="2604255671529671813">Error koneksi jaringan</translation> <translation id="2606246518223360146">Tautkan Data</translation> <translation id="2606454609872547359">Tidak, lanjutkan dengan ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_is.xtb b/chrome/app/resources/generated_resources_is.xtb index afed0b1..a628bc4 100644 --- a/chrome/app/resources/generated_resources_is.xtb +++ b/chrome/app/resources/generated_resources_is.xtb
@@ -1249,6 +1249,7 @@ <translation id="2366260648632264559">Sýna kerfistexta á þessu tungumáli</translation> <translation id="2367972762794486313">Sýna forrit</translation> <translation id="2371076942591664043">Opna að þessu loknu</translation> +<translation id="23721837607121582">Sækja snjallprófíl, netkerfi <ph name="NETWORK_INDEX" /> af <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Laga að pappír</translation> <translation id="2375406435414127095">Tengstu við símann þinn</translation> <translation id="2377588536920405462">Þú getur slökkt á staðsetningaraðgangi með því að slökkva á aðalstaðsetningarstillingunni í tækinu. Einnig er hægt að slökkva á notkun Wi-Fi, farsímakerfa og skynjara við ákvörðun staðsetningar í staðsetningarstillingunum.</translation> @@ -1442,7 +1443,6 @@ <translation id="2602501489742255173">Strjúktu upp til að hefjast handa</translation> <translation id="2603115962224169880">Hreinsa tölvu</translation> <translation id="2603463522847370204">Opna í hul&iðsglugga</translation> -<translation id="2603656971249947488">Fliparæma</translation> <translation id="2604255671529671813">Villa í nettengingu</translation> <translation id="2606246518223360146">Tengja gögn</translation> <translation id="2606454609872547359">Nei, halda áfram án ChromeVox</translation> @@ -2679,6 +2679,7 @@ <translation id="3969092967100188979">Kveikt, í reiki</translation> <translation id="3970114302595058915">Auðkenni</translation> <translation id="397105322502079400">Reiknar...</translation> +<translation id="3971140002794351170">Sækja snjallprófíl, netkerfi <ph name="NETWORK_INDEX" /> af <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Fingraför á þessum öryggislykli</translation> <translation id="3973660817924297510">Athugar aðgangsorð (<ph name="CHECKED_PASSWORDS" /> af <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Ekki náðist samband við þjón svæðis</translation> @@ -6467,6 +6468,7 @@ <translation id="8398877366907290961">Halda samt áfram</translation> <translation id="8400146488506985033">Vinna með einstaklinga</translation> <translation id="8401432541486058167">Sláðu inn PIN-númerið fyrir snjallkortið þitt.</translation> +<translation id="8403562727702715619">Nýlegt af Google Drive</translation> <translation id="8407199357649073301">Skráningarstig:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" />-net, tengist</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> getur breytt eftirfarandi skrám og möppum</translation> <translation id="8890170499370378450">Kann að hafa í för með sér gjöld fyrir farsímagögn</translation> <translation id="8890516388109605451">Uppruni</translation> +<translation id="8890529496706615641">Ekki var hægt að endurnefna prófíl. Reyndu aftur eða hafðu samband við símafyrirtækið þitt til að fá tæknilega aðstoð.</translation> <translation id="8892168913673237979">Allt til reiðu!</translation> <translation id="8893801527741465188">Fjarlægingu lokið</translation> <translation id="8893928184421379330">Því miður var ekki hægt að bera kennsl á tækið <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_it.xtb b/chrome/app/resources/generated_resources_it.xtb index 1ba23dd..bee53f1d 100644 --- a/chrome/app/resources/generated_resources_it.xtb +++ b/chrome/app/resources/generated_resources_it.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Mostra il testo di sistema in questa lingua</translation> <translation id="2367972762794486313">Mostra app</translation> <translation id="2371076942591664043">Apri al &termine</translation> +<translation id="23721837607121582">Scarica il profilo per dispositivi mobili, rete <ph name="NETWORK_INDEX" /> di <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Adatta a dimensioni del foglio</translation> <translation id="2375406435414127095">Collegati al telefono</translation> <translation id="2377588536920405462">Puoi disabilitare la geolocalizzazione disattivando l'impostazione Posizione principale sul tuo dispositivo. Puoi anche disattivare l'uso di reti Wi-Fi e mobili e di sensori per la geolocalizzazione nelle impostazioni di geolocalizzazione.</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">Scorri verso l'alto per iniziare</translation> <translation id="2603115962224169880">Pulisci il computer</translation> <translation id="2603463522847370204">Apri in finestra di navigazione in &incognito</translation> -<translation id="2603656971249947488">Tabstrip</translation> <translation id="2604255671529671813">Errore di connessione alla rete</translation> <translation id="2606246518223360146">Collega dati</translation> <translation id="2606454609872547359">No, continua senza ChromeVox</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">Attivo, in roaming</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Calcolo in corso...</translation> +<translation id="3971140002794351170">Scarica il profilo per dispositivi mobili, rete <ph name="NETWORK_INDEX" /> di <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Impronte registrate con questo token di sicurezza</translation> <translation id="3973660817924297510">Verifica delle password (<ph name="CHECKED_PASSWORDS" /> di <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Tentativo di contatto del server per area di autenticazione non riuscito</translation> @@ -6466,6 +6467,7 @@ <translation id="8398877366907290961">Procedi comunque</translation> <translation id="8400146488506985033">Gestisci utenti</translation> <translation id="8401432541486058167">Specifica il PIN associato alla tua smart card.</translation> +<translation id="8403562727702715619">Recentemente da Google Drive</translation> <translation id="8407199357649073301">Livello di log:</translation> <translation id="8408068190360279472">Rete <ph name="NETWORK_TYPE" />, collegamento in corso</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6906,6 +6908,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> può modificare i file e le cartelle indicati di seguito</translation> <translation id="8890170499370378450">Potrebbero esserti addebitati costi per l'utilizzo dei dati mobili</translation> <translation id="8890516388109605451">Fonti</translation> +<translation id="8890529496706615641">Impossibile rinominare il profilo. Riprova oppure contatta il tuo operatore per ricevere assistenza tecnica.</translation> <translation id="8892168913673237979">Finito.</translation> <translation id="8893801527741465188">Disinstallazione completata</translation> <translation id="8893928184421379330">Spiacenti, impossibile riconoscere il dispositivo <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_iw.xtb b/chrome/app/resources/generated_resources_iw.xtb index d611619..839a47e9 100644 --- a/chrome/app/resources/generated_resources_iw.xtb +++ b/chrome/app/resources/generated_resources_iw.xtb
@@ -1440,7 +1440,6 @@ <translation id="2602501489742255173">יש להחליק כלפי מעלה כדי להתחיל</translation> <translation id="2603115962224169880">ניקוי המחשב</translation> <translation id="2603463522847370204">פתיחה בחלון &אנונימי</translation> -<translation id="2603656971249947488">שורת כרטיסיות</translation> <translation id="2604255671529671813">שגיאת חיבור רשת</translation> <translation id="2606246518223360146">קישור נתונים</translation> <translation id="2606454609872547359">לא, אמשיך בלי ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb index 8369082..4ab01c4 100644 --- a/chrome/app/resources/generated_resources_ja.xtb +++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">システムのテキストをこの言語で表示</translation> <translation id="2367972762794486313">アプリを表示</translation> <translation id="2371076942591664043">ダウンロードしたら開く(&D)</translation> +<translation id="23721837607121582">モバイル プロファイルのダウンロード - <ph name="NETWORK_INDEX" /> 番目のネットワーク(全 <ph name="NETWORK_COUNT" /> 件)、<ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">用紙に合わせる</translation> <translation id="2375406435414127095">スマートフォンに接続</translation> <translation id="2377588536920405462">位置情報の使用を無効にするには、お使いのデバイスでメインの位置情報の設定を無効にします。また、位置情報の設定で、Wi‑Fi、モバイル ネットワーク、センサーを現在地の特定に使用しないよう指定することもできます。</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">開始するには上にスワイプします</translation> <translation id="2603115962224169880">パソコンのクリーンアップ</translation> <translation id="2603463522847370204">シークレット ウィンドウで開く(&I)</translation> -<translation id="2603656971249947488">タブバー</translation> <translation id="2604255671529671813">ネットワーク接続エラー</translation> <translation id="2606246518223360146">データをリンク</translation> <translation id="2606454609872547359">いいえ(ChromeVox なしで続行する)</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">オン(ローミングあり)</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">計算しています...</translation> +<translation id="3971140002794351170">モバイル プロファイルのダウンロード - <ph name="NETWORK_INDEX" /> 番目のネットワーク(全 <ph name="NETWORK_COUNT" /> 件)、<ph name="NETWORK_NAME" />、<ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">このセキュリティ キーのフィンガープリント</translation> <translation id="3973660817924297510">パスワードを確認しています(<ph name="CHECKED_PASSWORDS" /> 件目 / <ph name="TOTAL_PASSWORDS" /> 件中)…</translation> <translation id="3975565978598857337">レルムのサーバーに接続できませんでした</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">このまま続行</translation> <translation id="8400146488506985033">ユーザーを管理</translation> <translation id="8401432541486058167">スマートカードに関連付けられている PIN を入力してください。</translation> +<translation id="8403562727702715619">Google ドライブから最近</translation> <translation id="8407199357649073301">ログレベル:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> ネットワーク、接続中</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> は次のファイルとフォルダを編集できます</translation> <translation id="8890170499370378450">モバイルデータ通信料が発生することがあります</translation> <translation id="8890516388109605451">ソース</translation> +<translation id="8890529496706615641">プロファイルの名前を変更できませんでした。もう一度お試しいただくか、ご利用の携帯通信会社のテクニカル サポートにお問い合わせください。</translation> <translation id="8892168913673237979">設定完了。</translation> <translation id="8893801527741465188">アンインストールが完了しました</translation> <translation id="8893928184421379330">デバイス <ph name="DEVICE_LABEL" /> を認識できませんでした。</translation>
diff --git a/chrome/app/resources/generated_resources_ka.xtb b/chrome/app/resources/generated_resources_ka.xtb index 1303ba8..4829f9a 100644 --- a/chrome/app/resources/generated_resources_ka.xtb +++ b/chrome/app/resources/generated_resources_ka.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">სისტემის ტექსტის ჩვენება ამ ენაზე</translation> <translation id="2367972762794486313">პროგრამების ჩვენება</translation> <translation id="2371076942591664043">გახსენით როდესაც &შესრულებულია</translation> +<translation id="23721837607121582">მობილური პროფილის ჩამოტვირთვა, ქსელი <ph name="NETWORK_INDEX" /> / <ph name="NETWORK_COUNT" />-დან, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">გვერდზე მორგება</translation> <translation id="2375406435414127095">დაუკავშირდით თქვენს ტელეფონს</translation> <translation id="2377588536920405462">მდებარეობის გამორთვა შესაძლებელია თქვენს მოწყობილობაზე მდებარეობის მთავარი პარამეტრის გამორთვით. გარდა ამისა, შეგიძლიათ გამორთოთ Wi-Fi კავშირის, მობილური ქსელებისა და სენსორების გამოყენება მდებარეობის დასადგენად.</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">დასაწყებად გადაფურცლეთ ზემოთ</translation> <translation id="2603115962224169880">კომპიუტერის გასუფთავება</translation> <translation id="2603463522847370204">გახსნა &ინკოგნიტო ფანჯარაში</translation> -<translation id="2603656971249947488">ჩანართების ზოლი</translation> <translation id="2604255671529671813">ქსელთან კავშირის შეცდომა</translation> <translation id="2606246518223360146">მონაცემების მიბმა</translation> <translation id="2606454609872547359">არა, მსურს ChromeVox-ის გარეშე გაგრძელება</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">ჩართული, როუმინგი</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">ანგარიშობს…</translation> +<translation id="3971140002794351170">მობილური პროფილის ჩამოტვირთვა, ქსელი <ph name="NETWORK_INDEX" /> / <ph name="NETWORK_COUNT" />-დან, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">თითის ანაბეჭდები უსაფრთხოების ამ გასაღებზე</translation> <translation id="3973660817924297510">მიმდინარეობს პაროლების შემოწმება (<ph name="CHECKED_PASSWORDS" /> / <ph name="TOTAL_PASSWORDS" />-დან)…</translation> <translation id="3975565978598857337">სერვერთან არის თაობაზე დაკავშირება ვერ მოხერხდა</translation> @@ -6464,6 +6465,7 @@ <translation id="8398877366907290961">მაინც გაგრძელება</translation> <translation id="8400146488506985033">ადამიანების მართვა</translation> <translation id="8401432541486058167">მიუთითეთ PIN-კოდი, რომელიც დაკავშირებულია თქვენს სმარტ-ბარათთან.</translation> +<translation id="8403562727702715619">ბოლო დროს Google Drive-იდან</translation> <translation id="8407199357649073301">ჟურნალირების დონე:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> ქსელი, მიმდინარეობს დაკავშირება</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6904,6 +6906,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" />-ს შეუძლია მითითებული ფაილებისა და საქაღალდეების რედაქტირება</translation> <translation id="8890170499370378450">შესაძლოა, დაგეკისროთ მობილური ინტერნეტის საფასურის გადახდა</translation> <translation id="8890516388109605451">წყაროები</translation> +<translation id="8890529496706615641">პროფილის გადარქმევა ვერ მოხერხდა. ცადეთ ხელახლა ან დაუკავშირდით თქვენს ოპერატორს ტექნიკური მხარდაჭერისთვის.</translation> <translation id="8892168913673237979">ყველაფერი დაყენებულია!</translation> <translation id="8893801527741465188">დეინსტალაცია დასრულდა</translation> <translation id="8893928184421379330">ვწუხვართ, მოწყობილობა <ph name="DEVICE_LABEL" />-ის ამოცნობა ვერ მოხერხდა.</translation>
diff --git a/chrome/app/resources/generated_resources_kk.xtb b/chrome/app/resources/generated_resources_kk.xtb index 0f1446275..6cc4a453 100644 --- a/chrome/app/resources/generated_resources_kk.xtb +++ b/chrome/app/resources/generated_resources_kk.xtb
@@ -1245,6 +1245,7 @@ <translation id="2366260648632264559">Жүйе мәтінін осы тілде көрсету</translation> <translation id="2367972762794486313">Қолданбаларды көрсету</translation> <translation id="2371076942591664043">&Дайын болғанда ашу</translation> +<translation id="23721837607121582">Мобильдік профильді жүктеп алу, <ph name="NETWORK_INDEX" />/<ph name="NETWORK_COUNT" /> желі, <ph name="NETWORK_NAME" /> желісі</translation> <translation id="2373666622366160481">Қағаз өлшеміне сәйкестендіру</translation> <translation id="2375406435414127095">Телефоныңызға жалғаңыз</translation> <translation id="2377588536920405462">Құрылғыдағы негізгі орналасу параметрін өшіру арқылы орналасқан жердің анықталуын өшіруге болады. Сонымен қатар Wi‑Fi мен мобильдік желілердің және сенсорлардың орынды анықтау үшін қолданылуын геодерек параметрлерінен өшіре аласыз.</translation> @@ -1438,7 +1439,6 @@ <translation id="2602501489742255173">Бастау үшін жоғары қарай сырғытыңыз.</translation> <translation id="2603115962224169880">Компьютерді тазалау</translation> <translation id="2603463522847370204">&Инкогнито терезесінде ашу</translation> -<translation id="2603656971249947488">Қойындылар жолағы</translation> <translation id="2604255671529671813">Желімен байланыс қатесі</translation> <translation id="2606246518223360146">Деректерді байланыстыру</translation> <translation id="2606454609872547359">Жоқ, ChromeVox-сыз жалғастырамын</translation> @@ -2675,6 +2675,7 @@ <translation id="3969092967100188979">Қосулы, роумингімен</translation> <translation id="3970114302595058915">Идентификатор</translation> <translation id="397105322502079400">Есептелуде…</translation> +<translation id="3971140002794351170">Мобильдік профильді жүктеп алу, <ph name="NETWORK_INDEX" />/<ph name="NETWORK_COUNT" /> желі, <ph name="NETWORK_PROVIDER_NAME" /> провайдерінің <ph name="NETWORK_NAME" /> желісі</translation> <translation id="3971764089670057203">Осы қауіпсіздік кілтіндегі саусақ іздері</translation> <translation id="3973660817924297510">Құпия сөздерді (<ph name="CHECKED_PASSWORDS" />/<ph name="TOTAL_PASSWORDS" />) тексеру…</translation> <translation id="3975565978598857337">Аймақ серверіне қосылмады.</translation> @@ -6463,6 +6464,7 @@ <translation id="8398877366907290961">Бәрібір жалғастыру</translation> <translation id="8400146488506985033">Адамдарды басқару</translation> <translation id="8401432541486058167">Смарт картаңызбен байланыстырылған PIN кодын көрсетіңіз.</translation> +<translation id="8403562727702715619">Жақында шыққан Google Drive мүмкіндіктері</translation> <translation id="8407199357649073301">Журнал деңгейі:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> желісі, жалғануда</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6903,6 +6905,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> мына файлдар мен қалталарды өңдей алады.</translation> <translation id="8890170499370378450">Мобильдік интернет ақысы алынуы мүмкін.</translation> <translation id="8890516388109605451">Дереккөздер</translation> +<translation id="8890529496706615641">Профиль аты өзгертілмеді. Әрекетті қайталаңыз немесе техникалық қолдау үшін операторыңызға хабарласыңыз.</translation> <translation id="8892168913673237979">Бәрі дайын!</translation> <translation id="8893801527741465188">Жою аяқталды</translation> <translation id="8893928184421379330">Кешіріңіз, <ph name="DEVICE_LABEL" /> құрылғысын анықтау мүмкін емес.</translation>
diff --git a/chrome/app/resources/generated_resources_km.xtb b/chrome/app/resources/generated_resources_km.xtb index f28aa05..e910158b 100644 --- a/chrome/app/resources/generated_resources_km.xtb +++ b/chrome/app/resources/generated_resources_km.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">អូសឡើងលើ ដើម្បីចាប់ផ្ដើម</translation> <translation id="2603115962224169880">សម្អាតកុំព្យូទ័រ</translation> <translation id="2603463522847370204">បើកនៅក្នុងផ្ទាំងអនាមិក</translation> -<translation id="2603656971249947488">របារផ្ទាំង</translation> <translation id="2604255671529671813">មានបញ្ហាក្នុងការភ្ជាប់បណ្តាញ</translation> <translation id="2606246518223360146">ភ្ជាប់ទិន្នន័យ</translation> <translation id="2606454609872547359">ទេ បន្តដោយគ្មាន ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_kn.xtb b/chrome/app/resources/generated_resources_kn.xtb index 279df763..d508776 100644 --- a/chrome/app/resources/generated_resources_kn.xtb +++ b/chrome/app/resources/generated_resources_kn.xtb
@@ -1442,7 +1442,6 @@ <translation id="2602501489742255173">ಪ್ರಾರಂಭಿಸಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ</translation> <translation id="2603115962224169880">ಕಂಪ್ಯೂಟರ್ ಅನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಿ</translation> <translation id="2603463522847370204">&ಅಜ್ಞಾತ ವಿಂಡೋದಲ್ಲಿ ತೆರೆಯಿರಿ</translation> -<translation id="2603656971249947488">ಟ್ಯಾಬ್ ಸ್ಟ್ರೈಪ್</translation> <translation id="2604255671529671813">ನೆಟ್ವರ್ಕ್ ಸಂಪರ್ಕ ದೋಷ</translation> <translation id="2606246518223360146">ಡೇಟಾ ಲಿಂಕ್ ಮಾಡಿ</translation> <translation id="2606454609872547359">ಇಲ್ಲ, ChromeVox ಇಲ್ಲದೆಯೇ ಮುಂದುವರಿಸಿ</translation>
diff --git a/chrome/app/resources/generated_resources_ko.xtb b/chrome/app/resources/generated_resources_ko.xtb index 847f6c0..3d25577 100644 --- a/chrome/app/resources/generated_resources_ko.xtb +++ b/chrome/app/resources/generated_resources_ko.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">위로 스와이프하여 시작하기</translation> <translation id="2603115962224169880">컴퓨터 정리</translation> <translation id="2603463522847370204">시크릿 창에서 열기(&I)</translation> -<translation id="2603656971249947488">탭 표시줄</translation> <translation id="2604255671529671813">네트워크 연결 오류</translation> <translation id="2606246518223360146">데이터 연결</translation> <translation id="2606454609872547359">아니요, ChromeVox 활성화 없이 계속</translation>
diff --git a/chrome/app/resources/generated_resources_ky.xtb b/chrome/app/resources/generated_resources_ky.xtb index 494dadb..af6d9936 100644 --- a/chrome/app/resources/generated_resources_ky.xtb +++ b/chrome/app/resources/generated_resources_ky.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">Баштоо үчүн, өйдө серпип коюңуз</translation> <translation id="2603115962224169880">Компьютерди тазалоо</translation> <translation id="2603463522847370204">&Жашыруун терезеде ачуу</translation> -<translation id="2603656971249947488">Өтмөктөр тактасы</translation> <translation id="2604255671529671813">Тармакка туташуу катасы</translation> <translation id="2606246518223360146">Дайындарды байланыштыруу</translation> <translation id="2606454609872547359">Жок, ChromeVox жок эле улантам</translation>
diff --git a/chrome/app/resources/generated_resources_lo.xtb b/chrome/app/resources/generated_resources_lo.xtb index 245546b..553547d3 100644 --- a/chrome/app/resources/generated_resources_lo.xtb +++ b/chrome/app/resources/generated_resources_lo.xtb
@@ -1246,6 +1246,7 @@ <translation id="2366260648632264559">ສະແດງຂໍ້ຄວາມລະບົບເປັນພາສານີ້</translation> <translation id="2367972762794486313">ສະແດງແອັບ</translation> <translation id="2371076942591664043">ເປີດເມື່ອສໍາເລັດ</translation> +<translation id="23721837607121582">ດາວໂຫຼດໂປຣໄຟລ໌ມືຖື, ເຄືອຂ່າຍ <ph name="NETWORK_INDEX" /> ຈາກທັງໝົດ <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">ພໍດີກັບເຈ້ຍ</translation> <translation id="2375406435414127095">ເຊື່ອມຕໍ່ກັບໂທລະສັບຂອງທ່ານ</translation> <translation id="2377588536920405462">ທ່ານສາມາດປິດສະຖານທີ່ໄດ້ໂດຍການປິດການຕັ້ງຄ່າສະຖານທີ່ຫຼັກຢູ່ໃນອຸປະກອນຂອງທ່ານ. ນອກຈາກທ່ານຍັງສາມາດປິດການນຳໃຊ້ Wi‑Fi, ເຄືອຂ່າຍມືຖື ແລະ ເຊັນເຊີຕ່າງໆສຳລັບສະຖານທີ່ໄດ້ໃນການຕັ້ງຄ່າສະຖານທີ່.</translation> @@ -1439,7 +1440,6 @@ <translation id="2602501489742255173">ປັດຂຶ້ນເພື່ອເລີ່ມຕົ້ນ</translation> <translation id="2603115962224169880">ອະນາໄມຄອມພິວເຕີ</translation> <translation id="2603463522847370204">ເປີດຢູ່ໃນໜ້າຕ່າງທີ່ບໍ່ເຜີຍຕົນຕົວ</translation> -<translation id="2603656971249947488">ລາຍແຖບ</translation> <translation id="2604255671529671813">ການເຊື່ອມຕໍ່ເຄືອຂ່າຍຜິດພາດ</translation> <translation id="2606246518223360146">ລິ້ງຂໍ້ມູນ</translation> <translation id="2606454609872547359">ບໍ່, ສືບຕໍ່ໂດຍບໍ່ໃຊ້ ChromeVox</translation> @@ -2676,6 +2676,7 @@ <translation id="3969092967100188979">ເປີດ, ໂຣມມິງ</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">ກໍາລັງຄິດໄລ່...</translation> +<translation id="3971140002794351170">ດາວໂຫຼດໂປຣໄຟລ໌ມືຖື, ເຄືອຂ່າຍ <ph name="NETWORK_INDEX" /> ຈາກທັງໝົດ <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">ລາຍນິ້ວມືໃນກະແຈຄວາມປອດໄພນີ້</translation> <translation id="3973660817924297510">ກຳລັງກວດລະຫັດຜ່ານ (<ph name="CHECKED_PASSWORDS" /> ລາຍການຈາກທັງໝົດ <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">ການຕິດຕໍ່ຫາເຊີບເວີສຳລັບ realm ບໍ່ສຳເລັດ</translation> @@ -6463,6 +6464,7 @@ <translation id="8398877366907290961">ແນວໃດກໍ່ດໍາເນີນການຕໍ່</translation> <translation id="8400146488506985033">ຈັດການຜູ້ຄົນ</translation> <translation id="8401432541486058167">ໃຫ້ PIN ທີ່ເຊື່ອມໂຍງກັບບັດອັດສະລິຍະຂອງທ່ານ.</translation> +<translation id="8403562727702715619">ຫຼ້າສຸດຈາກ Google Drive</translation> <translation id="8407199357649073301">ລະດັບຂອງບັນທຶກ:</translation> <translation id="8408068190360279472">ເຄືອຂ່າຍ <ph name="NETWORK_TYPE" />, ກຳລັງເຊື່ອມຕໍ່</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6903,6 +6905,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> ສາມາດແກ້ໄຂໄຟລ໌ ແລະ ໂຟນເດີຕໍ່ໄປນີ້ໄດ້</translation> <translation id="8890170499370378450">ອາດມີການຮຽກເກັບຄ່າອິນເຕີເນັດມືຖື</translation> <translation id="8890516388109605451">ແຫລ່ງທີ່ມາ</translation> +<translation id="8890529496706615641">ບໍ່ສາມາດປ່ຽນຊື່ໂປຣໄຟລ໌ໄດ້. ກະລຸນາລອງໃໝ່ ຫຼື ຕິດຕໍ່ຫາຜູ້ໃຫ້ບໍລິການຂອງທ່ານສຳລັບການຊ່ວຍເຫຼືອທາງເທັກນິກ.</translation> <translation id="8892168913673237979">ຮຽບຮ້ອຍໝົດແລ້ວ!</translation> <translation id="8893801527741465188">ຖອນການຕິດຕັ້ງສຳເລັດແລ້ວ</translation> <translation id="8893928184421379330">ຂໍອະໄພ, ບໍ່ສາມາດຈົດຈໍາ <ph name="DEVICE_LABEL" /> ອຸປະກອນໄດ້.</translation>
diff --git a/chrome/app/resources/generated_resources_lt.xtb b/chrome/app/resources/generated_resources_lt.xtb index 9e6594c..f45700a7 100644 --- a/chrome/app/resources/generated_resources_lt.xtb +++ b/chrome/app/resources/generated_resources_lt.xtb
@@ -1251,6 +1251,7 @@ <translation id="2366260648632264559">Rodyti sistemos tekstą šia kalba</translation> <translation id="2367972762794486313">Rodyti programas</translation> <translation id="2371076942591664043">Baigus &atidaryti</translation> +<translation id="23721837607121582">Atsisiųsti mobiliojo ryšio tinklo profilį; <ph name="NETWORK_INDEX" /> tinklas iš <ph name="NETWORK_COUNT" />, „<ph name="NETWORK_NAME" />“</translation> <translation id="2373666622366160481">Pritaikyti pagal lapo dydį</translation> <translation id="2375406435414127095">Susieti su telefonu</translation> <translation id="2377588536920405462">Galite išjungti vietovės nustatymą išjungdami pagrindinį vietovės nustatymą savo įrenginyje. Vietovės nustatymuose taip pat galite išjungti „Wi‑Fi“, mobiliojo ryšio tinklų ir jutiklių naudojimą vietovei nustatyti.</translation> @@ -1444,7 +1445,6 @@ <translation id="2602501489742255173">Perbraukite aukštyn, jei norite pradėti</translation> <translation id="2603115962224169880">Išvalykite kompiuterį</translation> <translation id="2603463522847370204">Atidaryti &inkognito lange</translation> -<translation id="2603656971249947488">Skirtuko juostelė</translation> <translation id="2604255671529671813">Tinklo ryšio klaida</translation> <translation id="2606246518223360146">Susieti duomenis</translation> <translation id="2606454609872547359">Ne, tęsti be „ChromeVox“</translation> @@ -2681,6 +2681,7 @@ <translation id="3969092967100188979">Įjungta, veikia tarptinklinis ryšys</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Skaičiuojama...</translation> +<translation id="3971140002794351170">Atsisiųsti mobiliojo ryšio tinklo profilį; <ph name="NETWORK_INDEX" /> tinklas iš <ph name="NETWORK_COUNT" />, „<ph name="NETWORK_NAME" />“, „<ph name="NETWORK_PROVIDER_NAME" />“</translation> <translation id="3971764089670057203">Šio saugos rakto kontroliniai kodai</translation> <translation id="3973660817924297510">Tikrinami slaptažodžiai (<ph name="CHECKED_PASSWORDS" /> iš <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Nepavyko susisiekti su serveriu dėl srities</translation> @@ -6472,6 +6473,7 @@ <translation id="8398877366907290961">Vis tiek tęsti</translation> <translation id="8400146488506985033">Tvarkyti žmones</translation> <translation id="8401432541486058167">Nurodykite su išmaniąja kortele susietą PIN kodą.</translation> +<translation id="8403562727702715619">Neseniai iš „Google“ disko</translation> <translation id="8407199357649073301">Žurnalo lygis:</translation> <translation id="8408068190360279472">Tinklas: <ph name="NETWORK_TYPE" />, jungiamasi</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6915,6 +6917,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> gali redaguoti toliau nurodytus failus ir aplankus</translation> <translation id="8890170499370378450">Gali būti taikomi mobiliojo ryšio duomenų mokesčiai</translation> <translation id="8890516388109605451">Šaltiniai</translation> +<translation id="8890529496706615641">Nepavyko pervardyti profilio. Bandykite dar kartą arba susisiekite su operatoriumi dėl techninio palaikymo paslaugų.</translation> <translation id="8892168913673237979">Viskas nustatyta!</translation> <translation id="8893801527741465188">Pašalinta</translation> <translation id="8893928184421379330">Apgailestaujame, tačiau įrenginys <ph name="DEVICE_LABEL" /> neatpažįstamas.</translation>
diff --git a/chrome/app/resources/generated_resources_lv.xtb b/chrome/app/resources/generated_resources_lv.xtb index b55e53e..2a0048e0 100644 --- a/chrome/app/resources/generated_resources_lv.xtb +++ b/chrome/app/resources/generated_resources_lv.xtb
@@ -1250,6 +1250,7 @@ <translation id="2366260648632264559">Rādīt sistēmas tekstu šajā valodā</translation> <translation id="2367972762794486313">Rādīt lietotnes</translation> <translation id="2371076942591664043">Atvērt, kad esat beidzis</translation> +<translation id="23721837607121582">Lejupielādēt mobilo sakaru profilu, tīkls numur <ph name="NETWORK_INDEX" />, tīklu skaits ir <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Ietilpināt lapā</translation> <translation id="2375406435414127095">Savienošana ar tālruni</translation> <translation id="2377588536920405462">Varat izslēgt atrašanās vietas noteikšanu, savā ierīcē izslēdzot galveno atrašanās vietas noteikšanas iestatījumu. Atrašanās vietas iestatījumos varat arī izslēgt Wi‑Fi, mobilo tīklu un sensoru izmantošanu atrašanās vietas noteikšanai.</translation> @@ -1443,7 +1444,6 @@ <translation id="2602501489742255173">Lai sāktu darbu, velciet augšup</translation> <translation id="2603115962224169880">Tīriet datoru</translation> <translation id="2603463522847370204">Atvērt &inkognito režīma logā</translation> -<translation id="2603656971249947488">Ciļņu josla</translation> <translation id="2604255671529671813">Tīkla savienojuma kļūda</translation> <translation id="2606246518223360146">Saistīt datus</translation> <translation id="2606454609872547359">Nē, turpināt bez ChromeVox</translation> @@ -2680,6 +2680,7 @@ <translation id="3969092967100188979">Viesabonēšana ieslēgta, tiek izmantota</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Aprēķina...</translation> +<translation id="3971140002794351170">Lejupielādēt mobilo sakaru profilu, tīkls numur <ph name="NETWORK_INDEX" />, tīklu skaits ir <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Šai drošības atslēgai ir pirkstu nospiedumi</translation> <translation id="3973660817924297510">Notiek paroļu pārbaude (<ph name="CHECKED_PASSWORDS" /> no <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Sazināšanās ar serveri nozarojumam neizdevās</translation> @@ -6469,6 +6470,7 @@ <translation id="8398877366907290961">Turpināt jebkurā gadījumā</translation> <translation id="8400146488506985033">Pārvaldīt personas</translation> <translation id="8401432541486058167">Norādiet PIN, kas ir saistīts ar jūsu viedkarti.</translation> +<translation id="8403562727702715619">Jaunākais no Google diska</translation> <translation id="8407199357649073301">Žurnāla līmenis:</translation> <translation id="8408068190360279472">Tīkls: <ph name="NETWORK_TYPE" />, notiek savienojuma izveide</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6911,6 +6913,7 @@ <translation id="8889651696183044030">Vietne <ph name="ORIGIN" /> var rediģēt tālāk norādītos failus un mapes.</translation> <translation id="8890170499370378450">Var rasties izmaksas par mobilo datu pārraidi</translation> <translation id="8890516388109605451">Avoti</translation> +<translation id="8890529496706615641">Nevarēja pārdēvēt profilu. Lūdzu, mēģiniet vēlreiz vai sazinieties ar mobilo sakaru operatoru, lai saņemtu tehnisko atbalstu.</translation> <translation id="8892168913673237979">Gatavs!</translation> <translation id="8893801527741465188">Atinstalēšana pabeigta</translation> <translation id="8893928184421379330">Diemžēl ierīci <ph name="DEVICE_LABEL" /> nevarēja atpazīt.</translation>
diff --git a/chrome/app/resources/generated_resources_mk.xtb b/chrome/app/resources/generated_resources_mk.xtb index b9c9e12..dd742ef 100644 --- a/chrome/app/resources/generated_resources_mk.xtb +++ b/chrome/app/resources/generated_resources_mk.xtb
@@ -1442,7 +1442,6 @@ <translation id="2602501489742255173">Повлечете нагоре за да започнете</translation> <translation id="2603115962224169880">Чистење на компјутерот</translation> <translation id="2603463522847370204">Отвори во &инкогнито прозорец</translation> -<translation id="2603656971249947488">Лента за картички</translation> <translation id="2604255671529671813">Грешка во мрежното поврзување</translation> <translation id="2606246518223360146">Поврзи ги податоците</translation> <translation id="2606454609872547359">Не, продолжи без ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_ml.xtb b/chrome/app/resources/generated_resources_ml.xtb index 222a8e00..9863b894 100644 --- a/chrome/app/resources/generated_resources_ml.xtb +++ b/chrome/app/resources/generated_resources_ml.xtb
@@ -1245,6 +1245,7 @@ <translation id="2366260648632264559">സിസ്റ്റം ടെക്സ്റ്റ് ഈ ഭാഷയിൽ കാണിക്കുക</translation> <translation id="2367972762794486313">അപ്ലിക്കേഷനുകൾ കാണിക്കുക</translation> <translation id="2371076942591664043">ചെയ്തുകഴിയുമ്പോള് &തുറക്കുക</translation> +<translation id="23721837607121582">മൊബൈൽ പ്രൊഫൈൽ ഡൗൺലോഡ് ചെയ്യുക, <ph name="NETWORK_COUNT" /> എണ്ണത്തിൽ <ph name="NETWORK_INDEX" />-ാമത്തെ നെറ്റ്വർക്ക്, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">പേപ്പറിന് അനുയോജ്യമാക്കുക</translation> <translation id="2375406435414127095">ഫോണിലേക്ക് കണക്റ്റ് ചെയ്യുക</translation> <translation id="2377588536920405462">നിങ്ങളുടെ ഉപകരണത്തിലെ പ്രധാന ലൊക്കേഷൻ ക്രമീകരണം ഓഫാക്കുക വഴി നിങ്ങൾക്ക് ലൊക്കേഷൻ ഓഫാക്കാവുന്നതാണ്. ലൊക്കേഷന് വേണ്ടിയുള്ള വൈഫൈ, മൊബൈൽ നെറ്റ്വർക്കുകൾ, സെൻസറുകൾ എന്നിവയുടെ ഉപയോഗവും ലൊക്കേഷൻ ക്രമീകരണത്തിൽ ഓഫാക്കാനാവും.</translation> @@ -1438,7 +1439,6 @@ <translation id="2602501489742255173">ആരംഭിക്കുന്നതിന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക</translation> <translation id="2603115962224169880">നിങ്ങളുടെ കമ്പ്യൂട്ടർ ക്ലീൻ ചെയ്യുക</translation> <translation id="2603463522847370204">&അദൃശ്യ വിന്ഡോയില് തുറക്കുക</translation> -<translation id="2603656971249947488">തുറന്ന് വച്ചിട്ടുള്ള ടാബുകൾ</translation> <translation id="2604255671529671813">നെറ്റ്വർക്ക് കണക്ഷൻ പിശക്</translation> <translation id="2606246518223360146">ഡാറ്റ ലിങ്ക് ചെയ്യുക</translation> <translation id="2606454609872547359">വേണ്ട, ChromeVox ഇല്ലാതെ തുടരുക</translation> @@ -2674,6 +2674,7 @@ <translation id="3969092967100188979">ഓണാണ്, റോമിംഗിലാണ്</translation> <translation id="3970114302595058915">ഐഡി</translation> <translation id="397105322502079400">കണക്കാക്കുന്നു...</translation> +<translation id="3971140002794351170">മൊബൈൽ പ്രൊഫൈൽ ഡൗൺലോഡ് ചെയ്യുക, <ph name="NETWORK_COUNT" /> എണ്ണത്തിൽ <ph name="NETWORK_INDEX" />-ാമത്തെ നെറ്റ്വർക്ക്, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">ഈ സുരക്ഷാ കീയിലെ ഫിംഗർപ്രിന്റുകൾ</translation> <translation id="3973660817924297510">പാസ്വേഡുകൾ പരിശോധിക്കുന്നു (<ph name="TOTAL_PASSWORDS" />-ൽ <ph name="CHECKED_PASSWORDS" /> എണ്ണം)…</translation> <translation id="3975565978598857337">മേഖലയ്ക്കുള്ള സെർവറുമായി ബന്ധപ്പെടുന്നത് പരാജയപ്പെട്ടു</translation> @@ -6466,6 +6467,7 @@ <translation id="8398877366907290961">എങ്ങനെയാണെങ്കിലും മുന്നോട്ട് പോകുക</translation> <translation id="8400146488506985033">ആളുകളെ മാനേജുചെയ്യുക</translation> <translation id="8401432541486058167">നിങ്ങളുടെ സ്മാർട്ട് കാർഡിന്റെ പിൻ നൽകുക.</translation> +<translation id="8403562727702715619">Google Drive-ൽ നിന്ന് അടുത്തിടെയുള്ളത്</translation> <translation id="8407199357649073301">ലോഗ് ലെവൽ:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> നെറ്റ്വർക്ക്, കണക്റ്റ് ചെയ്യുന്നു</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6905,6 +6907,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" />എന്നതിന് ഇനിപ്പറയുന്ന ഫയലുകളും ഫോൾഡറുകളും എഡിറ്റ് ചെയ്യാനാവും</translation> <translation id="8890170499370378450">മൊബൈൽ ഡാറ്റാ നിരക്കുകൾ ഈടാക്കിയേക്കാം</translation> <translation id="8890516388109605451">ഉറവിടങ്ങള്</translation> +<translation id="8890529496706615641">പ്രൊഫൈലിന്റെ പേര് മാറ്റാനായില്ല. വീണ്ടും ശ്രമിക്കുക അല്ലെങ്കിൽ സാങ്കേതിക പിന്തുണയ്ക്ക് നിങ്ങളുടെ സേവനദാതാവിനെ ബന്ധപ്പെടുക.</translation> <translation id="8892168913673237979">എല്ലാം സജ്ജമായി!</translation> <translation id="8893801527741465188">അണ് ഇൻസ്റ്റാള് ചെയ്യൽ പൂർത്തിയായി</translation> <translation id="8893928184421379330">ക്ഷമിക്കണം, <ph name="DEVICE_LABEL" /> എന്ന ഉപകരണം അംഗീകരിക്കാൻ കഴിഞ്ഞില്ല.</translation>
diff --git a/chrome/app/resources/generated_resources_mn.xtb b/chrome/app/resources/generated_resources_mn.xtb index 59efcd34..11ad1bc 100644 --- a/chrome/app/resources/generated_resources_mn.xtb +++ b/chrome/app/resources/generated_resources_mn.xtb
@@ -1244,6 +1244,7 @@ <translation id="2366260648632264559">Системийн текстийг энэ хэлээр харуулах</translation> <translation id="2367972762794486313">Аппликейшнүүдийг харуулах</translation> <translation id="2371076942591664043">Татаж авч дууссаны дараа нээ</translation> +<translation id="23721837607121582">Мобайл профайл татах, <ph name="NETWORK_COUNT" />-н <ph name="NETWORK_INDEX" /> сүлжээ, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Цаасанд багтаах</translation> <translation id="2375406435414127095">Утсандаа холбогдох</translation> <translation id="2377588536920405462">Та төхөөрөмжийнхөө үндсэн Байршлын тохиргоог унтрааснаар байршлыг унтраах боломжтой. Та мөн байршилд зориулж Wi-Fi, мобайл сүлжээ болон мэдрэгчийг ашиглахыг байршлын тохиргоонд унтраах боломжтой.</translation> @@ -1436,7 +1437,6 @@ <translation id="2602501489742255173">Эхлүүлэхийн тулд дээш шударна уу</translation> <translation id="2603115962224169880">Компьютерийг цэвэрлэх</translation> <translation id="2603463522847370204">Нууцлалтай цонхонд нээх</translation> -<translation id="2603656971249947488">Таб зурвас</translation> <translation id="2604255671529671813">Сүлжээний холболтын алдаа</translation> <translation id="2606246518223360146">Өгөгдлийг холбох</translation> <translation id="2606454609872547359">Үгүй, ChromeVox-гүйгээр үргэлжлүүлнэ</translation> @@ -2672,6 +2672,7 @@ <translation id="3969092967100188979">Асаалттай, роумингтэй</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Тооцоолж байна ...</translation> +<translation id="3971140002794351170">Мобайл профайл татах, <ph name="NETWORK_COUNT" />-н <ph name="NETWORK_INDEX" /> сүлжээ, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Энэ аюулгүй байдлын түлхүүр дээр байгаа хурууны хээ</translation> <translation id="3973660817924297510">Нууц үгийг шалгаж байна (<ph name="TOTAL_PASSWORDS" />-н <ph name="CHECKED_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Домэйнээр серверт холбогдох амжилтгүй боллоо</translation> @@ -6457,6 +6458,7 @@ <translation id="8398877366907290961">Ямарч байсан үргэлжлүүлье</translation> <translation id="8400146488506985033">Хүмүүсийг удирдах</translation> <translation id="8401432541486058167">Таны ухаалаг карттай холбоотой ПИН-г оруулна уу.</translation> +<translation id="8403562727702715619">Саяхан Google Драйваас</translation> <translation id="8407199357649073301">Логийн түвшин:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> сүлжээ, холбогдож байна</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6895,6 +6897,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> дараах файл болон фолдерыг засах боломжтой</translation> <translation id="8890170499370378450">Мобайл дата төлбөр гарч болзошгүй</translation> <translation id="8890516388109605451">Эх сурвалж</translation> +<translation id="8890529496706615641">Профайлын нэрийг өөрчлөх боломжгүй. Дахин оролдож эсвэл техникийн тусламж авахаар оператор компанитайгаа холбогдоно уу.</translation> <translation id="8892168913673237979">Бүгд тохируулагдсан!</translation> <translation id="8893801527741465188">Амжилттай устгалаа</translation> <translation id="8893928184421379330">Уучлаарай, төхөөрөмжийг <ph name="DEVICE_LABEL" /> таних боломжгүй байна.</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb index 1399f520..580c672 100644 --- a/chrome/app/resources/generated_resources_mr.xtb +++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -1440,7 +1440,6 @@ <translation id="2602501489742255173">सुरू करण्यासाठी वर स्वाइप करा</translation> <translation id="2603115962224169880">काँप्युटर साफ करा</translation> <translation id="2603463522847370204">&गुप्त विंडोमध्ये उघडा</translation> -<translation id="2603656971249947488">टॅब स्ट्रिप</translation> <translation id="2604255671529671813">नेटवर्क कनेक्शन एरर</translation> <translation id="2606246518223360146">डेटा लिंक करा</translation> <translation id="2606454609872547359">नाही, ChromeVox शिवाय पुढे सुरू ठेवा</translation>
diff --git a/chrome/app/resources/generated_resources_ms.xtb b/chrome/app/resources/generated_resources_ms.xtb index 4335e05..e2c28e0f 100644 --- a/chrome/app/resources/generated_resources_ms.xtb +++ b/chrome/app/resources/generated_resources_ms.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">Leret ke atas untuk memulakan</translation> <translation id="2603115962224169880">Bersihkan komputer</translation> <translation id="2603463522847370204">Buka dalam tetingkap &inkognito</translation> -<translation id="2603656971249947488">Jalur tab</translation> <translation id="2604255671529671813">Ralat sambungan rangkaian</translation> <translation id="2606246518223360146">Pautkan Data</translation> <translation id="2606454609872547359">Tidak, teruskan tanpa ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_my.xtb b/chrome/app/resources/generated_resources_my.xtb index 61e877fdd..5f824e4 100644 --- a/chrome/app/resources/generated_resources_my.xtb +++ b/chrome/app/resources/generated_resources_my.xtb
@@ -1442,7 +1442,6 @@ <translation id="2602501489742255173">စတင်ရန် အပေါ်သို့ ပွတ်ဆွဲပါ</translation> <translation id="2603115962224169880">ကွန်ပျူတာကို ရှင်းလင်းခြင်း</translation> <translation id="2603463522847370204">ရုပ်ဖျက် ဝင်ဒိုး &ထဲမှာ ဖွင့်ရန်</translation> -<translation id="2603656971249947488">တဘ်ဘားတန်း</translation> <translation id="2604255671529671813">ကွန်ရက် ချိတ်ဆက်မှု အမှား</translation> <translation id="2606246518223360146">ဒေတာများကို လင့်ခ်ချိတ်ရန်</translation> <translation id="2606454609872547359">ChromeVox မပါဘဲ ရှေ့ဆက်ရန်</translation> @@ -2197,7 +2196,7 @@ <translation id="3458451003193188688">ကွန်ရက်အမှားအယွင်းကြောင့် ပကတိအသွင်စက်ကို ထည့်သွင်း၍မရပါ။ ထပ်စမ်းကြည့်ပါ သို့မဟုတ် သင့်စီမံခန့်ခွဲသူထံ ဆက်သွယ်ပါ။ အမှားကုဒ်- <ph name="ERROR_CODE" />။</translation> <translation id="3458794975359644386">မျှဝေမှု မလုပ်၍မရပါ</translation> <translation id="3459509316159669723">ပုံနှိပ်နေသည်</translation> -<translation id="3459697287128633276">သင့်အကောင့်ဖြင့် Google Play စတိုးကို အသုံးပြုခြင်းကို ဖွင့်ရန် သင်၏ အထောက်အထား ဝန်ဆောင်မှုပေးသူဖြင့် အထောက်အထားစိစစ်ပါ။</translation> +<translation id="3459697287128633276">သင့်အကောင့်ဖြင့် Google Play Store ကို အသုံးပြုခြင်းကို ဖွင့်ရန် သင်၏ အထောက်အထား ဝန်ဆောင်မှုပေးသူဖြင့် အထောက်အထားစိစစ်ပါ။</translation> <translation id="3462311546193741693">ဝဘ်ဆိုက်အများစုမှနေ၍ ထွက်လိုက်ပါမည်။ သင့် Google အကောင့်သို့ လက်မှတ်ထိုးဝင်ထားဦးမည်ဖြစ်၍ သင်စင့်ခ်လုပ်ထားသော ဒေတာများကို ရှင်းထုတ်နိုင်ပါသည်။</translation> <translation id="3462413494201477527">အကောင့် ပြင်ဆင်သတ်မှတ်ခြင်းအား ပယ်ဖျက်မည်လား?</translation> <translation id="3464145797867108663">အလုပ်ပရိုဖိုင်ကို ထည့်ရန်</translation> @@ -4714,7 +4713,7 @@ <translation id="6395423953133416962"><ph name="BEGIN_LINK1" />စနစ်ဆိုင်ရာ အချက်အလက်များ <ph name="END_LINK1" /> နှင့် <ph name="BEGIN_LINK2" />တိုင်းထွာချက်များ<ph name="END_LINK2" /> ပို့ရန်</translation> <translation id="6396481367412417758">သတ်မှတ်မှုကို ဖယ်ရှားရန် “<ph name="CURRENTKEY" />” ထပ်နှိပ်ပြီး ထွက်ပါ။</translation> <translation id="6396988158856674517">ဝဘ်ဆိုက်များအား လှုပ်ရှားမှု အာရုံခံစနစ်များ အသုံးပြုခြင်းကို တားမြစ်ရန်</translation> -<translation id="6398715114293939307">Google Play စတိုးကို ဖယ်ရှားရန်</translation> +<translation id="6398715114293939307">Google Play Store ကို ဖယ်ရှားရန်</translation> <translation id="6398765197997659313">မျက်နှာပြင် အပြည့်မှ ထွက်ရန်</translation> <translation id="6399774419735315745">သူလျှို</translation> <translation id="6404511346730675251">စာညှပ် တည်းဖြတ်ရန်</translation> @@ -6214,7 +6213,7 @@ <translation id="8101987792947961127">နောက်တစ်ကြိမ် reboot လုပ်လျှင် Powerwash လိုအပ်သည်။</translation> <translation id="8102139037507939978">system_logs.txt မှ 'ပုဂ္ဂိုလ်ရေးအရ ခွဲခြားသိရှိနိုင်သော အချက်အလက်များ' ကို ဖယ်ရှားသည်။</translation> <translation id="8102159139658438129">သင်ချိတ်ထားသောဖုန်းအတွက် ရွေးစရာများ ကြည့်ရန် <ph name="LINK_BEGIN" />ဆက်တင်များ<ph name="LINK_END" /> သို့ သွားပါ</translation> -<translation id="8107015733319732394">သင့် <ph name="DEVICE_TYPE" /> တွင် Google Play စတိုးကို ထည့်သွင်းနေပါသည်။ မိနစ်အနည်းငယ် ကြာနိုင်ပါသည်။</translation> +<translation id="8107015733319732394">သင့် <ph name="DEVICE_TYPE" /> တွင် Google Play Store ကို ထည့်သွင်းနေပါသည်။ မိနစ်အနည်းငယ် ကြာနိုင်ပါသည်။</translation> <translation id="810728361871746125">မျက်နှာပြင်ပြသမှုပုံရိပ် ပြတ်သားကိန်း</translation> <translation id="8108526232944491552">{COUNT,plural, =0{ပြင်ပအဖွဲ့အစည်း၏ ကွတ်ကီးများ မရှိပါ}=1{ပြင်ပအဖွဲ့အစည်း၏ ကွတ်ကီး ၁ ခုကို ပိတ်ထားသည်}other{ပြင်ပအဖွဲ့အစည်း၏ ကွတ်ကီး # ခုကို ပိတ်ထားသည်}}</translation> <translation id="810875025413331850">အနီးအနားတွင် ကိရိယာများ မရှိပါ။</translation> @@ -7027,7 +7026,7 @@ <translation id="9026731007018893674">ဒေါင်းလုဒ်</translation> <translation id="9026852570893462412">ဤလုပ်ဆောင်ချက်သည် မိနစ်အနည်းငယ်ကြာနိုင်ပါသည်။ ပကတိအသွင်စက်ကို ဒေါင်းလုဒ်လုပ်နေသည်။</translation> <translation id="9027459031423301635">လင့်ကို တဘ် & အသစ်ထဲမှာ ဖွင့်ရန်</translation> -<translation id="9030515284705930323">သင့်အဖွဲ့အစည်းသည် သင့်အကောင့်အတွက် Google Play စတိုးကို ဖွင့်မပေးရသေးပါ။ နောက်ထပ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။</translation> +<translation id="9030515284705930323">သင့်အဖွဲ့အစည်းသည် သင့်အကောင့်အတွက် Google Play Store ကို ဖွင့်မပေးရသေးပါ။ နောက်ထပ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။</translation> <translation id="9030785788945687215">Gmail</translation> <translation id="9030855135435061269"><ph name="PLUGIN_NAME" /> ကို မပံ့ပိုးတော့ပါ</translation> <translation id="9031549947500880805">Google Drive သို့ မိတ္တူကူးရန်။ သင်၏ ဒေတာများကို အလွယ်တကူ ပြန်ယူပါ သို့မဟုတ် စက်ပစ္စည်းကို အချိန်မရွေး ပြောင်းပါ။ သင်၏ မိတ္တူတွင် အက်ပ်ဒေတာများ ပါဝင်သည်။</translation>
diff --git a/chrome/app/resources/generated_resources_ne.xtb b/chrome/app/resources/generated_resources_ne.xtb index 4a7ea730..9f2452f 100644 --- a/chrome/app/resources/generated_resources_ne.xtb +++ b/chrome/app/resources/generated_resources_ne.xtb
@@ -1437,7 +1437,6 @@ <translation id="2602501489742255173">सुरु गर्न माथितिर स्वाइप गर्नुहोस्</translation> <translation id="2603115962224169880">कम्प्युटरमा ठाउँ खाली गर्नुहोस्</translation> <translation id="2603463522847370204">&इनकगनिटो विण्डोमा खोल्नुहोस्</translation> -<translation id="2603656971249947488">ट्याब स्ट्रिप</translation> <translation id="2604255671529671813">नेटवर्कको जडानसम्बन्धी त्रुटि</translation> <translation id="2606246518223360146">डेटा लिंक गर्नुहोस्</translation> <translation id="2606454609872547359">अहँ, ChromeVox सक्रिय नगरी अगाडि बढ्नुहोस्</translation>
diff --git a/chrome/app/resources/generated_resources_nl.xtb b/chrome/app/resources/generated_resources_nl.xtb index 7fe5ab8e..6c5e8e2 100644 --- a/chrome/app/resources/generated_resources_nl.xtb +++ b/chrome/app/resources/generated_resources_nl.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Systeemtekst in deze taal weergeven</translation> <translation id="2367972762794486313">Apps weergeven</translation> <translation id="2371076942591664043">Openen wanneer geree&d</translation> +<translation id="23721837607121582">Mobiel profiel downloaden, netwerk <ph name="NETWORK_INDEX" /> van <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Aanpassen aan papierformaat</translation> <translation id="2375406435414127095">Verbinding maken met je telefoon</translation> <translation id="2377588536920405462">Je kunt Locatie uitschakelen door de primaire instelling voor Locatie op je apparaat uit te schakelen. Je kunt het gebruik van wifi, mobiele netwerken en sensoren voor locatie ook uitschakelen via de locatie-instellingen.</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">Swipe omhoog om te beginnen</translation> <translation id="2603115962224169880">Computer opruimen</translation> <translation id="2603463522847370204">Openen in &incognitovenster</translation> -<translation id="2603656971249947488">Tabbladstrook</translation> <translation id="2604255671529671813">Fout bij netwerkverbinding</translation> <translation id="2606246518223360146">Gegevens linken</translation> <translation id="2606454609872547359">Nee, doorgaan zonder ChromeVox</translation> @@ -1503,7 +1503,7 @@ <translation id="2665394472441560184">Een nieuw woord toevoegen</translation> <translation id="2665647207431876759">Verlopen</translation> <translation id="2665717534925640469">Deze pagina wordt nu op volledig scherm weergegeven en heeft je muisaanwijzer uitgeschakeld.</translation> -<translation id="2665919335226618153">Er is een fout opgetreden tijdens het formatteren.</translation> +<translation id="2665919335226618153">Asjemenou! Er is iets misgegaan bij het formatteren.</translation> <translation id="2667463864537187133">Spellingcontrole beheren</translation> <translation id="2669241540496514785">Kan <ph name="APP_NAME" /> niet openen</translation> <translation id="2670102641511624474"><ph name="APP_NAME" /> deelt een Chrome-tabblad.</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">Aan, roaming</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Berekenen...</translation> +<translation id="3971140002794351170">Mobiel profiel downloaden, netwerk <ph name="NETWORK_INDEX" /> van <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Vingerafdrukken op deze beveiligingssleutel</translation> <translation id="3973660817924297510">Wachtwoorden controleren (<ph name="CHECKED_PASSWORDS" /> van <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Verbinding maken met server voor domein mislukt</translation> @@ -4128,7 +4129,7 @@ <translation id="5720705177508910913">Huidige gebruiker</translation> <translation id="572155275267014074">Android-instellingen</translation> <translation id="5722086096420375088">Groen/wit</translation> -<translation id="5722930212736070253">Helaas. Er is een fout voor Zip Archiver opgetreden.</translation> +<translation id="5722930212736070253">Asjemenou! Er is iets misgegaan met de Zip Archiver.</translation> <translation id="5723034813131030312">Voorkomen dat sites verbinding maken met seriële apparaten</translation> <translation id="572328651809341494">Recente tabbladen</translation> <translation id="5723508132121499792">Geen actieve achtergrondapps</translation> @@ -5604,7 +5605,7 @@ <translation id="7434635829372401939">Je instellingen synchroniseren</translation> <translation id="7434757724413878233">Muisversnelling</translation> <translation id="7434969625063495310">Kan de afdrukserver niet toevoegen. Controleer de configuratie van de server en probeer het opnieuw.</translation> -<translation id="7436921188514130341">Er is een fout opgetreden tijdens het wijzigen van de naam.</translation> +<translation id="7436921188514130341">Asjemenou! Er is iets misgegaan bij het veranderen van de naam.</translation> <translation id="7439519621174723623">Voeg een apparaatnaam toe om door te gaan</translation> <translation id="7441736921018636843">Als je deze instelling wilt wijzigen, moet je de <ph name="BEGIN_LINK" />synchronisatie resetten<ph name="END_LINK" /> om de wachtwoordzin voor synchronisatie te verwijderen</translation> <translation id="7441830548568730290">Andere gebruikers.</translation> @@ -6467,6 +6468,7 @@ <translation id="8398877366907290961">Toch doorgaan</translation> <translation id="8400146488506985033">Mensen beheren</translation> <translation id="8401432541486058167">Geef de pincode op die hoort bij je smartkaart.</translation> +<translation id="8403562727702715619">Onlangs vanuit Google Drive</translation> <translation id="8407199357649073301">Logniveau:</translation> <translation id="8408068190360279472">Netwerk: <ph name="NETWORK_TYPE" />, verbinden</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> kan de volgende bestanden en mappen bewerken</translation> <translation id="8890170499370378450">Er kunnen kosten voor mobiele data in rekening worden gebracht</translation> <translation id="8890516388109605451">Bronnen</translation> +<translation id="8890529496706615641">De naam van het profiel kan niet worden gewijzigd. Probeer het opnieuw of neem contact op met je provider voor technische support.</translation> <translation id="8892168913673237979">Helemaal klaar!</translation> <translation id="8893801527741465188">Verwijderen voltooid</translation> <translation id="8893928184421379330">Het apparaat <ph name="DEVICE_LABEL" /> kan niet worden herkend.</translation>
diff --git a/chrome/app/resources/generated_resources_no.xtb b/chrome/app/resources/generated_resources_no.xtb index f33025a..2af93f22 100644 --- a/chrome/app/resources/generated_resources_no.xtb +++ b/chrome/app/resources/generated_resources_no.xtb
@@ -1245,6 +1245,7 @@ <translation id="2366260648632264559">Vis systemtekst på dette språket</translation> <translation id="2367972762794486313">Vis apper</translation> <translation id="2371076942591664043">Åpne når ne&dlastingen er ferdig</translation> +<translation id="23721837607121582">Last ned mobilprofilen, nettverk <ph name="NETWORK_INDEX" /> av <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Tilpass til papiret</translation> <translation id="2375406435414127095">Koble til telefonen din</translation> <translation id="2377588536920405462">Du kan slå av Posisjon ved å slå av enhetens hovedinnstilling for Posisjon. Du kan også slå av bruken av Wi-Fi, mobilnettverk og sensorer for posisjon i posisjonsinnstillingene.</translation> @@ -1438,7 +1439,6 @@ <translation id="2602501489742255173">Sveip opp for å komme i gang</translation> <translation id="2603115962224169880">Rydd opp i datamaskinen</translation> <translation id="2603463522847370204">Åpne i &inkognitovindu</translation> -<translation id="2603656971249947488">Fanerad</translation> <translation id="2604255671529671813">Feil i nettverkstilkobling</translation> <translation id="2606246518223360146">Knytt sammen dataene</translation> <translation id="2606454609872547359">Nei, fortsett uten ChromeVox</translation> @@ -2673,6 +2673,7 @@ <translation id="3969092967100188979">På – roamer</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Beregner …</translation> +<translation id="3971140002794351170">Last ned mobilprofilen, nettverk <ph name="NETWORK_INDEX" /> av <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Fingeravtrykk på denne sikkerhetsnøkkelen</translation> <translation id="3973660817924297510">Sjekker passord (<ph name="CHECKED_PASSWORDS" /> av <ph name="TOTAL_PASSWORDS" />) …</translation> <translation id="3975565978598857337">Kunne ikke kontakte tjeneren for området</translation> @@ -6463,6 +6464,7 @@ <translation id="8398877366907290961">Fortsett likevel</translation> <translation id="8400146488506985033">Administrer personer</translation> <translation id="8401432541486058167">Oppgi PIN-koden som er tilknyttet smartkortet ditt.</translation> +<translation id="8403562727702715619">Nylig fra Google Disk</translation> <translation id="8407199357649073301">Loggnivå:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" />-nettverk – kobler til</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6903,6 +6905,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> kan redigere disse filene og mappene</translation> <translation id="8890170499370378450">Mobildatakostnader kan påløpe</translation> <translation id="8890516388109605451">Kilder</translation> +<translation id="8890529496706615641">Kunne ikke gi nytt navn til profilen. Prøv på nytt, eller kontakt operatøren for å få teknisk støtte.</translation> <translation id="8892168913673237979">Alt er klart!</translation> <translation id="8893801527741465188">Avinstalleringen er ferdig</translation> <translation id="8893928184421379330">Beklager, men enheten <ph name="DEVICE_LABEL" /> ble ikke gjenkjent.</translation>
diff --git a/chrome/app/resources/generated_resources_or.xtb b/chrome/app/resources/generated_resources_or.xtb index 854c617bc..e52634c 100644 --- a/chrome/app/resources/generated_resources_or.xtb +++ b/chrome/app/resources/generated_resources_or.xtb
@@ -1434,7 +1434,6 @@ <translation id="2602501489742255173">ଆରମ୍ଭ କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ</translation> <translation id="2603115962224169880">କମ୍ପ୍ୟୁଟର୍ ଖାଲି କରନ୍ତୁ</translation> <translation id="2603463522847370204">&ଇନ୍କଗ୍ନିଟୋ ୱିଣ୍ଡୋରେ ଖୋଲନ୍ତୁ</translation> -<translation id="2603656971249947488">ଟ୍ୟାବଷ୍ଟ୍ରିପ୍</translation> <translation id="2604255671529671813">ନେଟ୍ୱାର୍କ ସଂଯୋଗରେ ତ୍ରୁଟି</translation> <translation id="2606246518223360146">ଡାଟା ଲିଙ୍କ୍ କରନ୍ତୁ</translation> <translation id="2606454609872547359">ନା, ChromeVox ବିନା ଜାରି ରଖନ୍ତୁ</translation>
diff --git a/chrome/app/resources/generated_resources_pa.xtb b/chrome/app/resources/generated_resources_pa.xtb index 5e0ff52e..ac06c81 100644 --- a/chrome/app/resources/generated_resources_pa.xtb +++ b/chrome/app/resources/generated_resources_pa.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">ਸ਼ੁਰੂਆਤ ਕਰਨ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ</translation> <translation id="2603115962224169880">ਕੰਪਿਊਟਰ ਸਾਫ਼ ਕਰੋ</translation> <translation id="2603463522847370204">&ਗੁਮਨਾਮ window ਵਿੱਚ ਖੋਲ੍ਹੋ</translation> -<translation id="2603656971249947488">ਟੈਬ ਪੱਟੀ</translation> <translation id="2604255671529671813">ਨੈੱਟਵਰਕ ਕਨੈਕਸ਼ਨ ਗੜਬੜ</translation> <translation id="2606246518223360146">ਡਾਟਾ ਲਿੰਕ ਕਰੋ</translation> <translation id="2606454609872547359">ਨਹੀਂ, ChromeVox ਦੇ ਬਿਨਾਂ ਜਾਰੀ ਰੱਖੋ</translation>
diff --git a/chrome/app/resources/generated_resources_pl.xtb b/chrome/app/resources/generated_resources_pl.xtb index 025a887..5bc6fd8f 100644 --- a/chrome/app/resources/generated_resources_pl.xtb +++ b/chrome/app/resources/generated_resources_pl.xtb
@@ -418,7 +418,7 @@ <translation id="1436784010935106834">Usunięto</translation> <translation id="1437986450143295708">Opisz szczegółowo problem</translation> <translation id="144283815522798837">Wybrane elementy: <ph name="NUMBER_OF_ITEMS_SELECTED" /></translation> -<translation id="1442851588227551435">Ustawianie aktywnego biletu Kerberos</translation> +<translation id="1442851588227551435">Ustawianie aktywnego zgłoszenia Kerberos</translation> <translation id="1444628761356461360">Tym urządzeniem zarządza właściciel urządzenia: <ph name="OWNER_EMAIL" />.</translation> <translation id="144518587530125858">Nie można wczytać ścieżki „<ph name="IMAGE_PATH" />” dla motywu.</translation> <translation id="1451375123200651445">Strona internetowa, pojedynczy plik</translation> @@ -664,7 +664,7 @@ <translation id="1708338024780164500">(Nieaktywne)</translation> <translation id="1708713382908678956"><ph name="NAME_PH" /> (identyfikator: <ph name="ID_PH" />)</translation> <translation id="1709106626015023981"><ph name="WIDTH" /> x <ph name="HEIGHT" /> (natywna)</translation> -<translation id="1709217939274742847">Wybierz bilet, który ma być używany do uwierzytelniania. <ph name="LINK_BEGIN" />Więcej informacji<ph name="LINK_END" /></translation> +<translation id="1709217939274742847">Wybierz zgłoszenie, które ma być używane do uwierzytelniania. <ph name="LINK_BEGIN" />Więcej informacji<ph name="LINK_END" /></translation> <translation id="1709972045049031556">Nie udało się udostępnić</translation> <translation id="1711935594505774770">Spowoduje to usunięcie wszystkich danych i plików cookie zapisanych przez grupę <ph name="SITE_GROUP_NAME" />, należące do niej strony i jej zainstalowane aplikacje</translation> <translation id="1714644264617423774">Włącz ułatwienia dostępu, by uprościć obsługę urządzenia. <ph name="LINK_BEGIN" />Więcej informacji<ph name="LINK_END" /></translation> @@ -1246,6 +1246,7 @@ <translation id="2366260648632264559">Wyświetlaj tekst z systemu w tym języku</translation> <translation id="2367972762794486313">Pokaż aplikacje</translation> <translation id="2371076942591664043">Otwórz po &zakończeniu</translation> +<translation id="23721837607121582">Pobierz profil mobilny: sieć <ph name="NETWORK_INDEX" /> z <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Dopasuj do papieru</translation> <translation id="2375406435414127095">Połącz ze swoim telefonem</translation> <translation id="2377588536920405462">Aby wyłączyć lokalizację, wyłącz główne ustawienie Lokalizacja na swoim urządzeniu. W ustawieniach lokalizacji możesz też wyłączyć korzystanie z sieci Wi‑Fi, sieci komórkowych i czujników przy określaniu lokalizacji.</translation> @@ -1309,7 +1310,7 @@ <translation id="2453860139492968684">Zakończ</translation> <translation id="2454247629720664989">Słowo kluczowe</translation> <translation id="2454264884354864965">Kamera jest wyłączona</translation> -<translation id="245650153866130664">Aby automatycznie odświeżać bilet, zaznacz opcję „Zapamiętaj hasło”. Hasło będzie przechowywane wyłącznie na Twoim urządzeniu.</translation> +<translation id="245650153866130664">Aby automatycznie odświeżać zgłoszenie, zaznacz opcję „Zapamiętaj hasło”. Hasło będzie przechowywane wyłącznie na Twoim urządzeniu.</translation> <translation id="2457246892030921239"><ph name="APP_NAME" /> chce skopiować pliki z dysku <ph name="VOLUME_NAME" />.</translation> <translation id="2458379781610688953">Aktualizuj konto, <ph name="EMAIL" /></translation> <translation id="2458591546854598341">Token zarządzania urządzeniem jest nieprawidłowy.</translation> @@ -1367,7 +1368,7 @@ <translation id="2505324914378689427">{SCREEN_INDEX,plural, =1{Ekran #}few{Ekran #}many{Ekran #}other{Ekran #}}</translation> <translation id="2505402373176859469"><ph name="RECEIVED_AMOUNT" /> z <ph name="TOTAL_SIZE" /></translation> <translation id="250704661983564564">Rozmieszczanie wyświetlaczy</translation> -<translation id="2507253002925770350">Bilet został usunięty</translation> +<translation id="2507253002925770350">Zgłoszenie zostało usunięte</translation> <translation id="2507397597949272797"><ph name="NAME" /> – wstrzymano</translation> <translation id="2508428939232952663">Konto w Sklepie Google Play</translation> <translation id="2509495747794740764">Współczynnik skalowania musi wynosić od 10 do 200.</translation> @@ -1427,7 +1428,7 @@ <translation id="2580889980133367162">Zawsze zezwalaj <ph name="HOST" /> na pobieranie wielu plików</translation> <translation id="258095186877893873">Długie</translation> <translation id="2582253231918033891"><ph name="PRODUCT_NAME" /> <ph name="PRODUCT_VERSION" /> (platforma <ph name="PLATFORM_VERSION" />) <ph name="DEVICE_SERIAL_NUMBER" /></translation> -<translation id="2584109212074498965">Nie udało się pobrać biletu Kerberos. Spróbuj jeszcze raz lub skontaktuj się z administratorem urządzeń w Twojej organizacji. Kod błędu: <ph name="ERROR_CODE" />.</translation> +<translation id="2584109212074498965">Nie udało się pobrać zgłoszenia Kerberos. Spróbuj jeszcze raz lub skontaktuj się z administratorem urządzeń w Twojej organizacji. Kod błędu: <ph name="ERROR_CODE" />.</translation> <translation id="2585724835339714757">Ta karta udostępnia Twój ekran.</translation> <translation id="2586561813241011046">Nie udało się zainstalować <ph name="APP_NAME" />. Spróbuj jeszcze raz lub skontaktuj się z administratorem. Kod błędu: <ph name="ERROR_CODE" />.</translation> <translation id="2586657967955657006">Schowek</translation> @@ -1439,7 +1440,6 @@ <translation id="2602501489742255173">Przesuń palcem w górę, by rozpocząć</translation> <translation id="2603115962224169880">Oczyść komputer</translation> <translation id="2603463522847370204">Otwórz w oknie &incognito</translation> -<translation id="2603656971249947488">Pasek kart</translation> <translation id="2604255671529671813">Błąd połączenia z siecią</translation> <translation id="2606246518223360146">Połącz dane</translation> <translation id="2606454609872547359">Nie, kontynuuj bez ChromeVoksa</translation> @@ -2407,7 +2407,7 @@ <translation id="3700888195348409686">Wyświetlasz prezentację (<ph name="PAGE_ORIGIN" />)</translation> <translation id="3701167022068948696">Napraw teraz</translation> <translation id="3702500414347826004">Strony startowe zostały zmienione i zawierają <ph name="URL" />.</translation> -<translation id="3703699162703116302">Bilet odświeżony</translation> +<translation id="3703699162703116302">Zgłoszenie odświeżone</translation> <translation id="370415077757856453">JavaScript zablokowany</translation> <translation id="3704331259350077894">Zaprzestanie działania</translation> <translation id="3705722231355495246">-</translation> @@ -2676,6 +2676,7 @@ <translation id="3969092967100188979">Wł., w roamingu</translation> <translation id="3970114302595058915">Identyfikator</translation> <translation id="397105322502079400">Obliczanie...</translation> +<translation id="3971140002794351170">Pobierz profil mobilny: sieć <ph name="NETWORK_INDEX" /> z <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Odciski cyfrowe na tym kluczu bezpieczeństwa</translation> <translation id="3973660817924297510">Sprawdzam hasła (<ph name="CHECKED_PASSWORDS" /> z <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Nie udało się połączyć z serwerem obszaru</translation> @@ -3349,7 +3350,7 @@ <translation id="4814378367953456825">Wpisz nazwę tego odcisku</translation> <translation id="4816336393325437908">{COUNT,plural, =1{Usunięto 1 zakładkę}few{Usunięto {COUNT} zakładki}many{Usunięto {COUNT} zakładek}other{Usunięto {COUNT} zakładki}}</translation> <translation id="4819607494758673676">Powiadomienia od Asystenta Google</translation> -<translation id="4820236583224459650">Ustaw jako bilet aktywny</translation> +<translation id="4820236583224459650">Ustaw jako zgłoszenie aktywne</translation> <translation id="4821935166599369261">&Profilowanie włączone</translation> <translation id="4823484602432206655">Odczyt i zmiana ustawień użytkownika oraz urządzenia</translation> <translation id="4824037980212326045">Tworzenie i przywracanie kopii zapasowej Linuksa</translation> @@ -3568,7 +3569,7 @@ <translation id="5078638979202084724">Dodaj wszystkie karty do zakładek</translation> <translation id="5078796286268621944">Błędny kod PIN</translation> <translation id="5079950360618752063">Użyj sugerowanego hasła</translation> -<translation id="508059534790499809">Odświeżanie biletu Kerberos</translation> +<translation id="508059534790499809">Odświeżanie zgłoszenia Kerberos</translation> <translation id="5084230410268011727">Zezwalaj stronom internetowym na używanie czujników ruchu i światła</translation> <translation id="5084328598860513926">Proces obsługi administracyjnej został przerwany. Spróbuj jeszcze raz albo skontaktuj się z właścicielem lub administratorem urządzenia. Kod błędu: <ph name="ERROR_CODE" />.</translation> <translation id="5085162214018721575">Sprawdzanie dostępności aktualizacji</translation> @@ -3653,7 +3654,7 @@ <translation id="5178667623289523808">Znajdź poprzednie</translation> <translation id="5181140330217080051">Pobieranie</translation> <translation id="5184063094292164363">Konsola &JavaScript</translation> -<translation id="5184209580557088469">Istnieje już bilet przypisany do tej nazwy użytkownika</translation> +<translation id="5184209580557088469">Istnieje już zgłoszenie przypisane do tej nazwy użytkownika</translation> <translation id="5184662919967270437">Aktualizuję urządzenie</translation> <translation id="5185359571430619712">Sprawdź rozszerzenia</translation> <translation id="5185386675596372454">Najnowsza wersja rozszerzenia „<ph name="EXTENSION_NAME" />” została wyłączona, ponieważ wymaga więcej uprawnień.</translation> @@ -4468,7 +4469,7 @@ <translation id="6105994589138235234">Synchronizacja przeglądarki Chrome</translation> <translation id="6111972606040028426">Włącz Asystenta Google</translation> <translation id="6112294629795967147">Dotknij, by zmienić rozmiar</translation> -<translation id="6112727384379533756">Dodaj bilet</translation> +<translation id="6112727384379533756">Dodaj zgłoszenie</translation> <translation id="6112931163620622315">Sprawdź swój telefon</translation> <translation id="6113434369102685411">Ustaw domyślną wyszukiwarkę dla Chrome i Menu z aplikacjami na urządzeniu <ph name="DEVICE_TYPE" /></translation> <translation id="6113942107547980621">Aby używać Smart Lock, przełącz telefon na profil głównego użytkownika</translation> @@ -4996,7 +4997,7 @@ <translation id="6735304988756581115">Pokaż pliki cookie i inne dane witryn...</translation> <translation id="6736243959894955139">Adres</translation> <translation id="6736329909263487977"><ph name="ISSUED_BY" /> [<ph name="ISSUED_TO" />]</translation> -<translation id="6737663862851963468">Usuwanie biletu Kerberos</translation> +<translation id="6737663862851963468">Usuwanie zgłoszenia Kerberos</translation> <translation id="6739923123728562974">Pokaż skrót na pulpicie</translation> <translation id="6740234557573873150">Wstrzymano pobieranie <ph name="FILE_NAME" /></translation> <translation id="6741063444351041466"><ph name="BEGIN_LINK" />Twój administrator<ph name="END_LINK" /> wyłączył Bezpieczne przeglądanie</translation> @@ -6466,6 +6467,7 @@ <translation id="8398877366907290961">Kontynuuj mimo wszystko</translation> <translation id="8400146488506985033">Zarządzaj użytkownikami</translation> <translation id="8401432541486058167">Wpisz kod PIN powiązany z Twoją kartą elektroniczną.</translation> +<translation id="8403562727702715619">Ostatnie elementy z Dysku Google</translation> <translation id="8407199357649073301">Poziom rejestrowania:</translation> <translation id="8408068190360279472">Sieć <ph name="NETWORK_TYPE" />, łączę</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6592,7 +6594,7 @@ <translation id="8565650234829130278">Próbowano zmienić wersję aplikacji na starszą.</translation> <translation id="8569682776816196752">Nie znaleziono urządzeń docelowych</translation> <translation id="8571213806525832805">Ostatnie 4 tygodnie</translation> -<translation id="8571687764447439720">Dodawanie biletu Kerberos</translation> +<translation id="8571687764447439720">Dodawanie zgłoszenia Kerberos</translation> <translation id="8571814292654854151">Nadaj nazwę profilowi</translation> <translation id="8574990355410201600">Zawsze zezwalaj na odtwarzanie dźwięku na stronie <ph name="HOST" /></translation> <translation id="8575286410928791436">Aby zakończyć, przytrzymaj klawisz <ph name="KEY_EQUIVALENT" /></translation> @@ -6622,7 +6624,7 @@ <translation id="8601206103050338563">Uwierzytelnianie klienta WWW TLS</translation> <translation id="8602851771975208551">Inny program na Twoim komputerze dodał aplikację, która może zmienić działanie Chrome.</translation> <translation id="8605428685123651449">Pamięć SQLite</translation> -<translation id="8608618451198398104">Dodawanie biletu Kerberos</translation> +<translation id="8608618451198398104">Dodawanie zgłoszenia Kerberos</translation> <translation id="8609465669617005112">W górę</translation> <translation id="8610103157987623234">Nieprawidłowy format – spróbuj ponownie</translation> <translation id="8611682088849615761">Nadal zezwalaj tej stronie na pełną kontrolę nad urządzeniami MIDI</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030">Strona <ph name="ORIGIN" /> może edytować te pliki i foldery</translation> <translation id="8890170499370378450">Mogą się z tym wiązać opłaty</translation> <translation id="8890516388109605451">Źródła</translation> +<translation id="8890529496706615641">Nie udało się zmienić nazwy profilu. Spróbuj jeszcze raz lub skontaktuj się z operatorem, by uzyskać pomoc techniczną.</translation> <translation id="8892168913673237979">Wszystko gotowe.</translation> <translation id="8893801527741465188">Odinstalowano</translation> <translation id="8893928184421379330">Niestety, nie można rozpoznać urządzenia <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_pt-BR.xtb b/chrome/app/resources/generated_resources_pt-BR.xtb index 10c8630..08dbdf0 100644 --- a/chrome/app/resources/generated_resources_pt-BR.xtb +++ b/chrome/app/resources/generated_resources_pt-BR.xtb
@@ -1249,6 +1249,7 @@ <translation id="2366260648632264559">Mostrar texto do sistema nesse idioma</translation> <translation id="2367972762794486313">Mostrar aplicativos</translation> <translation id="2371076942591664043">Abrir quando estiver &concluído</translation> +<translation id="23721837607121582">Download do perfil móvel. Rede <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Ajustar à página</translation> <translation id="2375406435414127095">Conecte-se ao seu smartphone</translation> <translation id="2377588536920405462">Na configuração de localização principal do dispositivo é possível desativar esse recurso. Você também pode desativar o uso de Wi-Fi, redes móveis e sensores de local nessas configurações.</translation> @@ -1442,7 +1443,6 @@ <translation id="2602501489742255173">Deslize para cima para começar</translation> <translation id="2603115962224169880">Limpar o computador</translation> <translation id="2603463522847370204">Abrir em &janela anônima</translation> -<translation id="2603656971249947488">Barra de guias</translation> <translation id="2604255671529671813">Erro de conexão da rede</translation> <translation id="2606246518223360146">Vincular dados</translation> <translation id="2606454609872547359">Não, continuar sem o ChromeVox</translation> @@ -2680,6 +2680,7 @@ <translation id="3969092967100188979">Ativado, em roaming</translation> <translation id="3970114302595058915">Código</translation> <translation id="397105322502079400">Calculando...</translation> +<translation id="3971140002794351170">Download do perfil móvel. Rede <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Impressões digitais nesta chave de segurança</translation> <translation id="3973660817924297510">Verificando senhas (<ph name="CHECKED_PASSWORDS" /> de <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Falha ao entrar em contato com o servidor desse domínio</translation> @@ -6472,6 +6473,7 @@ <translation id="8398877366907290961">Continuar mesmo assim</translation> <translation id="8400146488506985033">Gerenciar pessoas</translation> <translation id="8401432541486058167">Insira o PIN associado ao seu cartão inteligente.</translation> +<translation id="8403562727702715619">Recentemente do Google Drive</translation> <translation id="8407199357649073301">Nível de registro:</translation> <translation id="8408068190360279472">Rede <ph name="NETWORK_TYPE" />, conectando</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6913,6 +6915,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> pode editar os arquivos e as pastas a seguir</translation> <translation id="8890170499370378450">Sujeito a cobrança para dados móveis</translation> <translation id="8890516388109605451">Fontes</translation> +<translation id="8890529496706615641">Não foi possível renomear o perfil. Tente novamente ou entre em contato com a operadora para receber suporte técnico.</translation> <translation id="8892168913673237979">Tudo pronto!</translation> <translation id="8893801527741465188">Desinstalação concluída</translation> <translation id="8893928184421379330">O dispositivo <ph name="DEVICE_LABEL" /> não foi reconhecido.</translation>
diff --git a/chrome/app/resources/generated_resources_pt-PT.xtb b/chrome/app/resources/generated_resources_pt-PT.xtb index 8ce9927..cd12ddb 100644 --- a/chrome/app/resources/generated_resources_pt-PT.xtb +++ b/chrome/app/resources/generated_resources_pt-PT.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Mostrar o texto do sistema neste idioma</translation> <translation id="2367972762794486313">Mostrar aplicações</translation> <translation id="2371076942591664043">Abrir quando estiver concluí&do</translation> +<translation id="23721837607121582">Transferir perfil móvel, rede <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Ajustar à folha de papel</translation> <translation id="2375406435414127095">Associar ao seu telemóvel</translation> <translation id="2377588536920405462">Pode desativar a Localização ao desativar a definição de Localização principal no seu dispositivo. Também pode desativar a utilização das redes Wi-Fi, das redes móveis e dos sensores para fins de localização nas definições de localização.</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">Deslize rapidamente para cima para começar.</translation> <translation id="2603115962224169880">Limpar o computador</translation> <translation id="2603463522847370204">Abrir na janela de &navegação anónima</translation> -<translation id="2603656971249947488">Faixa de separadores</translation> <translation id="2604255671529671813">Erro de ligação à rede</translation> <translation id="2606246518223360146">Associar dados</translation> <translation id="2606454609872547359">Não, continuar com o ChromeVox</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">Ativado, em roaming</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">A calcular...</translation> +<translation id="3971140002794351170">Transferir perfil móvel, rede <ph name="NETWORK_INDEX" /> de <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Impressões digitais nesta chave de segurança</translation> <translation id="3973660817924297510">A verificar palavras-passe (<ph name="CHECKED_PASSWORDS" /> de <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Falha ao contactar o servidor do domínio.</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">Prosseguir</translation> <translation id="8400146488506985033">Gerir pessoas</translation> <translation id="8401432541486058167">Indique o PIN que está associado ao seu cartão inteligente.</translation> +<translation id="8403562727702715619">Recentemente do Google Drive</translation> <translation id="8407199357649073301">Nível de registo:</translation> <translation id="8408068190360279472">Rede <ph name="NETWORK_TYPE" />, a ligar…</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> pode editar os seguintes ficheiros e pastas</translation> <translation id="8890170499370378450">Pode incorrer em custos de dados móveis</translation> <translation id="8890516388109605451">Fontes</translation> +<translation id="8890529496706615641">Não foi possível mudar o nome do perfil. Tente novamente ou contacte o operador para obter apoio técnico.</translation> <translation id="8892168913673237979">Está tudo pronto!</translation> <translation id="8893801527741465188">Desinstalação concluída</translation> <translation id="8893928184421379330">Lamentamos, não foi possível reconhecer o aparelho <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_ro.xtb b/chrome/app/resources/generated_resources_ro.xtb index 669e82c0..6128243 100644 --- a/chrome/app/resources/generated_resources_ro.xtb +++ b/chrome/app/resources/generated_resources_ro.xtb
@@ -1249,6 +1249,7 @@ <translation id="2366260648632264559">Afișează textul sistemului în această limbă</translation> <translation id="2367972762794486313">Afișați aplicații</translation> <translation id="2371076942591664043">Deschide când s-a &descărcat</translation> +<translation id="23721837607121582">Descarcă profilul mobil, Rețeaua <ph name="NETWORK_INDEX" /> din <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Potrivește în funcție de dimensiunile hârtiei</translation> <translation id="2375406435414127095">Conectează-te la telefon</translation> <translation id="2377588536920405462">Poți dezactiva locația oprind setarea principală privind locația de pe dispozitivul tău. Poți dezactiva și folosirea conexiunii Wi-Fi, a rețelelor mobile și a senzorilor pentru locație din setările privind locația.</translation> @@ -1442,7 +1443,6 @@ <translation id="2602501489742255173">Glisează în sus pentru a începe</translation> <translation id="2603115962224169880">Curăță computerul</translation> <translation id="2603463522847370204">Deschideți într-o &fereastră incognito</translation> -<translation id="2603656971249947488">Bară de file</translation> <translation id="2604255671529671813">Eroare de conectare la rețea</translation> <translation id="2606246518223360146">Conectează datele</translation> <translation id="2606454609872547359">Nu, continui fără ChromeVox</translation> @@ -2679,6 +2679,7 @@ <translation id="3969092967100188979">Activat, se utilizează roamingul</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Se calculează...</translation> +<translation id="3971140002794351170">Descarcă profilul mobil, Rețeaua <ph name="NETWORK_INDEX" /> din <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Amprentele digitale ale cheii de securitate</translation> <translation id="3973660817924297510">Se verifică parolele (<ph name="CHECKED_PASSWORDS" /> din <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Contactarea serverului pentru domeniu nu a reușit</translation> @@ -6469,6 +6470,7 @@ <translation id="8398877366907290961">Continuă oricum</translation> <translation id="8400146488506985033">Gestionează persoanele</translation> <translation id="8401432541486058167">Introdu codul PIN asociat cardului inteligent.</translation> +<translation id="8403562727702715619">Recent din Google Drive</translation> <translation id="8407199357649073301">Nivelul înregistrării:</translation> <translation id="8408068190360279472">Rețea <ph name="NETWORK_TYPE" />, se stabilește conexiunea</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6910,6 +6912,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> poate edita următoarele fișiere și dosare</translation> <translation id="8890170499370378450">Se pot aplica taxe pentru date mobile</translation> <translation id="8890516388109605451">Surse</translation> +<translation id="8890529496706615641">Profilul nu a putut fi redenumit. Încearcă din nou sau contactează operatorul pentru asistență tehnică.</translation> <translation id="8892168913673237979">Totul este pregătit!</translation> <translation id="8893801527741465188">Dezinstalarea este finalizată</translation> <translation id="8893928184421379330">Ne pare rău, dispozitivul <ph name="DEVICE_LABEL" /> nu a putut fi recunoscut.</translation>
diff --git a/chrome/app/resources/generated_resources_ru.xtb b/chrome/app/resources/generated_resources_ru.xtb index d66e5e4..ee51089 100644 --- a/chrome/app/resources/generated_resources_ru.xtb +++ b/chrome/app/resources/generated_resources_ru.xtb
@@ -1442,7 +1442,6 @@ <translation id="2602501489742255173">Чтобы начать, проведите по экрану вверх.</translation> <translation id="2603115962224169880">Удалить вредоносное ПО с компьютера</translation> <translation id="2603463522847370204">Открыть в режиме &инкогнито</translation> -<translation id="2603656971249947488">Панель вкладок</translation> <translation id="2604255671529671813">Ошибка подключения к сети</translation> <translation id="2606246518223360146">Связать данные</translation> <translation id="2606454609872547359">Нет, продолжить без ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_si.xtb b/chrome/app/resources/generated_resources_si.xtb index 6222754..c517fe9 100644 --- a/chrome/app/resources/generated_resources_si.xtb +++ b/chrome/app/resources/generated_resources_si.xtb
@@ -1246,6 +1246,7 @@ <translation id="2366260648632264559">පද්ධති පාඨය මෙම භාෂාවෙන් පෙන්වන්න</translation> <translation id="2367972762794486313">යෙදුම් පෙන්වන්න</translation> <translation id="2371076942591664043">නිම කළ විට විවෘත කරන්න (&d)</translation> +<translation id="23721837607121582">ජංගම පැතිකඩ බාගන්න, ජාල <ph name="NETWORK_COUNT" />කින් <ph name="NETWORK_INDEX" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">කඩදාසියට ගළපන්න</translation> <translation id="2375406435414127095">ඔබේ දුරකථනයට සම්බන්ධ කරන්න</translation> <translation id="2377588536920405462">ඔබට ඔබේ උපාංගයෙහි ප්රධාන සැකසීම අක්රිය කිරීමෙන් ස්ථානය අක්රිය කළ හැක. ඔබට Wi‑Fi, ජංගම ජාල සහ ස්ථාන සැකසීම් තුළ ස්ථානය සඳහා වන සංවේදක භාවිතය ද අක්රිය කළ හැක.</translation> @@ -1439,7 +1440,6 @@ <translation id="2602501489742255173">පටන් ගැනීමට උඩට ස්වයිප් කරන්න</translation> <translation id="2603115962224169880">පරිගණකය පිරිසිදු කරන්න</translation> <translation id="2603463522847370204">&අප්රකට කවුළුවක විවෘත කරන්න</translation> -<translation id="2603656971249947488">ටැබ් තීරුව</translation> <translation id="2604255671529671813">ජාල සබැඳුම් දෝෂය</translation> <translation id="2606246518223360146">සබැඳි දත්ත</translation> <translation id="2606454609872547359">එපා, ChromeVox රහිතව දිගටම කර ගෙන යන්න</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">සක්රීයයි, සැරිසරණය</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">ගණනය කරමින්...</translation> +<translation id="3971140002794351170">ජංගම පැතිකඩ බාගන්න, ජාල <ph name="NETWORK_COUNT" />කින් <ph name="NETWORK_INDEX" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">මෙම ආරක්ෂක යතුරේ ඇඟිලි සලකුණු</translation> <translation id="3973660817924297510">මුරපද පරීක්ෂා කෙරේ (<ph name="TOTAL_PASSWORDS" /> න් <ph name="CHECKED_PASSWORDS" />)…</translation> <translation id="3975565978598857337">ක්ෂේත්රය සඳහා සේවාදායකය සම්බන්ධ කිරීම අසාර්ථක විය</translation> @@ -6463,6 +6464,7 @@ <translation id="8398877366907290961">කෙසේ හෝ කරගෙන යන්න</translation> <translation id="8400146488506985033">පුද්ගලයින් කළමනාකරණය කරන්න</translation> <translation id="8401432541486058167">ඔබේ ස්මාර්ට් කාඩ්පත හා සම්බන්ධ රහස් අංකය ලබා දෙන්න.</translation> +<translation id="8403562727702715619">Google Drive වෙතින් මෑතදී</translation> <translation id="8407199357649073301">ලොග මට්ටම:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> ජාලය, සම්බන්ධ කෙරේ</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6904,6 +6906,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> හට පහත ගොනු සහ ෆෝල්ඩර සංස්කරණ කළ හැක</translation> <translation id="8890170499370378450">ජංගම දත්ත ගාස්තු ඇති විය හැකිය</translation> <translation id="8890516388109605451">මූලාශ්ර</translation> +<translation id="8890529496706615641">පැතිකඩ යළි නම් කළ නොහැකි විය. කරුණාකර නැවත උත්සාහ කරන්න, නැති නම් තාක්ෂණික සහාය සඳහා ඔබගේ වාහක සම්බන්ධ කර ගන්න.</translation> <translation id="8892168913673237979">මුළුමනින් සුදානම්ය!</translation> <translation id="8893801527741465188">අස්ථාපනය සම්පූර්ණයි</translation> <translation id="8893928184421379330">කනගාටුයි, උපාංග <ph name="DEVICE_LABEL" /> හඳුනාගත නොහැකි විය.</translation>
diff --git a/chrome/app/resources/generated_resources_sk.xtb b/chrome/app/resources/generated_resources_sk.xtb index ce3247917..f10ae3a 100644 --- a/chrome/app/resources/generated_resources_sk.xtb +++ b/chrome/app/resources/generated_resources_sk.xtb
@@ -1442,7 +1442,6 @@ <translation id="2602501489742255173">Začnite potiahnutím nahor</translation> <translation id="2603115962224169880">Vyčistiť počítač</translation> <translation id="2603463522847370204">Otvoriť v okne &inkognito</translation> -<translation id="2603656971249947488">Panel kariet</translation> <translation id="2604255671529671813">Chyba sieťového pripojenia</translation> <translation id="2606246518223360146">Prepojiť dáta</translation> <translation id="2606454609872547359">Nie, pokračovať bez čítačky ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_sl.xtb b/chrome/app/resources/generated_resources_sl.xtb index 458ec387..33a37a9 100644 --- a/chrome/app/resources/generated_resources_sl.xtb +++ b/chrome/app/resources/generated_resources_sl.xtb
@@ -1251,6 +1251,7 @@ <translation id="2366260648632264559">Prikaži sistemsko besedilo v tem jeziku</translation> <translation id="2367972762794486313">Pokaži aplikacije</translation> <translation id="2371076942591664043">Odpri, ko je &dokončano</translation> +<translation id="23721837607121582">Profil za prenos v mobilni napravi, omrežje <ph name="NETWORK_INDEX" /> od <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Prilagajanje velikosti papirja</translation> <translation id="2375406435414127095">Povežite se s telefonom</translation> <translation id="2377588536920405462">Zaznavanje lokacije lahko izklopite tako, da v napravi izklopite glavno lokacijsko nastavitev. V lokacijskih nastavitvah lahko izklopite tudi uporabo omrežij Wi-Fi, mobilnih omrežij in tipal za zaznavanje lokacije.</translation> @@ -1444,7 +1445,6 @@ <translation id="2602501489742255173">Povlecite navzgor, če želite začeti</translation> <translation id="2603115962224169880">Čiščenje računalnika</translation> <translation id="2603463522847370204">Odpri v &oknu brez beleženja zgodovine</translation> -<translation id="2603656971249947488">Trak z zavihki</translation> <translation id="2604255671529671813">Napaka v omrežni povezavi</translation> <translation id="2606246518223360146">Poveži podatke</translation> <translation id="2606454609872547359">Ne, nadaljuj brez ChromeVoxa</translation> @@ -2681,6 +2681,7 @@ <translation id="3969092967100188979">Vklopljeno, gostovanje</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Izračunavanje …</translation> +<translation id="3971140002794351170">Profil za prenos v mobilni napravi, omrežje <ph name="NETWORK_INDEX" /> od <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Prstni odtisi v tem varnostnem ključu</translation> <translation id="3973660817924297510">Preverjanje gesel (<ph name="CHECKED_PASSWORDS" /> od <ph name="TOTAL_PASSWORDS" />) …</translation> <translation id="3975565978598857337">Vzpostavljanje stika s strežnikom območja ni uspelo</translation> @@ -6327,7 +6328,7 @@ <translation id="8227119283605456246">Prilaganje datoteke</translation> <translation id="8230134520748321204">Želite shraniti geslo za <ph name="ORIGIN" />?</translation> <translation id="8234795456569844941">Pomagajte našim tehnikom odpraviti to težavo. Opišite, kaj se je zgodilo, tik preden se je prikazalo sporočilo o napaki profila:</translation> -<translation id="8235605354099176425">Omogočite <ph name="LINK1_BEGIN" />sinhronizacijo za Chrome<ph name="LINK1_END" />, če si želite ogledati nedavne Chromove zavihke.<ph name="LINK2_BEGIN" />Več o tem<ph name="LINK2_END" /></translation> +<translation id="8235605354099176425">Omogočite<ph name="LINK1_BEGIN" />sinhronizacijo za Chrome<ph name="LINK1_END" />, če si želite ogledati nedavne Chromove zavihke.<ph name="LINK2_BEGIN" />Več o tem<ph name="LINK2_END" /></translation> <translation id="8236917170563564587">Deli ta zavihek</translation> <translation id="8237647586961940482">Temno rožnata in rdeča</translation> <translation id="8239032431519548577">Včlanitev v poslovno okolje je dokončana</translation> @@ -6473,6 +6474,7 @@ <translation id="8398877366907290961">Vseeno nadaljuj</translation> <translation id="8400146488506985033">Upravljanje ljudi</translation> <translation id="8401432541486058167">Navedite kodo PIN, povezano s pametno kartico.</translation> +<translation id="8403562727702715619">Nedavno iz storitve Google Drive</translation> <translation id="8407199357649073301">Raven beleženja:</translation> <translation id="8408068190360279472">Omrežje <ph name="NETWORK_TYPE" />, vzpostavljanje povezave</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6916,6 +6918,7 @@ <translation id="8889651696183044030">Spletno mesto <ph name="ORIGIN" /> lahko ureja naslednje datoteke in mape</translation> <translation id="8890170499370378450">Morda boste morali plačati stroške prenosa podatkov v mobilnem omrežju.</translation> <translation id="8890516388109605451">Viri</translation> +<translation id="8890529496706615641">Profila ni bilo mogoče preimenovati. Poskusite znova ali se obrnite na operaterja za tehnično podporo.</translation> <translation id="8892168913673237979">Pripravljeni ste.</translation> <translation id="8893801527741465188">Odmestitev je dokončana</translation> <translation id="8893928184421379330">Naprave <ph name="DEVICE_LABEL" /> ni bilo mogoče prepoznati.</translation>
diff --git a/chrome/app/resources/generated_resources_sq.xtb b/chrome/app/resources/generated_resources_sq.xtb index 47defe84..033f28cd 100644 --- a/chrome/app/resources/generated_resources_sq.xtb +++ b/chrome/app/resources/generated_resources_sq.xtb
@@ -1438,7 +1438,6 @@ <translation id="2602501489742255173">Rrëshqit shpejt lart për të filluar</translation> <translation id="2603115962224169880">Pastro kompjuterin</translation> <translation id="2603463522847370204">Hape në &dritare "të fshehtë"</translation> -<translation id="2603656971249947488">Shiriti i skedave</translation> <translation id="2604255671529671813">Gabim në lidhjen e rrjetit</translation> <translation id="2606246518223360146">Lidh të dhënat</translation> <translation id="2606454609872547359">Jo, vazhdo me ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_sr-Latn.xtb b/chrome/app/resources/generated_resources_sr-Latn.xtb index 9be54b7..e891fc8d 100644 --- a/chrome/app/resources/generated_resources_sr-Latn.xtb +++ b/chrome/app/resources/generated_resources_sr-Latn.xtb
@@ -1247,6 +1247,7 @@ <translation id="2366260648632264559">Prikazuj sistemski tekst na ovom jeziku</translation> <translation id="2367972762794486313">Prikažite aplikacije</translation> <translation id="2371076942591664043">Otvori kad bude &dovršeno</translation> +<translation id="23721837607121582">Preuzmite profil za mobilne uređaje, <ph name="NETWORK_INDEX" />. mreža od <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Prilagodi papiru</translation> <translation id="2375406435414127095">Povežite se sa telefonom</translation> <translation id="2377588536920405462">Lokaciju možete da isključite ako isključite glavno podešavanje lokacije na uređaju. U podešavanjima lokacije možete da isključite korišćenje Wi‑Fi mreža i mobilnih mreža za lokaciju, kao i traženje Wi‑Fi mreža i Bluetooth uređaja.</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">Prevucite nagore da biste započeli</translation> <translation id="2603115962224169880">Očistite računar</translation> <translation id="2603463522847370204">Otvori u &prozoru bez arhiviranja</translation> -<translation id="2603656971249947488">Traka sa karticama</translation> <translation id="2604255671529671813">Greška mrežne veze</translation> <translation id="2606246518223360146">Poveži podatke</translation> <translation id="2606454609872547359">Ne, nastavi bez ChromeVox-a</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">Uključeno, roming</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">Izračunavanje...</translation> +<translation id="3971140002794351170">Preuzmite profil za mobilne uređaje, <ph name="NETWORK_INDEX" />. mreža od <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Otisci prstiju na ovom bezbednosnom ključu</translation> <translation id="3973660817924297510">Lozinke se proveravaju (<ph name="CHECKED_PASSWORDS" /> od <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Povezivanje sa serverom za domen nije uspelo</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">Ipak nastavi</translation> <translation id="8400146488506985033">Upravljaj ljudima</translation> <translation id="8401432541486058167">Navedite PIN koji je povezan sa pametnom karticom.</translation> +<translation id="8403562727702715619">Nedavno sa Google diska</translation> <translation id="8407199357649073301">Nivo evidencije:</translation> <translation id="8408068190360279472">Mreža <ph name="NETWORK_TYPE" />, povezuje se</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6910,6 +6912,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> može da menja datoteke i direktorijume u nastavku</translation> <translation id="8890170499370378450">Možda će doći do troškova za prenos podataka preko mobilnog operatera</translation> <translation id="8890516388109605451">Izvori</translation> +<translation id="8890529496706615641">Promena naziva profila nije uspela. Probajte ponovo ili zatražite tehničku podršku od mobilnog operatera.</translation> <translation id="8892168913673237979">Spremni ste!</translation> <translation id="8893801527741465188">Deinstaliranje je završeno</translation> <translation id="8893928184421379330">Žao nam je, nije bilo moguće prepoznati uređaj <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_sr.xtb b/chrome/app/resources/generated_resources_sr.xtb index fa23c0f..c50cad1 100644 --- a/chrome/app/resources/generated_resources_sr.xtb +++ b/chrome/app/resources/generated_resources_sr.xtb
@@ -1247,6 +1247,7 @@ <translation id="2366260648632264559">Приказуј системски текст на овом језику</translation> <translation id="2367972762794486313">Прикажите апликације</translation> <translation id="2371076942591664043">Отвори кад буде &довршено</translation> +<translation id="23721837607121582">Преузмите профил за мобилне уређаје, <ph name="NETWORK_INDEX" />. мрежа од <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Прилагоди папиру</translation> <translation id="2375406435414127095">Повежите се са телефоном</translation> <translation id="2377588536920405462">Локацију можете да искључите ако искључите главно подешавање локације на уређају. У подешавањима локације можете да искључите коришћење Wi‑Fi мрежа и мобилних мрежа за локацију, као и тражење Wi‑Fi мрежа и Bluetooth уређаја.</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">Превуците нагоре да бисте започели</translation> <translation id="2603115962224169880">Очистите рачунар</translation> <translation id="2603463522847370204">Отвори у &прозору без архивирања</translation> -<translation id="2603656971249947488">Трака са картицама</translation> <translation id="2604255671529671813">Грешка мрежне везе</translation> <translation id="2606246518223360146">Повежи податке</translation> <translation id="2606454609872547359">Не, настави без ChromeVox-а</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">Укључено, роминг</translation> <translation id="3970114302595058915">ИД</translation> <translation id="397105322502079400">Израчунавање...</translation> +<translation id="3971140002794351170">Преузмите профил за мобилне уређаје, <ph name="NETWORK_INDEX" />. мрежа од <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Отисци прстију на овом безбедносном кључу</translation> <translation id="3973660817924297510">Лозинке се проверавају (<ph name="CHECKED_PASSWORDS" /> од <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Повезивање са сервером за домен није успело</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">Ипак настави</translation> <translation id="8400146488506985033">Управљај људима</translation> <translation id="8401432541486058167">Наведите PIN који је повезан са паметном картицом.</translation> +<translation id="8403562727702715619">Недавно са Google диска</translation> <translation id="8407199357649073301">Ниво евиденције:</translation> <translation id="8408068190360279472">Мрежа <ph name="NETWORK_TYPE" />, повезује се</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6910,6 +6912,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> може да мења датотеке и директоријуме у наставку</translation> <translation id="8890170499370378450">Можда ће доћи до трошкова за пренос података преко мобилног оператера</translation> <translation id="8890516388109605451">Извори</translation> +<translation id="8890529496706615641">Промена назива профила није успела. Пробајте поново или затражите техничку подршку од мобилног оператера.</translation> <translation id="8892168913673237979">Спремни сте!</translation> <translation id="8893801527741465188">Деинсталирање је завршено</translation> <translation id="8893928184421379330">Жао нам је, није било могуће препознати уређај <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_sv.xtb b/chrome/app/resources/generated_resources_sv.xtb index 620e05c..dc585d2 100644 --- a/chrome/app/resources/generated_resources_sv.xtb +++ b/chrome/app/resources/generated_resources_sv.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">Visa systemtext på det här språket</translation> <translation id="2367972762794486313">Visa appar</translation> <translation id="2371076942591664043">Öppna när nedladdning är &klar</translation> +<translation id="23721837607121582">Ladda ned mobilprofil, Nätverk <ph name="NETWORK_INDEX" /> av <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Anpassa till papperets storlek</translation> <translation id="2375406435414127095">Anslut till mobilen</translation> <translation id="2377588536920405462">Du kan inaktivera plats genom att inaktivera huvudinställningen på enheten. Du kan även inaktivera användningen av Wi-Fi, mobilnätverk och sensorer för plats i platsinställningarna.</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">Kom igång genom att svepa uppåt</translation> <translation id="2603115962224169880">Rensa upp på datorn</translation> <translation id="2603463522847370204">Öppna i &inkognitofönster</translation> -<translation id="2603656971249947488">Flikhuvud</translation> <translation id="2604255671529671813">Fel vid nätverksanslutning</translation> <translation id="2606246518223360146">Länka Data</translation> <translation id="2606454609872547359">Nej, fortsätt utan ChromeVox</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">På, med roaming</translation> <translation id="3970114302595058915">Id</translation> <translation id="397105322502079400">Beräknar ...</translation> +<translation id="3971140002794351170">Ladda ned mobilprofil, Nätverk <ph name="NETWORK_INDEX" /> av <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Fingeravtryck på den här säkerhetsnyckeln</translation> <translation id="3973660817924297510">Kontrollerar lösenord (<ph name="CHECKED_PASSWORDS" /> av <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Det gick inte att kontakta servern för sfären</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">Fortsätt ändå</translation> <translation id="8400146488506985033">Hantera personer</translation> <translation id="8401432541486058167">Ange den pinkod som är kopplad till ditt smartkort.</translation> +<translation id="8403562727702715619">Nyligen från Google Drive</translation> <translation id="8407199357649073301">Loggnivå:</translation> <translation id="8408068190360279472">Nätverkstyp: <ph name="NETWORK_TYPE" />, ansluter</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> har redigeringsbehörighet till följande filer och mappar</translation> <translation id="8890170499370378450">Avgifter för mobildata kan tillkomma</translation> <translation id="8890516388109605451">Källor</translation> +<translation id="8890529496706615641">Det gick inte att byta namn på profilen. Försök igen eller kontakta operatören om du behöver teknisk support.</translation> <translation id="8892168913673237979">Klart!</translation> <translation id="8893801527741465188">Avinstallationen är slutförd</translation> <translation id="8893928184421379330">Det gick tyvärr inte att identifiera enheten <ph name="DEVICE_LABEL" />.</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb index deca1437..9ff0bea 100644 --- a/chrome/app/resources/generated_resources_sw.xtb +++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -1245,6 +1245,7 @@ <translation id="2366260648632264559">Onyesha maandishi ya mfumo katika lugha hii</translation> <translation id="2367972762794486313">Onyesha programu</translation> <translation id="2371076942591664043">Fungua baada ya &kumaliza</translation> +<translation id="23721837607121582">Pakua maelezo ya eSIM ya vifaa vya mkononi, Mtandao <ph name="NETWORK_INDEX" /> kati ya <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Fanya itoshe kwenye karatasi</translation> <translation id="2375406435414127095">Unganisha kwenye simu yako</translation> <translation id="2377588536920405462">Unaweza kuzima huduma ya Mahali kwa kuzima mipangilio ya msingi ya Mahali kwenye kifaa chako. Unaweza pia kuzima utumiaji wa Wi-Fi, mitandao ya simu na vitambuzi vya mahali katika mipangilio ya mahali.</translation> @@ -1438,7 +1439,6 @@ <translation id="2602501489742255173">Telezesha kidole kuelekea juu ili uanze</translation> <translation id="2603115962224169880">Futa programu hatari kwenye kompyuta yako</translation> <translation id="2603463522847370204">Fungua kwenye dirisha &chini kwa chini</translation> -<translation id="2603656971249947488">Ukanda wa vichupo</translation> <translation id="2604255671529671813">Hitilafu ya muunganisho wa mtandao</translation> <translation id="2606246518223360146">Unganisha Data</translation> <translation id="2606454609872547359">Hapana, endelea bila ChromeVox</translation> @@ -2675,6 +2675,7 @@ <translation id="3969092967100188979">Imewashwa, inatumia mitandao ya ng'ambo</translation> <translation id="3970114302595058915">Kitambulisho</translation> <translation id="397105322502079400">Inakokotoa...</translation> +<translation id="3971140002794351170">Pakua maelezo ya eSIM ya vifaa vya mkononi, Mtandao <ph name="NETWORK_INDEX" /> kati ya <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Alama za vidole zilizo kwenye ufunguo huu wa usalama</translation> <translation id="3973660817924297510">Inakagua manenosiri (<ph name="CHECKED_PASSWORDS" /> kati ya <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Imeshindwa kuwasiliana na sehemu kwenye seva</translation> @@ -6465,6 +6466,7 @@ <translation id="8398877366907290961">Endelea licha ya hayo</translation> <translation id="8400146488506985033">Simamia watu</translation> <translation id="8401432541486058167">Weka PIN inayohusiana na kadi yako mahiri.</translation> +<translation id="8403562727702715619">Hivi majuzi kutoka Hifadhi ya Google</translation> <translation id="8407199357649073301">Kiwango cha Kumbukumbu:</translation> <translation id="8408068190360279472">Mtandao wa <ph name="NETWORK_TYPE" />, inaunganisha</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6905,6 +6907,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> inaweza kubadilisha faili na folda zifuatazo</translation> <translation id="8890170499370378450">Huenda ukatozwa gharama za data ya mtandao wa simu</translation> <translation id="8890516388109605451">Vyanzo</translation> +<translation id="8890529496706615641">Imeshindwa kubadilisha jina la maelezo ya eSIM. Tafadhali jaribu tena au wasiliana na mtoa huduma wako kwa usaidizi wa kiufundi.</translation> <translation id="8892168913673237979">Zote zimesanidiwa!</translation> <translation id="8893801527741465188">Imemaliza kuondoa</translation> <translation id="8893928184421379330">Samahani, kifaa <ph name="DEVICE_LABEL" /> kisingeweza kutambuliwa.</translation>
diff --git a/chrome/app/resources/generated_resources_ta.xtb b/chrome/app/resources/generated_resources_ta.xtb index a51e335..6ec21135 100644 --- a/chrome/app/resources/generated_resources_ta.xtb +++ b/chrome/app/resources/generated_resources_ta.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">தொடங்குவதற்கு, மேல்நோக்கி ஸ்வைப் செய்யவும்</translation> <translation id="2603115962224169880">கம்ப்யூட்டரை மீட்டமைக்கவும்</translation> <translation id="2603463522847370204">&மறைநிலை சாளரத்தில் திற</translation> -<translation id="2603656971249947488">தாவல் பட்டை</translation> <translation id="2604255671529671813">நெட்வொர்க் இணைப்புப் பிழை</translation> <translation id="2606246518223360146">தரவை இணை</translation> <translation id="2606454609872547359">வேண்டாம். ChromeVox இல்லாமல் தொடர்க</translation> @@ -3977,7 +3976,7 @@ <translation id="554517701842997186">ரெண்டரர்</translation> <translation id="5545335608717746497">{NUM_TABS,plural, =1{குழுவில் தாவலைச் சேர்}other{குழுவில் தாவல்களைச் சேர்}}</translation> <translation id="5546865291508181392">கண்டுபிடி</translation> -<translation id="5548075230008247516">அனைத்தும் தேர்வுநீக்கப்பட்டன, தேர்வுப் பயன்முறையிலி</translation> +<translation id="5548075230008247516">அனைத்தும் தேர்வுநீக்கப்பட்டன, தேர்வுப் பயன்முறையிலிருந்து வெளியேறிவிட்டீர்கள்</translation> <translation id="5548159762883465903">{NUM_OTHER_TABS,plural, =0{"<ph name="TAB_TITLE" />"}=1{"<ph name="TAB_TITLE" />" மேலும் ஒரு தாவல்}other{"<ph name="TAB_TITLE" />" மேலும் # தாவல்கள்}}</translation> <translation id="5548606607480005320">பாதுகாப்புச் சரிபார்ப்பு</translation> <translation id="554903022911579950">Kerberos</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb index 24064c40..ac583c1 100644 --- a/chrome/app/resources/generated_resources_te.xtb +++ b/chrome/app/resources/generated_resources_te.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">ప్రారంభించడానికి పైకి స్వైప్ చేయండి</translation> <translation id="2603115962224169880">కంప్యూటర్ నుండి హానికరమైనవి తీసివేయండి</translation> <translation id="2603463522847370204">&ఒక అజ్ఞాత విండోలో తెరువు</translation> -<translation id="2603656971249947488">ట్యాబ్ల బార్</translation> <translation id="2604255671529671813">నెట్వర్క్ కనెక్షన్ ఎర్రర్</translation> <translation id="2606246518223360146">డేటాను లింక్ చేయి</translation> <translation id="2606454609872547359">వద్దు, ChromeVox లేకుండా కొనసాగించు</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb index 97bf288..93c0fea 100644 --- a/chrome/app/resources/generated_resources_th.xtb +++ b/chrome/app/resources/generated_resources_th.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">แสดงข้อความของระบบเป็นภาษานี้</translation> <translation id="2367972762794486313">แสดงแอป</translation> <translation id="2371076942591664043">เปิดเมื่อเ&สร็จ</translation> +<translation id="23721837607121582">ดาวน์โหลดโปรไฟล์อุปกรณ์เคลื่อนที่, เครือข่าย <ph name="NETWORK_INDEX" /> จาก <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">พอดีกับหน้ากระดาษ</translation> <translation id="2375406435414127095">เชื่อมต่อโทรศัพท์ของคุณ</translation> <translation id="2377588536920405462">คุณปิดตำแหน่งได้โดยปิดการตั้งค่าตำแหน่งหลักในอุปกรณ์ และยังปิดการใช้ Wi‑Fi, เครือข่ายมือถือ และเซ็นเซอร์สำหรับการบอกตำแหน่งในการตั้งค่าตำแหน่งได้ด้วย</translation> @@ -1441,7 +1442,6 @@ <translation id="2602501489742255173">เลื่อนขึ้นเพื่อเริ่มต้นใช้งาน</translation> <translation id="2603115962224169880">ล้างข้อมูลในคอมพิวเตอร์</translation> <translation id="2603463522847370204">เปิดใน&หน้าต่างที่ไม่ระบุตัวตน</translation> -<translation id="2603656971249947488">แนวแท็บ</translation> <translation id="2604255671529671813">ข้อผิดพลาดในการเชื่อมต่อเครือข่าย</translation> <translation id="2606246518223360146">ลิงก์ข้อมูล</translation> <translation id="2606454609872547359">ไม่ ดำเนินการต่อโดยไม่ใช้ ChromeVox</translation> @@ -2678,6 +2678,7 @@ <translation id="3969092967100188979">เปิด โรมมิ่ง</translation> <translation id="3970114302595058915">รหัส</translation> <translation id="397105322502079400">กำลังคำนวณ...</translation> +<translation id="3971140002794351170">ดาวน์โหลดโปรไฟล์อุปกรณ์เคลื่อนที่, เครือข่าย <ph name="NETWORK_INDEX" /> จาก <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">ลายนิ้วมือที่ลงทะเบียนในคีย์ความปลอดภัยนี้</translation> <translation id="3973660817924297510">กำลังตรวจสอบรหัสผ่าน (<ph name="CHECKED_PASSWORDS" /> จาก <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">ติดต่อเซิร์ฟเวอร์ของขอบเขตไม่สำเร็จ</translation> @@ -6468,6 +6469,7 @@ <translation id="8398877366907290961">ดำเนินการต่อ</translation> <translation id="8400146488506985033">จัดการบุคคล</translation> <translation id="8401432541486058167">ใส่ PIN ที่เชื่อมโยงกับสมาร์ทการ์ดของคุณ</translation> +<translation id="8403562727702715619">ล่าสุดจาก Google ไดรฟ์</translation> <translation id="8407199357649073301">ระดับบันทึก:</translation> <translation id="8408068190360279472">เครือข่าย <ph name="NETWORK_TYPE" /> กำลังเชื่อมต่อ</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> แก้ไขไฟล์และโฟลเดอร์ต่อไปนี้ได้</translation> <translation id="8890170499370378450">อาจมีค่าบริการอินเทอร์เน็ตมือถือ</translation> <translation id="8890516388109605451">แหล่งที่มา</translation> +<translation id="8890529496706615641">เปลี่ยนชื่อโปรไฟล์ไม่ได้ โปรดลองอีกครั้งหรือติดต่อผู้ให้บริการเพื่อรับการสนับสนุนด้านเทคนิค</translation> <translation id="8892168913673237979">เรียบร้อยแล้ว!</translation> <translation id="8893801527741465188">ถอนการติดตั้งเรียบร้อยแล้ว</translation> <translation id="8893928184421379330">ขออภัย ระบบไม่รู้จักอุปกรณ์ <ph name="DEVICE_LABEL" /></translation>
diff --git a/chrome/app/resources/generated_resources_tr.xtb b/chrome/app/resources/generated_resources_tr.xtb index eb2eb71..11df6d4 100644 --- a/chrome/app/resources/generated_resources_tr.xtb +++ b/chrome/app/resources/generated_resources_tr.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">Başlamak için yukarı doğru kaydırın</translation> <translation id="2603115962224169880">Bilgisayarı temizleme</translation> <translation id="2603463522847370204">&Gizli pencerede aç</translation> -<translation id="2603656971249947488">Sekme şeridi</translation> <translation id="2604255671529671813">Ağ bağlantısı hatası</translation> <translation id="2606246518223360146">Verileri Bağla</translation> <translation id="2606454609872547359">Hayır, ChromeVox olmadan devam et</translation>
diff --git a/chrome/app/resources/generated_resources_uk.xtb b/chrome/app/resources/generated_resources_uk.xtb index cfb69d7c..98315bbf8 100644 --- a/chrome/app/resources/generated_resources_uk.xtb +++ b/chrome/app/resources/generated_resources_uk.xtb
@@ -1251,6 +1251,7 @@ <translation id="2366260648632264559">Зробити мовою системи</translation> <translation id="2367972762794486313">Показати програми</translation> <translation id="2371076942591664043">Відкрити коли &виконано</translation> +<translation id="23721837607121582">Завантажити мобільний профіль, мережа <ph name="NETWORK_INDEX" /> з <ph name="NETWORK_COUNT" />, "<ph name="NETWORK_NAME" />"</translation> <translation id="2373666622366160481">За розміром паперу</translation> <translation id="2375406435414127095">Підключіться до телефона</translation> <translation id="2377588536920405462">Ви можете дезактивувати визначення місцезнаходження, вимкнувши на пристрої функцію "Доступ до моїх геоданих". У налаштуваннях цієї функції також можна вимкнути визначення місцезнаходження за допомогою Wi-Fi, мобільних мереж і датчиків.</translation> @@ -1444,7 +1445,6 @@ <translation id="2602501489742255173">Гортайте вгору, щоб почати</translation> <translation id="2603115962224169880">Очистити комп’ютер</translation> <translation id="2603463522847370204">Відкрити в &анонімному вікні</translation> -<translation id="2603656971249947488">Панель вкладок</translation> <translation id="2604255671529671813">Помилка з’єднання з мережею</translation> <translation id="2606246518223360146">Зв’язати профіль</translation> <translation id="2606454609872547359">Ні, продовжити без ChromeVox</translation> @@ -2681,6 +2681,7 @@ <translation id="3969092967100188979">Увімкнено, є роумінг</translation> <translation id="3970114302595058915">ІДЕНТИФІКАТОР</translation> <translation id="397105322502079400">Обчислення...</translation> +<translation id="3971140002794351170">Завантажити мобільний профіль, мережа <ph name="NETWORK_INDEX" /> з <ph name="NETWORK_COUNT" />, "<ph name="NETWORK_NAME" />", <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Цифрові відбитки на цьому ключі безпеки</translation> <translation id="3973660817924297510">Перевірка паролів (<ph name="CHECKED_PASSWORDS" /> з <ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Не вдалося зв'язатися із сервером для цієї області</translation> @@ -6471,6 +6472,7 @@ <translation id="8398877366907290961">Продовжити</translation> <translation id="8400146488506985033">Керувати користувачами</translation> <translation id="8401432541486058167">Укажіть PIN-код, зв'язаний із вашою розумною карткою.</translation> +<translation id="8403562727702715619">Нещодавні файли з Google Диска</translation> <translation id="8407199357649073301">Рівень журналу:</translation> <translation id="8408068190360279472">Мережа <ph name="NETWORK_TYPE" />: підключення</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6914,6 +6916,7 @@ <translation id="8889651696183044030">Сайт <ph name="ORIGIN" /> може змінювати вказані нижче файли й папки</translation> <translation id="8890170499370378450">Може стягуватися плата за мобільний трафік</translation> <translation id="8890516388109605451">Джерела</translation> +<translation id="8890529496706615641">Не вдалося перейменувати профіль. Повторіть спробу або зв'яжіться з оператором, щоб отримати технічну підтримку.</translation> <translation id="8892168913673237979">Готово!</translation> <translation id="8893801527741465188">Видалення завершено</translation> <translation id="8893928184421379330">На жаль, пристрій <ph name="DEVICE_LABEL" /> неможливо розпізнати.</translation>
diff --git a/chrome/app/resources/generated_resources_ur.xtb b/chrome/app/resources/generated_resources_ur.xtb index 159218a..b68e325 100644 --- a/chrome/app/resources/generated_resources_ur.xtb +++ b/chrome/app/resources/generated_resources_ur.xtb
@@ -1442,7 +1442,6 @@ <translation id="2602501489742255173">شروع کرنے کیلئے اوپر سوائپ کریں</translation> <translation id="2603115962224169880">کمپیوٹر صاف کریں</translation> <translation id="2603463522847370204">&پوشیدگی ونڈو میں کھولیں</translation> -<translation id="2603656971249947488">ٹیب اسٹرپ</translation> <translation id="2604255671529671813">نیٹ ورک کنکشن میں خرابی</translation> <translation id="2606246518223360146">ڈیٹا کو لنک کریں</translation> <translation id="2606454609872547359">نہیں، بغیر ChromeVox کے جاری رکھیں</translation>
diff --git a/chrome/app/resources/generated_resources_uz.xtb b/chrome/app/resources/generated_resources_uz.xtb index fe35f265..4db54a3 100644 --- a/chrome/app/resources/generated_resources_uz.xtb +++ b/chrome/app/resources/generated_resources_uz.xtb
@@ -1439,7 +1439,6 @@ <translation id="2602501489742255173">Boshlash uchun tepaga suring</translation> <translation id="2603115962224169880">Kompyuterni tozalash vositasi</translation> <translation id="2603463522847370204">&Inkognito rejimida ochish</translation> -<translation id="2603656971249947488">Darchalar paneli</translation> <translation id="2604255671529671813">Tarmoqqa ulanishda xato</translation> <translation id="2606246518223360146">Hisoblarni ulash</translation> <translation id="2606454609872547359">Yoʻq, nofaol ChromeVox bilan davom ettirish</translation> @@ -1618,7 +1617,7 @@ <translation id="2791529110887957050">Linux tizimini olib tashlash</translation> <translation id="2791952154587244007">Xatolik yuz berdi. Kiosk ilovalari ushbu qurilmada avtomatik ishga tushmaydi.</translation> <translation id="2792290659606763004">Android ilovalar olib tashlansinmi?</translation> -<translation id="2792465461386711506">Telefoningizdagi oxirgi Chrome varaqarini ochish uchun Chrome Sync funksiyasini yoqing</translation> +<translation id="2792465461386711506">Telefoningizdagi oxirgi Chrome varaqlarini ochish uchun Chrome Sync funksiyasini yoqing</translation> <translation id="2794233252405721443">Sayt bloklangan</translation> <translation id="2795716239552913152">Saytlar odatda mahalliy yangiliklar yoki atrofdagi doʻkonlar kabi tegishli funksiya yoki axborotlar uchun joylashuvingizdan foydalanadi</translation> <translation id="2796424461616874739">“<ph name="DEVICE_NAME" />” qurilmasiga ulanish vaqtida haqiqiylik tekshiruvidan javob kelmadi.</translation> @@ -3249,7 +3248,7 @@ <translation id="4671265665487288124">Saytlar birdaniga bir nechta fayl yuklab olishga ruxsat soʻrashi mumkin (tavsiya etiladi)</translation> <translation id="46733273239502219">Oʻrnatilgan ilovalardagi oflayn maʼlumotlar ham tozalab tashlanadi.</translation> <translation id="4673442866648850031">Stilus o‘chiqligida stilus vositalari ko‘rsatilsin</translation> -<translation id="4676595058027112862">Phone Hub, batafsil</translation> +<translation id="4676595058027112862">Phone Hub, Batafsil</translation> <translation id="4677772697204437347">GPU xotirasi</translation> <translation id="467823995058589466">Kamera yoqilmagan</translation> <translation id="4680105648806843642">Bu sahifada ovoz bloklangan</translation>
diff --git a/chrome/app/resources/generated_resources_vi.xtb b/chrome/app/resources/generated_resources_vi.xtb index c26301e..dbb68ab0 100644 --- a/chrome/app/resources/generated_resources_vi.xtb +++ b/chrome/app/resources/generated_resources_vi.xtb
@@ -1441,7 +1441,6 @@ <translation id="2602501489742255173">Vuốt lên để bắt đầu</translation> <translation id="2603115962224169880">Dọn dẹp máy tính</translation> <translation id="2603463522847370204">Mở trong cửa sổ ẩ&n danh</translation> -<translation id="2603656971249947488">Dải thẻ</translation> <translation id="2604255671529671813">Lỗi kết nối mạng</translation> <translation id="2606246518223360146">Liên kết dữ liệu</translation> <translation id="2606454609872547359">Không, tiếp tục mà không dùng ChromeVox</translation>
diff --git a/chrome/app/resources/generated_resources_zh-CN.xtb b/chrome/app/resources/generated_resources_zh-CN.xtb index 70738a7..2b3437d 100644 --- a/chrome/app/resources/generated_resources_zh-CN.xtb +++ b/chrome/app/resources/generated_resources_zh-CN.xtb
@@ -1437,7 +1437,6 @@ <translation id="2602501489742255173">向上滑动即可开始使用</translation> <translation id="2603115962224169880">清理计算机</translation> <translation id="2603463522847370204">在隐身窗口中打开(&I)</translation> -<translation id="2603656971249947488">标签栏</translation> <translation id="2604255671529671813">网络连接错误</translation> <translation id="2606246518223360146">关联数据</translation> <translation id="2606454609872547359">否,不启用 ChromeVox 并继续操作</translation>
diff --git a/chrome/app/resources/generated_resources_zh-HK.xtb b/chrome/app/resources/generated_resources_zh-HK.xtb index c1da9fef..811946f 100644 --- a/chrome/app/resources/generated_resources_zh-HK.xtb +++ b/chrome/app/resources/generated_resources_zh-HK.xtb
@@ -1248,6 +1248,7 @@ <translation id="2366260648632264559">以此語言顯示系統文字</translation> <translation id="2367972762794486313">顯示應用程式</translation> <translation id="2371076942591664043">完成後開啟(&D)</translation> +<translation id="23721837607121582">下載流動裝置設定檔,<ph name="NETWORK_COUNT" /> 個網絡之中嘅第 <ph name="NETWORK_INDEX" /> 個,<ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">依紙張大小自動調整</translation> <translation id="2375406435414127095">連線至您的手機</translation> <translation id="2377588536920405462">關閉裝置的主要位置資訊設定,即可關閉定位服務。您也可以在位置資訊設定中關閉使用 Wi‑Fi、流動網絡和感應器確定位置的功能。</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">向上滑動即可開始</translation> <translation id="2603115962224169880">清理電腦</translation> <translation id="2603463522847370204">在無痕式視窗中開啟(&I)</translation> -<translation id="2603656971249947488">分頁列</translation> <translation id="2604255671529671813">網絡連線錯誤</translation> <translation id="2606246518223360146">連結資料</translation> <translation id="2606454609872547359">否,不啟動 ChromeVox 並繼續操作</translation> @@ -2677,6 +2677,7 @@ <translation id="3969092967100188979">已啟用並正在使用</translation> <translation id="3970114302595058915">ID</translation> <translation id="397105322502079400">計算中…</translation> +<translation id="3971140002794351170">下載流動裝置設定檔,<ph name="NETWORK_COUNT" /> 個網絡之中嘅第 <ph name="NETWORK_INDEX" /> 個,<ph name="NETWORK_NAME" />,<ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">此安全金鑰上的指紋</translation> <translation id="3973660817924297510">正在檢查密碼 (已檢查 <ph name="CHECKED_PASSWORDS" /> 個,共 <ph name="TOTAL_PASSWORDS" /> 個)…</translation> <translation id="3975565978598857337">無法連線至指定的伺服器領域</translation> @@ -6466,6 +6467,7 @@ <translation id="8398877366907290961">仍要繼續</translation> <translation id="8400146488506985033">管理使用者</translation> <translation id="8401432541486058167">請輸入與智能資訊卡相關聯的 PIN。</translation> +<translation id="8403562727702715619">最近使用過的 Google 雲端硬碟檔案</translation> <translation id="8407199357649073301">記錄等級:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" />網絡,正在連線</translation> <translation id="8410775397654368139">Google Play</translation> @@ -6905,6 +6907,7 @@ <translation id="8889651696183044030"><ph name="ORIGIN" /> 可編輯以下檔案和資料夾</translation> <translation id="8890170499370378450">您可能需要支付流動數據費用</translation> <translation id="8890516388109605451">來源</translation> +<translation id="8890529496706615641">無法重新命名設定檔。請再試一次,或聯絡您的流動網絡供應商以獲取技術支援。</translation> <translation id="8892168913673237979">大功告成!</translation> <translation id="8893801527741465188">解除安裝完成</translation> <translation id="8893928184421379330">很抱歉,系統無法識別 <ph name="DEVICE_LABEL" /> 裝置。</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb index ea5c570..1ddb5e2 100644 --- a/chrome/app/resources/generated_resources_zh-TW.xtb +++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -1440,7 +1440,6 @@ <translation id="2602501489742255173">向上滑動即可開始使用</translation> <translation id="2603115962224169880">清理電腦</translation> <translation id="2603463522847370204">在無痕式視窗中開啟(&I)</translation> -<translation id="2603656971249947488">分頁列</translation> <translation id="2604255671529671813">網路連線錯誤</translation> <translation id="2606246518223360146">連結資料</translation> <translation id="2606454609872547359">否,不啟動 ChromeVox 並繼續操作</translation>
diff --git a/chrome/app/resources/generated_resources_zu.xtb b/chrome/app/resources/generated_resources_zu.xtb index 0f89b743..b5b2af4 100644 --- a/chrome/app/resources/generated_resources_zu.xtb +++ b/chrome/app/resources/generated_resources_zu.xtb
@@ -1247,6 +1247,7 @@ <translation id="2366260648632264559">Bonisa umbhalo wesistimu ngalolu limi</translation> <translation id="2367972762794486313">Bonisa izinhlelo zokusebenza</translation> <translation id="2371076942591664043">Vula uma kuqediwe</translation> +<translation id="23721837607121582">Landa iphroayela yeselula, Inethiwekhi engu-<ph name="NETWORK_INDEX" /> kwezingu-<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" /></translation> <translation id="2373666622366160481">Linganisa nephepha</translation> <translation id="2375406435414127095">Xhuma kufoni yakho</translation> <translation id="2377588536920405462">Ungavala indawo ngokuvala isilungiselelo esiyinhloko Sendawo kudivayisi yakho. Ungavala nokusetshenziswa kwe-Wi-Fi, amanethiwekhi eselula, nezinzwa zendawo kuzilungiselelo zendawo.</translation> @@ -1440,7 +1441,6 @@ <translation id="2602501489742255173">Swayiphela phezulu ukuze uqalise</translation> <translation id="2603115962224169880">Hlanza ikhompuyutha</translation> <translation id="2603463522847370204">Vula &Iwindi le-incognito</translation> -<translation id="2603656971249947488">Umugqa wamathebhu</translation> <translation id="2604255671529671813">Iphutha lokuxhuma inethiwekhi</translation> <translation id="2606246518223360146">Xhumanisa idatha</translation> <translation id="2606454609872547359">Cha, qhubeka ngaphandle kwe-ChromeVox</translation> @@ -2676,6 +2676,7 @@ <translation id="3969092967100188979">Ivuliwe, iyazulazula</translation> <translation id="3970114302595058915">I-ID</translation> <translation id="397105322502079400">Iyabala...</translation> +<translation id="3971140002794351170">Landa iphrofayela yeselula, Inethiwekhi engu-<ph name="NETWORK_INDEX" /> kwezingu-<ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation> <translation id="3971764089670057203">Izigxivizo zeminwe kulo khiye wokuqinisekisa ubunikazi</translation> <translation id="3973660817924297510">Kuhlola Amaphasiwedi (<ph name="CHECKED_PASSWORDS" /> kwangu-<ph name="TOTAL_PASSWORDS" />)…</translation> <translation id="3975565978598857337">Ukuxhumana neseva kwe-realm kuhlulekile</translation> @@ -6467,6 +6468,7 @@ <translation id="8398877366907290961">Qhubeka noma kunjalo</translation> <translation id="8400146488506985033">Phatha abantu</translation> <translation id="8401432541486058167">Nikeza iphinikhodi ehambisana ne-smart card sakho.</translation> +<translation id="8403562727702715619">Okwakamuva okuvela ku-Google Drayivu</translation> <translation id="8407199357649073301">Ilogu Yefayela:</translation> <translation id="8408068190360279472"><ph name="NETWORK_TYPE" /> inethiwekhi, ukuxhuma</translation> <translation id="8410775397654368139">I-Google Play</translation> @@ -6908,6 +6910,7 @@ <translation id="8889651696183044030">I-<ph name="ORIGIN" /> ingahlela amafayela alandelayo namafolda</translation> <translation id="8890170499370378450">Ingase ibe nezindleko zedatha yeselula</translation> <translation id="8890516388109605451">Imithombo</translation> +<translation id="8890529496706615641">Iphrofayela alikwazanga ukuqanjwa kabusha. Sicela uzame futhi noma uxhumane nenkampani yakho yenethiwekhi mayelana nosekelo lobuchwepheshe.</translation> <translation id="8892168913673237979">Konke kusethiwe?</translation> <translation id="8893801527741465188">Ukukhipha kuphelile</translation> <translation id="8893928184421379330">Uxolo, idivayisi ye-<ph name="DEVICE_LABEL" /> ayikwazanga ukubonwa.</translation>
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp index e6e2905..9e712f0 100644 --- a/chrome/app/settings_chromium_strings.grdp +++ b/chrome/app/settings_chromium_strings.grdp
@@ -161,7 +161,7 @@ </message> <if expr="chromeos"> <message name="IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2" desc="Description of the Account Manager Settings page. Shown just below the title of the page."> - If you have multiple Google Accounts, you can add them to your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Your accounts will be available in Chromium browser and Play Store, as well as services like Gmail, Drive, and YouTube.<ph name="LINK_BEGIN"><a></ph>Learn more<ph name="LINK_END"></a></ph> + If you have multiple Google Accounts, you can add them to your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Your accounts will be available in Chromium browser and Play Store, as well as services like Gmail, Drive, and YouTube. <ph name="LINK_BEGIN"><a></ph>Learn more<ph name="LINK_END"></a></ph> </message> </if>
diff --git a/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2.png.sha1 b/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2.png.sha1 index e3b4d5f0..0f86a72 100644 --- a/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2.png.sha1 +++ b/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2.png.sha1
@@ -1 +1 @@ -3b2082d4819066cf841fcc41e4ec7d76bc4f46d6 \ No newline at end of file +bf5eed4d46931a0b4e41246a5d5f1d46ad664243 \ No newline at end of file
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index 2659db4..550f3171 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -162,7 +162,7 @@ </message> <if expr="chromeos"> <message name="IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2" desc="Description of the Account Manager Settings page. Shown just below the title of the page."> - If you have multiple Google Accounts, you can add them to your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Your accounts will be available in Chrome browser and Play Store, as well as services like Gmail, Drive, and YouTube.<ph name="LINK_BEGIN"><a></ph>Learn more<ph name="LINK_END"></a></ph> + If you have multiple Google Accounts, you can add them to your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Your accounts will be available in Chrome browser and Play Store, as well as services like Gmail, Drive, and YouTube. <ph name="LINK_BEGIN"><a></ph>Learn more<ph name="LINK_END"></a></ph> </message> </if>
diff --git a/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2.png.sha1 b/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2.png.sha1 index 74f210c..18622ac 100644 --- a/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2.png.sha1 +++ b/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_ACCOUNT_MANAGER_DESCRIPTION_V2.png.sha1
@@ -1 +1 @@ -e264e7b899afe17312b148a7ba570aa0b38ddd6d \ No newline at end of file +0b2b93dfc34cdeb24878b5ce40e3c198fc179709 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index a0deade..8787a6d 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -4298,8 +4298,6 @@ "download/notification/download_notification_manager.h", "enterprise/reporting/android_app_info_generator.cc", "enterprise/reporting/android_app_info_generator.h", - "feedback/feedback_util_chromeos.cc", - "feedback/feedback_util_chromeos.h", "google/google_brand_chromeos.cc", "google/google_brand_chromeos.h", "google/google_brand_code_map_chromeos.cc",
diff --git a/chrome/browser/accessibility/caption_controller.cc b/chrome/browser/accessibility/caption_controller.cc index f8eb277b..0e960af 100644 --- a/chrome/browser/accessibility/caption_controller.cc +++ b/chrome/browser/accessibility/caption_controller.cc
@@ -101,18 +101,39 @@ enabled_ = enabled; if (enabled_) { - // Register SODA component and download speech model. - g_browser_process->local_state()->SetTime(prefs::kSodaScheduledDeletionTime, - base::Time()); - speech::SODAInstaller::GetInstance()->InstallSODA(profile_->GetPrefs()); - speech::SODAInstaller::GetInstance()->InstallLanguage(profile_->GetPrefs()); + // Only create the UI when SODA is downloaded--otherwise, wait for the SODA + // download to complete before creating the UI. This checks whether SODA is + // registered, which implies that it has already downloaded previously. It's + // possible for someone to enable Live Caption while SODA is downloading, in + // which case the UI will construct prematurely. + // TODO(crbug.com/1160272): Check whether SODA has downloaded without + // blocking the process. + if (speech::SODAInstaller::GetInstance()->IsSODARegistered()) { + UpdateUIEnabled(); + } else { + // Register SODA component and download speech model. + g_browser_process->local_state()->SetTime( + prefs::kSodaScheduledDeletionTime, base::Time()); + // Observe the SODA installation and call UpdateUIEnabled when it + // completes. + speech::SODAInstaller::GetInstance()->AddObserver(this); + speech::SODAInstaller::GetInstance()->InstallSODA(profile_->GetPrefs()); + speech::SODAInstaller::GetInstance()->InstallLanguage( + profile_->GetPrefs()); + } } else { // Schedule SODA to be deleted in 30 days if the feature is not enabled // before then. g_browser_process->local_state()->SetTime( prefs::kSodaScheduledDeletionTime, base::Time::Now() + base::TimeDelta::FromDays(kSodaCleanUpDelayInDays)); + UpdateUIEnabled(); } +} + +void CaptionController::OnSODAInstalled() { + DCHECK(enabled_); + speech::SODAInstaller::GetInstance()->RemoveObserver(this); UpdateUIEnabled(); } @@ -128,6 +149,9 @@ void CaptionController::UpdateUIEnabled() { if (enabled_) { + if (is_ui_constructed_) + return; + is_ui_constructed_ = true; // Create captions UI in each browser view. for (Browser* browser : *BrowserList::GetInstance()) { OnBrowserAdded(browser); @@ -138,12 +162,16 @@ // Observe caption style prefs. for (const char* const pref_name : kCaptionStylePrefsToObserve) { + DCHECK(!pref_change_registrar_->IsObserved(pref_name)); pref_change_registrar_->Add( pref_name, base::BindRepeating(&CaptionController::UpdateCaptionStyle, base::Unretained(this))); } UpdateCaptionStyle(); } else { + if (!is_ui_constructed_) + return; + is_ui_constructed_ = false; // Destroy caption bubble controllers. caption_bubble_controllers_.clear(); @@ -152,6 +180,7 @@ // Remove prefs to observe. for (const char* const pref_name : kCaptionStylePrefsToObserve) { + DCHECK(pref_change_registrar_->IsObserved(pref_name)); pref_change_registrar_->Remove(pref_name); } }
diff --git a/chrome/browser/accessibility/caption_controller.h b/chrome/browser/accessibility/caption_controller.h index 8feb5924..f3b0e36 100644 --- a/chrome/browser/accessibility/caption_controller.h +++ b/chrome/browser/accessibility/caption_controller.h
@@ -8,6 +8,7 @@ #include <memory> #include <unordered_map> +#include "chrome/browser/accessibility/soda_installer.h" #include "chrome/browser/ui/browser_list_observer.h" #include "chrome/common/caption.mojom.h" #include "components/keyed_service/core/keyed_service.h" @@ -38,7 +39,9 @@ // per profile and it lasts for the duration of the session. The caption // controller owns the live caption UI, which are caption bubble controllers. // -class CaptionController : public BrowserListObserver, public KeyedService { +class CaptionController : public BrowserListObserver, + public KeyedService, + public speech::SODAInstaller::Observer { public: explicit CaptionController(Profile* profile); ~CaptionController() override; @@ -71,6 +74,11 @@ void OnBrowserAdded(Browser* browser) override; void OnBrowserRemoved(Browser* browser) override; + // SODAInstaller::Observer: + void OnSODAInstalled() override; + void OnSODAProgress(int progress) override {} + void OnSODAError() override {} + void OnLiveCaptionEnabledChanged(); void OnLiveCaptionLanguageChanged(); bool IsLiveCaptionEnabled(); @@ -91,7 +99,13 @@ base::Optional<ui::CaptionStyle> caption_style_; + // Whether Live Caption is enabled. bool enabled_ = false; + + // Whether the UI has been created. The UI is created asynchronously from the + // feature being enabled--we wait for SODA to download first. This flag + // ensures that the UI is not constructed or deconstructed twice. + bool is_ui_constructed_ = false; }; } // namespace captions
diff --git a/chrome/browser/accessibility/caption_controller_browsertest.cc b/chrome/browser/accessibility/caption_controller_browsertest.cc index c97a964..7767862 100644 --- a/chrome/browser/accessibility/caption_controller_browsertest.cc +++ b/chrome/browser/accessibility/caption_controller_browsertest.cc
@@ -54,13 +54,22 @@ // InProcessBrowserTest overrides: void SetUp() override { - scoped_feature_list_.InitAndEnableFeature(media::kLiveCaption); + scoped_feature_list_.InitWithFeatures( + {media::kLiveCaption, media::kUseSodaForLiveCaption}, {}); InProcessBrowserTest::SetUp(); } void SetLiveCaptionEnabled(bool enabled) { browser()->profile()->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, enabled); + if (enabled) + speech::SODAInstaller::GetInstance()->NotifySODAInstalledForTesting(); + } + + void SetLiveCaptionEnabledForProfile(bool enabled, Profile* profile) { + profile->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, enabled); + if (enabled) + speech::SODAInstaller::GetInstance()->NotifySODAInstalledForTesting(); } CaptionController* GetController() { @@ -98,7 +107,7 @@ Profile* profile) { return GetControllerForProfile(profile)->DispatchTranscription( browser->tab_strip_model()->GetActiveWebContents(), - chrome::mojom::TranscriptionResult::New(text, true /* is_final */)); + chrome::mojom::TranscriptionResult::New(text, false /* is_final */)); } void OnError() { OnErrorOnBrowser(browser()); } @@ -200,6 +209,17 @@ EXPECT_EQ(0, NumBubbleControllers()); } +IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnSODAInstalled) { + EXPECT_EQ(0, NumBubbleControllers()); + browser()->profile()->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, + true); + EXPECT_EQ(0, NumBubbleControllers()); + + // The UI is only created after SODA is installed. + speech::SODAInstaller::GetInstance()->NotifySODAInstalledForTesting(); + EXPECT_EQ(1, NumBubbleControllers()); +} + IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnBrowserAdded) { EXPECT_EQ(0, NumBubbleControllers()); @@ -492,7 +512,7 @@ EXPECT_EQ(0, NumBubbleControllersForProfile(profile2)); // Enable live caption on profile2. - profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true); + SetLiveCaptionEnabledForProfile(true, profile2); EXPECT_EQ(1, NumBubbleControllersForProfile(profile1)); EXPECT_EQ(1, NumBubbleControllersForProfile(profile2)); @@ -502,7 +522,7 @@ EXPECT_EQ(1, NumBubbleControllersForProfile(profile2)); // Disable live caption on profile2. - profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, false); + SetLiveCaptionEnabledForProfile(false, profile2); EXPECT_EQ(0, NumBubbleControllersForProfile(profile1)); EXPECT_EQ(0, NumBubbleControllersForProfile(profile2)); } @@ -513,7 +533,7 @@ // Enable live caption on both profiles. SetLiveCaptionEnabled(true); - profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true); + SetLiveCaptionEnabledForProfile(true, profile2); // Add a new browser to profile1. Test that there are caption bubble // controllers on all of the existing browsers. @@ -557,7 +577,7 @@ // Enable live caption on both profiles. SetLiveCaptionEnabled(true); - profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true); + SetLiveCaptionEnabledForProfile(true, profile2); EXPECT_EQ(1, NumBubbleControllersForProfile(profile1)); EXPECT_EQ(1, NumBubbleControllersForProfile(profile2)); @@ -596,7 +616,7 @@ // Enable live caption on both profiles. SetLiveCaptionEnabled(true); - profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true); + SetLiveCaptionEnabledForProfile(true, profile2); // Dispatch transcription routes the transcription to the right browser on the // right profile. @@ -656,7 +676,7 @@ // Enable live caption on both profiles. SetLiveCaptionEnabled(true); - profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true); + SetLiveCaptionEnabledForProfile(true, profile2); // OnError routes to the right browser on the right profile. OnErrorOnBrowserForProfile(browser1, profile1); @@ -689,6 +709,6 @@ #endif } -#endif // !defined (OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) } // namespace captions
diff --git a/chrome/browser/accessibility/soda_installer.cc b/chrome/browser/accessibility/soda_installer.cc index a8f073392..ef9c8dc 100644 --- a/chrome/browser/accessibility/soda_installer.cc +++ b/chrome/browser/accessibility/soda_installer.cc
@@ -33,4 +33,9 @@ observer.OnSODAProgress(percent); } +void SODAInstaller::NotifySODAInstalledForTesting() { + if (!IsSODARegistered()) + NotifyOnSODAInstalled(); +} + } // namespace speech
diff --git a/chrome/browser/accessibility/soda_installer.h b/chrome/browser/accessibility/soda_installer.h index 44b7fdc7..0b60ae9 100644 --- a/chrome/browser/accessibility/soda_installer.h +++ b/chrome/browser/accessibility/soda_installer.h
@@ -51,12 +51,18 @@ // should be. virtual void InstallLanguage(PrefService* prefs) = 0; + // Returns whether or not SODA is already registered on this device. + virtual bool IsSODARegistered() = 0; + // Adds an observer to the observer list. void AddObserver(Observer* observer); // Removes an observer from the observer list. void RemoveObserver(Observer* observer); + void NotifySODAInstalledForTesting(); + + protected: // Notifies the observers that the SODA installation has completed. void NotifyOnSODAInstalled(); @@ -67,7 +73,6 @@ // Progress is the download percentage out of 100. void NotifyOnSODAProgress(int progress); - protected: base::ObserverList<Observer> observers_; };
diff --git a/chrome/browser/accessibility/soda_installer_impl.cc b/chrome/browser/accessibility/soda_installer_impl.cc index 232c0d1..47e57f9 100644 --- a/chrome/browser/accessibility/soda_installer_impl.cc +++ b/chrome/browser/accessibility/soda_installer_impl.cc
@@ -6,9 +6,11 @@ #include <map> #include <string> +#include <vector> #include "base/bind.h" #include "base/check_op.h" +#include "base/feature_list.h" #include "base/no_destructor.h" #include "base/numerics/ranges.h" #include "chrome/browser/browser_process.h" @@ -18,6 +20,7 @@ #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "components/update_client/crx_update_item.h" +#include "media/base/media_switches.h" namespace { @@ -83,6 +86,26 @@ } } +bool SODAInstallerImpl::IsSODARegistered() { + if (!base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) + return true; + std::vector<std::string> component_ids = + g_browser_process->component_updater()->GetComponentIDs(); + bool has_soda = false; + bool has_language_pack = false; + for (std::string id : component_ids) { + if (id == component_updater::SODAComponentInstallerPolicy::GetExtensionId()) + has_soda = true; + if (id == component_updater::SodaEnUsComponentInstallerPolicy:: + GetExtensionId() || + id == component_updater::SodaJaJpComponentInstallerPolicy:: + GetExtensionId()) { + has_language_pack = true; + } + } + return has_soda && has_language_pack; +} + void SODAInstallerImpl::OnEvent(Events event, const std::string& id) { if (id != component_updater::SODAComponentInstallerPolicy::GetExtensionId() && id != component_updater::SodaEnUsComponentInstallerPolicy::
diff --git a/chrome/browser/accessibility/soda_installer_impl.h b/chrome/browser/accessibility/soda_installer_impl.h index 2174f07..d10277f 100644 --- a/chrome/browser/accessibility/soda_installer_impl.h +++ b/chrome/browser/accessibility/soda_installer_impl.h
@@ -33,6 +33,7 @@ // SODAInstaller: void InstallSODA(PrefService* prefs) override; void InstallLanguage(PrefService* prefs) override; + bool IsSODARegistered() override; private: // component_updater::ServiceObserver:
diff --git a/chrome/browser/background/background_contents.cc b/chrome/browser/background/background_contents.cc index bc27b3d..11ef1a4 100644 --- a/chrome/browser/background/background_contents.cc +++ b/chrome/browser/background/background_contents.cc
@@ -48,10 +48,6 @@ opener ? opener->GetRoutingID() : MSG_ROUTING_NONE; create_params.is_never_visible = true; - // This isn't semantically sensible, but it is what the old code implicitly - // did. - create_params.renderer_initiated_creation = !is_new_browsing_instance; - if (session_storage_namespace) { content::SessionStorageNamespaceMap session_storage_namespace_map; session_storage_namespace_map.insert(
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index faf1e2bf2..8120949 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -757,7 +757,7 @@ RegisterWebUIControllerInterfaceBinder< chromeos::network_health::mojom::NetworkHealthService, - chromeos::NetworkUI>(map); + chromeos::NetworkUI, chromeos::ConnectivityDiagnosticsUI>(map); RegisterWebUIControllerInterfaceBinder< chromeos::network_diagnostics::mojom::NetworkDiagnosticsRoutines,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 67665ca1..618153f 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -880,7 +880,6 @@ "borealis/borealis_app_launcher.h", "borealis/borealis_context.cc", "borealis/borealis_context.h", - "borealis/borealis_context_manager.cc", "borealis/borealis_context_manager.h", "borealis/borealis_context_manager_impl.cc", "borealis/borealis_context_manager_impl.h",
diff --git a/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.cc b/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.cc index 47cb0853..9a93b718 100644 --- a/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.cc +++ b/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.cc
@@ -45,6 +45,11 @@ // TODO(crbug.com/1111002): Install SODA language. } +bool SODAInstallerImplChromeOS::IsSODARegistered() { + // TODO(crbug.com/1111002): Return whether SODA is registered. + return !base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption); +} + void SODAInstallerImplChromeOS::OnSODAInstalled( const chromeos::DlcserviceClient::InstallResult& install_result) { if (install_result.error == dlcservice::kErrorNone) {
diff --git a/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.h b/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.h index c3892767..7c851a5 100644 --- a/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.h +++ b/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.h
@@ -25,6 +25,7 @@ // SODAInstaller: void InstallSODA(PrefService* prefs) override; void InstallLanguage(PrefService* prefs) override; + bool IsSODARegistered() override; private: // This function is the InstallCallback for DlcserviceClient::Install().
diff --git a/chrome/browser/chromeos/borealis/borealis_app_launcher.cc b/chrome/browser/chromeos/borealis/borealis_app_launcher.cc index dd800b8..7999fc2 100644 --- a/chrome/browser/chromeos/borealis/borealis_app_launcher.cc +++ b/chrome/browser/chromeos/borealis/borealis_app_launcher.cc
@@ -89,14 +89,15 @@ base::BindOnce( [](std::string app_id, BorealisAppLauncher::OnLaunchedCallback callback, - BorealisContextManager::Result result) { - if (!result.Ok()) { - LOG(ERROR) << "Failed to launch " << app_id << ": " - << result.FailureReason(); + BorealisContextManager::ContextOrFailure result) { + if (!result) { + LOG(ERROR) << "Failed to launch " << app_id << "(code " + << result.Error().error() + << "): " << result.Error().description(); std::move(callback).Run(LaunchResult::kError); return; } - BorealisAppLauncher::Launch(result.Success(), std::move(app_id), + BorealisAppLauncher::Launch(*result.Value(), std::move(app_id), std::move(callback)); }, std::move(app_id), std::move(callback)));
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager.cc b/chrome/browser/chromeos/borealis/borealis_context_manager.cc deleted file mode 100644 index b655055..0000000 --- a/chrome/browser/chromeos/borealis/borealis_context_manager.cc +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/borealis/borealis_context_manager.h" - -namespace borealis { - -BorealisContextManager::Result::Result(const BorealisContext* ctx) - : result_(BorealisStartupResult::kSuccess), failure_reason_(), ctx_(ctx) { - DCHECK(ctx); -} - -BorealisContextManager::Result::Result(BorealisStartupResult result, - std::string failure_reason) - : result_(result), - failure_reason_(std::move(failure_reason)), - ctx_(nullptr) { - DCHECK(result != BorealisStartupResult::kSuccess); -} - -BorealisContextManager::Result::~Result() = default; - -bool BorealisContextManager::Result::Ok() const { - return result_ == BorealisStartupResult::kSuccess; -} - -BorealisStartupResult BorealisContextManager::Result::Failure() const { - DCHECK(!Ok()); - return result_; -} - -const std::string& BorealisContextManager::Result::FailureReason() const { - DCHECK(!Ok()); - return failure_reason_; -} - -const BorealisContext& BorealisContextManager::Result::Success() const { - DCHECK(Ok()); - return *ctx_; -} - -} // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager.h b/chrome/browser/chromeos/borealis/borealis_context_manager.h index fbaadb225..5461b6b1 100644 --- a/chrome/browser/chromeos/borealis/borealis_context_manager.h +++ b/chrome/browser/chromeos/borealis/borealis_context_manager.h
@@ -9,6 +9,8 @@ #include "base/callback.h" #include "chrome/browser/chromeos/borealis/borealis_metrics.h" +#include "chrome/browser/chromeos/borealis/infra/described.h" +#include "chrome/browser/chromeos/borealis/infra/expected.h" #include "components/keyed_service/core/keyed_service.h" namespace borealis { @@ -19,38 +21,12 @@ public: // An attempt to launch borealis. If the launch succeeds, holds a reference to // the context created for that launch, otherwise holds an error. - class Result { - public: - // Used to indicate that the result was a success. - explicit Result(const BorealisContext* ctx); - - // Used to indicate the the result was a failure. - Result(BorealisStartupResult result, std::string failure_reason); - - ~Result(); - - // Returns true if the result was successful. - bool Ok() const; - - // In the event of a failed launch, returns the result code for that error. - BorealisStartupResult Failure() const; - - // In the event of a failed launch, returns the message provided. - const std::string& FailureReason() const; - - // In the event of a successful launch, returns a handle to the context - // created for that launch. - const BorealisContext& Success() const; - - private: - BorealisStartupResult result_; - std::string failure_reason_; - const BorealisContext* ctx_; - }; + using ContextOrFailure = + Expected<BorealisContext*, Described<BorealisStartupResult>>; // Convenience definition for the callback provided by clients wanting to // launch borealis. - using ResultCallback = base::OnceCallback<void(Result)>; + using ResultCallback = base::OnceCallback<void(ContextOrFailure)>; BorealisContextManager() = default; BorealisContextManager(const BorealisContextManager&) = delete;
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc index 27e45b4..65dbbe7 100644 --- a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc +++ b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc
@@ -87,7 +87,8 @@ void BorealisContextManagerImpl::StartBorealis(ResultCallback callback) { if (context_) { - std::move(callback).Run(BorealisContextManager::Result(context_.get())); + std::move(callback).Run( + BorealisContextManager::ContextOrFailure(context_.get())); return; } AddCallback(std::move(callback)); @@ -156,20 +157,22 @@ DCHECK(in_progress_startup_); in_progress_startup_.reset(); - BorealisContextManager::Result completion_result_for_clients = + BorealisContextManager::ContextOrFailure completion_result_for_clients = completion_result.Handle( base::BindOnce( [](std::unique_ptr<BorealisContext>* out_context, std::unique_ptr<BorealisContext>& success) { std::swap(*out_context, success); - return BorealisContextManager::Result(out_context->get()); + return BorealisContextManager::ContextOrFailure( + out_context->get()); }, &context_), base::BindOnce([](Described<BorealisStartupResult>& failure) { LOG(ERROR) << "Startup failed: failure=" << failure.error() << " message=" << failure.description(); - return BorealisContextManager::Result(failure.error(), - failure.description()); + return BorealisContextManager::ContextOrFailure::Unexpected( + Described<BorealisStartupResult>{failure.error(), + failure.description()}); })); while (!callback_queue_.empty()) {
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h index 06c3cfb0a..e7f4a98 100644 --- a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h +++ b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h
@@ -79,7 +79,7 @@ // Returns the result of the startup (i.e. the context if it succeeds, or an // error if it doesn't). - BorealisContextManager::Result GetResult( + BorealisContextManager::ContextOrFailure GetResult( const Startup::Result& completion_result); Profile* const profile_;
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc b/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc index 0949d80f..bf70935d 100644 --- a/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc +++ b/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc
@@ -26,13 +26,14 @@ namespace { MATCHER(IsSuccessResult, "") { - return arg.Ok() && arg.Success().vm_name() == "test_vm_name"; + return arg && arg.Value()->vm_name() == "test_vm_name"; } MATCHER(IsFailureResult, "") { - return !arg.Ok() && - arg.Failure() == borealis::BorealisStartupResult::kStartVmFailed && - arg.FailureReason() == "Something went wrong!"; + return !arg && + arg.Error().error() == + borealis::BorealisStartupResult::kStartVmFailed && + arg.Error().description() == "Something went wrong!"; } class MockTask : public BorealisTask { @@ -83,7 +84,7 @@ return base::BindOnce(&ResultCallbackHandler::Callback, base::Unretained(this)); } - MOCK_METHOD(void, Callback, (BorealisContextManager::Result), ()); + MOCK_METHOD(void, Callback, (BorealisContextManager::ContextOrFailure), ()); }; class BorealisContextManagerTest : public testing::Test { @@ -131,11 +132,12 @@ BorealisContextManagerImplForTesting context_manager( profile_.get(), /*tasks=*/0, /*success=*/true); EXPECT_CALL(callback_expectation, Callback(testing::_)) - .WillOnce(testing::Invoke([](BorealisContextManager::Result result) { - EXPECT_TRUE(result.Ok()); - // Even with no tasks, the context will give the VM a name. - EXPECT_EQ(result.Success().vm_name(), "borealis"); - })); + .WillOnce( + testing::Invoke([](BorealisContextManager::ContextOrFailure result) { + EXPECT_TRUE(result); + // Even with no tasks, the context will give the VM a name. + EXPECT_EQ(result.Value()->vm_name(), "borealis"); + })); context_manager.StartBorealis(callback_expectation.GetCallback()); task_environment_.RunUntilIdle(); } @@ -252,10 +254,12 @@ TEST_F(BorealisContextManagerTest, ShutDownCancelsRequestsAndTerminatesVm) { testing::StrictMock<ResultCallbackHandler> callback_expectation; EXPECT_CALL(callback_expectation, Callback(testing::_)) - .WillOnce(testing::Invoke([](BorealisContextManager::Result result) { - EXPECT_FALSE(result.Ok()); - EXPECT_EQ(result.Failure(), BorealisStartupResult::kCancelled); - })); + .WillOnce( + testing::Invoke([](BorealisContextManager::ContextOrFailure result) { + EXPECT_FALSE(result); + EXPECT_EQ(result.Error().error(), + BorealisStartupResult::kCancelled); + })); NeverCompletingContextManager context_manager(profile_.get()); context_manager.StartBorealis(callback_expectation.GetCallback());
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc index 356102b..b52d60b5 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -476,14 +476,10 @@ IDS_FILE_BROWSER_CONFLICT_DIALOG_MESSAGE); SET_STRING("CONFLICT_DIALOG_REPLACE", IDS_FILE_BROWSER_CONFLICT_DIALOG_REPLACE); - SET_STRING("COPIED", IDS_FILE_BROWSER_COPIED); - SET_STRING("COPIED_TO", IDS_FILE_BROWSER_COPIED_TO); SET_STRING("COPY_BUTTON_LABEL", IDS_FILE_BROWSER_COPY_BUTTON_LABEL); SET_STRING("COPY_FILESYSTEM_ERROR", IDS_FILE_BROWSER_COPY_FILESYSTEM_ERROR); - // TODO (crbug/1093603): Clean up after FilesTransferDetails launch. SET_STRING("COPY_FILE_NAME", IDS_FILE_BROWSER_COPY_FILE_NAME); SET_STRING("COPY_ITEMS_REMAINING", IDS_FILE_BROWSER_COPY_ITEMS_REMAINING); - // TODO: End. SET_STRING("COPY_FILE_NAME_LONG", IDS_FILE_BROWSER_COPY_FILE_NAME_LONG); SET_STRING("COPY_ITEMS_REMAINING_LONG", IDS_FILE_BROWSER_COPY_ITEMS_REMAINING_LONG); @@ -718,12 +714,8 @@ IDS_FILE_BROWSER_METADATA_BOX_YEAR_RECORDED); SET_STRING("MOUNT_ARCHIVE", IDS_FILE_BROWSER_MOUNT_ARCHIVE); SET_STRING("MOVE_FILESYSTEM_ERROR", IDS_FILE_BROWSER_MOVE_FILESYSTEM_ERROR); - SET_STRING("MOVED", IDS_FILE_BROWSER_MOVED); - SET_STRING("MOVED_TO", IDS_FILE_BROWSER_MOVED_TO); - // TODO (crbug/1093603): Clean up after FilesTransferDetails launch. SET_STRING("MOVE_FILE_NAME", IDS_FILE_BROWSER_MOVE_FILE_NAME); SET_STRING("MOVE_ITEMS_REMAINING", IDS_FILE_BROWSER_MOVE_ITEMS_REMAINING); - // TODO: End. SET_STRING("MOVE_FILE_NAME_LONG", IDS_FILE_BROWSER_MOVE_FILE_NAME_LONG); SET_STRING("MOVE_ITEMS_REMAINING_LONG", IDS_FILE_BROWSER_MOVE_ITEMS_REMAINING_LONG); @@ -849,7 +841,6 @@ SET_STRING("SELECT_ALL_COMMAND_LABEL", IDS_FILE_BROWSER_SELECT_ALL_COMMAND_LABEL); SET_STRING("TASKS_BUTTON_LABEL", IDS_FILE_BROWSER_TASKS_BUTTON_LABEL); - SET_STRING("TO_FOLDER_NAME", IDS_FILE_BROWSER_TO_FOLDER_NAME); SET_STRING("TOGGLE_HIDDEN_FILES_COMMAND_LABEL", IDS_FILE_BROWSER_TOGGLE_HIDDEN_FILES_COMMAND_LABEL); SET_STRING("SHARE_BUTTON_LABEL", IDS_FILE_BROWSER_SHARE_BUTTON_LABEL);
diff --git a/chrome/browser/chromeos/fileapi/file_change_service.cc b/chrome/browser/chromeos/fileapi/file_change_service.cc index 39230b5..c6d625ec 100644 --- a/chrome/browser/chromeos/fileapi/file_change_service.cc +++ b/chrome/browser/chromeos/fileapi/file_change_service.cc
@@ -18,6 +18,11 @@ observer_list_.RemoveObserver(observer); } +void FileChangeService::NotifyFileModified(const storage::FileSystemURL& url) { + for (FileChangeServiceObserver& observer : observer_list_) + observer.OnFileModified(url); +} + void FileChangeService::NotifyFileCopied(const storage::FileSystemURL& src, const storage::FileSystemURL& dst) { for (FileChangeServiceObserver& observer : observer_list_)
diff --git a/chrome/browser/chromeos/fileapi/file_change_service.h b/chrome/browser/chromeos/fileapi/file_change_service.h index 4b6c6c5..05a0354 100644 --- a/chrome/browser/chromeos/fileapi/file_change_service.h +++ b/chrome/browser/chromeos/fileapi/file_change_service.h
@@ -25,6 +25,9 @@ void AddObserver(FileChangeServiceObserver* observer); void RemoveObserver(FileChangeServiceObserver* observer); + // Notifies the service that a file identified by `url` has been modified. + void NotifyFileModified(const storage::FileSystemURL& url); + // Notifies the service that a file has been copied from `src` to `dst`. void NotifyFileCopied(const storage::FileSystemURL& src, const storage::FileSystemURL& dst);
diff --git a/chrome/browser/chromeos/fileapi/file_change_service_observer.h b/chrome/browser/chromeos/fileapi/file_change_service_observer.h index 1582d82f..5b1376c 100644 --- a/chrome/browser/chromeos/fileapi/file_change_service_observer.h +++ b/chrome/browser/chromeos/fileapi/file_change_service_observer.h
@@ -16,6 +16,10 @@ // An interface for an observer which receives `FileChangeService` events. class FileChangeServiceObserver : public base::CheckedObserver { public: + // Invoked when a file identified by `url` has been modified. Note that this + // will not get called on file creation or deletion. + virtual void OnFileModified(const storage::FileSystemURL& url) {} + // Invoked when a file has been copied from `src` to `dst`. virtual void OnFileCopied(const storage::FileSystemURL& src, const storage::FileSystemURL& dst) {}
diff --git a/chrome/browser/chromeos/fileapi/file_change_service_unittest.cc b/chrome/browser/chromeos/fileapi/file_change_service_unittest.cc index cc86417d..5728f00d 100644 --- a/chrome/browser/chromeos/fileapi/file_change_service_unittest.cc +++ b/chrome/browser/chromeos/fileapi/file_change_service_unittest.cc
@@ -6,16 +6,24 @@ #include "base/files/scoped_temp_dir.h" #include "base/scoped_observation.h" +#include "base/test/bind.h" #include "base/unguessable_token.h" #include "chrome/browser/chromeos/file_manager/app_id.h" #include "chrome/browser/chromeos/file_manager/fileapi_util.h" #include "chrome/browser/chromeos/fileapi/file_change_service_factory.h" #include "chrome/browser/chromeos/fileapi/file_change_service_observer.h" +#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_profile_manager.h" +#include "components/user_manager/scoped_user_manager.h" +#include "mojo/public/cpp/system/data_pipe.h" +#include "mojo/public/cpp/system/data_pipe_producer.h" +#include "mojo/public/cpp/system/string_data_source.h" +#include "storage/browser/blob/blob_storage_context.h" #include "storage/browser/file_system/external_mount_points.h" #include "storage/browser/file_system/file_system_operation_runner.h" #include "storage/browser/test/async_file_test_helper.h" +#include "storage/browser/test/mock_blob_util.h" #include "testing/gmock/include/gmock/gmock.h" namespace chromeos { @@ -37,12 +45,41 @@ return GetFileSystemContext(profile)->operation_runner(); } +// Creates a mojo data pipe with the provided `content`. +mojo::ScopedDataPipeConsumerHandle CreateStream(const std::string& contents) { + mojo::ScopedDataPipeProducerHandle producer_handle; + mojo::ScopedDataPipeConsumerHandle consumer_handle; + MojoCreateDataPipeOptions options; + options.struct_size = sizeof(MojoCreateDataPipeOptions); + options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; + options.element_num_bytes = 1; + options.capacity_num_bytes = 16; + mojo::CreateDataPipe(&options, &producer_handle, &consumer_handle); + CHECK(producer_handle.is_valid()); + auto producer = + std::make_unique<mojo::DataPipeProducer>(std::move(producer_handle)); + auto* producer_raw = producer.get(); + producer_raw->Write( + std::make_unique<mojo::StringDataSource>( + contents, mojo::StringDataSource::AsyncWritingMode:: + STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION), + base::BindOnce( + base::DoNothing::Once<std::unique_ptr<mojo::DataPipeProducer>, + MojoResult>(), + std::move(producer))); + return consumer_handle; +} + // MockFileChangeServiceObserver ----------------------------------------------- class MockFileChangeServiceObserver : public FileChangeServiceObserver { public: // FileChangeServiceObserver: MOCK_METHOD(void, + OnFileModified, + (const storage::FileSystemURL& url), + (override)); + MOCK_METHOD(void, OnFileCopied, (const storage::FileSystemURL& src, const storage::FileSystemURL& dst), @@ -98,6 +135,52 @@ temp_dir_.GetPath().Append(base::FilePath::FromUTF8Unsafe(path))); } + // Synchronously writes `content` to the file specified by `url`. + base::File::Error WriteFile(const storage::FileSystemURL& url, + const std::string& data) { + storage::BlobStorageContext blob_storage_context; + storage::ScopedTextBlob blob(&blob_storage_context, "blob-id:test", data); + base::File::Error result = base::File::FILE_ERROR_FAILED; + base::RunLoop run_loop; + GetFileSystemContext(profile_)->operation_runner()->Write( + url, blob.GetBlobDataHandle(), 0, + base::BindLambdaForTesting([&](base::File::Error operation_result, + int64_t bytes, bool complete) { + if (!complete) + return; + result = operation_result; + run_loop.Quit(); + })); + run_loop.Run(); + return result; + } + + // Synchronously writes contents from `stream` to the file specified by `url`. + base::File::Error WriteStreamToFile( + const storage::FileSystemURL& url, + mojo::ScopedDataPipeConsumerHandle stream) { + base::File::Error result = base::File::FILE_ERROR_FAILED; + base::RunLoop run_loop; + GetFileSystemContext(profile_)->operation_runner()->WriteStream( + url, std::move(stream), 0, + base::BindLambdaForTesting([&](base::File::Error operation_result, + int64_t bytes, bool complete) { + if (!complete) + return; + result = operation_result; + run_loop.Quit(); + })); + run_loop.Run(); + return result; + } + + // Synchronously truncates the file specified by `url` to `size`. + base::File::Error TruncateFile(const storage::FileSystemURL& url, + size_t size) { + storage::FileSystemContext* context = GetFileSystemContext(profile_); + return storage::AsyncFileTestHelper::TruncateFile(context, url, size); + } + // Synchronously copies the file specified by `src` to `dst`. base::File::Error CopyFile(const storage::FileSystemURL& src, const storage::FileSystemURL& dst) { @@ -144,13 +227,19 @@ class FileChangeServiceTest : public BrowserWithTestWindowTest { public: - FileChangeServiceTest() = default; + FileChangeServiceTest() + : fake_user_manager_(new chromeos::FakeChromeUserManager), + user_manager_enabler_(base::WrapUnique(fake_user_manager_)) {} + FileChangeServiceTest(const FileChangeServiceTest& other) = delete; FileChangeServiceTest& operator=(const FileChangeServiceTest& other) = delete; ~FileChangeServiceTest() override = default; // Creates and returns a new profile for the specified `name`. TestingProfile* CreateProfileWithName(const std::string& name) { + const AccountId account_id(AccountId::FromUserEmail(name)); + fake_user_manager_->AddUser(account_id); + fake_user_manager_->LoginUser(account_id); return profile_manager()->CreateTestingProfile(name); } @@ -160,6 +249,9 @@ constexpr char kPrimaryProfileName[] = "primary_profile"; return CreateProfileWithName(kPrimaryProfileName); } + + chromeos::FakeChromeUserManager* fake_user_manager_; + user_manager::ScopedUserManager user_manager_enabler_; }; } // namespace @@ -205,16 +297,61 @@ ASSERT_EQ(temp_file_system.CreateFile(src), base::File::FILE_OK); - EXPECT_CALL(mock_observer, OnFileCopied) - .WillRepeatedly([&](const storage::FileSystemURL& propagated_src, - const storage::FileSystemURL& propagated_dst) { - EXPECT_EQ(src, propagated_src); - EXPECT_EQ(dst, propagated_dst); + EXPECT_CALL(mock_observer, OnFileModified) + .WillRepeatedly([&](const storage::FileSystemURL& propagated_url) { + EXPECT_EQ(dst, propagated_url); }); - ASSERT_EQ(temp_file_system.CopyFile(src, dst), base::File::FILE_OK); + { + base::RunLoop copy_run_loop; + EXPECT_CALL(mock_observer, OnFileCopied) + .WillOnce([&](const storage::FileSystemURL& propagated_src, + const storage::FileSystemURL& propagated_dst) { + EXPECT_EQ(src, propagated_src); + EXPECT_EQ(dst, propagated_dst); + copy_run_loop.Quit(); + }) + .RetiresOnSaturation(); + + base::RunLoop modify_run_loop; + EXPECT_CALL(mock_observer, OnFileModified) + .WillOnce([&](const storage::FileSystemURL& propagated_url) { + EXPECT_EQ(dst, propagated_url); + modify_run_loop.Quit(); + }) + .RetiresOnSaturation(); + + ASSERT_EQ(temp_file_system.CopyFile(src, dst), base::File::FILE_OK); + copy_run_loop.Run(); + modify_run_loop.Run(); + } + + ::testing::Mock::VerifyAndClearExpectations(&mock_observer); ASSERT_EQ(temp_file_system.RemoveFile(dst), base::File::FILE_OK); - ASSERT_EQ(temp_file_system.CopyFileLocal(src, dst), base::File::FILE_OK); + + { + base::RunLoop copy_run_loop; + EXPECT_CALL(mock_observer, OnFileCopied) + .WillOnce([&](const storage::FileSystemURL& propagated_src, + const storage::FileSystemURL& propagated_dst) { + EXPECT_EQ(src, propagated_src); + EXPECT_EQ(dst, propagated_dst); + copy_run_loop.Quit(); + }) + .RetiresOnSaturation(); + + base::RunLoop modify_run_loop; + EXPECT_CALL(mock_observer, OnFileModified) + .WillOnce([&](const storage::FileSystemURL& propagated_url) { + EXPECT_EQ(dst, propagated_url); + modify_run_loop.Quit(); + }) + .RetiresOnSaturation(); + + ASSERT_EQ(temp_file_system.CopyFileLocal(src, dst), base::File::FILE_OK); + copy_run_loop.Run(); + modify_run_loop.Run(); + } } // Verifies `OnFileMoved` events are propagated to observers. @@ -236,16 +373,115 @@ ASSERT_EQ(temp_file_system.CreateFile(src), base::File::FILE_OK); - EXPECT_CALL(mock_observer, OnFileMoved) - .WillRepeatedly([&](const storage::FileSystemURL& propagated_src, - const storage::FileSystemURL& propagated_dst) { - EXPECT_EQ(src, propagated_src); - EXPECT_EQ(dst, propagated_dst); - }); + { + base::RunLoop move_run_loop; + EXPECT_CALL(mock_observer, OnFileMoved) + // NOTE: `Move()` internally calls `MoveFileLocal()`, so move operation + // gets reported twice. + .WillOnce([&](const storage::FileSystemURL& propagated_src, + const storage::FileSystemURL& propagated_dst) { + EXPECT_EQ(src, propagated_src); + EXPECT_EQ(dst, propagated_dst); + }) + .WillOnce([&](const storage::FileSystemURL& propagated_src, + const storage::FileSystemURL& propagated_dst) { + EXPECT_EQ(src, propagated_src); + EXPECT_EQ(dst, propagated_dst); + move_run_loop.Quit(); + }) + .RetiresOnSaturation(); - ASSERT_EQ(temp_file_system.MoveFile(src, dst), base::File::FILE_OK); - std::swap(dst, src); - ASSERT_EQ(temp_file_system.MoveFileLocal(src, dst), base::File::FILE_OK); + EXPECT_CALL(mock_observer, OnFileModified).Times(0); + + ASSERT_EQ(temp_file_system.MoveFile(src, dst), base::File::FILE_OK); + move_run_loop.Run(); + } + + ::testing::Mock::VerifyAndClearExpectations(&mock_observer); + + { + base::RunLoop move_run_loop; + EXPECT_CALL(mock_observer, OnFileMoved) + .WillOnce([&](const storage::FileSystemURL& propagated_src, + const storage::FileSystemURL& propagated_dst) { + EXPECT_EQ(dst, propagated_src); + EXPECT_EQ(src, propagated_dst); + move_run_loop.Quit(); + }) + .RetiresOnSaturation(); + + EXPECT_CALL(mock_observer, OnFileModified).Times(0); + ASSERT_EQ(temp_file_system.MoveFileLocal(dst, src), base::File::FILE_OK); + + move_run_loop.Run(); + } +} + +// Verifies `OnFileModified` events are propagated to observers. +TEST_F(FileChangeServiceTest, PropagatesOnFileModifiedEvents) { + auto* profile = GetProfile(); + auto* service = FileChangeServiceFactory::GetInstance()->GetService(profile); + ASSERT_TRUE(service); + + testing::NiceMock<MockFileChangeServiceObserver> mock_observer; + base::ScopedObservation<FileChangeService, FileChangeServiceObserver> + scoped_observation{&mock_observer}; + scoped_observation.Observe(service); + + TempFileSystem temp_file_system(profile); + temp_file_system.SetUp(); + + storage::FileSystemURL url = + temp_file_system.CreateFileSystemURL("test_file"); + + ASSERT_EQ(temp_file_system.CreateFile(url), base::File::FILE_OK); + + // Test writing to file. + { + base::RunLoop modify_run_loop; + EXPECT_CALL(mock_observer, OnFileModified) + .WillOnce([&](const storage::FileSystemURL& propagated_url) { + EXPECT_EQ(url, propagated_url); + modify_run_loop.Quit(); + }) + .RetiresOnSaturation(); + + ASSERT_EQ(temp_file_system.WriteFile(url, "Test file contents\n"), + base::File::FILE_OK); + modify_run_loop.Run(); + } + + ::testing::Mock::VerifyAndClearExpectations(&mock_observer); + + // Test truncating file. + { + base::RunLoop modify_run_loop; + EXPECT_CALL(mock_observer, OnFileModified) + .WillOnce([&](const storage::FileSystemURL& propagated_url) { + EXPECT_EQ(url, propagated_url); + modify_run_loop.Quit(); + }) + .RetiresOnSaturation(); + + ASSERT_EQ(temp_file_system.TruncateFile(url, 10), base::File::FILE_OK); + modify_run_loop.Run(); + } + + // Test writing a stream to file. + { + base::RunLoop modify_run_loop; + EXPECT_CALL(mock_observer, OnFileModified) + .WillOnce([&](const storage::FileSystemURL& propagated_url) { + EXPECT_EQ(url, propagated_url); + modify_run_loop.Quit(); + }) + .RetiresOnSaturation(); + + ASSERT_EQ(temp_file_system.WriteStreamToFile( + url, CreateStream("Test file contents from stream")), + base::File::FILE_OK); + modify_run_loop.Run(); + } } } // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/observable_file_system_operation_impl.cc b/chrome/browser/chromeos/fileapi/observable_file_system_operation_impl.cc index 03504bc..cb5095a 100644 --- a/chrome/browser/chromeos/fileapi/observable_file_system_operation_impl.cc +++ b/chrome/browser/chromeos/fileapi/observable_file_system_operation_impl.cc
@@ -16,6 +16,7 @@ namespace { using StatusCallback = storage::FileSystemOperation::StatusCallback; +using WriteCallback = storage::FileSystemOperation::WriteCallback; // Helpers --------------------------------------------------------------------- @@ -34,8 +35,10 @@ const storage::FileSystemURL& dst) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); FileChangeService* service = GetFileChangeService(account_id); - if (service) + if (service) { + service->NotifyFileModified(dst); service->NotifyFileCopied(src, dst); + } } // Notifies the `FileChangeService` associated with the given `account_id` of a @@ -50,6 +53,28 @@ service->NotifyFileMoved(src, dst); } +// Notifies the `FileChangeService` associated with the given `account_id` of a +// file under `url` getting modified. This method may only be called from the +// browser UI thread. +void NotifyFileModifiedOnUiThread(const AccountId& account_id, + const storage::FileSystemURL& url) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + FileChangeService* service = GetFileChangeService(account_id); + if (service) + service->NotifyFileModified(url); +} + +// Returns a `WriteCallback` which runs the specified callbacks in order. +WriteCallback RunInOrderCallback(WriteCallback a, WriteCallback b) { + return base::BindRepeating( + [](WriteCallback a, WriteCallback b, base::File::Error result, + int64_t bytes, bool complete) { + std::move(a).Run(result, bytes, complete); + std::move(b).Run(result, bytes, complete); + }, + std::move(a), std::move(b)); +} + // Returns a `StatusCallback` which runs the specified callbacks in order. StatusCallback RunInOrderCallback(StatusCallback a, StatusCallback b) { return base::BindOnce( @@ -73,6 +98,21 @@ std::move(closure)); } +// Returns a `WriteCallback` which runs the specified `closure` on the browser +// UI thread if `complete` is set. +WriteCallback RunOnUiThreadOnCompleteCallback( + const base::RepeatingClosure& closure) { + return base::BindRepeating( + [](const base::RepeatingClosure& closure, base::File::Error result, + int64_t bytes, bool complete) { + if (complete && result == base::File::FILE_OK) { + auto task_runner = content::GetUIThreadTaskRunner({}); + task_runner->PostTask(FROM_HERE, std::move(closure)); + } + }, + std::move(closure)); +} + } // namespace // ObservableFileSystemOperationImpl ------------------------------------------- @@ -144,4 +184,39 @@ std::move(callback))); } +void ObservableFileSystemOperationImpl::WriteBlob( + const storage::FileSystemURL& url, + std::unique_ptr<storage::FileWriterDelegate> writer_delegate, + std::unique_ptr<storage::BlobReader> blob_reader, + const WriteCallback& callback) { + storage::FileSystemOperationImpl::WriteBlob( + url, std::move(writer_delegate), std::move(blob_reader), + RunInOrderCallback(RunOnUiThreadOnCompleteCallback(base::BindRepeating( + &NotifyFileModifiedOnUiThread, account_id_, url)), + std::move(callback))); +} + +void ObservableFileSystemOperationImpl::Write( + const storage::FileSystemURL& url, + std::unique_ptr<storage::FileWriterDelegate> writer_delegate, + mojo::ScopedDataPipeConsumerHandle data_pipe, + const WriteCallback& callback) { + storage::FileSystemOperationImpl::Write( + url, std::move(writer_delegate), std::move(data_pipe), + RunInOrderCallback(RunOnUiThreadOnCompleteCallback(base::BindRepeating( + &NotifyFileModifiedOnUiThread, account_id_, url)), + std::move(callback))); +} + +void ObservableFileSystemOperationImpl::Truncate( + const storage::FileSystemURL& url, + int64_t length, + StatusCallback callback) { + storage::FileSystemOperationImpl::Truncate( + url, length, + RunInOrderCallback(RunOnUiThreadOnSuccessCallback(base::BindOnce( + &NotifyFileModifiedOnUiThread, account_id_, url)), + std::move(callback))); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/observable_file_system_operation_impl.h b/chrome/browser/chromeos/fileapi/observable_file_system_operation_impl.h index 698d9c8..4afa280a 100644 --- a/chrome/browser/chromeos/fileapi/observable_file_system_operation_impl.h +++ b/chrome/browser/chromeos/fileapi/observable_file_system_operation_impl.h
@@ -49,6 +49,17 @@ const storage::FileSystemURL& dst, CopyOrMoveOption option, StatusCallback callback) override; + void WriteBlob(const storage::FileSystemURL& url, + std::unique_ptr<storage::FileWriterDelegate> writer_delegate, + std::unique_ptr<storage::BlobReader> blob_reader, + const WriteCallback& callback) override; + void Write(const storage::FileSystemURL& url, + std::unique_ptr<storage::FileWriterDelegate> writer_delegate, + mojo::ScopedDataPipeConsumerHandle data_pipe, + const WriteCallback& callback) override; + void Truncate(const storage::FileSystemURL& url, + int64_t length, + StatusCallback callback) override; const AccountId account_id_; base::WeakPtrFactory<ObservableFileSystemOperationImpl> weak_factory_{this};
diff --git a/chrome/browser/chromeos/login/login_ui_browsertest.cc b/chrome/browser/chromeos/login/login_ui_browsertest.cc index a47222a..f7db98a 100644 --- a/chrome/browser/chromeos/login/login_ui_browsertest.cc +++ b/chrome/browser/chromeos/login/login_ui_browsertest.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "ash/public/cpp/login_screen_test_api.h" -#include "base/test/scoped_feature_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/lock/screen_locker_tester.h" #include "chrome/browser/chromeos/login/login_manager_test.h" @@ -24,7 +23,6 @@ #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h" #include "chrome/common/pref_names.h" -#include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_pref_names.h" #include "components/prefs/pref_service.h" #include "components/user_manager/known_user.h" @@ -168,10 +166,7 @@ class DisplayPasswordButtonTest : public LoginManagerTest { public: - DisplayPasswordButtonTest() : LoginManagerTest() { - feature_list_.InitWithFeatures( - {chromeos::features::kLoginDisplayPasswordButton}, {}); - } + DisplayPasswordButtonTest() : LoginManagerTest() {} void LoginAndLock(const LoginManagerMixin::TestUserInfo& test_user) { chromeos::WizardController::SkipPostLoginScreensForTesting(); @@ -187,7 +182,7 @@ void SetDisplayPasswordButtonEnabledLoginAndLock( bool display_password_button_enabled) { - // Sets the feature by user policy + // Enables the login display password buttonn by user policy. { std::unique_ptr<ScopedUserPolicyUpdate> scoped_user_policy_update = user_policy_mixin_.RequestPolicyUpdate(); @@ -219,9 +214,6 @@ AccountId::FromUserEmailGaiaId("user@example.com", "22222")}; UserPolicyMixin user_policy_mixin_{&mixin_host_, managed_user_.account_id}; LoginManagerMixin login_manager_mixin_{&mixin_host_}; - - private: - base::test::ScopedFeatureList feature_list_; }; // Check if the display password button is shown on the lock screen after having
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc index 789f39e..e12c320 100644 --- a/chrome/browser/chromeos/login/webview_login_browsertest.cc +++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -135,14 +135,15 @@ storage_partition->GetNetworkContext()->GetCookieManager( cookie_manager.BindNewPipeAndPassReceiver()); - net::CanonicalCookie cookie( - kTestCookieName, kTestCookieValue, kTestCookieHost, "/", base::Time(), - base::Time(), base::Time(), true /* secure */, false /* httponly*/, - net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM, - false /* same_party */); + std::unique_ptr<net::CanonicalCookie> cookie = + net::CanonicalCookie::CreateUnsafeCookieForTesting( + kTestCookieName, kTestCookieValue, kTestCookieHost, "/", base::Time(), + base::Time(), base::Time(), true /* secure */, false /* httponly*/, + net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM, + false /* same_party */); base::RunLoop run_loop; cookie_manager->SetCanonicalCookie( - cookie, net::cookie_util::SimulatedCookieSource(cookie, "https"), + *cookie, net::cookie_util::SimulatedCookieSource(*cookie, "https"), net::CookieOptions(), base::BindOnce(&InjectCookieDoneCallback, run_loop.QuitClosure())); run_loop.Run();
diff --git a/chrome/browser/chromeos/net/network_diagnostics/README.md b/chrome/browser/chromeos/net/network_diagnostics/README.md index f8c2e8b..908a7d25 100644 --- a/chrome/browser/chromeos/net/network_diagnostics/README.md +++ b/chrome/browser/chromeos/net/network_diagnostics/README.md
@@ -127,8 +127,15 @@ Problems: * `kNoActiveNetworks`: No active networks found. * `kRestrictedConnectivity`: The active network is behind a captive portal and - has restricted connectivity. -* `kCaptivePortalState`: The active network is behind a captive portal. + has restricted connectivity. +* `kUnknownPortalState`: The active network is not connected or the portal + state is not available. +* `kPortalSuspected`: A portal is suspected but no redirect was provided. +* `kPortal`: The network is in a portal state with a redirect URL. +* `kProxyAuthRequired`: A proxy requiring authentication is detected. +* `kNoInternet`: The active network is connected but no internet is available + and no proxy was detected. + ### Firewall Routines @@ -169,7 +176,7 @@ #### VideoConferencing -Tests the device's video conferencing capabalities by testing whether the device +Tests the device's video conferencing capabilities by testing whether the device can: 1. Contact either a default or specified STUN server via UDP. 2. Contact either a default or specified STUN server via TCP.
diff --git a/chrome/browser/chromeos/printing/print_servers_manager.cc b/chrome/browser/chromeos/printing/print_servers_manager.cc index 0e84842f..e7c6b79 100644 --- a/chrome/browser/chromeos/printing/print_servers_manager.cc +++ b/chrome/browser/chromeos/printing/print_servers_manager.cc
@@ -177,7 +177,7 @@ Profile* profile) { return std::make_unique<PrintServersManagerImpl>( PrintServersPolicyProvider::Create(profile), - ServerPrintersProvider::Create()); + ServerPrintersProvider::Create(profile)); } // static
diff --git a/chrome/browser/chromeos/printing/server_printers_fetcher.cc b/chrome/browser/chromeos/printing/server_printers_fetcher.cc index 66b480d..1963cc8 100644 --- a/chrome/browser/chromeos/printing/server_printers_fetcher.cc +++ b/chrome/browser/chromeos/printing/server_printers_fetcher.cc
@@ -16,8 +16,8 @@ #include "base/task/post_task.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/net/system_network_context_manager.h" +#include "chrome/browser/profiles/profile.h" #include "components/device_event_log/device_event_log.h" #include "net/base/load_flags.h" #include "services/network/public/cpp/resource_request.h" @@ -46,6 +46,7 @@ : public network::SimpleURLLoaderStreamConsumer { public: PrivateImplementation(const ServerPrintersFetcher* owner, + Profile* profile, const GURL& server_url, const std::string& server_name, ServerPrintersFetcher::OnPrintersFetchedCallback cb) @@ -60,10 +61,9 @@ task_runner_for_callback_ = base::SequencedTaskRunnerHandle::Get(); // Post task to execute. task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &PrivateImplementation::SendQuery, base::Unretained(this), - g_browser_process->shared_url_loader_factory()->Clone())); + FROM_HERE, base::BindOnce(&PrivateImplementation::SendQuery, + base::Unretained(this), + profile->GetURLLoaderFactory()->Clone())); } ~PrivateImplementation() override = default; @@ -230,10 +230,12 @@ DISALLOW_COPY_AND_ASSIGN(PrivateImplementation); }; -ServerPrintersFetcher::ServerPrintersFetcher(const GURL& server_url, +ServerPrintersFetcher::ServerPrintersFetcher(Profile* profile, + const GURL& server_url, const std::string& server_name, OnPrintersFetchedCallback cb) : pim_(new PrivateImplementation(this, + profile, server_url, server_name, std::move(cb)),
diff --git a/chrome/browser/chromeos/printing/server_printers_fetcher.h b/chrome/browser/chromeos/printing/server_printers_fetcher.h index 031bfc33..546a2d50 100644 --- a/chrome/browser/chromeos/printing/server_printers_fetcher.h +++ b/chrome/browser/chromeos/printing/server_printers_fetcher.h
@@ -13,6 +13,7 @@ #include "chrome/browser/chromeos/printing/printer_detector.h" class GURL; +class Profile; namespace chromeos { @@ -40,7 +41,8 @@ const GURL& server_url, std::vector<PrinterDetector::DetectedPrinter>&& printers)>; - ServerPrintersFetcher(const GURL& server_url, + ServerPrintersFetcher(Profile* profile, + const GURL& server_url, const std::string& server_name, OnPrintersFetchedCallback cb); virtual ~ServerPrintersFetcher();
diff --git a/chrome/browser/chromeos/printing/server_printers_provider.cc b/chrome/browser/chromeos/printing/server_printers_provider.cc index 1231fe8..26f42ed 100644 --- a/chrome/browser/chromeos/printing/server_printers_provider.cc +++ b/chrome/browser/chromeos/printing/server_printers_provider.cc
@@ -42,7 +42,7 @@ : public ServerPrintersProvider, public base::SupportsWeakPtr<ServerPrintersProviderImpl> { public: - ServerPrintersProviderImpl() { + explicit ServerPrintersProviderImpl(Profile* profile) : profile_(profile) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } @@ -96,7 +96,7 @@ // This is a new print server: query for printers. fetchers_.emplace( url, std::make_unique<ServerPrintersFetcher>( - url, name, + profile_, url, name, base::BindRepeating( &ServerPrintersProviderImpl::OnPrintersFetched, weak_ptr_factory_.GetWeakPtr()))); @@ -158,6 +158,8 @@ return (servers_are_complete_ && fetchers_.empty()); } + Profile* profile_; + // A callback to propagate update of the resultant list of server printers. OnPrintersUpdateCallback callback_; @@ -178,8 +180,9 @@ } // namespace // static -std::unique_ptr<ServerPrintersProvider> ServerPrintersProvider::Create() { - return std::make_unique<ServerPrintersProviderImpl>(); +std::unique_ptr<ServerPrintersProvider> ServerPrintersProvider::Create( + Profile* profile) { + return std::make_unique<ServerPrintersProviderImpl>(profile); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/server_printers_provider.h b/chrome/browser/chromeos/printing/server_printers_provider.h index df08c5b..e0b7f45 100644 --- a/chrome/browser/chromeos/printing/server_printers_provider.h +++ b/chrome/browser/chromeos/printing/server_printers_provider.h
@@ -14,6 +14,8 @@ #include "chrome/browser/chromeos/printing/printer_detector.h" #include "components/keyed_service/core/keyed_service.h" +class Profile; + namespace chromeos { // Given a list of external print servers, uses ServerPrintersFetcher to track @@ -24,7 +26,7 @@ // sequence, the callback is also called from this sequence. class ServerPrintersProvider { public: - static std::unique_ptr<ServerPrintersProvider> Create(); + static std::unique_ptr<ServerPrintersProvider> Create(Profile* profile); virtual ~ServerPrintersProvider() = default; using OnPrintersUpdateCallback = base::RepeatingCallback<void(bool complete)>;
diff --git a/chrome/browser/chromeos/printing/server_printers_provider_unittest.cc b/chrome/browser/chromeos/printing/server_printers_provider_unittest.cc index 8399c54..7ffdc9b 100644 --- a/chrome/browser/chromeos/printing/server_printers_provider_unittest.cc +++ b/chrome/browser/chromeos/printing/server_printers_provider_unittest.cc
@@ -12,7 +12,7 @@ #include "chrome/browser/chromeos/printing/print_servers_provider.h" #include "chrome/browser/chromeos/printing/print_servers_provider_factory.h" #include "chrome/test/base/scoped_testing_local_state.h" -#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" #include "components/policy/proto/chrome_device_policy.pb.h" #include "components/user_manager/scoped_user_manager.h" #include "content/public/test/browser_task_environment.h" @@ -32,6 +32,20 @@ namespace { +class TestingProfileWithURLLoaderFactory : public TestingProfile { + public: + explicit TestingProfileWithURLLoaderFactory( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + : url_loader_factory_(url_loader_factory) {} + scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() + override { + return url_loader_factory_; + } + + private: + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; +}; + chromeos::PrintServer PrintServer1() { GURL url("http://192.168.1.5/printer"); chromeos::PrintServer print_server("id1", url, "LexaPrint"); @@ -80,20 +94,13 @@ } class ServerPrintersProviderTest : public ::testing::Test { - public: - ServerPrintersProviderTest() - : test_shared_loader_factory_( - base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( - &test_url_loader_factory_)) {} - protected: void SetUp() override { - TestingBrowserProcess::GetGlobal()->SetSharedURLLoaderFactory( - test_shared_loader_factory_); - + test_profile_ = std::make_unique<TestingProfileWithURLLoaderFactory>( + test_url_loader_factory_.GetSafeWeakWrapper()); ASSERT_TRUE(test_server_.Start()); - - server_printers_provider_ = ServerPrintersProvider::Create(); + server_printers_provider_ = + ServerPrintersProvider::Create(test_profile_.get()); } void TearDown() override { PrintServersProviderFactory::Get()->Shutdown(); } @@ -127,8 +134,7 @@ network::TestURLLoaderFactory test_url_loader_factory_; - scoped_refptr<network::WeakWrapperSharedURLLoaderFactory> - test_shared_loader_factory_; + std::unique_ptr<TestingProfileWithURLLoaderFactory> test_profile_; net::test_server::EmbeddedTestServer test_server_;
diff --git a/chrome/browser/chromeos/web_applications/chrome_camera_app_ui_constants.h b/chrome/browser/chromeos/web_applications/chrome_camera_app_ui_constants.h index 9b534e1..8ea3e2d8 100644 --- a/chrome/browser/chromeos/web_applications/chrome_camera_app_ui_constants.h +++ b/chrome/browser/chromeos/web_applications/chrome_camera_app_ui_constants.h
@@ -5,9 +5,10 @@ #ifndef CHROME_BROWSER_CHROMEOS_WEB_APPLICATIONS_CHROME_CAMERA_APP_UI_CONSTANTS_H_ #define CHROME_BROWSER_CHROMEOS_WEB_APPLICATIONS_CHROME_CAMERA_APP_UI_CONSTANTS_H_ +// All window size number here are referred to inner size excluding top bar. constexpr int kChromeCameraAppDefaultWidth = 788; -constexpr int kChromeCameraAppDefaultHeight = 460; +constexpr int kChromeCameraAppDefaultHeight = 428; constexpr int kChromeCameraAppMinimumWidth = 505; -constexpr int kChromeCameraAppMinimumHeight = 460; +constexpr int kChromeCameraAppMinimumHeight = 428; #endif // CHROME_BROWSER_CHROMEOS_WEB_APPLICATIONS_CHROME_CAMERA_APP_UI_CONSTANTS_H_
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc index beffad4a..0f155c82 100644 --- a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc +++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
@@ -5,18 +5,21 @@ #include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h" #include "base/check.h" +#include "base/logging.h" #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h" MockChromeJsErrorReportProcessor::MockChromeJsErrorReportProcessor() = default; MockChromeJsErrorReportProcessor::~MockChromeJsErrorReportProcessor() = default; void MockChromeJsErrorReportProcessor::SetAsDefault() { + LOG(INFO) << "MockChromeJsErrorReportProcessor installed as error processor"; JsErrorReportProcessor::SetDefault(this); } // static void MockChromeJsErrorReportProcessor::SetDefaultTo( scoped_refptr<JsErrorReportProcessor> new_default) { + LOG(INFO) << "MockChromeJsErrorReportProcessor uninstalled"; JsErrorReportProcessor::SetDefault(new_default); }
diff --git a/chrome/browser/error_reporting/webui_js_error_reporting_browsertest.cc b/chrome/browser/error_reporting/webui_js_error_reporting_browsertest.cc index 089da33..c0ae65075 100644 --- a/chrome/browser/error_reporting/webui_js_error_reporting_browsertest.cc +++ b/chrome/browser/error_reporting/webui_js_error_reporting_browsertest.cc
@@ -5,13 +5,23 @@ #include <memory> #include "base/test/scoped_feature_list.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h" +#include "chrome/browser/prefs/session_startup_pref.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sessions/session_service_factory.h" +#include "chrome/browser/sessions/session_service_test_helper.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/common/pref_names.h" #include "chrome/common/webui_url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h" +#include "components/keep_alive_registry/keep_alive_types.h" +#include "components/keep_alive_registry/scoped_keep_alive.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_features.h" #include "content/public/test/browser_test.h" @@ -25,18 +35,31 @@ using ::testing::HasSubstr; +namespace { +// Must match message in +// chrome/browser/resources/webui_js_error/webui_js_error.js, but with URL +// escapes. +constexpr char kPageLoadMessage[] = + "WebUI%20JS%20Error%3A%20printing%20error%20on%20page%20load"; +} // namespace + class WebUIJSErrorReportingTest : public InProcessBrowserTest { public: + WebUIJSErrorReportingTest() : error_url_(chrome::kChromeUIWebUIJsErrorURL) { + CHECK(error_url_.is_valid()); + } + void SetUpInProcessBrowserTestFixture() override { scoped_feature_list_.InitAndEnableFeatureWithParameters( features::kSendWebUIJavaScriptErrorReports, {{features::kSendWebUIJavaScriptErrorReportsSendToProductionVariation, - "true"}}); + "false"}}); InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); } protected: base::test::ScopedFeatureList scoped_feature_list_; + const GURL error_url_; }; IN_PROC_BROWSER_TEST_F(WebUIJSErrorReportingTest, ReportsErrors) { @@ -47,19 +70,12 @@ MockCrashEndpoint endpoint(embedded_test_server()); ScopedMockChromeJsErrorReportProcessor mock_processor(endpoint); - GURL url(chrome::kChromeUIWebUIJsErrorURL); - ASSERT_TRUE(url.is_valid()); - NavigateParams navigate(browser(), url, ui::PAGE_TRANSITION_TYPED); + NavigateParams navigate(browser(), error_url_, ui::PAGE_TRANSITION_TYPED); ui_test_utils::NavigateToURL(&navigate); // Look for page load error report. MockCrashEndpoint::Report report = endpoint.WaitForReport(); EXPECT_EQ(endpoint.report_count(), 1); - // Must match message in - // chrome/browser/resources/webui_js_error/webui_js_error.js, but with URL - // escapes. - constexpr char kPageLoadMessage[] = - "WebUI%20JS%20Error%3A%20printing%20error%20on%20page%20load"; EXPECT_THAT(report.query, HasSubstr(kPageLoadMessage)); // Expect that we get a good stack trace as well EXPECT_THAT(report.content, AllOf(HasSubstr("logsErrorDuringPageLoadOuter"), @@ -107,3 +123,51 @@ EXPECT_THAT(report.query, HasSubstr(kUnhandledPromiseRejectionMessage)); // V8 doesn't produce stacks for unhandle promise rejections. } + +// Set up a profile with "Continue where you left off". Navigate to the JS error +// page. Ensure that when the browser is closed and reopened, on-page-load +// errors are still reported. +IN_PROC_BROWSER_TEST_F(WebUIJSErrorReportingTest, + ReportsErrorsDuringContinueWhereYouLeftOff) { + MockCrashEndpoint endpoint(embedded_test_server()); + auto mock_processor = + std::make_unique<ScopedMockChromeJsErrorReportProcessor>(endpoint); + + Profile* profile = browser()->profile(); + SessionStartupPref pref(SessionStartupPref::LAST); + SessionStartupPref::SetStartupPref(profile, pref); + profile->GetPrefs()->SetBoolean(prefs::kHasSeenWelcomePage, true); + + chrome::NewTab(browser()); + ui_test_utils::NavigateToURL(browser(), error_url_); + endpoint.WaitForReport(); + endpoint.clear_last_report(); + + // Restart browser. Note: We can't do the normal PRE_Name / Name browsertest + // pattern here because the Continue Where You Left Off pages are loaded + // before the test starts, so we don't have a chance to set up the mock + // error processor. + { + ScopedKeepAlive keep_alive(KeepAliveOrigin::SESSION_RESTORE, + KeepAliveRestartOption::DISABLED); + CloseBrowserSynchronously(browser()); + + // Create a new error processor to reset the list of already seen reports, + // otherwise the report gets thrown away as a duplicate. + mock_processor.reset(); + mock_processor = + std::make_unique<ScopedMockChromeJsErrorReportProcessor>(endpoint); + SessionServiceTestHelper helper( + SessionServiceFactory::GetForProfileForSessionRestore(profile)); + helper.SetForceBrowserNotAliveWithNoWindows(true); + helper.ReleaseService(); + chrome::NewEmptyWindow(profile); + + // ScopedKeepAlive goes out of scope, so the new browser will return to + // normal behavior. + } + + MockCrashEndpoint::Report report = endpoint.WaitForReport(); + EXPECT_EQ(endpoint.report_count(), 2); + EXPECT_THAT(report.query, HasSubstr(kPageLoadMessage)); +}
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc index e1958c5..2ec2412 100644 --- a/chrome/browser/extensions/api/automation/automation_apitest.cc +++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -469,7 +469,13 @@ << message_; } -IN_PROC_BROWSER_TEST_F(AutomationApiTest, TextareaAppendPerf) { +#if BUILDFLAG(IS_CHROMEOS_ASH) && defined(MEMORY_SANITIZER) +// TODO(http://crbug.com/1162238): flaky on ChromeOS. +#define MAYBE_TextareaAppendPerf DISABLED_TextareaAppendPerf +#else +#define MAYBE_TextareaAppendPerf TextareaAppendPerf +#endif +IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_TextareaAppendPerf) { StartEmbeddedTestServer(); {
diff --git a/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc b/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc index 96b5419..221c6c41 100644 --- a/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc +++ b/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc
@@ -155,10 +155,10 @@ const Extension* target_extension, content::WebContents* source_contents, const GURL& source_url, - const base::Callback<void(bool)>& callback) { + base::OnceCallback<void(bool)> callback) { DCHECK(context->IsOffTheRecord()); IncognitoConnectability::Get(context)->Query( - target_extension, source_contents, source_url, callback); + target_extension, source_contents, source_url, std::move(callback)); } } // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.h b/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.h index 050786e..83108e8 100644 --- a/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.h +++ b/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.h
@@ -44,7 +44,7 @@ const Extension* extension, content::WebContents* web_contents, const GURL& url, - const base::Callback<void(bool)>& callback) override; + base::OnceCallback<void(bool)> callback) override; private: DISALLOW_COPY_AND_ASSIGN(ChromeMessagingDelegate);
diff --git a/chrome/browser/extensions/api/messaging/incognito_connectability.cc b/chrome/browser/extensions/api/messaging/incognito_connectability.cc index 2851891..a472319a 100644 --- a/chrome/browser/extensions/api/messaging/incognito_connectability.cc +++ b/chrome/browser/extensions/api/messaging/incognito_connectability.cc
@@ -60,24 +60,23 @@ return BrowserContextKeyedAPIFactory<IncognitoConnectability>::Get(context); } -void IncognitoConnectability::Query( - const Extension* extension, - content::WebContents* web_contents, - const GURL& url, - const base::Callback<void(bool)>& callback) { +void IncognitoConnectability::Query(const Extension* extension, + content::WebContents* web_contents, + const GURL& url, + base::OnceCallback<void(bool)> callback) { GURL origin = url.GetOrigin(); if (origin.is_empty()) { - callback.Run(false); + std::move(callback).Run(false); return; } if (IsInMap(extension, origin, allowed_origins_)) { - callback.Run(true); + std::move(callback).Run(true); return; } if (IsInMap(extension, origin, disallowed_origins_)) { - callback.Run(false); + std::move(callback).Run(false); return; } @@ -86,7 +85,7 @@ InfoBarService* infobar_service = InfoBarService::FromWebContents(web_contents); TabContext& tab_context = pending_origin[infobar_service]; - tab_context.callbacks.push_back(callback); + tab_context.callbacks.push_back(std::move(callback)); if (tab_context.infobar) { // This tab is already displaying an infobar for this extension and origin. return; @@ -125,9 +124,6 @@ IncognitoConnectability::TabContext::TabContext() : infobar(nullptr) { } -IncognitoConnectability::TabContext::TabContext(const TabContext& other) = - default; - IncognitoConnectability::TabContext::~TabContext() { } @@ -149,12 +145,13 @@ break; } - DCHECK(base::Contains(pending_origins_, make_pair(extension_id, origin))); - PendingOrigin& pending_origin = - pending_origins_[make_pair(extension_id, origin)]; + PendingOriginMap::iterator origin_it = + pending_origins_.find(make_pair(extension_id, origin)); + DCHECK(origin_it != pending_origins_.end()); + PendingOrigin& pending_origin = origin_it->second; DCHECK(base::Contains(pending_origin, infobar_service)); - std::vector<base::Callback<void(bool)>> callbacks; + std::vector<base::OnceCallback<void(bool)>> callbacks; if (response == ScopedAlertTracker::INTERACTIVE) { // No definitive answer for this extension and origin. Execute only the // callbacks associated with this tab. @@ -164,9 +161,9 @@ } else { // We have a definitive answer for this extension and origin. Close all // other infobars and answer all the callbacks. - for (const auto& map_entry : pending_origin) { + for (auto& map_entry : pending_origin) { InfoBarService* other_infobar_service = map_entry.first; - const TabContext& other_tab_context = map_entry.second; + TabContext& other_tab_context = map_entry.second; if (other_infobar_service != infobar_service) { // Disarm the delegate so that it doesn't think the infobar has been // dismissed. @@ -176,15 +173,17 @@ delegate->set_answered(); other_infobar_service->RemoveInfoBar(other_tab_context.infobar); } - callbacks.insert(callbacks.end(), other_tab_context.callbacks.begin(), - other_tab_context.callbacks.end()); + callbacks.insert( + callbacks.end(), + std::make_move_iterator(other_tab_context.callbacks.begin()), + std::make_move_iterator(other_tab_context.callbacks.end())); } - pending_origins_.erase(make_pair(extension_id, origin)); + pending_origins_.erase(origin_it); } DCHECK(!callbacks.empty()); - for (const auto& callback : callbacks) { - callback.Run(response == ScopedAlertTracker::ALWAYS_ALLOW); + for (auto& callback : callbacks) { + std::move(callback).Run(response == ScopedAlertTracker::ALWAYS_ALLOW); } }
diff --git a/chrome/browser/extensions/api/messaging/incognito_connectability.h b/chrome/browser/extensions/api/messaging/incognito_connectability.h index f0fe400..3dbf249 100644 --- a/chrome/browser/extensions/api/messaging/incognito_connectability.h +++ b/chrome/browser/extensions/api/messaging/incognito_connectability.h
@@ -66,20 +66,24 @@ void Query(const Extension* extension, content::WebContents* web_contents, const GURL& url, - const base::Callback<void(bool)>& callback); + base::OnceCallback<void(bool)> callback); private: struct TabContext { TabContext(); - TabContext(const TabContext& other); ~TabContext(); + // TabContext can't be copied since the callbacks are OnceCallback (and + // hence, move-only). + TabContext(const TabContext& other) = delete; + TabContext& operator=(const TabContext&) = delete; + // The infobar being shown in a given tab. The InfoBarService maintains // ownership of this object. This struct must always be destroyed before the // infobar it tracks. infobars::InfoBar* infobar; // Connectability queries outstanding on this infobar. - std::vector<base::Callback<void(bool)>> callbacks; + std::vector<base::OnceCallback<void(bool)>> callbacks; }; friend class BrowserContextKeyedAPIFactory<IncognitoConnectability>; @@ -87,10 +91,10 @@ explicit IncognitoConnectability(content::BrowserContext* context); ~IncognitoConnectability() override; - typedef std::map<std::string, std::set<GURL> > ExtensionToOriginsMap; - typedef std::pair<std::string, GURL> ExtensionOriginPair; - typedef std::map<InfoBarService*, TabContext> PendingOrigin; - typedef std::map<ExtensionOriginPair, PendingOrigin> PendingOriginMap; + using ExtensionToOriginsMap = std::map<std::string, std::set<GURL>>; + using ExtensionOriginPair = std::pair<std::string, GURL>; + using PendingOrigin = std::map<InfoBarService*, TabContext>; + using PendingOriginMap = std::map<ExtensionOriginPair, PendingOrigin>; // Called with the user's selection from the infobar. // |response == INTERACTIVE| indicates that the user closed the infobar
diff --git a/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc b/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc index 7455a98..28b905bd 100644 --- a/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc +++ b/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
@@ -136,6 +136,9 @@ // Crashes on Lacros only. http://crbug.com/1150133 #if BUILDFLAG(IS_CHROMEOS_LACROS) #define MAYBE_TabCurrentWindow DISABLED_TabCurrentWindow +// Flakes on Linux Tests (Release Only). http://crbug.com/1162432 +#elif defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(NDEBUG) +#define MAYBE_TabCurrentWindow DISABLED_TabCurrentWindow #else #define MAYBE_TabCurrentWindow TabCurrentWindow #endif
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc index a7504ba..d6e752c 100644 --- a/chrome/browser/extensions/tab_helper.cc +++ b/chrome/browser/extensions/tab_helper.cc
@@ -323,9 +323,15 @@ } void TabHelper::SetTabId(content::RenderFrameHost* render_frame_host) { - render_frame_host->Send(new ExtensionMsg_SetTabId( - render_frame_host->GetRoutingID(), - sessions::SessionTabHelper::IdForTab(web_contents()).id())); + // When this is called from the TabHelper constructor during WebContents + // creation, the renderer-side Frame object would not have been created yet. + // We should wait for RenderFrameCreated() to happen, to avoid sending this + // message twice. + if (render_frame_host->IsRenderFrameCreated()) { + render_frame_host->Send(new ExtensionMsg_SetTabId( + render_frame_host->GetRoutingID(), + sessions::SessionTabHelper::IdForTab(web_contents()).id())); + } } WEB_CONTENTS_USER_DATA_KEY_IMPL(TabHelper)
diff --git a/chrome/browser/feedback/feedback_util_chromeos.cc b/chrome/browser/feedback/feedback_util_chromeos.cc deleted file mode 100644 index f1b980f..0000000 --- a/chrome/browser/feedback/feedback_util_chromeos.cc +++ /dev/null
@@ -1,69 +0,0 @@ -// 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. - -#include "chrome/browser/feedback/feedback_util_chromeos.h" - -#include "base/bind.h" -#include "base/callback.h" -#include "chrome/browser/feedback/feedback_uploader_chrome.h" -#include "chrome/browser/feedback/feedback_uploader_factory_chrome.h" -#include "chrome/browser/feedback/system_logs/chrome_system_logs_fetcher.h" -#include "chrome/browser/profiles/profile.h" -#include "components/feedback/feedback_data.h" -#include "components/feedback/feedback_report.h" -#include "components/feedback/system_logs/system_logs_fetcher.h" -#include "extensions/browser/api/feedback_private/feedback_private_api.h" -#include "extensions/browser/api/feedback_private/feedback_service.h" - -using feedback::FeedbackData; - -namespace feedback_util { - -namespace { - -extensions::FeedbackService* GetFeedbackService(Profile* profile) { - return extensions::FeedbackPrivateAPI::GetFactoryInstance() - ->Get(profile) - ->GetService(); -} - -void OnGetSystemInformation( - Profile* profile, - const std::string& description, - const SendSysLogFeedbackCallback& callback, - bool send_tab_titles, - std::unique_ptr<system_logs::SystemLogsResponse> sys_info) { - scoped_refptr<FeedbackData> feedback_data = - base::MakeRefCounted<FeedbackData>( - feedback::FeedbackUploaderFactoryChrome::GetForBrowserContext( - profile)); - - feedback_data->set_context(profile); - feedback_data->set_description(description); - if (sys_info) - feedback_data->AddLogs(std::move(*sys_info)); - - if (!send_tab_titles) { - feedback_data->RemoveLog( - feedback::FeedbackReport::kMemUsageWithTabTitlesKey); - } - feedback_data->CompressSystemInfo(); - - GetFeedbackService(profile)->SendFeedback(feedback_data, callback); -} - -} // namespace - -void SendSysLogFeedback(Profile* profile, - const std::string& description, - const SendSysLogFeedbackCallback& callback, - bool send_tab_titles) { - // |fetcher| deletes itself after calling its callback. - system_logs::SystemLogsFetcher* fetcher = - system_logs::BuildChromeSystemLogsFetcher(/*scrub_data=*/true); - fetcher->Fetch(base::BindOnce(&OnGetSystemInformation, profile, description, - callback, send_tab_titles)); -} - -} // namespace feedback_util
diff --git a/chrome/browser/feedback/feedback_util_chromeos.h b/chrome/browser/feedback/feedback_util_chromeos.h deleted file mode 100644 index cffc512..0000000 --- a/chrome/browser/feedback/feedback_util_chromeos.h +++ /dev/null
@@ -1,28 +0,0 @@ -// 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. - -#ifndef CHROME_BROWSER_FEEDBACK_FEEDBACK_UTIL_CHROMEOS_H_ -#define CHROME_BROWSER_FEEDBACK_FEEDBACK_UTIL_CHROMEOS_H_ - -#include <string> - -#include "base/callback_forward.h" -#include "base/memory/ref_counted.h" - -class Profile; - -namespace feedback_util { - -// Sends a system log feedback from the given |profile| with the -// given |description|. |callback| will be invoked when the feedback is sent. -// If |send_tab_titles| is true, include open tab titles in the report. -using SendSysLogFeedbackCallback = base::RepeatingCallback<void(bool)>; -void SendSysLogFeedback(Profile* profile, - const std::string& description, - const SendSysLogFeedbackCallback& callback, - bool send_tab_titles); - -} // namespace feedback_util - -#endif // CHROME_BROWSER_FEEDBACK_FEEDBACK_UTIL_CHROMEOS_H_
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index dd644bb..d422b89b 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -3101,6 +3101,11 @@ "expiry_milestone": 89 }, { + "name": "ios-persist-crash-restore-infobar", + "owners": [ "thegreenfrog", "bling-flags@google.com" ], + "expiry_milestone": 91 + }, + { "name": "ios-shared-highlighting-color-change", "owners": [ "cheickcisse" ], "expiry_milestone": 92
diff --git a/chrome/browser/login_detection/login_detection_browsertest.cc b/chrome/browser/login_detection/login_detection_browsertest.cc index 50764072..c4892d1 100644 --- a/chrome/browser/login_detection/login_detection_browsertest.cc +++ b/chrome/browser/login_detection/login_detection_browsertest.cc
@@ -16,6 +16,7 @@ #include "components/ukm/test_ukm_recorder.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gtest/include/gtest/gtest.h" @@ -23,7 +24,8 @@ class LoginDetectionBrowserTest : public InProcessBrowserTest { public: - LoginDetectionBrowserTest() { + LoginDetectionBrowserTest() + : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) { scoped_feature_list_.InitWithFeaturesAndParameters( {{kLoginDetection, {}}, {site_isolation::features::kSiteIsolationForPasswordSites, {}}}, @@ -31,8 +33,8 @@ } void SetUpOnMainThread() override { - embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); - ASSERT_TRUE(embedded_test_server()->Start()); + https_test_server_.ServeFilesFromSourceDirectory("chrome/test/data"); + ASSERT_TRUE(https_test_server_.Start()); histogram_tester_ = std::make_unique<base::HistogramTester>(); } @@ -47,6 +49,7 @@ } protected: + net::EmbeddedTestServer https_test_server_; std::unique_ptr<base::HistogramTester> histogram_tester_; base::test::ScopedFeatureList scoped_feature_list_; }; @@ -54,8 +57,7 @@ // Verifies that sites saved manual passworded list are detected correctly. IN_PROC_BROWSER_TEST_F(LoginDetectionBrowserTest, NavigateToManualPasswordedSite) { - GURL test_url( - embedded_test_server()->GetURL("www.saved.com", "/title1.html")); + GURL test_url(https_test_server_.GetURL("www.saved.com", "/title1.html")); // Initial navigation will not be treated as no login. ui_test_utils::NavigateToURL(browser(), test_url); @@ -72,14 +74,49 @@ // Navigations to other subdomains of saved.com are treated as login too. ResetHistogramTester(); ui_test_utils::NavigateToURL( - browser(), - embedded_test_server()->GetURL("mobile.saved.com", "/title1.html")); + browser(), https_test_server_.GetURL("mobile.saved.com", "/title1.html")); ExpectLoginDetectionTypeMetric(LoginDetectionType::kPasswordEnteredLogin); ResetHistogramTester(); ui_test_utils::NavigateToURL( - browser(), embedded_test_server()->GetURL("saved.com", "/title1.html")); + browser(), https_test_server_.GetURL("saved.com", "/title1.html")); ExpectLoginDetectionTypeMetric(LoginDetectionType::kPasswordEnteredLogin); } +IN_PROC_BROWSER_TEST_F(LoginDetectionBrowserTest, PopUpBasedOAuthLoginFlow) { + // Navigate to the OAuth requestor. + ui_test_utils::NavigateToURL( + browser(), https_test_server_.GetURL("www.foo.com", "/title1.html")); + ExpectLoginDetectionTypeMetric(LoginDetectionType::kNoLogin); + ResetHistogramTester(); + + // Create a popup for the navigation flow. + content::WebContentsAddedObserver web_contents_added_observer; + ASSERT_TRUE(content::ExecuteScript( + browser()->tab_strip_model()->GetActiveWebContents(), + content::JsReplace( + "window.open($1, 'oauth_window', 'width=10,height=10');", + https_test_server_.GetURL("www.oauthprovider.com", + "/title2.html?client_id=123")))); + auto* popup_contents = web_contents_added_observer.GetWebContents(); + content::TestNavigationObserver observer(popup_contents); + observer.WaitForNavigationFinished(); + // This popup navigation is treated as not logged-in too. + ExpectLoginDetectionTypeMetric(LoginDetectionType::kNoLogin); + ResetHistogramTester(); + + // When the popup is closed, it will be detected as OAuth login. + content::WebContentsDestroyedWatcher destroyed_watcher(popup_contents); + EXPECT_TRUE(ExecJs(popup_contents, "window.close()")); + destroyed_watcher.Wait(); + ExpectLoginDetectionTypeMetric( + LoginDetectionType::kOauthPopUpFirstTimeLoginFlow); + ResetHistogramTester(); + + // Subsequent navigations to the OAuth requestor site will be treated as OAuth + ui_test_utils::NavigateToURL( + browser(), https_test_server_.GetURL("www.foo.com", "/title3.html")); + ExpectLoginDetectionTypeMetric(LoginDetectionType::kOauthLogin); +} + } // namespace login_detection
diff --git a/chrome/browser/login_detection/login_detection_tab_helper.cc b/chrome/browser/login_detection/login_detection_tab_helper.cc index c306f185..c5a2029 100644 --- a/chrome/browser/login_detection/login_detection_tab_helper.cc +++ b/chrome/browser/login_detection/login_detection_tab_helper.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/login_detection/login_detection_util.h" #include "chrome/browser/profiles/profile.h" #include "components/prefs/pref_service.h" +#include "components/ukm/content/source_url_recorder.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" @@ -55,7 +56,8 @@ LoginDetectionTabHelper::LoginDetectionTabHelper( content::WebContents* web_contents) - : content::WebContentsObserver(web_contents) { + : content::WebContentsObserver(web_contents), + oauth_login_detector_(std::make_unique<OAuthLoginDetector>()) { DCHECK(IsLoginDetectionFeatureEnabled()); } @@ -84,7 +86,7 @@ // Check if OAuth login on the site happened now. This check should happen // first before other checks since this could be a repeated OAuth login and // the time of login will be updated. - if (auto signedin_site = oauth_login_detector_.GetSuccessfulLoginFlowSite( + if (auto signedin_site = oauth_login_detector_->GetSuccessfulLoginFlowSite( prev_navigation_url, navigation_handle->GetRedirectChain())) { prefs::SaveSiteToOAuthSignedInList(GetPrefs(web_contents()), *signedin_site); @@ -104,6 +106,39 @@ navigation_handle->GetNextPageUkmSourceId()); } +void LoginDetectionTabHelper::DidOpenRequestedURL( + content::WebContents* new_contents, + content::RenderFrameHost* source_render_frame_host, + const GURL& url, + const content::Referrer& referrer, + WindowOpenDisposition disposition, + ui::PageTransition transition, + bool started_from_context_menu, + bool renderer_initiated) { + if (disposition != WindowOpenDisposition::NEW_POPUP) + return; + if (auto* new_tab_helper = + LoginDetectionTabHelper::FromWebContents(new_contents)) { + new_tab_helper->DidOpenAsPopUp(web_contents()->GetLastCommittedURL()); + } +} + +void LoginDetectionTabHelper::DidOpenAsPopUp( + const GURL& opener_navigation_url) { + oauth_login_detector_->DidOpenAsPopUp(opener_navigation_url); +} + +void LoginDetectionTabHelper::WebContentsDestroyed() { + if (auto signedin_site = oauth_login_detector_->GetPopUpLoginFlowSite()) { + RecordLoginDetectionMetrics( + LoginDetectionType::kOauthPopUpFirstTimeLoginFlow, + ukm::GetSourceIdForWebContentsDocument(web_contents())); + prefs::SaveSiteToOAuthSignedInList(GetPrefs(web_contents()), + *signedin_site); + } + oauth_login_detector_.reset(); +} + WEB_CONTENTS_USER_DATA_KEY_IMPL(LoginDetectionTabHelper) } // namespace login_detection
diff --git a/chrome/browser/login_detection/login_detection_tab_helper.h b/chrome/browser/login_detection/login_detection_tab_helper.h index ed8b4f1..a43f7f9 100644 --- a/chrome/browser/login_detection/login_detection_tab_helper.h +++ b/chrome/browser/login_detection/login_detection_tab_helper.h
@@ -33,12 +33,25 @@ explicit LoginDetectionTabHelper(content::WebContents* web_contents); + // Indicates this WebContents was opened as a popup, and the opener + // WebContents had the |opener_navigation_url|. + void DidOpenAsPopUp(const GURL& opener_navigation_url); + // content::WebContentsObserver. void DidFinishNavigation( content::NavigationHandle* navigation_handle) override; + void DidOpenRequestedURL(content::WebContents* new_contents, + content::RenderFrameHost* source_render_frame_host, + const GURL& url, + const content::Referrer& referrer, + WindowOpenDisposition disposition, + ui::PageTransition transition, + bool started_from_context_menu, + bool renderer_initiated) override; + void WebContentsDestroyed() override; // Detects successful OAuth login flows. - OAuthLoginDetector oauth_login_detector_; + std::unique_ptr<OAuthLoginDetector> oauth_login_detector_; WEB_CONTENTS_USER_DATA_KEY_DECL(); };
diff --git a/chrome/browser/login_detection/login_detection_type.h b/chrome/browser/login_detection/login_detection_type.h index b47b3b2e..dba46436 100644 --- a/chrome/browser/login_detection/login_detection_type.h +++ b/chrome/browser/login_detection/login_detection_type.h
@@ -36,7 +36,10 @@ // The site has credentials saved in the password manager. kPasswordManagerSavedSite, - kMaxValue = kPasswordManagerSavedSite + // Successful popup based OAuth login flow was detected. + kOauthPopUpFirstTimeLoginFlow, + + kMaxValue = kOauthPopUpFirstTimeLoginFlow }; } // namespace login_detection
diff --git a/chrome/browser/login_detection/oauth_login_detector.cc b/chrome/browser/login_detection/oauth_login_detector.cc index 0fecf6e..5abee39e5 100644 --- a/chrome/browser/login_detection/oauth_login_detector.cc +++ b/chrome/browser/login_detection/oauth_login_detector.cc
@@ -48,31 +48,66 @@ base::Optional<GURL> OAuthLoginDetector::GetSuccessfulLoginFlowSite( const GURL& prev_navigation_url, const std::vector<GURL>& redirect_chain) { - for (const auto& navigation_url : redirect_chain) { + for (size_t i = 0; i < redirect_chain.size(); i++) { + GURL navigation_url = redirect_chain[i]; // Allow login flows to be detected only on HTTPS pages. if (!navigation_url.SchemeIs(url::kHttpsScheme)) { - login_flow_info_ = base::nullopt; + login_flow_info_.reset(); return base::nullopt; } // Check for OAuth login completion. if (login_flow_info_ && CheckSuccessfulLoginCompletion(navigation_url)) { auto oauth_requestor_site = login_flow_info_->oauth_requestor_site; - login_flow_info_ = base::nullopt; + login_flow_info_.reset(); return oauth_requestor_site; } // Check for start of login flow. - if (!login_flow_info_ && prev_navigation_url.is_valid() && - prev_navigation_url.SchemeIsHTTPOrHTTPS() && + if (!login_flow_info_ && DoAllQueryParamsExist(login_flow_start_query_params_, navigation_url)) { - login_flow_info_ = - OAuthLoginFlowInfo(navigation_url, prev_navigation_url.GetOrigin()); + if (popup_opener_navigation_site_) { + // When this detector is opened for a popup window, treat the site of + // the popup opener window site as the OAuth requestor site. + login_flow_info_ = + OAuthLoginFlowInfo(navigation_url, *popup_opener_navigation_site_); + } else if (prev_navigation_url.is_valid() && + prev_navigation_url.SchemeIsHTTPOrHTTPS()) { + login_flow_info_ = + OAuthLoginFlowInfo(navigation_url, prev_navigation_url.GetOrigin()); + } else if (i != 0) { + // Treat the start of the redirect chain as the previous navigation URL. + // This allows detecting cases when a new window is opened to perform + // the OAuth login. + login_flow_info_ = + OAuthLoginFlowInfo(navigation_url, redirect_chain[0].GetOrigin()); + } } } + if (login_flow_info_) + login_flow_info_->count_navigations_since_login_flow_start++; return base::nullopt; } +void OAuthLoginDetector::DidOpenAsPopUp(const GURL& opener_navigation_url) { + if (opener_navigation_url.is_valid() && + opener_navigation_url.SchemeIs(url::kHttpsScheme)) { + popup_opener_navigation_site_ = opener_navigation_url.GetOrigin(); + } +} + +base::Optional<GURL> OAuthLoginDetector::GetPopUpLoginFlowSite() const { + // OAuth has never started. + if (!login_flow_info_) + return base::nullopt; + + // Only consider OAuth completion when this is a popup window. + if (!popup_opener_navigation_site_) + return base::nullopt; + + return login_flow_info_->oauth_requestor_site; +} + bool OAuthLoginDetector::CheckSuccessfulLoginCompletion( const GURL& navigation_url) { DCHECK(login_flow_info_.has_value()); @@ -83,26 +118,32 @@ GetOAuthLoginFlowStartToCompleteLimit()) { // Navigation limit reached - reset the state so that login flow was never // started. - login_flow_info_ = base::nullopt; + login_flow_info_.reset(); return false; } - std::string navigation_site = GetSiteNameForURL(navigation_url); // Check the OAuth login completion that returns the authorzation code and // token to the OAuth requestor site, does not happen for the OAuth provider // site. - if (GetSiteNameForURL(login_flow_info_->oauth_provider_site) == - navigation_site) { - login_flow_info_->count_navigations_since_login_flow_start++; + if (GetSiteNameForURL(navigation_url) == + GetSiteNameForURL(login_flow_info_->oauth_provider_site)) { return false; } - if (!DoAllQueryParamsExist(login_flow_complete_query_params_, - navigation_url)) { - login_flow_info_->count_navigations_since_login_flow_start++; - return false; + // Check for OAuth login completion parameters. This should not happen for the + // OAuth provider site, since this returns the authorzation code and token to + // the OAuth requestor site. + if (DoAllQueryParamsExist(login_flow_complete_query_params_, + navigation_url)) { + return true; } - return true; + + // PopUp based login completion flow should only navigate within the OAuth + // provider site. + if (popup_opener_navigation_site_) + login_flow_info_.reset(); + + return false; } } // namespace login_detection
diff --git a/chrome/browser/login_detection/oauth_login_detector.h b/chrome/browser/login_detection/oauth_login_detector.h index c8b9752..b036bd1 100644 --- a/chrome/browser/login_detection/oauth_login_detector.h +++ b/chrome/browser/login_detection/oauth_login_detector.h
@@ -16,15 +16,26 @@ // Detects successful OAuth login flow based on heuristics that observe certain // request parameters to determine start and completion of OAuth login flow. // +// OAuth Start: // Initially, there is a navigation to the OAuth requestor site, and that // triggers navigation to the OAuth provider site with certain request -// parameters to identify the OAuth start. +// parameters to identify the OAuth start. This start navigation could happen on +// the same page as the initial navigation or on a new popup window using +// window.open(), in which case DidOpenAsPopUp() is used to keep track of the +// requestor site. // -// The OAuth requestor authenticates the user and returns the authorization code +// OAuth Completion: +// The OAuth provider authenticates the user and returns the authorization code // or token to the requestor. This redirect request has certain reqest // parameters to identify as OAuth completion. Note that this requestor site can // be quite different from the OAuth requestor site seen in the initial // navigation. +// OAuth completion is different in the case of popup based login flow. The +// authorization code is sent via different means (for example postMessage()), +// and is not easily detectable. So, closing of the popup can be used as OAuth +// completion signal. These detections could be false positives, but are reduced +// by allowing only navigations to the OAuth provider site, and by limiting the +// number of navigations in the popup window. class OAuthLoginDetector { public: OAuthLoginDetector(); @@ -42,6 +53,14 @@ const GURL& prev_navigation_url, const std::vector<GURL>& redirect_chain); + // Returns the OAuth requestor site when popup based login flow is detected, + // otherwise base::nullopt is returned. + base::Optional<GURL> GetPopUpLoginFlowSite() const; + + // Indicates this detector is opened for a popup window, and the opener window + // had the |opener_navigation_url|. + void DidOpenAsPopUp(const GURL& opener_navigation_url); + private: struct OAuthLoginFlowInfo { OAuthLoginFlowInfo(const GURL& oauth_provider_site, @@ -76,6 +95,10 @@ // OAuth login flow. Created on the start of login flow, and destroyed when // the flow completes successfully or navigation limit is reached. base::Optional<OAuthLoginFlowInfo> login_flow_info_; + + // The site that opened this detector window as a popup. base::nullopt when + // this detector is not opened as a popup. + base::Optional<GURL> popup_opener_navigation_site_; }; } // namespace login_detection
diff --git a/chrome/browser/login_detection/oauth_login_detector_unittest.cc b/chrome/browser/login_detection/oauth_login_detector_unittest.cc index da865bc..9e0de6c4 100644 --- a/chrome/browser/login_detection/oauth_login_detector_unittest.cc +++ b/chrome/browser/login_detection/oauth_login_detector_unittest.cc
@@ -29,6 +29,7 @@ GURL("https://foo.com/login.html"), {GURL("https://oauth.com/authenticate?client_id=123"), GURL("https://foo.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); } TEST_F(OAuthLoginDetectorTest, OAuthLoginWithMultipleQueryParams) { @@ -38,6 +39,7 @@ {GURL("https://oauth.com/" "authenticate?client_id=123&redirect_uri=foo.com"), GURL("https://foo.com/redirect?scope=userinfo&code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); } TEST(OAuthLoginDetectorTestWithParams, OAuthLoginRequiringMultipleQueryParams) { @@ -55,6 +57,7 @@ "authenticate?client_id=123&redirect_uri=foo.com"), GURL("https://foo.com/redirect?scope=userinfo&code=secret")})); + EXPECT_FALSE(detector.GetPopUpLoginFlowSite()); } TEST(OAuthLoginDetectorTestWithParams, OAuthLoginMissingMultipleQueryParams) { @@ -69,6 +72,7 @@ GURL("https://foo.com/login.html"), {GURL("https://oauth.com/authenticate?client_id=123"), GURL("https://foo.com/redirect?code=secret")})); + EXPECT_FALSE(detector.GetPopUpLoginFlowSite()); } TEST_F(OAuthLoginDetectorTest, LoginNotDetectedForHTTP) { @@ -76,17 +80,36 @@ GURL("https://foo.com/login.html"), {GURL("http://oauth.com/authenticate?client_id=123"), GURL("http://foo.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); } // Test that small number of intermediate navigations within OAuth start and // completion are allowed. TEST_F(OAuthLoginDetectorTest, IntermediateNavigationsAfterOAuthStart) { - EXPECT_EQ(GURL("https://foo.com/"), - *oauth_login_detector_->GetSuccessfulLoginFlowSite( - GURL("https://foo.com/login.html"), - {GURL("https://oauth.com/authenticate?client_id=123"), - GURL("https://oauth.com/login"), - GURL("https://foo.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://foo.com/login.html"), + { + GURL("https://oauth.com/authenticate?client_id=123"), + GURL("https://oauth.com/login"), + })); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://oauth.com/login"), + { + GURL("https://oauth.com/login?username=123&password=123"), + GURL("https://oauth.com/relogin"), + })); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://oauth.com/relogin"), + { + GURL("https://oauth.com/login?username=123&password=123"), + GURL("https://oauth.com/relogin"), + })); + EXPECT_TRUE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://oauth.com/relogin"), + {GURL("https://oauth.com/login?username=123&password=123"), + GURL("https://oauth.com/loginsuccess"), + GURL("https://foo.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); } // Test that OAuth login is not allowed when too many intermediate navigations @@ -94,10 +117,48 @@ TEST_F(OAuthLoginDetectorTest, TooManyIntermediateNavigationsAfterOAuthStart) { EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( GURL("https://foo.com/login.html"), - {GURL("https://oauth.com/authenticate?client_id=123"), - GURL("https://oauth.com/login"), GURL("https://oauth.com/login"), - GURL("https://oauth.com/login"), GURL("https://oauth.com/login"), + { + GURL("https://oauth.com/authenticate?client_id=123"), + GURL("https://oauth.com/login"), + })); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://oauth.com/login"), + { + GURL("https://oauth.com/login?username=123&password=123"), + GURL("https://oauth.com/relogin"), + })); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://oauth.com/relogin"), + { + GURL("https://oauth.com/login?username=123&password=123"), + GURL("https://oauth.com/relogin"), + })); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://oauth.com/relogin"), + { + GURL("https://oauth.com/login?username=123&password=123"), + GURL("https://oauth.com/relogin"), + })); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://oauth.com/relogin"), + {GURL("https://oauth.com/login?username=123&password=123"), + GURL("https://oauth.com/loginsuccess"), GURL("https://foo.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); +} + +// Test that too many redirects are allowed within the same navigation. +TEST_F(OAuthLoginDetectorTest, RedirectNavigationsAfterOAuthStart) { + EXPECT_EQ(GURL("https://foo.com/"), + *oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL("https://foo.com/login.html"), + {GURL("https://oauth.com/authenticate?client_id=123"), + GURL("https://oauth.com/login"), + GURL("https://oauth.com/loginfailed"), + GURL("https://oauth.com/relogin"), + GURL("https://oauth.com/loginsuccess"), + GURL("https://foo.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); } // Test that OAuth login is detected when there are intermediate navigations to @@ -109,6 +170,7 @@ {GURL("https://oauth.com/authenticate?client_id=123"), GURL("https://bar.com/page.html"), GURL("https://foo.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); } // Test that OAuth requestor site is correctly detected when the site that @@ -119,6 +181,7 @@ GURL("https://foo.com/login.html"), {GURL("https://oauth.com/authenticate?client_id=123"), GURL("https://fooauth.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); } // Test that OAuth completion navigation does not happen for the OAuth provider @@ -128,6 +191,35 @@ GURL("https://foo.com/login.html"), {GURL("https://oauth.com/authenticate?client_id=123"), GURL("https://oauth.com/redirect?code=secret")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); +} + +TEST_F(OAuthLoginDetectorTest, PopUpLoginFlow) { + oauth_login_detector_->DidOpenAsPopUp(GURL("https://www.foo.com")); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL(), {GURL("https://oauth.com/authenticate?client_id=123")})); + EXPECT_EQ(GURL("https://www.foo.com/"), + *oauth_login_detector_->GetPopUpLoginFlowSite()); +} + +// Tests the popup flow where navigation to non-provider site happens, and login +// is not detected in that case. +TEST_F(OAuthLoginDetectorTest, PopUpLoginFlowNonOAuthProviderNavigations) { + oauth_login_detector_->DidOpenAsPopUp(GURL("https://www.foo.com")); + EXPECT_FALSE(oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL(), {GURL("https://oauth.com/authenticate?client_id=123"), + GURL("https://bar.com/non-oauth-provider.html")})); + EXPECT_FALSE(oauth_login_detector_->GetPopUpLoginFlowSite()); +} + +// Tests the login flow where a new window is opened to perform login. +TEST_F(OAuthLoginDetectorTest, NewWindowLoginFlow) { + EXPECT_EQ(GURL("https://www.foo.com/"), + *oauth_login_detector_->GetSuccessfulLoginFlowSite( + GURL() /* Empty URL due to the initial navigation*/, + {GURL("https://www.foo.com/login.html"), + GURL("https://oauth.com/authenticate?client_id=123"), + GURL("https://foo.com/redirect?code=secret")})); } } // namespace login_detection
diff --git a/chrome/browser/login_detection/password_store_sites_browsertest.cc b/chrome/browser/login_detection/password_store_sites_browsertest.cc index 9256d63..44726460 100644 --- a/chrome/browser/login_detection/password_store_sites_browsertest.cc +++ b/chrome/browser/login_detection/password_store_sites_browsertest.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/password_manager/account_password_store_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/sync/test/integration/passwords_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" @@ -25,14 +26,12 @@ scoped_refptr<password_manager::PasswordStore> GetProfilePasswordStore() { return PasswordStoreFactory::GetForProfile( - ProfileManager::GetActiveUserProfile(), - ServiceAccessType::EXPLICIT_ACCESS); + browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS); } scoped_refptr<password_manager::PasswordStore> GetAccountPasswordStore() { return AccountPasswordStoreFactory::GetForProfile( - ProfileManager::GetActiveUserProfile(), - ServiceAccessType::EXPLICIT_ACCESS); + browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS); } void AddLoginForSite(password_manager::PasswordStore* password_store, @@ -44,15 +43,15 @@ form.username_value = base::ASCIIToUTF16("my_username"); form.password_value = base::ASCIIToUTF16("my_password"); form.blocked_by_user = false; - password_store->AddLogin(form); - WaitForPasswordStoreUpdate(password_store); + passwords_helper::AddLogin(password_store, form); + base::RunLoop().RunUntilIdle(); } // Wait for the password store taskrunner to complete its event processing. void WaitForPasswordStoreUpdate( password_manager::PasswordStore* password_store) { base::WaitableEvent waitable_event( - base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); password_store->ScheduleTask(base::BindOnce( &base::WaitableEvent::Signal, base::Unretained(&waitable_event)));
diff --git a/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc b/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc index c346529..34d64791 100644 --- a/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc +++ b/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc
@@ -848,6 +848,8 @@ VariationsHttpHeadersBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitch( switches::kLoadingPredictorAllowLocalRequestForTesting); + command_line->AppendSwitch( + switches::kLoadingPredictorOptimizationGuideAllowNonGwsForTesting); } std::unique_ptr<content::TestNavigationManager> NavigateToURLAsync(
diff --git a/chrome/browser/net/load_timing_browsertest.cc b/chrome/browser/net/load_timing_browsertest.cc index 08a1e10..2829b9ec 100644 --- a/chrome/browser/net/load_timing_browsertest.cc +++ b/chrome/browser/net/load_timing_browsertest.cc
@@ -134,7 +134,7 @@ } // TODO(crbug.com/1128033): Flaky on ChromeOS and Mac. -#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC) +#if defined(OS_CHROMEOS) || defined(OS_MAC) #define MAYBE_HTTPS DISABLED_HTTPS #else #define MAYBE_HTTPS HTTPS
diff --git a/chrome/browser/net/profile_network_context_service_browsertest.cc b/chrome/browser/net/profile_network_context_service_browsertest.cc index 2c4e032..c089bcf 100644 --- a/chrome/browser/net/profile_network_context_service_browsertest.cc +++ b/chrome/browser/net/profile_network_context_service_browsertest.cc
@@ -55,6 +55,7 @@ #include "mojo/public/cpp/system/data_pipe_utils.h" #include "net/base/features.h" #include "net/base/load_flags.h" +#include "net/disk_cache/cache_util.h" #include "net/http/http_auth_preferences.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" @@ -92,6 +93,19 @@ return loader_factory_; } + void CheckDiskCacheSizeHistogramRecorded() { + std::string all_metrics; + do { + content::FetchHistogramsFromChildProcesses(); + metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); + all_metrics = histograms_.GetAllHistogramsRecorded(); + } while (std::string::npos == + all_metrics.find("HttpCache.MaxFileSizeOnInit")); + } + + base::HistogramTester histograms_; + protected: // The HttpCache is only created when a request is issued, thus we perform a // navigation to ensure that the http cache is initialized. @@ -143,6 +157,42 @@ /*in_memory=*/false, empty_relative_partition_path, &network_context_params, &cert_verifier_creation_params); EXPECT_EQ(0, network_context_params.http_cache_max_size); + + CheckDiskCacheSizeHistogramRecorded(); +} + +class DiskCachesizeExperiment : public ProfileNetworkContextServiceBrowsertest { + public: + DiskCachesizeExperiment() = default; + ~DiskCachesizeExperiment() override = default; + + void SetUp() override { + std::map<std::string, std::string> field_trial_params; + field_trial_params["percent_relative_size"] = "200"; + feature_list_.InitAndEnableFeatureWithParameters( + disk_cache::kChangeDiskCacheSizeExperiment, field_trial_params); + ProfileNetworkContextServiceBrowsertest::SetUp(); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(DiskCachesizeExperiment, ScaledCacheSize) { + // We don't have a great way of directly checking that the disk cache has the + // correct max size, but we can make sure that we set up our network context + // params correctly and that the histogram is recorded. + ProfileNetworkContextService* profile_network_context_service = + ProfileNetworkContextServiceFactory::GetForContext(browser()->profile()); + base::FilePath empty_relative_partition_path; + network::mojom::NetworkContextParams network_context_params; + network::mojom::CertVerifierCreationParams cert_verifier_creation_params; + profile_network_context_service->ConfigureNetworkContextParams( + /*in_memory=*/false, empty_relative_partition_path, + &network_context_params, &cert_verifier_creation_params); + EXPECT_EQ(0, network_context_params.http_cache_max_size); + + CheckDiskCacheSizeHistogramRecorded(); } IN_PROC_BROWSER_TEST_F(ProfileNetworkContextServiceBrowsertest, BrotliEnabled) {
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager.cc b/chrome/browser/optimization_guide/prediction/prediction_manager.cc index 61a48a6..2024b45 100644 --- a/chrome/browser/optimization_guide/prediction/prediction_manager.cc +++ b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
@@ -274,7 +274,7 @@ void PredictionManager::RegisterOptimizationTargets( const std::vector<proto::OptimizationTarget>& optimization_targets) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (optimization_targets.empty()) return; @@ -348,7 +348,7 @@ content::NavigationHandle* navigation_handle, const base::flat_map<proto::ClientModelFeature, float>& override_client_model_feature_values) const { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); proto::ClientModelFeature client_model_feature; if (!proto::ClientModelFeature_Parse(model_feature, &client_model_feature)) @@ -437,7 +437,7 @@ const base::flat_set<std::string>& model_features, const base::flat_map<proto::ClientModelFeature, float>& override_client_model_feature_values) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::flat_map<std::string, float> feature_map; if (model_features.size() == 0) return feature_map; @@ -479,7 +479,7 @@ proto::OptimizationTarget optimization_target, const base::flat_map<proto::ClientModelFeature, float>& override_client_model_feature_values) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(navigation_handle->GetURL().SchemeIsHTTPOrHTTPS()); OptimizationGuideNavigationData* navigation_data = @@ -558,7 +558,7 @@ void PredictionManager::OnEffectiveConnectionTypeChanged( net::EffectiveConnectionType effective_connection_type) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); current_effective_connection_type_ = effective_connection_type; } @@ -588,7 +588,7 @@ } void PredictionManager::FetchModelsAndHostModelFeatures() { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!ShouldFetchModelsAndHostModelFeatures(profile_)) return; @@ -689,7 +689,7 @@ void PredictionManager::OnModelsAndHostFeaturesFetched( base::Optional<std::unique_ptr<proto::GetModelsResponse>> get_models_response_data) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!get_models_response_data) return; @@ -713,7 +713,7 @@ void PredictionManager::UpdateHostModelFeatures( const google::protobuf::RepeatedPtrField<proto::HostModelFeatures>& host_model_features) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::unique_ptr<StoreUpdateData> host_model_features_update_data = StoreUpdateData::CreateHostModelFeaturesStoreUpdateData( /*update_time=*/clock_->Now() + kUpdateModelsAndFeaturesDelay, @@ -734,7 +734,7 @@ std::unique_ptr<PredictionModel> PredictionManager::CreatePredictionModel( const proto::PredictionModel& model) const { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return PredictionModel::Create( std::make_unique<proto::PredictionModel>(model)); } @@ -742,7 +742,7 @@ void PredictionManager::UpdatePredictionModels( const google::protobuf::RepeatedPtrField<proto::PredictionModel>& prediction_models) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::unique_ptr<StoreUpdateData> prediction_model_update_data = StoreUpdateData::CreatePredictionModelStoreUpdateData(); bool has_models_to_update = false; @@ -813,13 +813,13 @@ } void PredictionManager::OnPredictionModelsStored() { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); LOCAL_HISTOGRAM_BOOLEAN( "OptimizationGuide.PredictionManager.PredictionModelsStored", true); } void PredictionManager::OnHostModelFeaturesStored() { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); LOCAL_HISTOGRAM_BOOLEAN( "OptimizationGuide.PredictionManager.HostModelFeaturesStored", true); @@ -838,7 +838,7 @@ } void PredictionManager::OnStoreInitialized() { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); store_is_ready_ = true; // Only load host model features if there are optimization targets registered. @@ -855,7 +855,7 @@ } void PredictionManager::LoadHostModelFeatures() { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Load the host model features first, each prediction model requires the set // of host model features to be known before creation. model_and_features_store_->LoadAllHostModelFeatures( @@ -866,7 +866,7 @@ void PredictionManager::OnLoadHostModelFeatures( std::unique_ptr<std::vector<proto::HostModelFeatures>> all_host_model_features) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // If the store returns an empty vector of host model features, the store // contains no host model features. However, the load is otherwise complete // and prediction models can be loaded but they will require no host model @@ -887,7 +887,7 @@ void PredictionManager::LoadPredictionModels( const base::flat_set<proto::OptimizationTarget>& optimization_targets) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(host_model_features_loaded_); OptimizationGuideStore::EntryKey model_entry_key; @@ -911,7 +911,7 @@ void PredictionManager::OnLoadPredictionModel( std::unique_ptr<proto::PredictionModel> model) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!model) return; @@ -922,7 +922,7 @@ void PredictionManager::OnProcessLoadedModel( std::unique_ptr<proto::PredictionModel> model, bool success) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (success) { base::UmaHistogramSparse( "OptimizationGuide.PredictionModelLoadedVersion." + @@ -943,7 +943,7 @@ bool PredictionManager::ProcessAndStoreLoadedModel( const proto::PredictionModel& model) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!model.model_info().has_optimization_target()) return false; if (!model.model_info().has_version()) @@ -993,7 +993,7 @@ bool PredictionManager::ShouldUpdateStoredModelForTarget( proto::OptimizationTarget optimization_target, int64_t new_version) const { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto model_file_it = optimization_target_prediction_model_file_map_.find(optimization_target); @@ -1011,7 +1011,7 @@ void PredictionManager::StoreLoadedPredictionModelFile( proto::OptimizationTarget optimization_target, std::unique_ptr<PredictionModelFile> prediction_model_file) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); bool has_model_for_target = optimization_target_prediction_model_map_.contains(optimization_target); @@ -1036,7 +1036,7 @@ void PredictionManager::StoreLoadedPredictionModel( proto::OptimizationTarget optimization_target, std::unique_ptr<PredictionModel> prediction_model) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); bool has_model_file_for_target = optimization_target_prediction_model_file_map_.contains( @@ -1053,7 +1053,7 @@ bool PredictionManager::ProcessAndStoreHostModelFeatures( const proto::HostModelFeatures& host_model_features) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!host_model_features.has_host()) return false; if (host_model_features.model_features_size() == 0) @@ -1104,7 +1104,7 @@ } base::Time PredictionManager::GetLastFetchAttemptTime() const { - SEQUENCE_CHECKER(squence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return base::Time::FromDeltaSinceWindowsEpoch( base::TimeDelta::FromMicroseconds( pref_service_->GetInt64(prefs::kModelAndFeaturesLastFetchAttempt))); @@ -1133,7 +1133,7 @@ void PredictionManager::SetLastModelAndFeaturesFetchAttemptTime( base::Time last_attempt_time) { - SEQUENCE_CHECKER(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); pref_service_->SetInt64( prefs::kModelAndFeaturesLastFetchAttempt, last_attempt_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc index 51a379f..da0bb3f 100644 --- a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc +++ b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc
@@ -9,6 +9,7 @@ #include "base/optional.h" #include "base/path_service.h" #include "base/strings/utf_string_conversions.h" +#include "base/task/thread_pool/thread_pool_instance.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_path_override.h" @@ -135,7 +136,15 @@ download_manager()->OnDownloadFailed(guid); } - void RunUntilIdle() { task_environment()->RunUntilIdle(); } + void RunUntilIdle() { + task_environment()->RunUntilIdle(); + + // Wait for all delayed tasks to finish. + base::RunLoop run_loop; + base::ThreadPoolInstance::Get()->FlushAsyncForTesting( + run_loop.QuitClosure()); + run_loop.Run(); + } base::FilePath GetFilePathForDownloadFileStatus( PredictionModelDownloadFileStatus file_status) {
diff --git a/chrome/browser/predictors/loading_predictor_browsertest.cc b/chrome/browser/predictors/loading_predictor_browsertest.cc index c36d940..9ee6a0e 100644 --- a/chrome/browser/predictors/loading_predictor_browsertest.cc +++ b/chrome/browser/predictors/loading_predictor_browsertest.cc
@@ -1661,6 +1661,12 @@ } } + void SetUpCommandLine(base::CommandLine* cmd) override { + LoadingPredictorBrowserTest::SetUpCommandLine(cmd); + cmd->AppendSwitch( + switches::kLoadingPredictorOptimizationGuideAllowNonGwsForTesting); + } + bool IsLocalPredictionEnabled() const { return std::get<0>(GetParam()); } bool ShouldUseOptimizationGuidePredictions() const { @@ -2023,6 +2029,8 @@ } void SetUpCommandLine(base::CommandLine* command_line) override { + LoadingPredictorBrowserTestWithOptimizationGuide::SetUpCommandLine( + command_line); command_line->AppendSwitch( switches::kLoadingPredictorAllowLocalRequestForTesting); }
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper.cc b/chrome/browser/predictors/loading_predictor_tab_helper.cc index e6d88799..a975b14a 100644 --- a/chrome/browser/predictors/loading_predictor_tab_helper.cc +++ b/chrome/browser/predictors/loading_predictor_tab_helper.cc
@@ -7,6 +7,7 @@ #include <set> #include <string> +#include "base/command_line.h" #include "base/metrics/histogram_macros.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" @@ -14,8 +15,10 @@ #include "chrome/browser/predictors/loading_predictor_factory.h" #include "chrome/browser/predictors/predictors_enums.h" #include "chrome/browser/predictors/predictors_features.h" +#include "chrome/browser/predictors/predictors_switches.h" #include "chrome/browser/prefetch/no_state_prefetch/prerender_manager_factory.h" #include "chrome/browser/profiles/profile.h" +#include "components/google/core/common/google_util.h" #include "components/no_state_prefetch/browser/prerender_manager.h" #include "components/optimization_guide/optimization_guide_decider.h" #include "components/optimization_guide/proto/hints.pb.h" @@ -129,6 +132,11 @@ OptimizationHintsReceiveStatus status_; }; +bool IsFromGwsPageLoad(content::WebContents* web_contents) { + GURL previous_main_frame_url = web_contents->GetLastCommittedURL(); + return google_util::IsGoogleSearchUrl(previous_main_frame_url); +} + } // namespace LoadingPredictorTabHelper::LoadingPredictorTabHelper( @@ -181,6 +189,13 @@ if (!optimization_guide_decider_) return; + // Only consult Optimization Guide if it is a FromGWS page load. + if (!IsFromGwsPageLoad(web_contents()) && + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kLoadingPredictorOptimizationGuideAllowNonGwsForTesting)) { + return; + } + last_optimization_guide_prediction_ = OptimizationGuidePrediction(); last_optimization_guide_prediction_->decision = optimization_guide::OptimizationGuideDecision::kUnknown;
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc b/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc index 66054e3..4653c2a 100644 --- a/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc +++ b/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc
@@ -59,7 +59,6 @@ const LoadingPredictorConfig& config) : LoadingDataCollector(nullptr, nullptr, config) {} -// TODO(crbug/1035698): Migrate to TestOptimizationGuideDecider when provided. class MockOptimizationGuideKeyedService : public OptimizationGuideKeyedService { public: explicit MockOptimizationGuideKeyedService( @@ -339,14 +338,54 @@ {}); } + void NavigateToGwsInMainFrame() { + NavigateAndCommitInMainFrameAndVerifyMetrics( + "https://www.google.com/search?q=test"); + } + private: base::test::ScopedFeatureList scoped_feature_list_; }; // Tests that document on load completed is recorded with correct navigation +// id and that optimization guide is not consulted when not from GWS. +TEST_F(LoadingPredictorTabHelperOptimizationGuideDeciderTest, + DocumentOnLoadCompletedOptimizationGuideNotFromGWS) { + base::HistogramTester histogram_tester; + + EXPECT_CALL( + *mock_optimization_guide_keyed_service_, + CanApplyOptimizationAsync(_, optimization_guide::proto::LOADING_PREDICTOR, + base::test::IsNotNullCallback())) + .Times(0); + NavigateAndCommitInMainFrameAndVerifyMetrics("http://test.org"); + auto navigation_id = + CreateNavigationID(GetTabID(), "http://test.org", + web_contents()->GetMainFrame()->GetPageUkmSourceId()); + + // Adding subframe navigation to ensure that the committed main frame url will + // be used. + auto* subframe = + content::RenderFrameHostTester::For(main_rfh())->AppendChild("subframe"); + NavigateAndCommitInFrame("http://sub.test.org", subframe); + + const base::Optional<OptimizationGuidePrediction> + null_optimization_guide_prediction; + EXPECT_CALL(*mock_collector_, + RecordMainFrameLoadComplete(navigation_id, + null_optimization_guide_prediction)); + tab_helper_->DocumentOnLoadCompletedInMainFrame(); + + histogram_tester.ExpectTotalCount( + "LoadingPredictor.OptimizationHintsReceiveStatus", 0); +} + +// Tests that document on load completed is recorded with correct navigation // id and optimization guide prediction. TEST_F(LoadingPredictorTabHelperOptimizationGuideDeciderTest, DocumentOnLoadCompletedOptimizationGuide) { + NavigateToGwsInMainFrame(); + base::HistogramTester histogram_tester; optimization_guide::OptimizationMetadata optimization_metadata; @@ -398,6 +437,8 @@ // id and optimization guide prediction. TEST_F(LoadingPredictorTabHelperOptimizationGuideDeciderTest, DocumentOnLoadCompletedOptimizationGuidePredictionComesAfterCommit) { + NavigateToGwsInMainFrame(); + base::HistogramTester histogram_tester; optimization_guide::OptimizationMetadata optimization_metadata; @@ -457,6 +498,8 @@ // has redirects. TEST_F(LoadingPredictorTabHelperOptimizationGuideDeciderTest, DocumentOnLoadCompletedOptimizationGuidePredictionArrivedAfterRedirect) { + NavigateToGwsInMainFrame(); + base::HistogramTester histogram_tester; auto navigation = content::NavigationSimulator::CreateRendererInitiated( @@ -521,6 +564,8 @@ // id and optimization guide prediction when the prediction has not arrived. TEST_F(LoadingPredictorTabHelperOptimizationGuideDeciderTest, DocumentOnLoadCompletedOptimizationGuidePredictionHasNotArrived) { + NavigateToGwsInMainFrame(); + base::HistogramTester histogram_tester; EXPECT_CALL( @@ -557,6 +602,8 @@ TEST_F( LoadingPredictorTabHelperOptimizationGuideDeciderTest, DocumentOnLoadCompletedOptimizationGuidePredictionComesAfterDocumentOnLoad) { + NavigateToGwsInMainFrame(); + base::HistogramTester histogram_tester; optimization_guide::OptimizationMetadata optimization_metadata; @@ -608,6 +655,8 @@ // id and optimization guide prediction with no prediction.. TEST_F(LoadingPredictorTabHelperOptimizationGuideDeciderTest, DocumentOnLoadCompletedOptimizationGuidePredictionArrivedNoPrediction) { + NavigateToGwsInMainFrame(); + base::HistogramTester histogram_tester; // The problem here is that mock_collector_ is a strict mock, which expects @@ -652,6 +701,8 @@ TEST_F( LoadingPredictorTabHelperOptimizationGuideDeciderTest, DocumentOnLoadCompletedOptimizationGuidePredictionArrivedNoLoadingPredictorMetadata) { + NavigateToGwsInMainFrame(); + base::HistogramTester histogram_tester; // The problem here is that mock_collector_ is a strict mock, which expects @@ -714,6 +765,8 @@ // id and optimization guide prediction. TEST_F(LoadingPredictorTabHelperOptimizationGuideDeciderWithPrefetchTest, DocumentOnLoadCompletedOptimizationGuide) { + NavigateToGwsInMainFrame(); + base::HistogramTester histogram_tester; optimization_guide::OptimizationMetadata optimization_metadata;
diff --git a/chrome/browser/predictors/predictors_switches.cc b/chrome/browser/predictors/predictors_switches.cc index 058ad43..1d9759a 100644 --- a/chrome/browser/predictors/predictors_switches.cc +++ b/chrome/browser/predictors/predictors_switches.cc
@@ -11,4 +11,9 @@ const char kLoadingPredictorAllowLocalRequestForTesting[] = "loading-predictor-allow-local-request-for-testing"; +// Allows the loading predictor to consult the optimization guide on non-GWS +// page loads. +const char kLoadingPredictorOptimizationGuideAllowNonGwsForTesting[] = + "loading-predictor-optimization-guide-allow-non-gws"; + } // namespace switches
diff --git a/chrome/browser/predictors/predictors_switches.h b/chrome/browser/predictors/predictors_switches.h index 555f253..905d62f2 100644 --- a/chrome/browser/predictors/predictors_switches.h +++ b/chrome/browser/predictors/predictors_switches.h
@@ -9,6 +9,8 @@ extern const char kLoadingPredictorAllowLocalRequestForTesting[]; +extern const char kLoadingPredictorOptimizationGuideAllowNonGwsForTesting[]; + } // namespace switches #endif // CHROME_BROWSER_PREDICTORS_PREDICTORS_SWITCHES_H_
diff --git a/chrome/browser/profiles/profile_attributes_storage.cc b/chrome/browser/profiles/profile_attributes_storage.cc index 4103cbc..ed9eb11 100644 --- a/chrome/browser/profiles/profile_attributes_storage.cc +++ b/chrome/browser/profiles/profile_attributes_storage.cc
@@ -130,28 +130,32 @@ // their names. For ties, the profile path is compared next. class ProfileAttributesSortComparator { public: - explicit ProfileAttributesSortComparator(icu::Collator* collator); + ProfileAttributesSortComparator(icu::Collator* collator, bool use_local_name) + : collator_(collator), use_local_name_(use_local_name) {} + bool operator()(const ProfileAttributesEntry* const a, - const ProfileAttributesEntry* const b) const; + const ProfileAttributesEntry* const b) const { + UCollationResult result = base::i18n::CompareString16WithCollator( + *collator_, GetValue(a), GetValue(b)); + if (result != UCOL_EQUAL) + return result == UCOL_LESS; + + // If the names are the same, then compare the paths, which must be unique. + return a->GetPath().value() < b->GetPath().value(); + } + private: + base::string16 GetValue(const ProfileAttributesEntry* const entry) const { + if (use_local_name_) + return entry->GetLocalProfileName(); + + return entry->GetName(); + } + icu::Collator* collator_; + bool use_local_name_; }; -ProfileAttributesSortComparator::ProfileAttributesSortComparator( - icu::Collator* collator) : collator_(collator) {} - -bool ProfileAttributesSortComparator::operator()( - const ProfileAttributesEntry* const a, - const ProfileAttributesEntry* const b) const { - UCollationResult result = base::i18n::CompareString16WithCollator( - *collator_, a->GetName(), b->GetName()); - if (result != UCOL_EQUAL) - return result == UCOL_LESS; - - // If the names are the same, then compare the paths, which must be unique. - return a->GetPath().value() < b->GetPath().value(); -} - MultiProfileUserType GetMultiProfileUserType( const std::vector<ProfileAttributesEntry*>& entries) { DCHECK_GT(entries.size(), 0u); @@ -255,7 +259,8 @@ } std::vector<ProfileAttributesEntry*> -ProfileAttributesStorage::GetAllProfilesAttributesSortedByName() { +ProfileAttributesStorage::GetAllProfilesAttributesSorted( + bool use_local_profile_name) { std::vector<ProfileAttributesEntry*> ret = GetAllProfilesAttributes(); // Do not allocate the collator and sort if it is not necessary. if (ret.size() < 2) @@ -268,11 +273,22 @@ icu::Collator::createInstance(error_code)); DCHECK(U_SUCCESS(error_code)); - std::sort(ret.begin(), ret.end(), - ProfileAttributesSortComparator(collator.get())); + std::sort( + ret.begin(), ret.end(), + ProfileAttributesSortComparator(collator.get(), use_local_profile_name)); return ret; } +std::vector<ProfileAttributesEntry*> +ProfileAttributesStorage::GetAllProfilesAttributesSortedByName() { + return GetAllProfilesAttributesSorted(false); +} + +std::vector<ProfileAttributesEntry*> +ProfileAttributesStorage::GetAllProfilesAttributesSortedByLocalProfilName() { + return GetAllProfilesAttributesSorted(true); +} + base::string16 ProfileAttributesStorage::ChooseNameForNewProfile( size_t icon_index) const { base::string16 name;
diff --git a/chrome/browser/profiles/profile_attributes_storage.h b/chrome/browser/profiles/profile_attributes_storage.h index feb07458..55d65b88 100644 --- a/chrome/browser/profiles/profile_attributes_storage.h +++ b/chrome/browser/profiles/profile_attributes_storage.h
@@ -70,7 +70,10 @@ // Returns a vector containing one attributes entry per known profile. They // are not sorted in any particular order. std::vector<ProfileAttributesEntry*> GetAllProfilesAttributes(); + std::vector<ProfileAttributesEntry*> GetAllProfilesAttributesSortedByName(); + std::vector<ProfileAttributesEntry*> + GetAllProfilesAttributesSortedByLocalProfilName(); // Populates |entry| with the data for the profile at |path| and returns true // if the operation is successful and |entry| can be used. Returns false @@ -197,6 +200,9 @@ scoped_refptr<base::SequencedTaskRunner> file_task_runner_; private: + std::vector<ProfileAttributesEntry*> GetAllProfilesAttributesSorted( + bool use_local_profile_name); + // Called when the picture given by |key| has been loaded from disk and // decoded into |image|. void OnAvatarPictureLoaded(const base::FilePath& profile_path,
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_en-GB.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_en-GB.xtb index 413e98f..3ba3d8fc 100644 --- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_en-GB.xtb +++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_en-GB.xtb
@@ -356,7 +356,7 @@ <translation id="3458865416877308321"><ph name="NAME" />, switch off</translation> <translation id="3466530247399808663">An invalid key press</translation> <translation id="3468959318854349468">No title</translation> -<translation id="3469413619751135069">Pale Green</translation> +<translation id="3469413619751135069">Pale green</translation> <translation id="3490765818161916458">List grid</translation> <translation id="3492609944033322585">{COUNT,plural, =1{right bracket}other{# right brackets}}</translation> <translation id="3494946239022273294">mnuitm</translation>
diff --git a/chrome/browser/resources/chromeos/login/debug/debug.js b/chrome/browser/resources/chromeos/login/debug/debug.js index 33c04221..11cbb1a 100644 --- a/chrome/browser/resources/chromeos/login/debug/debug.js +++ b/chrome/browser/resources/chromeos/login/debug/debug.js
@@ -885,7 +885,7 @@ }], }, { - id: 'multidevice-setup', + id: 'multidevice-setup-screen', kind: ScreenKind.NORMAL, }, {
diff --git a/chrome/browser/resources/chromeos/login/enterprise_enrollment.js b/chrome/browser/resources/chromeos/login/enterprise_enrollment.js index 5a384210..2d1be6c 100644 --- a/chrome/browser/resources/chromeos/login/enterprise_enrollment.js +++ b/chrome/browser/resources/chromeos/login/enterprise_enrollment.js
@@ -6,6 +6,8 @@ * @fileoverview Polymer element for Enterprise Enrollment screen. */ +(function() { + /* Code which is embedded inside of the webview. See below for details. /** @const */ var INJECTED_WEBVIEW_SCRIPT = String.raw` @@ -35,6 +37,14 @@ ACTIVE_DIRECTORY_JOIN_ERROR: 'active-directory-join-error', }; +/** + * The same steps as in offline-ad-login-element. + */ +const adLoginStep = { + UNLOCK: 'unlock', + CREDS: 'creds', +}; + Polymer({ is: 'enterprise-enrollment-element', @@ -392,6 +402,7 @@ if (step === ENROLLMENT_STEP.AD_JOIN) { this.$.adJoinUI.disabled = false; this.$.adJoinUI.loading = false; + this.$.adJoinUI.focus(); } this.isCancelDisabled = (step === ENROLLMENT_STEP.SIGNIN && !this.isManualEnrollment_) || @@ -418,7 +429,11 @@ this.$.adJoinUI.machineName = machineName; this.$.adJoinUI.userName = userName; this.$.adJoinUI.errorState = errorState; - this.$.adJoinUI.unlockPasswordStep = showUnlockConfig; + if (showUnlockConfig) { + this.$.adJoinUI.setUIStep(adLoginStep.UNLOCK); + } else { + this.$.adJoinUI.setUIStep(adLoginStep.CREDS); + } }, /** @@ -428,7 +443,8 @@ setAdJoinConfiguration(options) { this.$.adJoinUI.disabled = false; this.$.adJoinUI.setJoinConfigurationOptions(options); - this.$.adJoinUI.unlockPasswordStep = false; + this.$.adJoinUI.setUIStep(adLoginStep.CREDS); + this.$.adJoinUI.focus(); }, /** @@ -593,3 +609,4 @@ return authenticatorDialogDisplayed || isSamlSsoVisible; }, }); +})();
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.css b/chrome/browser/resources/chromeos/login/offline_ad_login.css deleted file mode 100644 index c6c941d6..0000000 --- a/chrome/browser/resources/chromeos/login/offline_ad_login.css +++ /dev/null
@@ -1,74 +0,0 @@ -/* Copyright 2018 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Offline AD login page mostly uses styles from offline_gaia.css. - * Only changes to offline gaia style are defined here. - */ - -.select-title { - color: var(--google-grey-900); - font-size: 13px; - line-height: var(--subtitle-line-height); - padding-right: 16px; -} - -oobe-dialog [slot='subtitle'] { - color: rgb(95, 99, 104); - padding-bottom: 64px; - padding-top: 2px; -} - -.encryption-subtitle { - color: --google-grey-600; - padding-bottom: 9px; - padding-top: 9px; -} - -.encryption-select-row { - padding-bottom: 24px; -} - -iron-icon[icon='cr:warning'] { - color: var(--google-yellow-500); - margin-bottom: 0; - margin-inline-end: 15px; - margin-inline-start: 0; - margin-top: 0; -} - -.select-divider-line { - border-bottom: 1px solid #ebebeb; - display: block; - margin-inline-end: 0; - margin-inline-start: 0; - position: relative; -} - -.top-line { - margin-bottom: 8px; -} - -.bottom-line { - margin-bottom: 26px; - margin-top: 8px; -} - -.md-select { - height: 32px; - width: 240px; -} - -#moreOptionsDlg [slot='title'] { - padding-bottom: 18px; - padding-top: 20px; -} - -#moreOptionsDlg { - --cr-input-error-display: none; -} - -#orgUnitInput { - padding-bottom: 28px; -}
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.html b/chrome/browser/resources/chromeos/login/offline_ad_login.html index e696960e..77d04fe 100644 --- a/chrome/browser/resources/chromeos/login/offline_ad_login.html +++ b/chrome/browser/resources/chromeos/login/offline_ad_login.html
@@ -21,7 +21,6 @@ Attributes: 'isDomainJoin' - Whether the screen is for domain join. For the join it contains some specific elements (e.g. machine name input). - 'unlockPasswordStep' - Whether the unlock password step should be shown. 'realm' - The AD realm the device is managed by. 'userRealm' - Autocomplete realm for the user input. 'disabled' - Whether the UI disabled. Could be used to disable the UI @@ -50,9 +49,73 @@ <dom-module id="offline-ad-login-element"> <template> <style include="md-select oobe-dialog-host"> + .select-title { + color: var(--google-grey-900); + font-size: 13px; + line-height: var(--subtitle-line-height); + padding-inline-end: 16px; + } + + oobe-dialog[slot='subtitle'] { + color: rgb(95, 99, 104); + padding-bottom: 64px; + padding-top: 2px; + } + + .encryption-subtitle { + color: --google-grey-600; + padding-bottom: 9px; + padding-top: 9px; + } + + .encryption-select-row { + padding-bottom: 24px; + } + + iron-icon[icon='cr:warning'] { + color: var(--google-yellow-500); + margin-bottom: 0; + margin-inline-end: 15px; + margin-inline-start: 0; + margin-top: 0; + } + + .select-divider-line { + border-bottom: 1px solid #ebebeb; + display: block; + margin-inline-end: 0; + margin-inline-start: 0; + position: relative; + } + + .top-line { + margin-bottom: 8px; + } + + .bottom-line { + margin-bottom: 26px; + margin-top: 8px; + } + + .md-select { + height: 32px; + width: 240px; + } + + #moreOptionsDlg[slot='title'] { + padding-bottom: 18px; + padding-top: 20px; + } + + #moreOptionsDlg { + --cr-input-error-display: none; + } + + #orgUnitInput { + padding-bottom: 28px; + } </style> - <link rel="stylesheet" href="offline_ad_login.css"> - <oobe-dialog id="unlockStep" hidden="[[!unlockPasswordStep]]" + <oobe-dialog id="unlockStep" for-step="unlock" title-key="adUnlockTitle" subtitle-key="adUnlockSubtitle" aria-label$="[[i18nDynamic(locale, adWelcomeMessagekey)]]" has-buttons> @@ -75,7 +138,7 @@ on-click="onUnlockPasswordEntered_"></oobe-next-button> </div> </oobe-dialog> - <oobe-dialog id="credsStep" hidden="[[unlockPasswordStep]]" + <oobe-dialog id="credsStep" for-step="creds" title-key="[[adWelcomeMessageKey]]" aria-label$="[[i18nDynamic(locale, adWelcomeMessagekey)]]" has-buttons> <hd-iron-icon slot="oobe-icon" hidden="[[!isDomainJoin]]"
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.js b/chrome/browser/resources/chromeos/login/offline_ad_login.js index d5f4c765..6788ef753 100644 --- a/chrome/browser/resources/chromeos/login/offline_ad_login.js +++ b/chrome/browser/resources/chromeos/login/offline_ad_login.js
@@ -6,6 +6,9 @@ * @fileoverview Polymer element for displaying AD domain joining and AD * Authenticate user screens. */ + +(function() { + // Possible error states of the screen. Must be in the same order as // ActiveDirectoryErrorState enum values. /** @enum {number} */ var ACTIVE_DIRECTORY_ERROR_STATE = { @@ -17,6 +20,11 @@ BAD_UNLOCK_PASSWORD: 5, }; +const adLoginStep = { + UNLOCK: 'unlock', + CREDS: 'creds', +}; + var DEFAULT_ENCRYPTION_TYPES = 'strong'; /** @typedef {Iterable<{value: string, title: string, selected: boolean, @@ -32,7 +40,7 @@ Polymer({ is: 'offline-ad-login-element', - behaviors: [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior], + behaviors: [OobeI18nBehavior, LoginScreenBehavior, MultiStepBehavior], EXTERNAL_API: [ 'reset', @@ -53,10 +61,6 @@ */ isDomainJoin: {type: Boolean, value: false}, /** - * Whether the unlock option should be shown. - */ - unlockPasswordStep: {type: Boolean, value: false, observer: 'focus'}, - /** * The kerberos realm (AD Domain), the machine is part of. */ realm: {type: String}, @@ -138,6 +142,12 @@ 'calculateUserInputValue_(selectedConfigOption_)', ], + UI_STEPS: adLoginStep, + + defaultUIStep() { + return adLoginStep.CREDS; + }, + /** @private Used for 'More options' dialog. */ storedOrgUnit_: String, @@ -231,7 +241,7 @@ }, focus() { - if (this.unlockPasswordStep) { + if (this.uiStep === adLoginStep.UNLOCK) { this.$.unlockPasswordInput.focus(); } else if (this.isDomainJoin && !this.$.machineNameInput.value) { this.$.machineNameInput.focus(); @@ -383,14 +393,16 @@ /** @private */ onSkipClicked_() { this.$.backToUnlockButton.hidden = false; - this.unlockPasswordStep = false; + this.setUIStep(adLoginStep.CREDS); + this.focus(); }, /** @private */ onBackToUnlock_() { if (this.disabled) return; - this.unlockPasswordStep = true; + this.setUIStep(adLoginStep.UNLOCK); + this.focus(); }, /** @@ -581,3 +593,4 @@ this.$.credsStep.classList.remove('full-disabled'); }, }); +})();
diff --git a/chrome/browser/resources/chromeos/login/oobe_supervision_transition.css b/chrome/browser/resources/chromeos/login/oobe_supervision_transition.css deleted file mode 100644 index 13e6be1..0000000 --- a/chrome/browser/resources/chromeos/login/oobe_supervision_transition.css +++ /dev/null
@@ -1,18 +0,0 @@ -/* Copyright 2018 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -paper-progress { - --paper-progress-active-color: rgb(66, 133, 244); - --paper-progress-container-color: rgb(206, 224, 252); - --paper-progress-secondary-color: rgb(66, 133, 244); - display: block; - height: 3px; - padding: 40px 0 0 0; - width: 100%; -} - -.supervision-icon { - --iron-icon-height: 32px; - --iron-icon-width: 32px; -}
diff --git a/chrome/browser/resources/chromeos/login/oobe_supervision_transition.html b/chrome/browser/resources/chromeos/login/oobe_supervision_transition.html index 6c5fa5e..0512c693 100644 --- a/chrome/browser/resources/chromeos/login/oobe_supervision_transition.html +++ b/chrome/browser/resources/chromeos/login/oobe_supervision_transition.html
@@ -9,11 +9,25 @@ <dom-module id="supervision-transition-element"> <template> - <style include="oobe-dialog-host"></style> - <link rel="stylesheet" href="oobe_supervision_transition.css"> + <style include="oobe-dialog-host"> + paper-progress { + --paper-progress-active-color: rgb(66, 133, 244); /*#4285F4*/ + --paper-progress-container-color: rgb(206, 224, 252); /*#CEE0FC*/ + --paper-progress-secondary-color: rgb(66, 133, 244); /*#4285F4*/ + display: block; + height: 3px; + padding: 40px 0 0 0; + width: 100%; + } + + .supervision-icon { + --iron-icon-height: 32px; + --iron-icon-width: 32px; + } + </style> <oobe-dialog id="supervisionTransitionDialog" role="alert" aria-label$="[[getDialogA11yTitle_(locale, isRemovingSupervision_)]]" - subtitle-key="supervisionTransitionIntroMessage"> + subtitle-key="supervisionTransitionIntroMessage" for-step="progress"> <iron-icon src="chrome://oobe/supervision_icon.png" slot="oobe-icon" class="supervision-icon" aria-hidden="true"> </iron-icon> @@ -34,13 +48,15 @@ title-key="supervisionTransitionErrorTitle" subtitle-key="supervisionTransitionErrorMessage" aria-label$="[[i18nDynamic(locale,'supervisionTransitionErrorTitle')]]" - has-buttons hidden> + has-buttons for-step="error"> <iron-icon src="chrome://oobe/supervision_icon.png" slot="oobe-icon" aria-hidden="true"> </iron-icon> <div slot="bottom-buttons" class="layout horizontal end-justified"> <oobe-text-button id="accept-button" on-click="onAcceptAndContinue_" - text-key="supervisionTransitionButton" inverse></oobe-text-button> + text-key="supervisionTransitionButton" class="focus-on-show" + inverse> + </oobe-text-button> </div> </oobe-dialog> </template>
diff --git a/chrome/browser/resources/chromeos/login/oobe_supervision_transition.js b/chrome/browser/resources/chromeos/login/oobe_supervision_transition.js index 6835688..86b3984d 100644 --- a/chrome/browser/resources/chromeos/login/oobe_supervision_transition.js +++ b/chrome/browser/resources/chromeos/login/oobe_supervision_transition.js
@@ -7,10 +7,17 @@ * transition screen. */ +(function() { + +const UIState = { + PROGRESS: 'progress', + ERROR: 'error', +}; + Polymer({ is: 'supervision-transition-element', - behaviors: [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior], + behaviors: [OobeI18nBehavior, LoginScreenBehavior, MultiStepBehavior], properties: { /** @@ -19,6 +26,12 @@ isRemovingSupervision_: Boolean, }, + UI_STEPS: UIState, + + defaultUIStep() { + return UIState.PROGRESS; + }, + ready() { this.initializeLoginScreen('SupervisionTransitionScreen', { resetAllowed: false, @@ -48,10 +61,7 @@ /** @private */ showSupervisionTransitionFailedScreen_() { - this.$.supervisionTransitionDialog.hidden = true; - this.$.supervisionTransitionErrorDialog.hidden = false; - this.$.supervisionTransitionErrorDialog.show(); - this.$.supervisionTransitionErrorDialog.focus(); + this.setUIStep(UIState.ERROR); }, /** @@ -63,3 +73,4 @@ chrome.send('finishSupervisionTransition'); }, }); +})();
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/quick_action_controller_form.js b/chrome/browser/resources/chromeos/multidevice_internals/quick_action_controller_form.js index 618c994..697a3b2c 100644 --- a/chrome/browser/resources/chromeos/multidevice_internals/quick_action_controller_form.js +++ b/chrome/browser/resources/chromeos/multidevice_internals/quick_action_controller_form.js
@@ -49,6 +49,7 @@ TetherStatus.CONNECTION_AVAILABLE, TetherStatus.CONNECTING, TetherStatus.CONNECTED, + TetherStatus.NO_RECEPTION, ]; }, readonly: true,
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/types.js b/chrome/browser/resources/chromeos/multidevice_internals/types.js index 1eca6a0..443f6e8 100644 --- a/chrome/browser/resources/chromeos/multidevice_internals/types.js +++ b/chrome/browser/resources/chromeos/multidevice_internals/types.js
@@ -212,6 +212,7 @@ CONNECTION_AVAILABLE: 2, CONNECTING: 3, CONNECTED: 4, + NO_RECEPTION: 5, }; /** @@ -224,6 +225,7 @@ [TetherStatus.CONNECTION_AVAILABLE, 'Connection available'], [TetherStatus.CONNECTING, 'Connecting'], [TetherStatus.CONNECTED, 'Connected'], + [TetherStatus.NO_RECEPTION, 'No reception'], ]); /**
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.html b/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.html index 6ec772da..0353766 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.html +++ b/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.html
@@ -392,8 +392,7 @@ <cr-toggle class="contact-toggle" checked="{{item.checked}}" disabled="[[!isVisibility_( - selectedVisibility,'some')]]" - on-click="syncContactToggleState_"> + selectedVisibility,'some')]]"> </cr-toggle> </template> </div>
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.js b/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.js index 81af2cf..c42f209 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.js +++ b/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.js
@@ -140,7 +140,6 @@ observers: [ 'settingsChanged_(settings.visibility)', - 'selectedVisibilityChanged_(selectedVisibility)', ], /** @override */ @@ -268,23 +267,6 @@ }, /** - * Sync the latest contact toggle states and update allowedContacts through - * the contact manager. - * @private - */ - syncContactToggleState_() { - const allowedContacts = []; - if (this.contacts) { - for (const contact of this.contacts) { - if (contact.checked) { - allowedContacts.push(contact.id); - } - } - } - this.contactManager_.setAllowedContacts(allowedContacts); - }, - - /** * TODO(crbug.com/1128256): Remove after specs/a11y. * Call from the JS debug console to test scrolling. * @param {number} numContacts @@ -342,17 +324,6 @@ }, /** - * @param {string} selectedVisibility - * @private - */ - selectedVisibilityChanged_(selectedVisibility) { - const visibility = visibilityStringToValue(this.selectedVisibility); - if (visibility) { - this.set('settings.visibility', visibility); - } - }, - - /** * @param {string} contactsState * @return {boolean} true when the radio group should be disabled * @private @@ -532,5 +503,26 @@ return ''; } }, + + /** + * Save visibility setting and sync allowed contacts with contact manager. + * @public + */ + saveVisibilityAndAllowedContacts() { + const visibility = visibilityStringToValue(this.selectedVisibility); + if (visibility) { + this.set('settings.visibility', visibility); + } + + const allowedContacts = []; + if (this.contacts) { + for (const contact of this.contacts) { + if (contact.checked) { + allowedContacts.push(contact.id); + } + } + } + this.contactManager_.setAllowedContacts(allowedContacts); + }, }); })();
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js b/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js index 7c85e2dc..da0a429 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js +++ b/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js
@@ -33,6 +33,9 @@ listeners: {'next': 'onNext_', 'manage-contacts': 'onManageContacts_'}, onNext_() { + const contactVisibility = /** @type {NearbyContactVisibilityElement} */ + (this.$.contactVisibility); + contactVisibility.saveVisibilityAndAllowedContacts(); this.set('settings.enabled', true); this.fire('onboarding-complete'); },
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html index 41b101f..4bd7d285 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html
@@ -261,10 +261,13 @@ </settings-toggle-button> </template> <!-- SIM Info (Cellular only). --> + <!-- TODO(crbug/1093185): Remove when updatedCellularActivationUi + flag launches --> <template is="dom-if" if="[[showCellularSim_(managedProperties_)]]" restamp> <div class="settings-box single-column stretch"> - <network-siminfo device-state="[[deviceState_]]"> + <network-siminfo id="cellularSimInfo" + device-state="[[deviceState_]]"> </network-siminfo> </div> </template> @@ -299,6 +302,14 @@ <!-- Advanced section --> <iron-collapse opened="[[advancedExpanded_]]"> <div class="settings-box single-column stretch indented first"> + <!-- SIM Info (Cellular only). --> + <template is="dom-if" + if="[[showCellularSimUpdatedUi_(managedProperties_)]]" restamp> + <div class="single-column stretch"> + <network-siminfo device-state="[[deviceState_]]"> + </network-siminfo> + </div> + </template> <!-- Metered (WiFi and Cellular only). --> <template is="dom-if" if="[[showMetered_(managedProperties_, showMeteredToggle_)]]">
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.js index 442e40e..03f9922 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.js +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.js
@@ -191,6 +191,14 @@ }, /** @private */ + isUpdatedCellularUiEnabled_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('updatedCellularActivationUi'); + } + }, + + /** @private */ advancedExpanded_: Boolean, /** @private */ @@ -2114,13 +2122,26 @@ * @private */ showCellularSim_(managedProperties) { - return !!managedProperties && + return !!managedProperties && !this.isUpdatedCellularUiEnabled_ && managedProperties.type === chromeos.networkConfig.mojom.NetworkType.kCellular && managedProperties.typeProperties.cellular.family !== 'CDMA'; }, /** + * @param {!chromeos.networkConfig.mojom.ManagedProperties} managedProperties + * @return {boolean} + * @private + */ + showCellularSimUpdatedUi_(managedProperties) { + return !!managedProperties && this.isUpdatedCellularUiEnabled_ && + managedProperties.type === + chromeos.networkConfig.mojom.NetworkType.kCellular && + managedProperties.typeProperties.cellular.family !== 'CDMA'; + }, + + + /** * @param {!chromeos.networkConfig.mojom.ManagedProperties|undefined} * managedProperties * @return {boolean}
diff --git a/chrome/browser/resources/settings/chromeos/localized_link/localized_link.html b/chrome/browser/resources/settings/chromeos/localized_link/localized_link.html index 407a785..f9fd8c6f 100644 --- a/chrome/browser/resources/settings/chromeos/localized_link/localized_link.html +++ b/chrome/browser/resources/settings/chromeos/localized_link/localized_link.html
@@ -5,7 +5,11 @@ <dom-module id="settings-localized-link"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + :host { + --cr-subsequent-anchors-of-span-margin: 0; + } + </style> <div id="container" inner-h-t-m-l="[[getAriaLabelledContent_(localizedString, linkUrl)]]"> </div>
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_task_continuation_disabled_link.html b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_task_continuation_disabled_link.html index 6f25e82..4cb47ce 100644 --- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_task_continuation_disabled_link.html +++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_task_continuation_disabled_link.html
@@ -9,7 +9,11 @@ <dom-module id="settings-multidevice-task-continuation-disabled-link"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + :host { + --cr-subsequent-anchors-of-span-margin: 0; + } + </style> <div id="container" inner-h-t-m-l="[[getAriaLabelledContent_()]]"> </div>
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.html b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.html index 3e8e9919..ec8fa62 100644 --- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.html +++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_wifi_sync_disabled_link.html
@@ -10,7 +10,11 @@ <dom-module id="settings-multidevice-wifi-sync-disabled-link"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + :host { + --cr-subsequent-anchors-of-span-margin: 0; + } + </style> <div id="container" inner-h-t-m-l="[[getAriaLabelledContent_()]]"> </div>
diff --git a/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.html b/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.html index 35107c71..5b8fa85 100644 --- a/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.html +++ b/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.html
@@ -48,7 +48,8 @@ $i18n{nearbyShareVisibilityPageSubtitle} </h2> <div slot="body"> - <nearby-contact-visibility settings="{{settings}}"> + <nearby-contact-visibility id="contactVisibility" + settings="{{settings}}"> </nearby-contact-visibility> </div> <div class="layout horizontal center" slot="button-container">
diff --git a/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js b/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js index c6164405..dbc6507 100644 --- a/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js +++ b/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js
@@ -20,6 +20,9 @@ /** @private */ onDoneClick_() { + const contactVisibility = /** @type {NearbyContactVisibilityElement} */ + (this.$.contactVisibility); + contactVisibility.saveVisibilityAndAllowedContacts(); const dialog = /** @type {!CrDialogElement} */ (this.$.dialog); if (dialog.open) { dialog.close();
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html index 551b9f76..63e28b9e 100644 --- a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html +++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html
@@ -19,7 +19,9 @@ } #prompt { + color: var(--cr-primary-text-color); height: 40px; + margin-top: 8px; white-space: pre-line; } @@ -29,7 +31,7 @@ display: flex; flex-direction: column; gap: 12px; - height: 88px; + height: 60px; margin-top: 20px; overflow: auto; padding: 16px; @@ -39,9 +41,40 @@ display: flex; } - .switch-assignment-icon { + .icon { margin-inline-end: 10px; } + + .add-assignment-icon { + --iron-icon-fill-color: var(--cros-icon-color-secondary); + } + + .assigned-icon { + --iron-icon-fill-color: var(--cros-icon-color-prominent); + } + + .remove-assignment-icon { + --iron-icon-fill-color: var(--cros-icon-color-alert); + } + + #errorIcon { + --iron-icon-fill-color: var(--cros-icon-color-alert); + } + + #button-container { + margin-inline-end: 10px; + padding-top: 8px; + } + + #errorContainer { + height: 40px; + margin-top: 16px; + } + + #error { + color: var(--cros-icon-color-alert); + display: flex; + } </style> <cr-dialog id="switchAccessActionAssignmentDialog" show-on-attach> <div slot="title">[[dialogTitle_]]</div> @@ -54,16 +87,27 @@ <template is="dom-if" if="[[assignments_.length]]"> <template is="dom-repeat" items="[[assignments_]]" as="assignment"> <div class="switch-assignment"> - <iron-icon icon="os-settings:hollow-check-circle" - class="switch-assignment-icon"> + <iron-icon icon="os-settings:[[computeIcon_(assignment, assignmentState_)]]" + class$="icon [[computeIcon_(assignment, assignmentState_)]]-icon" + aria-label="[[computeIconLabel_(assignment, assignmentState_)]]"> </iron-icon> [[assignment]] </div> </template> </template> </div> + <div id="errorContainer"> + <template is="dom-if" if="[[errorText_]]"> + <div id="error" aria-live="polite"> + <iron-icon id="errorIcon" icon="os-settings:error" class="icon" + aria-label="$i18n{switchAccessActionAssignmentDialogErrorIconLabel}"> + </iron-icon> + [[errorText_]] + </div> + </template> + </div> </div> - <div slot="button-container"> + <div id="button-container" slot="button-container"> <cr-button class="exit-button" on-click="onExitClick_" id="exit"> $i18n{switchAccessActionAssignmentDialogExit}
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js index e7cecc8b..14bc1514 100644 --- a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js
@@ -15,13 +15,14 @@ * @enum {number} */ /* #export */ const AssignmentState = { - WAIT_FOR_KEY: 0, + WAIT_FOR_CONFIRMATION_REMOVAL: 0, WAIT_FOR_CONFIRMATION: 1, - WAIT_FOR_CONFIRMATION_REMOVAL: 2, - WARN_NOT_CONFIRMED: 3, - WARN_ALREADY_ASSIGNED_ACTION: 4, - WARN_UNRECOGNIZED_KEY: 5, - WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH: 6, + WAIT_FOR_KEY: 2, + WARN_ALREADY_ASSIGNED_ACTION: 3, + WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH: 4, + WARN_NOT_CONFIRMED_REMOVAL: 5, + WARN_NOT_CONFIRMED: 6, + WARN_UNRECOGNIZED_KEY: 7, }; /** @@ -35,6 +36,16 @@ previous: 'settings.a11y.switch_access.previous.key_codes' }; +/** + * Various icons representing the state of a given key assignment. + * @enum {string} + */ +/* #export */ const AssignmentIcon = { + ASSIGNED: 'assigned', + ADD_ASSIGNMENT: 'add-assignment', + REMOVE_ASSIGNMENT: 'remove-assignment', +}; + Polymer({ is: 'settings-switch-access-action-assignment-dialog', @@ -101,6 +112,15 @@ computed: 'computePromptText_(assignmentState_, assignments_)', }, + /** + * Error text shown on the dialog with error symbol. Hidden if blank. + * @private {string} + */ + errorText_: { + type: String, + computed: 'computeErrorText_(assignmentState_)', + }, + /** @private {!SwitchAccessCommand} */ alreadyAssignedAction_: String, @@ -173,6 +193,7 @@ this.handleKeyEventInWaitForConfirmationRemoval_(event); break; case AssignmentState.WARN_NOT_CONFIRMED: + case AssignmentState.WARN_NOT_CONFIRMED_REMOVAL: case AssignmentState.WARN_ALREADY_ASSIGNED_ACTION: case AssignmentState.WARN_UNRECOGNIZED_KEY: case AssignmentState.WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH: @@ -217,6 +238,7 @@ return; } this.assignmentState_ = AssignmentState.WAIT_FOR_CONFIRMATION; + this.push('assignments_', this.currentKey_); }, /** @@ -249,7 +271,7 @@ handleKeyEventInWaitForConfirmationRemoval_(event) { if (this.currentKeyCode_ !== event.keyCode) { this.unexpectedKey_ = event.key; - this.assignmentState_ = AssignmentState.WARN_NOT_CONFIRMED; + this.assignmentState_ = AssignmentState.WARN_NOT_CONFIRMED_REMOVAL; return; } @@ -314,31 +336,98 @@ }, /** - * @param {AssignmentState} assignmentState + * Returns the image to use for the assignment's icon. The value must match + * one of iron-icon's os-settings:(*) icon names. + * @param {string} assignment + * @return {AssignmentIcon} + * @private + */ + computeIcon_(assignment) { + if (assignment !== this.currentKey_) { + return AssignmentIcon.ASSIGNED; + } + + switch (this.assignmentState_) { + case AssignmentState.WAIT_FOR_KEY: + case AssignmentState.WARN_ALREADY_ASSIGNED_ACTION: + case AssignmentState.WARN_UNRECOGNIZED_KEY: + case AssignmentState.WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH: + return AssignmentIcon.ASSIGNED; + case AssignmentState.WAIT_FOR_CONFIRMATION: + case AssignmentState.WARN_NOT_CONFIRMED: + return AssignmentIcon.ADD_ASSIGNMENT; + case AssignmentState.WAIT_FOR_CONFIRMATION_REMOVAL: + case AssignmentState.WARN_NOT_CONFIRMED_REMOVAL: + return AssignmentIcon.REMOVE_ASSIGNMENT; + } + throw new Error('Invalid assignment state.'); + }, + + /** + * Returns the icon label describing the icon for the specified assignment. + * @param {string} assignment + * @return {string} + * @private + */ + computeIconLabel_(assignment) { + const icon = this.computeIcon_(assignment); + switch (icon) { + case AssignmentIcon.ASSIGNED: + return this.i18n('switchAccessActionAssignmentDialogAssignedIconLabel'); + case AssignmentIcon.ADD_ASSIGNMENT: + return this.i18n( + 'switchAccessActionAssignmentDialogAddAssignmentIconLabel'); + case AssignmentIcon.REMOVE_ASSIGNMENT: + return this.i18n( + 'switchAccessActionAssignmentDialogRemoveAssignmentIconLabel'); + } + throw new Error('Invalid assignment icon.'); + }, + + /** + * @param {!AssignmentState} assignmentState + * @param {!Array<string>} assignments * @return {string} * @private */ computePromptText_(assignmentState, assignments) { switch (assignmentState) { case AssignmentState.WAIT_FOR_KEY: + case AssignmentState.WARN_ALREADY_ASSIGNED_ACTION: + case AssignmentState.WARN_UNRECOGNIZED_KEY: + case AssignmentState.WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH: if (!assignments.length) { return this.i18n( - 'switchAccessActionAssignmentDialogWaitForKeyPromptNoSwitches'); + 'switchAccessActionAssignmentDialogWaitForKeyPromptNoSwitches', + this.getLabelForAction_(this.action)); } return this.i18n( 'switchAccessActionAssignmentDialogWaitForKeyPromptAtLeastOneSwitch'); case AssignmentState.WAIT_FOR_CONFIRMATION: + case AssignmentState.WARN_NOT_CONFIRMED: return this.i18n( 'switchAccessActionAssignmentDialogWaitForConfirmationPrompt', this.currentKey_); case AssignmentState.WAIT_FOR_CONFIRMATION_REMOVAL: + case AssignmentState.WARN_NOT_CONFIRMED_REMOVAL: return this.i18n( 'switchAccessActionAssignmentDialogWaitForConfirmationRemovalPrompt', this.currentKey_); + } + throw new Error('Invalid assignment state.'); + }, + + /** + * @param {!AssignmentState} assignmentState + * @return {string} + * @private + */ + computeErrorText_(assignmentState) { + switch (assignmentState) { case AssignmentState.WARN_NOT_CONFIRMED: + case AssignmentState.WARN_NOT_CONFIRMED_REMOVAL: return this.i18n( - 'switchAccessActionAssignmentDialogWarnNotConfirmedPrompt', - this.unexpectedKey_, this.currentKey_); + 'switchAccessActionAssignmentDialogWarnNotConfirmedPrompt'); case AssignmentState.WARN_ALREADY_ASSIGNED_ACTION: return this.i18n( 'switchAccessActionAssignmentDialogWarnAlreadyAssignedActionPrompt', @@ -350,8 +439,11 @@ case AssignmentState.WARN_CANNOT_REMOVE_LAST_SELECT_SWITCH: return this.i18n( 'switchAccessActionAssignmentDialogWarnCannotRemoveLastSelectSwitch'); - default: + case AssignmentState.WAIT_FOR_KEY: + case AssignmentState.WAIT_FOR_CONFIRMATION: + case AssignmentState.WAIT_FOR_CONFIRMATION_REMOVAL: return ''; } + throw new Error('Invalid assignment state.'); }, });
diff --git a/chrome/browser/resources/settings/chromeos/os_icons.html b/chrome/browser/resources/settings/chromeos/os_icons.html index 3c07eb5..6ea4866 100644 --- a/chrome/browser/resources/settings/chromeos/os_icons.html +++ b/chrome/browser/resources/settings/chromeos/os_icons.html
@@ -66,7 +66,6 @@ <g id="google-drive"><path fill-rule="evenodd" clip-rule="evenodd" d="M18.7333 12L13.0167 2H7.31665V2.00833L13.025 12H18.7333ZM8.27502 12.8334L5.41669 17.8334H16.35L19.2084 12.8334H8.27502ZM6.59167 3.26672L1.125 12.8334L3.98333 17.8251L9.45 8.26672C9.45 8.27506 6.59167 3.26672 6.59167 3.26672Z"></path></g> <g id="google-play"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.8167 9.06658L14.2667 7.61658L11.8834 9.99991L14.2667 12.3832L16.8167 10.9332C17.275 10.6749 17.5 10.3416 17.5 9.99991C17.5 9.65824 17.275 9.32491 16.8167 9.06658ZM3.92498 2.04163C4.93332 3.04996 10.9417 9.05829 10.9417 9.05829L13.0666 6.93329L4.14998 1.88329C4.09165 1.84996 4.03332 1.82496 3.97498 1.79996C3.83332 1.74163 3.72498 1.84163 3.84998 1.97496C3.87498 1.99163 3.89998 2.01663 3.92498 2.04163ZM3.92501 17.9583C3.90001 17.9833 3.87501 18.0083 3.85834 18.025C3.73334 18.15 3.84168 18.2583 3.98334 18.2C4.04168 18.175 4.10001 18.15 4.15834 18.1166L13.0667 13.0667L10.9417 10.9417C10.9417 10.9417 4.94168 16.95 3.92501 17.9583ZM10 9.99995C10 9.99995 2.975 2.97495 2.81667 2.81662C2.65833 2.65828 2.5 2.75828 2.5 2.97495V17.025C2.5 17.2416 2.65833 17.3416 2.81667 17.1833C2.975 17.025 10 9.99995 10 9.99995Z"></path></g> <g id="hard-drive"><path d="M14 14C14 14.5523 13.5523 15 13 15C12.4477 15 12 14.5523 12 14C12 13.4477 12.4477 13 13 13C13.5523 13 14 13.4477 14 14Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M5 2C3.89543 2 3 2.89543 3 4V16C3 17.1046 3.89543 18 5 18H15C16.1046 18 17 17.1046 17 16V4C17 2.89543 16.1046 2 15 2H5ZM5 16H15V12H5V16ZM5 10H15V4H5V10Z"></path></g> - <g id="hollow-check-circle"><path d="M11.7071 5.29289C11.3166 4.90237 10.6834 4.90237 10.2929 5.29289L7 8.58579L5.70711 7.29289C5.31658 6.90237 4.68342 6.90237 4.29289 7.29289C3.90237 7.68342 3.90237 8.31658 4.29289 8.70711L6.29289 10.7071C6.68342 11.0976 7.31658 11.0976 7.70711 10.7071L11.7071 6.70711C12.0976 6.31658 12.0976 5.68342 11.7071 5.29289Z" fill="#1A73E8"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16ZM8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14Z" fill="#1A73E8"></path></g> <g id="ic-checked-filled"><circle cx="10" cy="10" r="8" fill="#1A73E8"></circle><path fill-rule="evenodd" clip-rule="evenodd" d="M8.33333 11.833L6.16667 9.66634L5 10.833L8.33333 14.1663L15 7.49967L13.8333 6.33301L8.33333 11.833Z" fill="white"></path></g> <g id="lock"><path d="M11.75 12.5C11.75 13.4665 10.9665 14.25 10 14.25C9.0335 14.25 8.25 13.4665 8.25 12.5C8.25 11.5335 9.0335 10.75 10 10.75C10.9665 10.75 11.75 11.5335 11.75 12.5Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M14 7H13.5V5C13.5 3.34315 11.6569 2 10 2C8.34315 2 6.5 3.34315 6.5 5V7H6C4.89543 7 4 7.89543 4 9V16C4 17.1046 4.89543 18 6 18H14C15.1046 18 16 17.1046 16 16V9C16 7.89543 15.1046 7 14 7ZM12 5.5V7H8V5.5C8 5 8.5 3.5 10 3.5C11.5 3.5 12 5 12 5.5ZM6 9V16H14V9H6Z"></path></g> <g id="keyboard"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 3H2C0.9 3 0.01 3.9 0.01 5L0 15C0 16.1 0.9 17 2 17H18C19.1 17 20 16.1 20 15V5C20 3.9 19.1 3 18 3ZM18 5V15H2V5H18ZM11 6H9V8H11V6ZM9 9H11V11H9V9ZM8 6H6V8H8V6ZM6 9H8V11H6V9ZM5 9H3V11H5V9ZM3 6H5V8H3V6ZM14 12H6V14H14V12ZM12 9H14V11H12V9ZM14 6H12V8H14V6ZM15 9H17V11H15V9ZM17 6H15V8H17V6Z"></path></g> @@ -78,6 +77,13 @@ <g id="stylus"><path fill-rule="evenodd" clip-rule="evenodd" d="M2 14.6662V18H5.32305L12.0225 11.3057L8.69053 7.97192L2 14.6662ZM15.6565 2.26452L17.7356 4.33592C18.0821 4.68263 18.091 5.2516 17.7445 5.59831L12.9732 10.3634L9.63234 7.02073L11.8803 4.77153L11.2317 4.12255L6.20266 9.15435L4.95874 7.90974L10.6186 2.25563C10.9651 1.90892 11.5426 1.91781 11.8803 2.26452L13.142 3.51803L14.4037 2.26452C14.7413 1.91781 15.31 1.91781 15.6565 2.26452Z"></path></g> <g id="sync"><path fill-rule="evenodd" clip-rule="evenodd" d="M8.99977 3.07092L8.9991 5.1002C6.71731 5.56382 5 7.58136 5 10C5 11.8507 6.00553 13.4666 7.50008 14.3311L7.5 12H9V17H4V15.5L5.6705 15.5009C4.04414 14.2191 3 12.2315 3 10C3 6.55562 5.48772 3.69227 8.76441 3.1087L8.99977 3.07092ZM16 3V4.5L14.3315 4.5007C15.9567 5.78256 17 7.76944 17 10C17 13.5264 14.3924 16.4438 11.0002 16.9291L11.0009 14.8998C13.2827 14.4362 15 12.4186 15 10C15 8.14968 13.9949 6.5341 12.5009 5.66945L12.5 8H11V3H16Z"></path></g> <g id="wallpaper"><path fill-rule="evenodd" clip-rule="evenodd" d="M4 3H16C17.1046 3 18 3.89543 18 5V15C18 16.1046 17.1046 17 16 17H4C2.89543 17 2 16.1046 2 15V5C2 3.89543 2.89543 3 4 3ZM4 5V15H16V5H4ZM6 13L9 7L11 11L12 9.5L14 13H6Z"></path></g> + + <!-- Switch Access Action Assignment Dialog icons --> + <g id="add-assignment" fill-rule="evenodd"><path fill-rule="evenodd" clip-rule="evenodd" d="M14 9V11H11V14H9V11H6V9H9V6H11V9H14ZM10 2C5.576 2 2 5.576 2 10C2 14.424 5.576 18 10 18C14.424 18 18 14.424 18 10C18 5.576 14.424 2 10 2ZM10 16C6.6925 16 4 13.3075 4 10C4 6.6925 6.6925 4 10 4C13.3075 4 16 6.6925 16 10C16 13.3075 13.3075 16 10 16Z"></path></g> + <g id="assigned"><path d="M13.7071 7.29289C13.3166 6.90237 12.6834 6.90237 12.2929 7.29289L9 10.5858L7.70711 9.29289C7.31658 8.90237 6.68342 8.90237 6.29289 9.29289C5.90237 9.68342 5.90237 10.3166 6.29289 10.7071L8.29289 12.7071C8.68342 13.0976 9.31658 13.0976 9.70711 12.7071L13.7071 8.70711C14.0976 8.31658 14.0976 7.68342 13.7071 7.29289Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18ZM10 16C13.3137 16 16 13.3137 16 10C16 6.68629 13.3137 4 10 4C6.68629 4 4 6.68629 4 10C4 13.3137 6.68629 16 10 16Z"></path></g> + <g id="error"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 10H11V6H9V10ZM10 2C5.584 2 2 5.584 2 10C2 14.416 5.584 18 10 18C14.416 18 18 14.416 18 10C18 5.584 14.416 2 10 2ZM10 16C6.6925 16 4 13.3075 4 10C4 6.6925 6.6925 4 10 4C13.3075 4 16 6.6925 16 10C16 13.3075 13.3075 16 10 16ZM9 14H11V12H9V14Z"></path></g> + <g id="remove-assignment" fill-rule="evenodd"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.072 6.79999L9.99999 8.87199L7.92799 6.79999L6.79999 7.92799L8.87199 9.99999L6.79999 12.072L7.92799 13.2L9.99999 11.128L12.072 13.2L13.2 12.072L11.128 9.99999L13.2 7.92799L12.072 6.79999ZM10 2C5.576 2 2 5.576 2 10C2 14.424 5.576 18 10 18C14.424 18 18 14.424 18 10C18 5.576 14.424 2 10 2ZM10 16C6.6925 16 4 13.3075 4 10C4 6.6925 6.6925 4 10 4C13.3075 4 16 6.6925 16 10C16 13.3075 13.3075 16 10 16Z"></path></g> + <!-- Keep alphabetized. --> <!--
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html index ee45ea3..4044019 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.html +++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -6,7 +6,6 @@ .explain-selected { color: var(--google-green-refresh-700); font-weight: initial; - margin-top: 4px; } @media (prefers-color-scheme: dark) { @@ -181,7 +180,7 @@ item.language.code, language.prospectiveUILanguage)]] [[isTranslationTarget_(item.language.code, languages.translateTarget)]]"> - <div class="start"> + <div class="start cr-padded-text"> <div title="[[item.language.nativeDisplayName]]"> [[item.language.displayName]] </div>
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html index b446e9cd..bc4e518c 100644 --- a/chrome/browser/resources/settings/settings_shared_css.html +++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -79,7 +79,7 @@ } span ~ a { - margin-inline-start: 4px; + margin-inline-start: var(--cr-subsequent-anchors-of-span-margin, 4px); } a[href] {
diff --git a/chrome/browser/resources/signin/profile_picker/icons.js b/chrome/browser/resources/signin/profile_picker/icons.js index bb41c08..6d56e02 100644 --- a/chrome/browser/resources/signin/profile_picker/icons.js +++ b/chrome/browser/resources/signin/profile_picker/icons.js
@@ -25,6 +25,10 @@ <g id="lock" viewBox="0 0 48 48"> <path d="M0 0h48v48H0z" fill="none"/><path d="M36 16h-2v-4c0-5.52-4.48-10-10-10S14 6.48 14 12v4h-2c-2.21 0-4 1.79-4 4v20c0 2.21 1.79 4 4 4h24c2.21 0 4-1.79 4-4V20c0-2.21-1.79-4-4-4zM24 34c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4zm6.2-18H17.8v-4c0-3.42 2.78-6.2 6.2-6.2 3.42 0 6.2 2.78 6.2 6.2v4z"/> </g> + + <g id="create" viewBox="0 0 24 24"> + <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/> + </g> </defs> </svg>`; document.head.appendChild(element);
diff --git a/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js b/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js index aa08729..304dea62 100644 --- a/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js +++ b/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
@@ -122,6 +122,13 @@ */ createProfile( profileName, profileColor, avatarUrl, isGeneric, createShortcut) {} + + /** + * Sets the local profile name. + * @param {string} profilePath + * @param {string} profileName + */ + setProfileName(profilePath, profileName) {} } /** @implements {ManageProfilesBrowserProxy} */ @@ -183,6 +190,11 @@ 'createProfile', [profileName, profileColor, avatarUrl, isGeneric, createShortcut]); } + + /** @override */ + setProfileName(profilePath, profileName) { + chrome.send('setProfileName', [profilePath, profileName]); + } } addSingletonGetter(ManageProfilesBrowserProxyImpl);
diff --git a/chrome/browser/resources/signin/profile_picker/profile_card.html b/chrome/browser/resources/signin/profile_picker/profile_card.html index 7721b68..7add1911 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_card.html +++ b/chrome/browser/resources/signin/profile_picker/profile_card.html
@@ -1,9 +1,11 @@ <style include="profile-picker-shared cr-hidden-style"> #profileCardContainer { border-radius: inherit; + height: 100%; /* Allows descendants to be absolute positioned relatively to the container */ - position: relative + position: relative; + width: 100%; } cr-button { @@ -45,8 +47,8 @@ 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; - justify-content: center; height: var(--domain-icon-size); + justify-content: center; position: absolute; right: -6px; top: calc(var(--avatar-icon-size) - var(--domain-icon-size) @@ -75,6 +77,41 @@ width: 16px; } + div.profile-card-info { + bottom: 0; + font-weight: normal; + } + + cr-input { + --cr-input-background-color: none; + --cr-input-padding-top: 0; + font-weight: 500; + top: 0; + } + + #hoverUnderline { + border-bottom: 2px solid var(--google-grey-refresh-300); + border-radius: 0; + height: 0; + left: 0; + margin: auto; + opacity: 0; + position: absolute; + right: 0; + top: 38px; + width: 0; + } + + cr-input[focused_] + #hoverUnderline { + visibility: hidden; + } + + #profileNameInputWrapper:hover #hoverUnderline { + opacity: 1; + transition: opacity 120ms ease-in, width 180ms ease-out; + width: 130px; + } + @media (prefers-color-scheme: dark) { cr-button { --card-background-color: var(--google-grey-800); @@ -89,14 +126,16 @@ iron-icon { --iron-icon-fill-color: var(--google-grey-500); } + + #hoverUnderline { + border-color: var(--google-grey-refresh-700); + } } </style> <div id="profileCardContainer"> <cr-button on-click="onProfileClick_" aria-label="[[profileState.localProfileName]]"> - <!-- TODO(msalama): Implement editing local profile name in place --> - <div class="profile-card-info">[[profileState.localProfileName]]</div> <div id="avatarContainer"> <img class="profile-avatar" alt="" src="[[profileState.avatarIcon]]"> <div id="iconContainer" hidden="[[!profileState.isManaged]]"> @@ -104,12 +143,23 @@ </div> </div> <div class="profile-card-info"> - <div hidden="[[profileState.needsSignin]]">[[profileState.gaiaName]]</div> + <div id="gaiaName" hidden="[[profileState.needsSignin]]"> + [[profileState.gaiaName]] + </div> <div id="forceSigninContainer" hidden="[[!profileState.needsSignin]]"> <div>$i18n{needsSigninPrompt}</div> <iron-icon id="forceSigninIcon" icon="profiles:lock"></iron-icon> </div> </div> </cr-button> + <div id="profileNameInputWrapper"> + <cr-input class="profile-card-info" id="nameInput" + value="[[profileState.localProfileName]]" + on-change="onProfileNameChanged_" on-keydown="onProfileNameKeydown_" + on-blur="onProfileNameInputBlur_" pattern="[[pattern_]]" + auto-validate spellcheck="false" required> + </cr-input> + <div id="hoverUnderline"></div> + </div> <profile-card-menu profile-state="[[profileState]]"></profile-card-menu> </div>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_card.js b/chrome/browser/resources/signin/profile_picker/profile_card.js index 173d064..8c2803b7 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_card.js +++ b/chrome/browser/resources/signin/profile_picker/profile_card.js
@@ -6,6 +6,7 @@ import 'chrome://resources/cr_elements/icons.m.js'; import './profile_card_menu.js'; import './profile_picker_shared_css.js'; +import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ManageProfilesBrowserProxy, ManageProfilesBrowserProxyImpl, ProfileState} from './manage_profiles_browser_proxy.js'; @@ -20,6 +21,11 @@ profileState: { type: Object, }, + + pattern_: { + type: String, + value: '.*\\S.*', + }, }, /** @private {ManageProfilesBrowserProxy} */ @@ -36,4 +42,41 @@ this.manageProfilesBrowserProxy_.launchSelectedProfile( this.profileState.profilePath); }, + + /** + * Handler for when the profile name field is changed, then blurred. + * @param {!Event} event + * @private + */ + onProfileNameChanged_(event) { + if (event.target.invalid) { + return; + } + + this.manageProfilesBrowserProxy_.setProfileName( + this.profileState.profilePath, event.target.value); + + event.target.blur(); + }, + + /** + * Handler for profile name keydowns. + * @param {!Event} event + * @private + */ + onProfileNameKeydown_(event) { + if (event.key === 'Escape' || event.key === 'Enter') { + event.target.blur(); + } + }, + + /** + * Handler for profile name blur. + * @private + */ + onProfileNameInputBlur_() { + if (this.$.nameInput.invalid) { + this.$.nameInput.value = this.profileState.localProfileName; + } + }, });
diff --git a/chrome/browser/resources/signin/profile_picker/profile_card_menu.html b/chrome/browser/resources/signin/profile_picker/profile_card_menu.html index 9d1df884..3a9366c 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_card_menu.html +++ b/chrome/browser/resources/signin/profile_picker/profile_card_menu.html
@@ -13,6 +13,16 @@ font-weight: normal; } + #actionMenu iron-icon { + padding-inline-end: 14px; + } + + #actionMenu button { + --iron-icon-height: 16px; + --iron-icon-width: 16px; + padding-inline-start: 14px; + } + #removeActionMenu { pointer-events: none; } @@ -98,9 +108,11 @@ <cr-action-menu id="actionMenu" role-description="$i18n{menu}"> <button class="dropdown-item" on-click="onRemoveButtonClicked_"> + <iron-icon icon="cr:delete" aria-hidden="true"></iron-icon> $i18n{profileMenuRemoveText} </button> <button class="dropdown-item" on-click="onCustomizeButtonClicked_"> + <iron-icon icon="profiles:create" aria-hidden="true"></iron-icon> $i18n{profileMenuCustomizeText} </button> </cr-action-menu>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_card_menu.js b/chrome/browser/resources/signin/profile_picker/profile_card_menu.js index 835ae37..f56d636 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_card_menu.js +++ b/chrome/browser/resources/signin/profile_picker/profile_card_menu.js
@@ -7,6 +7,7 @@ import 'chrome://resources/cr_elements/cr_icons_css.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import './profile_picker_shared_css.js'; +import './icons.js'; import {assertNotReached} from 'chrome://resources/js/assert.m.js'; import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html index 8f3673e..fb033e1d 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html +++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
@@ -85,6 +85,12 @@ #addProfile { border: 1px dashed; border-color: var(--google-grey-400); + position: relative; + } + + #addProfileButtonLabel { + font-weight: 500; + top: 0; } cr-icon-button[iron-icon='profiles:add'] { @@ -125,6 +131,7 @@ #addProfile { border-color: var(--google-grey-refresh-700); + position: relative; } cr-icon-button[iron-icon='profiles:add'] { @@ -158,8 +165,6 @@ <cr-icon-button iron-icon="profiles:add" on-click="onAddProfileClick_" aria-labelledby="addProfileButtonLabel"> </cr-icon-button> - <!-- Empty div to maintain alignment with other profile cards. --> - <div class="profile-card-info"></div> </div> </div> </div>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html index 7881c9e..6f5b874 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html +++ b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
@@ -30,12 +30,13 @@ } .profile-card-info { + --profile-card-info-height: 52px; color: var(--cr-primary-text-color); font-size: var(--text-font-size); - font-weight: 500; height: 20px; overflow: hidden; padding: 16px; + position: absolute; text-align: center; text-overflow: ellipsis; white-space: nowrap;
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninHelper.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninHelper.java index 5309344..3cc3c86 100644 --- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninHelper.java +++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninHelper.java
@@ -6,6 +6,7 @@ import android.accounts.Account; import android.content.Context; +import android.util.Pair; import androidx.annotation.VisibleForTesting; @@ -55,17 +56,17 @@ @Override public List<String> getAccountChangeEvents(Context context, int index, String accountName) { try { - List<AccountChangeEvent> list = + List<AccountChangeEvent> accountChangeEvents = GoogleAuthUtil.getAccountChangeEvents(context, index, accountName); - List<String> result = new ArrayList<>(list.size()); - for (AccountChangeEvent e : list) { - if (e.getChangeType() == GoogleAuthUtil.CHANGE_TYPE_ACCOUNT_RENAMED_TO) { - result.add(e.getChangeData()); + List<String> changedNames = new ArrayList<>(accountChangeEvents.size()); + for (AccountChangeEvent event : accountChangeEvents) { + if (event.getChangeType() == GoogleAuthUtil.CHANGE_TYPE_ACCOUNT_RENAMED_TO) { + changedNames.add(event.getChangeData()); } else { - result.add(null); + changedNames.add(null); } } - return result; + return changedNames; } catch (IOException | GoogleAuthException e) { Log.w(TAG, "Failed to get change events", e); } @@ -119,7 +120,10 @@ String renamedAccount = mPrefsManager.getNewSignedInAccountName(); if (accountsChanged && renamedAccount != null) { - handleAccountRename(syncAccount.getEmail(), renamedAccount); + Log.i(TAG, + "handleAccountRename from: " + syncAccount.getEmail() + " to " + + renamedAccount); + handleAccountRename(renamedAccount); return; } @@ -165,9 +169,7 @@ * In the (near) future, we should just be clearing all the cached email address here * and have the UI re-fetch the emailing address based on the ID. */ - private void handleAccountRename(final String oldName, final String newName) { - Log.i(TAG, "handleAccountRename from: " + oldName + " to " + newName); - + private void handleAccountRename(final String newName) { // TODO(acleung): I think most of the operations need to run on the main // thread. May be we should have a progress Dialog? @@ -201,52 +203,46 @@ @VisibleForTesting public static void updateAccountRenameData( - AccountChangeEventChecker checker, String currentName) { - // Skip the search if there is no signed in account. - if (currentName == null) return; + AccountChangeEventChecker checker, String currentAccountName) { + final SigninPreferencesManager prefsManager = SigninPreferencesManager.getInstance(); + final int currentEventIndex = prefsManager.getLastAccountChangedEventIndex(); + final Pair<Integer, String> newEventIndexAndAccountName = + findAccountRenameEvent(checker, currentEventIndex, currentAccountName); + if (currentEventIndex != newEventIndexAndAccountName.first) { + prefsManager.setLastAccountChangedEventIndex(newEventIndexAndAccountName.first); + } + if (!currentAccountName.equals(newEventIndexAndAccountName.second)) { + prefsManager.setNewSignedInAccountName(newEventIndexAndAccountName.second); + } + } - String newName = currentName; - - SigninPreferencesManager prefsManager = SigninPreferencesManager.getInstance(); - int eventIndex = prefsManager.getLastAccountChangedEventIndex(); - int newIndex = eventIndex; - - try { - outerLoop: - while (true) { - final List<Account> accounts = - AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts(); - List<String> nameChanges = checker.getAccountChangeEvents( - ContextUtils.getApplicationContext(), newIndex, newName); - for (String name : nameChanges) { - if (name != null) { - // We have found a rename event of the current account. - // We need to check if that account is further renamed. - newName = name; - if (AccountUtils.findAccountByName(accounts, newName) == null) { - newIndex = 0; // Start from the beginning of the new account. - continue outerLoop; - } - break; - } + /** + * Finds the account rename event. + * @return A pair including the account change event index and the changed account name. + * When there's no pending rename event, the event index is still updated to the + * last read index to avoid reading the same data again in the future. + */ + private static Pair<Integer, String> findAccountRenameEvent( + AccountChangeEventChecker checker, int eventIndex, String accountName) { + final List<Account> accounts = + AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts(); + final List<String> changedNames = checker.getAccountChangeEvents( + ContextUtils.getApplicationContext(), eventIndex, accountName); + final int newEventIndex = changedNames.size(); + for (String changedName : changedNames) { + if (changedName != null) { + // We have found a rename event of the current account. + // We need to check if that account is further renamed. + if (AccountUtils.findAccountByName(accounts, changedName) == null) { + // Start from the beginning of the new account if account does not exist on + // device + return findAccountRenameEvent(checker, 0, changedName); + } else { + return new Pair<>(newEventIndex, changedName); } - - // If there is no rename event pending. Update the last read index to avoid - // re-reading them in the future. - newIndex = nameChanges.size(); - break; } - } catch (Exception e) { - Log.w(TAG, "Error while looking for rename events.", e); } - - if (!currentName.equals(newName)) { - prefsManager.setNewSignedInAccountName(newName); - } - - if (newIndex != eventIndex) { - prefsManager.setLastAccountChangedEventIndex(newIndex); - } + return new Pair<>(newEventIndex, accountName); } /**
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java index 646d5f068..18dca46f 100644 --- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java +++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java
@@ -8,6 +8,7 @@ import androidx.annotation.VisibleForTesting; import org.chromium.base.Callback; +import org.chromium.base.Log; import org.chromium.base.ThreadUtils; import org.chromium.base.TraceEvent; import org.chromium.base.UserData; @@ -234,7 +235,11 @@ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) protected void save() { if (mIsTabSaveEnabledSupplier != null && mIsTabSaveEnabledSupplier.get()) { - mPersistedTabDataStorage.save(mTab.getId(), mPersistedTabDataId, serializeAndLog()); + byte[] serialized = serializeAndLog(); + if (serialized == null) { + return; + } + mPersistedTabDataStorage.save(mTab.getId(), mPersistedTabDataId, serialized); } } @@ -243,11 +248,17 @@ */ abstract byte[] serialize(); - private byte[] serializeAndLog() { + @VisibleForTesting + protected byte[] serializeAndLog() { byte[] res; try (TraceEvent e = TraceEvent.scoped("PersistedTabData.Serialize")) { res = serialize(); + } catch (OutOfMemoryError oe) { + Log.e(TAG, "Out of memory error when attempting to save PersistedTabData"); + res = null; } + // TODO(crbug.com/1162293) convert to enum histogram and differentiate null/not null/out of + // memory RecordHistogram.recordBooleanHistogram( "Tabs.PersistedTabData.Serialize." + getUmaTag(), res != null); return res;
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_fa.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_fa.xtb index 981acdab..4b82ee2 100644 --- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_fa.xtb +++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_fa.xtb
@@ -870,7 +870,7 @@ <translation id="6981982820502123353">دسترسپذیری</translation> <translation id="6989267951144302301">بارگیری نشد</translation> <translation id="6990079615885386641">دریافت برنامه از فروشگاه Google Play: <ph name="APP_ACTION" /></translation> -<translation id="6995899638241819463">اگر گذرواژهها به دلیل نقض داده لو رفته باشد، هشدار میدهد</translation> +<translation id="6995899638241819463">اگر گذرواژهها دراثر سرقت اطلاعات شبکه لورفته باشند، به شما اطلاع داده شود</translation> <translation id="7015203776128479407">راهاندازی اولیه همگامسازی کامل نشد. همگامسازی خاموش است.</translation> <translation id="7022756207310403729">بازکردن در مرورگر</translation> <translation id="702463548815491781">توصیه در زمانیکه TalkBack یا «دسترسی کلیدی» روشن است</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_pl.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_pl.xtb index bc1bb66..a26698b 100644 --- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_pl.xtb +++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_pl.xtb
@@ -250,7 +250,7 @@ <translation id="2723001399770238859">dźwięk</translation> <translation id="2728754400939377704">Sortuj według witryny</translation> <translation id="2744248271121720757">Kliknij słowo, by szybko je wyszukać lub wyświetlić powiązane czynności</translation> -<translation id="2760989362628427051">Włącz tryb ciemny, gdy urządzenie ma włączony tryb ciemny lub oszczędzanie baterii</translation> +<translation id="2760989362628427051">Włącz ciemny motyw, gdy urządzenie ma włączony ciemny motyw lub Oszczędzanie baterii</translation> <translation id="2762000892062317888">przed chwilą</translation> <translation id="2776236159752647997">Więcej ustawień związanych z prywatnością, bezpieczeństwem i zbieraniem danych znajdziesz w sekcji <ph name="BEGIN_LINK" />Usługi Google<ph name="END_LINK" />.</translation> <translation id="2777555524387840389">Pozostało: <ph name="SECONDS" /> s</translation> @@ -954,7 +954,7 @@ <translation id="7577900504646297215">Zarządzaj zainteresowaniami</translation> <translation id="757855969265046257">{FILES,plural, =1{Pobrano <ph name="FILES_DOWNLOADED_ONE" /> plik}few{Pobrano <ph name="FILES_DOWNLOADED_MANY" /> pliki}many{Pobrano <ph name="FILES_DOWNLOADED_MANY" /> plików}other{Pobrano <ph name="FILES_DOWNLOADED_MANY" /> pliku}}</translation> <translation id="7583262514280211622">Tu znajdziesz swoją listę Do przeczytania</translation> -<translation id="7588219262685291874">Włącz tryb ciemny, gdy na urządzeniu jest aktywne oszczędzanie baterii</translation> +<translation id="7588219262685291874">Włącz ciemny motyw, gdy na urządzeniu jest aktywne oszczędzanie baterii</translation> <translation id="7593557518625677601">Otwórz ustawienia Androida i ponownie włącz jego synchronizację, by uruchomić Synchronizację Chrome</translation> <translation id="7596558890252710462">System operacyjny</translation> <translation id="7605594153474022051">Synchronizacja nie działa</translation>
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc index 1fe46e7..ef1a1f5 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
@@ -221,11 +221,11 @@ } using ShowNotificationCallback = - base::Callback<void(ScreenshotResult screenshot_result, - const base::FilePath& screenshot_path)>; + base::OnceCallback<void(ScreenshotResult screenshot_result, + const base::FilePath& screenshot_path)>; void SaveScreenshot(scoped_refptr<base::TaskRunner> ui_task_runner, - const ShowNotificationCallback& callback, + ShowNotificationCallback callback, const base::FilePath& screenshot_path, scoped_refptr<base::RefCountedMemory> png_data, ScreenshotFileResult result, @@ -258,7 +258,8 @@ // Report the result on the UI thread. ui_task_runner->PostTask( - FROM_HERE, base::BindOnce(callback, screenshot_result, screenshot_path)); + FROM_HERE, + base::BindOnce(std::move(callback), screenshot_result, screenshot_path)); } void EnsureLocalDirectoryExists( @@ -270,11 +271,11 @@ if (!base::CreateDirectory(path.DirName())) { LOG(ERROR) << "Failed to ensure the existence of " << path.DirName().value(); - callback.Run(ScreenshotFileResult::CREATE_DIR_FAILED, path); + std::move(callback).Run(ScreenshotFileResult::CREATE_DIR_FAILED, path); return; } - callback.Run(ScreenshotFileResult::SUCCESS, path); + std::move(callback).Run(ScreenshotFileResult::SUCCESS, path); } } // namespace @@ -394,22 +395,23 @@ screenshot_directory.AppendASCII(screenshot_basename + ".png"); ShowNotificationCallback screenshot_complete_callback( - base::Bind(&ChromeScreenshotGrabber::OnScreenshotCompleted, - weak_factory_.GetWeakPtr())); + base::BindOnce(&ChromeScreenshotGrabber::OnScreenshotCompleted, + weak_factory_.GetWeakPtr())); PrepareFileAndRunOnBlockingPool( screenshot_path, - base::Bind(&SaveScreenshot, base::ThreadTaskRunnerHandle::Get(), - screenshot_complete_callback, screenshot_path, png_data)); + base::BindOnce(&SaveScreenshot, base::ThreadTaskRunnerHandle::Get(), + std::move(screenshot_complete_callback), screenshot_path, + png_data)); } void ChromeScreenshotGrabber::PrepareFileAndRunOnBlockingPool( const base::FilePath& path, - const FileCallback& callback) { + FileCallback callback) { base::ThreadPool::PostTask( FROM_HERE, {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, - base::BindOnce(EnsureLocalDirectoryExists, path, callback)); + base::BindOnce(EnsureLocalDirectoryExists, path, std::move(callback))); } void ChromeScreenshotGrabber::OnScreenshotCompleted(
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.h b/chrome/browser/ui/ash/chrome_screenshot_grabber.h index 1ec85ad..4591c68 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber.h +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.h
@@ -44,8 +44,8 @@ public: // Callback called with the |result| of trying to create a local writable // |path| for the possibly remote path. - using FileCallback = base::Callback<void(ScreenshotFileResult result, - const base::FilePath& path)>; + using FileCallback = base::OnceCallback<void(ScreenshotFileResult result, + const base::FilePath& path)>; ChromeScreenshotGrabber(); ~ChromeScreenshotGrabber() override; @@ -81,7 +81,7 @@ // Prepares a writable file for |path|. void PrepareFileAndRunOnBlockingPool(const base::FilePath& path, - const FileCallback& callback); + FileCallback callback); // Called once all file writing is completed, or on error. void OnScreenshotCompleted(ui::ScreenshotResult result,
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc b/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc index 0fdb132..b442a97 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc
@@ -15,6 +15,7 @@ #include "base/callback_helpers.h" #include "base/files/file_util.h" #include "base/scoped_observer.h" +#include "base/test/bind.h" #include "base/unguessable_token.h" #include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/extensions/component_loader.h" @@ -195,10 +196,13 @@ auto item = HoldingSpaceItem::CreateFileBackedItem( type, file_path, holding_space_util::ResolveFileSystemUrl(profile, file_path), - /*image=*/ - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + base::BindLambdaForTesting( + [&](HoldingSpaceItem::Type type, const base::FilePath& path) { + return std::make_unique<HoldingSpaceImage>( + path, + /*placeholder=*/gfx::ImageSkia(), + /*async_bitmap_resolver=*/base::DoNothing()); + })); auto* item_ptr = item.get();
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc index 2170004..9edf185c0 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc
@@ -39,6 +39,16 @@ // Helpers --------------------------------------------------------------------- +// Creates an empty holding space image. +std::unique_ptr<HoldingSpaceImage> CreateTestHoldingSpaceImage( + HoldingSpaceItem::Type type, + const base::FilePath& file_path) { + return std::make_unique<HoldingSpaceImage>( + file_path, + /*placeholder=*/gfx::ImageSkia(), + /*async_bitmap_resolver=*/base::DoNothing()); +} + // Copies the file for the `relative_path` in the test data directory to // downloads directory, and returns the path to the copy. base::FilePath TestFile(Profile* profile, const std::string& relative_path) { @@ -165,10 +175,7 @@ // Create a holding space item backed by a non-existing file. auto holding_space_item = HoldingSpaceItem::CreateFileBackedItem( HoldingSpaceItem::Type::kDownload, base::FilePath("foo"), - GURL("filesystem:fake"), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + GURL("filesystem:fake"), base::BindOnce(&CreateTestHoldingSpaceImage)); // We expect `HoldingSpaceClient::OpenItems()` to fail when the backing file // for `holding_space_item` does not exist. @@ -218,10 +225,7 @@ // Create a holding space item backed by a non-existing file. auto holding_space_item = HoldingSpaceItem::CreateFileBackedItem( HoldingSpaceItem::Type::kDownload, base::FilePath("foo"), - GURL("filesystem:fake"), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + GURL("filesystem:fake"), base::BindOnce(&CreateTestHoldingSpaceImage)); // We expect `HoldingSpaceClient::ShowItemInFolder()` to fail when the // backing file for `holding_space_item` does not exist.
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc b/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc index 540b07d..d887971 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc
@@ -42,12 +42,15 @@ // deletion. const base::FilePath path_to_watch = file_path.DirName(); - if (!base::Contains(watchers_, path_to_watch)) { - watchers_[path_to_watch] = std::make_unique<base::FilePathWatcher>(); - watchers_[path_to_watch]->Watch( + auto it = watchers_.lower_bound(path_to_watch); + if (it == watchers_.end() || it->first != path_to_watch) { + it = watchers_.emplace_hint(it, std::piecewise_construct, + std::forward_as_tuple(path_to_watch), + std::forward_as_tuple()); + it->second.Watch( path_to_watch, base::FilePathWatcher::Type::kNonRecursive, - base::Bind(&FileSystemWatcher::OnFilePathChanged, - weak_factory_.GetWeakPtr())); + base::BindRepeating(&FileSystemWatcher::OnFilePathChanged, + weak_factory_.GetWeakPtr())); } // If the target path got deleted while request to add a watcher was in @@ -74,7 +77,7 @@ SEQUENCE_CHECKER(sequence_checker_); base::FilePathWatcher::Callback callback_; - std::map<base::FilePath, std::unique_ptr<base::FilePathWatcher>> watchers_; + std::map<base::FilePath, base::FilePathWatcher> watchers_; base::WeakPtrFactory<FileSystemWatcher> weak_factory_{this}; }; @@ -99,8 +102,8 @@ void HoldingSpaceFileSystemDelegate::Init() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); file_system_watcher_ = std::make_unique<FileSystemWatcher>( - base::Bind(&HoldingSpaceFileSystemDelegate::OnFilePathChanged, - weak_factory_.GetWeakPtr())); + base::BindRepeating(&HoldingSpaceFileSystemDelegate::OnFilePathChanged, + weak_factory_.GetWeakPtr())); file_change_service_observer_.Observe( chromeos::FileChangeServiceFactory::GetInstance()->GetService(profile()));
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc index 2d5030fc..bf7ddb2 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
@@ -137,9 +137,7 @@ items.push_back(HoldingSpaceItem::CreateFileBackedItem( HoldingSpaceItem::Type::kPinnedFile, file_system_url.path(), file_system_url.ToGURL(), - holding_space_util::ResolveImage(&thumbnail_loader_, - HoldingSpaceItem::Type::kPinnedFile, - file_system_url.path()))); + base::BindOnce(&holding_space_util::ResolveImage, &thumbnail_loader_))); // When pinning an item which already exists in holding space, the pin // action should be recorded on the alternative item backed by the same file @@ -224,9 +222,7 @@ AddItem(HoldingSpaceItem::CreateFileBackedItem( HoldingSpaceItem::Type::kScreenshot, screenshot_file, file_system_url, - holding_space_util::ResolveImage(&thumbnail_loader_, - HoldingSpaceItem::Type::kScreenshot, - screenshot_file))); + base::BindOnce(&holding_space_util::ResolveImage, &thumbnail_loader_))); } void HoldingSpaceKeyedService::AddDownload( @@ -243,9 +239,7 @@ AddItem(HoldingSpaceItem::CreateFileBackedItem( HoldingSpaceItem::Type::kDownload, download_file, file_system_url, - holding_space_util::ResolveImage(&thumbnail_loader_, - HoldingSpaceItem::Type::kDownload, - download_file))); + base::BindOnce(&holding_space_util::ResolveImage, &thumbnail_loader_))); } void HoldingSpaceKeyedService::AddNearbyShare( @@ -262,9 +256,7 @@ AddItem(HoldingSpaceItem::CreateFileBackedItem( HoldingSpaceItem::Type::kNearbyShare, nearby_share_path, file_system_url, - holding_space_util::ResolveImage(&thumbnail_loader_, - HoldingSpaceItem::Type::kNearbyShare, - nearby_share_path))); + base::BindOnce(&holding_space_util::ResolveImage, &thumbnail_loader_))); } void HoldingSpaceKeyedService::AddScreenRecording( @@ -277,9 +269,7 @@ AddItem(HoldingSpaceItem::CreateFileBackedItem( HoldingSpaceItem::Type::kScreenRecording, screen_recording_file, file_system_url, - holding_space_util::ResolveImage(&thumbnail_loader_, - HoldingSpaceItem::Type::kScreenRecording, - screen_recording_file))); + base::BindOnce(&holding_space_util::ResolveImage, &thumbnail_loader_))); } void HoldingSpaceKeyedService::AddItem(std::unique_ptr<HoldingSpaceItem> item) {
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc index 64178372..fc397d6a2 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
@@ -240,9 +240,13 @@ HoldingSpaceItem::CreateFileBackedItem( HoldingSpaceItem::Type::kDownload, item_path, holding_space_util::ResolveFileSystemUrl(profile, item_path), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + base::BindLambdaForTesting([&](HoldingSpaceItem::Type type, + const base::FilePath& file_path) { + return std::make_unique<HoldingSpaceImage>( + file_path, + /*placeholder=*/gfx::ImageSkia(), + /*async_bitmap_resolver=*/base::DoNothing()); + })); const HoldingSpaceItem* item_ptr = item.get(); holding_space_model->AddItem(std::move(item)); @@ -307,7 +311,7 @@ case FileSystemType::kDriveFs: // Set up drive integration service for test. ASSERT_TRUE(test_cache_root_.CreateUniqueTempDir()); - create_drive_integration_service_ = base::Bind( + create_drive_integration_service_ = base::BindRepeating( &HoldingSpaceKeyedServiceBrowserTest::CreateDriveIntegrationService, base::Unretained(this)); service_factory_for_test_ = std::make_unique<
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc index 32dfab35..589cda4 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
@@ -64,6 +64,16 @@ namespace { +// Creates an empty holding space image. +std::unique_ptr<HoldingSpaceImage> CreateTestHoldingSpaceImage( + HoldingSpaceItem::Type type, + const base::FilePath& file_path) { + return std::make_unique<HoldingSpaceImage>( + file_path, + /*placeholder=*/gfx::ImageSkia(), + /*async_bitmap_resolver=*/base::DoNothing()); +} + std::vector<HoldingSpaceItem::Type> GetHoldingSpaceItemTypes() { std::vector<HoldingSpaceItem::Type> types; for (int i = 0; i <= static_cast<int>(HoldingSpaceItem::Type::kMaxValue); ++i) @@ -547,9 +557,9 @@ auto holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, file_path, file_system_url, - holding_space_util::ResolveImage( - primary_holding_space_service->thumbnail_loader_for_testing(), type, - file_path)); + base::BindOnce( + &holding_space_util::ResolveImage, + primary_holding_space_service->thumbnail_loader_for_testing())); persisted_holding_space_items.Append(holding_space_item->Serialize()); primary_holding_space_model->AddItem(std::move(holding_space_item)); @@ -610,9 +620,9 @@ // Create the holding space item. auto holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, file_path, file_system_url, - holding_space_util::ResolveImage( - primary_holding_space_service->thumbnail_loader_for_testing(), type, - file_path)); + base::BindOnce( + &holding_space_util::ResolveImage, + primary_holding_space_service->thumbnail_loader_for_testing())); // Add the holding space item to the model and verify persistence. persisted_holding_space_items.Append(holding_space_item->Serialize()); @@ -721,10 +731,9 @@ auto fresh_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, file, file_system_url, - holding_space_util::ResolveImage( - primary_holding_space_service - ->thumbnail_loader_for_testing(), - type, file)); + base::BindOnce(&holding_space_util::ResolveImage, + primary_holding_space_service + ->thumbnail_loader_for_testing())); persisted_holding_space_items_before_restoration->Append( fresh_holding_space_item->Serialize()); @@ -739,15 +748,12 @@ restored_holding_space_items.push_back( std::move(fresh_holding_space_item)); + base::FilePath file_path = downloads_mount->GetRootPath().AppendASCII( + base::UnguessableToken::Create().ToString()); auto stale_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( - type, - downloads_mount->GetRootPath().AppendASCII( - base::UnguessableToken::Create().ToString()), - GURL("filesystem:fake_file_system_url"), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + type, file_path, GURL("filesystem:fake_file_system_url"), + base::BindOnce(&CreateTestHoldingSpaceImage)); // NOTE: While the `stale_holding_space_item` is persisted here, we do // *not* expect it to be restored or to be persisted after model @@ -828,9 +834,7 @@ auto delayed_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, delayed_mount_file, GURL("filesystem:fake"), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + base::BindOnce(&CreateTestHoldingSpaceImage)); // The item should be restored after delayed volume mount, and remain // in persistent storage. persisted_holding_space_items_before_restoration->Append( @@ -842,13 +846,12 @@ restored_holding_space_items.push_back( std::move(delayed_holding_space_item)); + const base::FilePath non_existent_path = + delayed_mount->GetRootPath().Append("non-existent"); auto non_existant_delayed_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( - type, delayed_mount->GetRootPath().Append("non-existent"), - GURL("filesystem:fake"), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + type, non_existent_path, GURL("filesystem:fake"), + base::BindOnce(&CreateTestHoldingSpaceImage)); // The item should be removed from the model and persistent storage // after delayed volume mount (when it can be confirmed the backing // file does not exist) - the item should remain in persistent storage @@ -863,10 +866,9 @@ auto fresh_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, file, file_system_url, - holding_space_util::ResolveImage( - primary_holding_space_service - ->thumbnail_loader_for_testing(), - type, file)); + base::BindOnce(&holding_space_util::ResolveImage, + primary_holding_space_service + ->thumbnail_loader_for_testing())); // The item should be immediately added to the model, and remain in // the persistent storage. @@ -987,9 +989,7 @@ auto delayed_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, delayed_mount_file, GURL("filesystem:fake"), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + base::BindOnce(&CreateTestHoldingSpaceImage)); // The item should be restored after delayed volume mount, and remain // in persistent storage. persisted_holding_space_items_before_restoration->Append( @@ -999,13 +999,12 @@ restored_holding_space_items.push_back( std::move(delayed_holding_space_item)); + base::FilePath non_existent_path = + delayed_mount->GetRootPath().Append("non-existent"); auto non_existant_delayed_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( - type, delayed_mount->GetRootPath().Append("non-existent"), - GURL("filesystem:fake"), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + type, non_existent_path, GURL("filesystem:fake"), + base::BindOnce(&CreateTestHoldingSpaceImage)); // The item should be removed from the model and persistent storage // after delayed volume mount (when it can be confirmed the backing // file does not exist) - the item should remain in persistent storage @@ -1018,10 +1017,9 @@ auto fresh_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, file, file_system_url, - holding_space_util::ResolveImage( - primary_holding_space_service - ->thumbnail_loader_for_testing(), - type, file)); + base::BindOnce(&holding_space_util::ResolveImage, + primary_holding_space_service + ->thumbnail_loader_for_testing())); // The item should be immediately added to the model, and remain in // the persistent storage. @@ -1121,10 +1119,9 @@ auto fresh_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, file, file_system_url, - holding_space_util::ResolveImage( - primary_holding_space_service - ->thumbnail_loader_for_testing(), - type, file)); + base::BindOnce(&holding_space_util::ResolveImage, + primary_holding_space_service + ->thumbnail_loader_for_testing())); // The item should be immediately added to the model, and remain in // the persistent storage. @@ -1277,10 +1274,9 @@ auto fresh_holding_space_item = HoldingSpaceItem::CreateFileBackedItem( type, file, file_system_url, - holding_space_util::ResolveImage( - primary_holding_space_service - ->thumbnail_loader_for_testing(), - type, file)); + base::BindOnce(&holding_space_util::ResolveImage, + primary_holding_space_service + ->thumbnail_loader_for_testing())); persisted_holding_space_items_before_restoration->Append( fresh_holding_space_item->Serialize()); @@ -1302,9 +1298,7 @@ HoldingSpaceItem::CreateFileBackedItem( type, stale_item_file, GetFileSystemUrl(GetProfile(), stale_item_file), - std::make_unique<HoldingSpaceImage>( - /*placeholder=*/gfx::ImageSkia(), - /*async_bitmap_resolver=*/base::DoNothing())); + base::BindOnce(&CreateTestHoldingSpaceImage)); // NOTE: While the `stale_holding_space_item` is persisted here, we do // *not* expect it to be restored or to be persisted after model
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_util.cc b/chrome/browser/ui/ash/holding_space/holding_space_util.cc index 3ab9fb5..b040d18 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_util.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_util.cc
@@ -179,7 +179,7 @@ HoldingSpaceItem::Type type, const base::FilePath& file_path) { return std::make_unique<HoldingSpaceImage>( - GetPlaceholderImage(type, file_path), + file_path, GetPlaceholderImage(type, file_path), base::BindRepeating( [](const base::WeakPtr<HoldingSpaceThumbnailLoader>& thumbnail_loader, const base::FilePath& file_path, const gfx::Size& size, @@ -188,7 +188,7 @@ thumbnail_loader->Load({file_path, size, scale_factor}, std::move(callback)); }, - thumbnail_loader->GetWeakPtr(), file_path)); + thumbnail_loader->GetWeakPtr())); } gfx::ImageSkia CreatePlaceholderImage(const gfx::ImageSkia& file_type_image,
diff --git a/chrome/browser/ui/ash/ime_controller_client_unittest.cc b/chrome/browser/ui/ash/ime_controller_client_unittest.cc index 66c856a..c76a7eb 100644 --- a/chrome/browser/ui/ash/ime_controller_client_unittest.cc +++ b/chrome/browser/ui/ash/ime_controller_client_unittest.cc
@@ -152,7 +152,7 @@ public: ImeControllerClientTest() { input_method_manager_.delegate_.set_get_localized_string_callback( - base::Bind(&GetLocalizedString)); + base::BindRepeating(&GetLocalizedString)); } ~ImeControllerClientTest() override = default;
diff --git a/chrome/browser/ui/ash/in_session_auth_dialog_client.cc b/chrome/browser/ui/ash/in_session_auth_dialog_client.cc index fbdcb13..d2baa89 100644 --- a/chrome/browser/ui/ash/in_session_auth_dialog_client.cc +++ b/chrome/browser/ui/ash/in_session_auth_dialog_client.cc
@@ -171,8 +171,8 @@ base::BindOnce( &ExtendedAuthenticator::AuthenticateToCheck, GetExtendedAuthenticator(), user_context, - base::Bind(&InSessionAuthDialogClient::OnPasswordAuthSuccess, - weak_factory_.GetWeakPtr(), user_context))); + base::BindOnce(&InSessionAuthDialogClient::OnPasswordAuthSuccess, + weak_factory_.GetWeakPtr(), user_context))); } void InSessionAuthDialogClient::OnPasswordAuthSuccess(
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc index b770e05..6312916 100644 --- a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc +++ b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
@@ -350,7 +350,7 @@ ui::SimpleMenuModel* menu_model) { extension_menu_items_ = std::make_unique<extensions::ContextMenuMatcher>( controller()->profile(), this, menu_model, - base::Bind(MenuItemHasLauncherContext)); + base::BindRepeating(MenuItemHasLauncherContext)); int index = 0; extension_menu_items_->AppendExtensionItems(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc index 231215e..91dd75d 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -1307,15 +1307,16 @@ pref_change_registrar_.Init(profile()->GetPrefs()); pref_change_registrar_.Add( prefs::kPolicyPinnedLauncherApps, - base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromSync, - base::Unretained(this))); + base::BindRepeating(&ChromeLauncherController::UpdateAppLaunchersFromSync, + base::Unretained(this))); // Handling of prefs::kArcEnabled change should be called deferred to avoid // race condition when OnAppUninstalledPrepared for ARC apps is called after // UpdateAppLaunchersFromSync. pref_change_registrar_.Add( arc::prefs::kArcEnabled, - base::Bind(&ChromeLauncherController::ScheduleUpdateAppLaunchersFromSync, - base::Unretained(this))); + base::BindRepeating( + &ChromeLauncherController::ScheduleUpdateAppLaunchersFromSync, + base::Unretained(this))); app_list::AppListSyncableService* app_list_syncable_service = app_list::AppListSyncableServiceFactory::GetForProfile(profile());
diff --git a/chrome/browser/ui/ash/network/enrollment_dialog_view.cc b/chrome/browser/ui/ash/network/enrollment_dialog_view.cc index d4b790f9..f1865675 100644 --- a/chrome/browser/ui/ash/network/enrollment_dialog_view.cc +++ b/chrome/browser/ui/ash/network/enrollment_dialog_view.cc
@@ -49,8 +49,7 @@ static void ShowDialog(const std::string& network_name, Profile* profile, - const GURL& target_uri, - const base::Closure& connect); + const GURL& target_uri); // views::DialogDelegateView overrides bool Accept() override; @@ -65,15 +64,13 @@ private: EnrollmentDialogView(const std::string& network_name, Profile* profile, - const GURL& target_uri, - const base::Closure& connect); + const GURL& target_uri); void InitDialog(); bool accepted_; std::string network_name_; Profile* profile_; GURL target_uri_; - base::Closure connect_; bool added_cert_; }; @@ -82,13 +79,11 @@ EnrollmentDialogView::EnrollmentDialogView(const std::string& network_name, Profile* profile, - const GURL& target_uri, - const base::Closure& connect) + const GURL& target_uri) : accepted_(false), network_name_(network_name), profile_(profile), target_uri_(target_uri), - connect_(connect), added_cert_(false) { SetTitle(l10n_util::GetStringUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_TITLE)); DialogDelegate::SetButtonLabel( @@ -104,10 +99,9 @@ // static void EnrollmentDialogView::ShowDialog(const std::string& network_name, Profile* profile, - const GURL& target_uri, - const base::Closure& connect) { + const GURL& target_uri) { EnrollmentDialogView* dialog_view = - new EnrollmentDialogView(network_name, profile, target_uri, connect); + new EnrollmentDialogView(network_name, profile, target_uri); views::Widget::InitParams params = views::DialogDelegate::GetDialogWidgetInitParams( @@ -198,9 +192,7 @@ Profile* profile); ~DialogEnrollmentDelegate(); - // EnrollmentDelegate overrides - bool Enroll(const std::vector<std::string>& uri_list, - const base::Closure& connect); + bool Enroll(const std::vector<std::string>& uri_list); private: std::string network_guid_; @@ -220,8 +212,8 @@ DialogEnrollmentDelegate::~DialogEnrollmentDelegate() {} -bool DialogEnrollmentDelegate::Enroll(const std::vector<std::string>& uri_list, - const base::Closure& post_action) { +bool DialogEnrollmentDelegate::Enroll( + const std::vector<std::string>& uri_list) { // Keep the closure for later activation if we notice that // a certificate has been added. @@ -236,8 +228,7 @@ // the enrollment dialog. NET_LOG(EVENT) << "Showing enrollment dialog for: " << NetworkGuidId(network_guid_); - EnrollmentDialogView::ShowDialog(network_name_, profile_, uri, - post_action); + EnrollmentDialogView::ShowDialog(network_name_, profile_, uri); return true; } NET_LOG(DEBUG) << "Nonstandard URI: " + uri.spec() @@ -250,10 +241,6 @@ return false; } -void EnrollmentComplete(const std::string& network_id) { - NET_LOG(USER) << "Enrollment Complete for: " << NetworkGuidId(network_id); -} - // Decides if the enrollment dialog is allowed in the current login state. bool EnrollmentDialogAllowed(Profile* profile) { // Enrollment dialog is currently not supported on the sign-in profile. @@ -335,8 +322,7 @@ DialogEnrollmentDelegate* enrollment = new DialogEnrollmentDelegate(network_id, network->name(), profile); - return enrollment->Enroll(cert_config.pattern.enrollment_uri_list(), - base::Bind(&EnrollmentComplete, network_id)); + return enrollment->Enroll(cert_config.pattern.enrollment_uri_list()); } } // namespace enrollment
diff --git a/chrome/browser/ui/ash/network/network_portal_notification_controller.cc b/chrome/browser/ui/ash/network/network_portal_notification_controller.cc index 23a3fd0b..dea0d6f 100644 --- a/chrome/browser/ui/ash/network/network_portal_notification_controller.cc +++ b/chrome/browser/ui/ash/network/network_portal_notification_controller.cc
@@ -11,6 +11,7 @@ #include "ash/public/cpp/notification_utils.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/macros.h" @@ -188,7 +189,7 @@ const NetworkPortalWebDialog* dialog) { if (dialog == dialog_) { dialog_ = nullptr; - ProfileHelper::Get()->ClearSigninProfile(base::Closure()); + ProfileHelper::Get()->ClearSigninProfile(base::NullCallback()); } }
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.cc b/chrome/browser/ui/ash/network/network_state_notifier.cc index fab9efc..ef2e2be 100644 --- a/chrome/browser/ui/ash/network/network_state_notifier.cc +++ b/chrome/browser/ui/ash/network/network_state_notifier.cc
@@ -82,7 +82,7 @@ const std::string& network_type, const base::string16& title, const base::string16& message, - const base::Closure& callback) { + base::RepeatingClosure callback) { NET_LOG(ERROR) << "ShowErrorNotification: " << identifier << ": " << base::UTF16ToUTF8(title); std::unique_ptr<message_center::Notification> notification = @@ -93,7 +93,8 @@ message_center::NotifierType::SYSTEM_COMPONENT, kNotifierNetworkError), message_center::RichNotificationData(), - new message_center::HandleNotificationClickDelegate(callback), + new message_center::HandleNotificationClickDelegate( + std::move(callback)), GetErrorNotificationVectorIcon(network_type), message_center::SystemNotificationWarningLevel::WARNING); SystemNotificationHelper::GetInstance()->Display(*notification); @@ -309,8 +310,9 @@ NetworkId(primary_network), kNetworkOutOfCreditsNotificationId, primary_network->type(), l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE), error_msg, - base::Bind(&NetworkStateNotifier::ShowMobileSetup, - weak_ptr_factory_.GetWeakPtr(), primary_network->guid())); + base::BindRepeating(&NetworkStateNotifier::ShowMobileSetup, + weak_ptr_factory_.GetWeakPtr(), + primary_network->guid())); } } @@ -343,8 +345,9 @@ message_center::NotifierType::SYSTEM_COMPONENT, kNotifierNetwork), {}, new message_center::HandleNotificationClickDelegate( - base::Bind(&NetworkStateNotifier::ShowNetworkSettings, - weak_ptr_factory_.GetWeakPtr(), cellular_guid)), + base::BindRepeating(&NetworkStateNotifier::ShowNetworkSettings, + weak_ptr_factory_.GetWeakPtr(), + cellular_guid)), kNotificationMobileDataIcon, message_center::SystemNotificationWarningLevel::WARNING); SystemNotificationHelper::GetInstance()->Display(*notification); @@ -363,8 +366,8 @@ // Get the up-to-date properties for the network and display the error. NetworkHandler::Get()->network_configuration_handler()->GetShillProperties( network->path(), - base::BindOnce(&NetworkStateNotifier::OnConnectErrorGetProperties, - weak_ptr_factory_.GetWeakPtr(), error_name)); + base::BindRepeating(&NetworkStateNotifier::OnConnectErrorGetProperties, + weak_ptr_factory_.GetWeakPtr(), error_name)); } void NetworkStateNotifier::ShowMobileActivationErrorForGuid( @@ -388,8 +391,9 @@ kNotifierNetworkError), {}, new message_center::HandleNotificationClickDelegate( - base::Bind(&NetworkStateNotifier::ShowNetworkSettings, - weak_ptr_factory_.GetWeakPtr(), cellular->guid())), + base::BindRepeating(&NetworkStateNotifier::ShowNetworkSettings, + weak_ptr_factory_.GetWeakPtr(), + cellular->guid())), kNotificationMobileDataOffIcon, message_center::SystemNotificationWarningLevel::WARNING); SystemNotificationHelper::GetInstance()->Display(*notification); @@ -515,8 +519,8 @@ ShowErrorNotification( NetworkPathId(service_path), kNetworkConnectNotificationId, network_type, l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE), error_msg, - base::Bind(&NetworkStateNotifier::ShowNetworkSettings, - weak_ptr_factory_.GetWeakPtr(), guid)); + base::BindRepeating(&NetworkStateNotifier::ShowNetworkSettings, + weak_ptr_factory_.GetWeakPtr(), guid)); } void NetworkStateNotifier::ShowVpnDisconnectedNotification(VpnDetails* vpn) { @@ -527,8 +531,8 @@ NetworkGuidId(vpn->guid), kNetworkConnectNotificationId, shill::kTypeVPN, l10n_util::GetStringUTF16(IDS_NETWORK_VPN_CONNECTION_LOST_TITLE), error_msg, - base::Bind(&NetworkStateNotifier::ShowNetworkSettings, - weak_ptr_factory_.GetWeakPtr(), vpn->guid)); + base::BindRepeating(&NetworkStateNotifier::ShowNetworkSettings, + weak_ptr_factory_.GetWeakPtr(), vpn->guid)); } void NetworkStateNotifier::ShowNetworkSettings(const std::string& network_id) {
diff --git a/chrome/browser/ui/ash/tab_scrubber_browsertest.cc b/chrome/browser/ui/ash/tab_scrubber_browsertest.cc index f56f7ef..45bf498 100644 --- a/chrome/browser/ui/ash/tab_scrubber_browsertest.cc +++ b/chrome/browser/ui/ash/tab_scrubber_browsertest.cc
@@ -75,7 +75,7 @@ } ImmersiveModeController* immersive_controller_; - base::Closure quit_closure_; + base::OnceClosure quit_closure_; DISALLOW_COPY_AND_ASSIGN(ImmersiveRevealEndedWaiter); };
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.cc b/chrome/browser/ui/ash/wallpaper_controller_client.cc index 4ba4d28..481896237 100644 --- a/chrome/browser/ui/ash/wallpaper_controller_client.cc +++ b/chrome/browser/ui/ash/wallpaper_controller_client.cc
@@ -87,10 +87,12 @@ } // Calls |callback| when system salt is ready. (|CanGetFilesId| returns true.) -void AddCanGetFilesIdCallback(const base::Closure& callback) { +void AddCanGetFilesIdCallback(base::OnceClosure callback) { // System salt may not be initialized in tests. - if (chromeos::SystemSaltGetter::IsInitialized()) - chromeos::SystemSaltGetter::Get()->AddOnSystemSaltReady(callback); + if (chromeos::SystemSaltGetter::IsInitialized()) { + chromeos::SystemSaltGetter::Get()->AddOnSystemSaltReady( + std::move(callback)); + } } // Returns true if |users| contains users other than device local accounts. @@ -266,8 +268,8 @@ << "Cannot get wallpaper files id in SetDefaultWallpaper. This " "should never happen under normal circumstances."; AddCanGetFilesIdCallback( - base::Bind(&WallpaperControllerClient::SetDefaultWallpaper, - weak_factory_.GetWeakPtr(), account_id, show_wallpaper)); + base::BindOnce(&WallpaperControllerClient::SetDefaultWallpaper, + weak_factory_.GetWeakPtr(), account_id, show_wallpaper)); return; } @@ -291,7 +293,7 @@ // Postpone setting the wallpaper until we can get files id. See // https://crbug.com/615239. if (!CanGetFilesId()) { - AddCanGetFilesIdCallback(base::Bind( + AddCanGetFilesIdCallback(base::BindOnce( &WallpaperControllerClient::SetPolicyWallpaper, weak_factory_.GetWeakPtr(), account_id, base::Passed(std::move(data)))); return; @@ -356,8 +358,8 @@ << "Cannot get wallpaper files id in RemoveUserWallpaper. This " "should never happen under normal circumstances."; AddCanGetFilesIdCallback( - base::Bind(&WallpaperControllerClient::RemoveUserWallpaper, - weak_factory_.GetWeakPtr(), account_id)); + base::BindOnce(&WallpaperControllerClient::RemoveUserWallpaper, + weak_factory_.GetWeakPtr(), account_id)); return; } @@ -376,8 +378,8 @@ << "Cannot get wallpaper files id in RemovePolicyWallpaper. This " "should never happen under normal circumstances."; AddCanGetFilesIdCallback( - base::Bind(&WallpaperControllerClient::RemovePolicyWallpaper, - weak_factory_.GetWeakPtr(), account_id)); + base::BindOnce(&WallpaperControllerClient::RemovePolicyWallpaper, + weak_factory_.GetWeakPtr(), account_id)); return; }
diff --git a/chrome/browser/ui/extensions/blocked_action_bubble_delegate.cc b/chrome/browser/ui/extensions/blocked_action_bubble_delegate.cc index 17ee47f..9ce5fe0 100644 --- a/chrome/browser/ui/extensions/blocked_action_bubble_delegate.cc +++ b/chrome/browser/ui/extensions/blocked_action_bubble_delegate.cc
@@ -59,7 +59,7 @@ } void BlockedActionBubbleDelegate::OnBubbleShown( - const base::Closure& close_bubble_callback) {} + base::OnceClosure close_bubble_callback) {} void BlockedActionBubbleDelegate::OnBubbleClosed(CloseAction action) { std::move(callback_).Run(action);
diff --git a/chrome/browser/ui/extensions/blocked_action_bubble_delegate.h b/chrome/browser/ui/extensions/blocked_action_bubble_delegate.h index bcbd6e8..578a201c 100644 --- a/chrome/browser/ui/extensions/blocked_action_bubble_delegate.h +++ b/chrome/browser/ui/extensions/blocked_action_bubble_delegate.h
@@ -30,7 +30,7 @@ std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> GetExtraViewInfo() override; std::string GetAnchorActionId() override; - void OnBubbleShown(const base::Closure& close_bubble_callback) override; + void OnBubbleShown(base::OnceClosure close_bubble_callback) override; void OnBubbleClosed(CloseAction action) override; base::OnceCallback<void(CloseAction)> callback_;
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_bridge.cc b/chrome/browser/ui/extensions/extension_message_bubble_bridge.cc index 0a71e49..f9203cc 100644 --- a/chrome/browser/ui/extensions/extension_message_bubble_bridge.cc +++ b/chrome/browser/ui/extensions/extension_message_bubble_bridge.cc
@@ -85,8 +85,8 @@ } void ExtensionMessageBubbleBridge::OnBubbleShown( - const base::Closure& close_bubble_callback) { - controller_->OnShown(close_bubble_callback); + base::OnceClosure close_bubble_callback) { + controller_->OnShown(std::move(close_bubble_callback)); } void ExtensionMessageBubbleBridge::OnBubbleClosed(CloseAction action) {
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_bridge.h b/chrome/browser/ui/extensions/extension_message_bubble_bridge.h index 3b6ea53e..4d6be65 100644 --- a/chrome/browser/ui/extensions/extension_message_bubble_bridge.h +++ b/chrome/browser/ui/extensions/extension_message_bubble_bridge.h
@@ -36,7 +36,7 @@ ui::DialogButton GetDefaultDialogButton() override; std::unique_ptr<ExtraViewInfo> GetExtraViewInfo() override; std::string GetAnchorActionId() override; - void OnBubbleShown(const base::Closure& close_bubble_callback) override; + void OnBubbleShown(base::OnceClosure close_bubble_callback) override; void OnBubbleClosed(CloseAction action) override; std::unique_ptr<extensions::ExtensionMessageBubbleController> controller_;
diff --git a/chrome/browser/ui/extensions/extensions_container.h b/chrome/browser/ui/extensions/extensions_container.h index c767143..b353378 100644 --- a/chrome/browser/ui/extensions/extensions_container.h +++ b/chrome/browser/ui/extensions/extensions_container.h
@@ -61,7 +61,7 @@ // |closure| will be called once any animation is complete. virtual void PopOutAction(ToolbarActionViewController* action, bool is_sticky, - const base::Closure& closure) = 0; + base::OnceClosure closure) = 0; // Shows the popup for the action with |id| as the result of an API call, // returning true if a popup is shown.
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc index fc4ead0..c21a03c 100644 --- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc +++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
@@ -559,7 +559,7 @@ EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); // Pop out Extension 3 (index 3). - base::Closure closure = base::DoNothing(); + base::RepeatingClosure closure = base::DoNothing(); ToolbarActionsBar* const toolbar_actions_bar = ToolbarActionsBar::FromBrowserWindow(browser()->window()); EXPECT_EQ(extension3->id(), toolbar_actions_bar->GetActions()[2]->GetId());
diff --git a/chrome/browser/ui/toolbar/media_router_action_controller.cc b/chrome/browser/ui/toolbar/media_router_action_controller.cc index 63fd6512..9c50697 100644 --- a/chrome/browser/ui/toolbar/media_router_action_controller.cc +++ b/chrome/browser/ui/toolbar/media_router_action_controller.cc
@@ -148,8 +148,8 @@ pref_change_registrar_.Init(profile->GetPrefs()); pref_change_registrar_.Add( prefs::kShowCastIconInToolbar, - base::Bind(&MediaRouterActionController::MaybeAddOrRemoveAction, - base::Unretained(this))); + base::BindRepeating(&MediaRouterActionController::MaybeAddOrRemoveAction, + base::Unretained(this))); if (profile_->IsRegularProfile()) { media_router::MediaRouterMetrics::RecordIconStateAtInit( MediaRouterActionController::GetAlwaysShowActionPref(profile_));
diff --git a/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.cc b/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.cc index 7d6830b..bf2f791d 100644 --- a/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.cc +++ b/chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.cc
@@ -7,6 +7,7 @@ #include "base/check.h" #include "base/logging.h" #include "base/macros.h" +#include "base/threading/thread_restrictions.h" class TestToolbarActionsBarBubbleDelegate::DelegateImpl : public ToolbarActionsBarBubbleDelegate { @@ -38,7 +39,7 @@ return nullptr; } std::string GetAnchorActionId() override { return std::string(); } - void OnBubbleShown(const base::Closure& close_bubble_callback) override { + void OnBubbleShown(base::OnceClosure close_bubble_callback) override { CHECK(!parent_->shown_); parent_->shown_ = true; }
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc index 3fb3b33..f7fc4fe 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -474,8 +474,7 @@ if (pending_bubble_controller_) { ShowToolbarActionBubble(std::move(pending_bubble_controller_)); } else if (!popped_out_closure_.is_null()) { - popped_out_closure_.Run(); - popped_out_closure_.Reset(); + std::move(popped_out_closure_).Run(); } } @@ -515,7 +514,7 @@ void ToolbarActionsBar::PopOutAction(ToolbarActionViewController* controller, bool is_sticky, - const base::Closure& closure) { + base::OnceClosure closure) { DCHECK(!in_overflow_mode()) << "Only the main bar can pop out actions."; DCHECK(!popped_out_action_) << "Only one action can be popped out at a time!"; bool needs_redraw = !IsActionVisibleOnToolbar(controller); @@ -531,9 +530,10 @@ ResizeDelegate(gfx::Tween::LINEAR); if (!delegate_->IsAnimating()) { // Don't call the closure re-entrantly. - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(closure)); } else { - popped_out_closure_ = closure; + popped_out_closure_ = std::move(closure); } }
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h index 1e58a23d..fc0c2d5 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -242,7 +242,7 @@ bool CloseOverflowMenuIfOpen() override; void PopOutAction(ToolbarActionViewController* action, bool is_sticky, - const base::Closure& closure) override; + base::OnceClosure closure) override; bool ShowToolbarActionPopupForAPICall(const std::string& id) override; void ShowToolbarActionBubble( std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; @@ -351,7 +351,7 @@ // The task to alert the |popped_out_action_| that animation has finished, and // it is fully popped out. - base::Closure popped_out_closure_; + base::OnceClosure popped_out_closure_; // The controller for the toolbar action bubble to show once animation // finishes, if any.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h b/chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h index 5c5bbe6a..1eb7c953 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h
@@ -83,7 +83,7 @@ // Called when the bubble is shown. Accepts a callback from platform-specifc // ui code to close the bubble. - virtual void OnBubbleShown(const base::Closure& close_bubble_callback) = 0; + virtual void OnBubbleShown(base::OnceClosure close_bubble_callback) = 0; // Called when the bubble is closed with the type of action the user took. virtual void OnBubbleClosed(CloseAction action) = 0;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc index b86fdb0..52a65e3 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_model.cc +++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -70,8 +70,8 @@ if (watch_toolbar_order || watch_pinned_extensions) { pref_change_registrar_.Init(prefs_); pref_change_callback_ = - base::Bind(&ToolbarActionsModel::OnActionToolbarPrefChange, - base::Unretained(this)); + base::BindRepeating(&ToolbarActionsModel::OnActionToolbarPrefChange, + base::Unretained(this)); if (watch_toolbar_order) { pref_change_registrar_.Add(extensions::pref_names::kToolbar,
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h index a6644ac..60ca0e9 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_model.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -342,7 +342,7 @@ // For observing change of toolbar order preference by external entity (sync). PrefChangeRegistrar pref_change_registrar_; - base::Closure pref_change_callback_; + base::RepeatingClosure pref_change_callback_; ScopedObserver<extensions::LoadErrorReporter, extensions::LoadErrorReporter::Observer>
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble.cc b/chrome/browser/ui/views/accessibility/caption_bubble.cc index 7688c78..579a580 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble.cc
@@ -193,6 +193,85 @@ BEGIN_METADATA(CaptionBubbleFrameView, views::BubbleFrameView) END_METADATA +class CaptionBubbleLabel : public views::Label { + public: + METADATA_HEADER(CaptionBubbleLabel); + CaptionBubbleLabel() = default; + ~CaptionBubbleLabel() override = default; + CaptionBubbleLabel(const CaptionBubbleLabel&) = delete; + CaptionBubbleLabel& operator=(const CaptionBubbleLabel&) = delete; + + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->role = ax::mojom::Role::kParagraph; + } + + void SetText(const base::string16& text) override { + views::Label::SetText(text); + + // Only update ViewAccessibility if accessibility is enabled. + if (content::BrowserAccessibilityState::GetInstance() + ->GetAccessibilityMode() + .is_mode_off()) { + return; + } + + auto& ax_lines = GetViewAccessibility().virtual_children(); + if (text.empty() && !ax_lines.empty()) { + GetViewAccessibility().RemoveAllVirtualChildViews(); + return; + } + + const size_t num_lines = GetRequiredLines(); + size_t start = 0; + for (size_t i = 0; i < num_lines - 1; ++i) { + size_t end = GetTextIndexOfLine(i + 1); + base::string16 substring = text.substr(start, end - start); + UpdateAXLine(substring, i, gfx::Range(start, end)); + start = end; + } + base::string16 substring = text.substr(start, text.size() - start); + if (!substring.empty()) { + UpdateAXLine(substring, num_lines - 1, gfx::Range(start, text.size())); + } + + // Remove all ax_lines that don't have a corresponding line. + size_t num_ax_lines = ax_lines.size(); + for (size_t i = num_lines; i < num_ax_lines; ++i) { + GetViewAccessibility().RemoveVirtualChildView(ax_lines.back().get()); + } + + NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true); + } + + private: + void UpdateAXLine(const base::string16& line_text, + const size_t line_index, + const gfx::Range& text_range) { + auto& ax_lines = GetViewAccessibility().virtual_children(); + + // Add a new virtual child for a new line of text. + DCHECK(line_index <= ax_lines.size()); + if (line_index == ax_lines.size()) { + auto ax_line = std::make_unique<views::AXVirtualView>(); + ax_line->GetCustomData().role = ax::mojom::Role::kStaticText; + GetViewAccessibility().AddVirtualChildView(std::move(ax_line)); + } + + // Set the virtual child's name as line text. + ui::AXNodeData& ax_node_data = ax_lines[line_index]->GetCustomData(); + if (base::UTF8ToUTF16(ax_node_data.GetStringAttribute( + ax::mojom::StringAttribute::kName)) != line_text) { + ax_node_data.SetName(line_text); + std::vector<gfx::Rect> bounds = GetSubstringBounds(text_range); + DCHECK_EQ(bounds.size(), 1u); + ax_node_data.relative_bounds.bounds = gfx::RectF(bounds[0]); + } + } +}; + +BEGIN_METADATA(CaptionBubbleLabel, views::Label) +END_METADATA + CaptionBubble::CaptionBubble(views::View* anchor, BrowserView* browser_view, base::OnceClosure destroyed_callback) @@ -345,7 +424,7 @@ // The caption bubble starts out hidden and unable to be activated. SetCanActivate(false); - auto label = std::make_unique<views::Label>(); + auto label = std::make_unique<CaptionBubbleLabel>(); label->SetMultiLine(true); label->SetMaximumWidth(kMaxWidthDip - kSidePaddingDip * 2); label->SetEnabledColor(SK_ColorWHITE); @@ -366,6 +445,7 @@ title->SetBackgroundColor(SK_ColorTRANSPARENT); title->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); title->SetText(l10n_util::GetStringUTF16(IDS_LIVE_CAPTION_BUBBLE_TITLE)); + title->GetViewAccessibility().OverrideIsIgnored(true); auto error_text = std::make_unique<views::Label>(); error_text->SetEnabledColor(SK_ColorWHITE); @@ -510,11 +590,12 @@ } void CaptionBubble::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ax::mojom::Role::kDialog; node_data->SetName(title_->GetText()); - node_data->role = ax::mojom::Role::kCaption; - if (model_ && model_->HasError()) { - node_data->SetDescription(error_text_->GetText()); - } +} + +base::string16 CaptionBubble::GetAccessibleWindowTitle() const { + return title_->GetText(); } void CaptionBubble::AddedToWidget() { @@ -564,64 +645,6 @@ UpdateBubbleAndTitleVisibility(); if (GetWidget()->IsVisible()) inactivity_timer_->Reset(); - - // Only update ViewAccessibility if accessibility is enabled. - if (content::BrowserAccessibilityState::GetInstance() - ->GetAccessibilityMode() - .is_mode_off() || - model_->HasError()) { - return; - } - - auto& virtual_children = GetViewAccessibility().virtual_children(); - if (text.empty() && !virtual_children.empty()) { - GetViewAccessibility().RemoveAllVirtualChildViews(); - return; - } - - const size_t num_lines = GetNumLinesInLabel(); - size_t start = 0; - for (size_t i = 0; i < num_lines - 1; ++i) { - size_t end = GetTextIndexOfLineInLabel(i + 1); - std::string substring = text.substr(start, end - start); - AddVirtualChildView(substring, i, gfx::Range(start, end)); - start = end; - } - std::string substring = text.substr(start, text.size() - start); - if (!substring.empty()) { - AddVirtualChildView(substring, num_lines - 1, - gfx::Range(start, text.size())); - } - - // Remove all virtual children that don't have a corresponding line. - size_t num_virtual_children = virtual_children.size(); - for (size_t i = num_lines; i < num_virtual_children; ++i) { - GetViewAccessibility().RemoveVirtualChildView( - virtual_children.back().get()); - } -} - -void CaptionBubble::AddVirtualChildView(const std::string& name, - const size_t line_index, - const gfx::Range& range) { - auto& virtual_children = GetViewAccessibility().virtual_children(); - - // Add a new virtual child for a new line of text. - DCHECK(line_index <= virtual_children.size()); - if (line_index == virtual_children.size()) { - auto view = std::make_unique<views::AXVirtualView>(); - GetViewAccessibility().AddVirtualChildView(std::move(view)); - } - - // Set the virtual child's name as the content of the line. - ui::AXNodeData& ax_node_data = virtual_children[line_index]->GetCustomData(); - if (ax_node_data.GetStringAttribute(ax::mojom::StringAttribute::kName) != - name) { - ax_node_data.SetName(name); - std::vector<gfx::Rect> bounds = label_->GetSubstringBounds(range); - DCHECK_EQ(bounds.size(), 1u); - ax_node_data.relative_bounds.bounds = gfx::RectF(bounds[0]); - } } void CaptionBubble::OnErrorChanged() { @@ -629,17 +652,11 @@ bool has_error = model_->HasError(); label_->SetVisible(!has_error); error_message_->SetVisible(has_error); + expand_button_->SetVisible(!has_error && !is_expanded_); + collapse_button_->SetVisible(!has_error && is_expanded_); // The error is only 1 line, so redraw the bubble. Redraw(); - - if (has_error && - !content::BrowserAccessibilityState::GetInstance() - ->GetAccessibilityMode() - .is_mode_off() && - !GetViewAccessibility().virtual_children().empty()) { - GetViewAccessibility().RemoveAllVirtualChildViews(); - } } void CaptionBubble::OnIsExpandedChanged() { @@ -661,26 +678,37 @@ void CaptionBubble::UpdateBubbleVisibility() { DCHECK(GetWidget()); + // If there is no model set, do not show the bubble. if (!model_) { - // If there is no model set, do not show the bubble. if (GetWidget()->IsVisible()) GetWidget()->Hide(); - } else if (!can_layout_ || model_->IsClosed()) { - // Hide the widget if there is no room for it or the model is closed. + return; + } + + // Hide the widget if there is no room for it, the model is closed. or the + // bubble has no activity. Activity is defined as transcription received from + // the speech service or user interacting with the bubble through focus, + // pressing buttons, or dragging. + if (!can_layout_ || model_->IsClosed() || !HasActivity()) { if (GetWidget()->IsVisible()) GetWidget()->Hide(); - } else if (!model_->GetFullText().empty() || model_->HasError()) { - // Show the widget if it has text or an error to display. + return; + } + + // Show the widget if it has text or an error to display. + if (!model_->GetFullText().empty() || model_->HasError()) { if (!GetWidget()->IsVisible()) { GetWidget()->ShowInactive(); GetViewAccessibility().AnnounceText(l10n_util::GetStringUTF16( IDS_LIVE_CAPTION_BUBBLE_APPEAR_SCREENREADER_ANNOUNCEMENT)); LogSessionEvent(SessionEvent::kStreamStarted); } - } else if (GetWidget()->IsVisible()) { - // No text and no error. Hide it. - GetWidget()->Hide(); + return; } + + // No text and no error. Hide it. + if (GetWidget()->IsVisible()) + GetWidget()->Hide(); } void CaptionBubble::OnWidgetVisibilityChanged(views::Widget* widget, @@ -774,20 +802,34 @@ LogSessionEvent(SessionEvent::kStreamEnded); if (GetWidget()->IsVisible()) GetWidget()->Hide(); + + // Clear the partial and final text in the caption bubble model and the label. + // Does not affect the speech service. The speech service will emit a final + // result after ~10-15 seconds of no audio which the caption bubble will + // receive but will not display. If the speech service is in the middle of a + // recognition phrase, and the caption bubble regains activity (such as if the + // audio stream restarts), the speech service will emit partial results that + // contain text cleared by the UI. + model_->ClearText(); } -std::string CaptionBubble::GetLabelTextForTesting() { - return base::UTF16ToUTF8(label_->GetText()); +bool CaptionBubble::HasActivity() { + return model_ && (inactivity_timer_->IsRunning() || HasFocus() || + !model_->GetFullText().empty() || model_->HasError()); } -std::vector<std::string> CaptionBubble::GetVirtualChildrenTextForTesting() { - auto& virtual_children = GetViewAccessibility().virtual_children(); - std::vector<std::string> texts; - for (auto& virtual_child : virtual_children) { - texts.push_back(virtual_child->GetCustomData().GetStringAttribute( +views::Label* CaptionBubble::GetLabelForTesting() { + return static_cast<views::Label*>(label_); +} + +std::vector<std::string> CaptionBubble::GetAXLineTextForTesting() { + auto& ax_lines = label_->GetViewAccessibility().virtual_children(); + std::vector<std::string> line_texts; + for (auto& ax_line : ax_lines) { + line_texts.push_back(ax_line->GetCustomData().GetStringAttribute( ax::mojom::StringAttribute::kName)); } - return texts; + return line_texts; } base::RetainingOneShotTimer* CaptionBubble::GetInactivityTimerForTesting() {
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble.h b/chrome/browser/ui/views/accessibility/caption_bubble.h index 7304bba0..7d06ce8 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble.h +++ b/chrome/browser/ui/views/accessibility/caption_bubble.h
@@ -38,6 +38,7 @@ namespace captions { class CaptionBubbleFrameView; +class CaptionBubbleLabel; /////////////////////////////////////////////////////////////////////////////// // Caption Bubble @@ -66,17 +67,11 @@ // the caption text size. void UpdateCaptionStyle(base::Optional<ui::CaptionStyle> caption_style); - // For the provided line index, gets the corresponding rendered line in the - // label and returns the text position of the first character of that line. - // Returns the same value regardless of whether the label is visible or not. - // TODO(crbug.com/1055150): This feature is launching for English first. - // Make sure this is correct for all languages. - size_t GetTextIndexOfLineInLabel(size_t line) const; + // Returns whether the bubble has activity, with the above definition of + // activity. + bool HasActivity(); - // Returns the number of lines in the caption bubble label that are rendered. - size_t GetNumLinesInLabel() const; - - std::string GetLabelTextForTesting(); + views::Label* GetLabelForTesting(); base::RetainingOneShotTimer* GetInactivityTimerForTesting(); void set_tick_clock_for_testing(const base::TickClock* tick_clock) { tick_clock_ = tick_clock; @@ -97,6 +92,7 @@ void OnFocus() override; void OnBlur() override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + base::string16 GetAccessibleWindowTitle() const override; void AddedToWidget() override; private: @@ -124,6 +120,16 @@ void UpdateBubbleVisibility(); void UpdateBubbleAndTitleVisibility(); + // For the provided line index, gets the corresponding rendered line in the + // label and returns the text position of the first character of that line. + // Returns the same value regardless of whether the label is visible or not. + // TODO(crbug.com/1055150): This feature is launching for English first. + // Make sure this is correct for all languages. + size_t GetTextIndexOfLineInLabel(size_t line) const; + + // Returns the number of lines in the caption bubble label that are rendered. + size_t GetNumLinesInLabel() const; + double GetTextScaleFactor(); int GetNumLinesVisible(); void UpdateTextSize(); @@ -133,10 +139,7 @@ views::Button::PressedCallback callback, const gfx::VectorIcon& icon, const int tooltip_text_id); - void AddVirtualChildView(const std::string& name, - const size_t i, - const gfx::Range& range); - std::vector<std::string> GetVirtualChildrenTextForTesting(); + std::vector<std::string> GetAXLineTextForTesting(); // After 5 seconds of inactivity, hide the caption bubble. Activity is defined // as transcription received from the speech service or user interacting with @@ -144,7 +147,7 @@ void OnInactivityTimeout(); // Unowned. Owned by views hierarchy. - views::Label* label_; + CaptionBubbleLabel* label_; views::Label* title_; views::Label* error_text_; views::ImageView* error_icon_;
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc index 017c286..70a7e19 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc
@@ -78,8 +78,16 @@ CaptionBubbleModel* caption_bubble_model = caption_bubble_models_[web_contents].get(); - caption_bubble_model->SetPartialText(transcription_result->transcription); + // If the caption bubble has no activity and it receives a final + // transcription, don't set text. The speech service sends a final + // transcription after several seconds of no audio. This prevents the bubble + // reappearing with a final transcription after it had disappeared due to no + // activity. + if (!caption_bubble_->HasActivity() && transcription_result->is_final) + return true; + + caption_bubble_model->SetPartialText(transcription_result->transcription); if (transcription_result->is_final) caption_bubble_model->CommitPartialText(); @@ -140,7 +148,10 @@ } std::string CaptionBubbleControllerViews::GetBubbleLabelTextForTesting() { - return caption_bubble_ ? caption_bubble_->GetLabelTextForTesting() : ""; + return caption_bubble_ + ? base::UTF16ToUTF8( + caption_bubble_->GetLabelForTesting()->GetText()) // IN-TEST + : ""; } } // namespace captions
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc index 6c8f7e9cf..36449ee 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
@@ -60,13 +60,21 @@ } views::Label* GetLabel() { - return controller_ ? controller_->caption_bubble_->label_ : nullptr; + return controller_ ? controller_->caption_bubble_->GetLabelForTesting() + : nullptr; } views::Label* GetTitle() { return controller_ ? controller_->caption_bubble_->title_ : nullptr; } + std::string GetAccessibleWindowTitle() { + return controller_ + ? base::UTF16ToUTF8( + controller_->caption_bubble_->GetAccessibleWindowTitle()) + : ""; + } + views::Button* GetCloseButton() { return controller_ ? controller_->caption_bubble_->close_button_ : nullptr; } @@ -96,6 +104,10 @@ return controller_ ? controller_->GetBubbleLabelTextForTesting() : ""; } + size_t GetNumLinesInLabel() { + return controller_ ? controller_->caption_bubble_->GetNumLinesInLabel() : 0; + } + views::Widget* GetCaptionWidget() { return controller_ ? controller_->caption_widget_ : nullptr; } @@ -162,8 +174,8 @@ browser()->tab_strip_model()->GetWebContentsAt(tab_index)); } - std::vector<std::string> GetVirtualChildrenText() { - return GetBubble()->GetVirtualChildrenTextForTesting(); + std::vector<std::string> GetAXLineText() { + return GetBubble()->GetAXLineTextForTesting(); } void SetTickClockForTesting(const base::TickClock* tick_clock) { @@ -394,21 +406,24 @@ EXPECT_TRUE(GetLabel()->GetVisible()); EXPECT_FALSE(GetErrorMessage()->GetVisible()); - OnError(0); + OnError(); EXPECT_FALSE(GetTitle()->GetVisible()); EXPECT_FALSE(GetLabel()->GetVisible()); EXPECT_TRUE(GetErrorMessage()->GetVisible()); - // Setting text during an error shouldn't cause the error to disappear. + // Setting text during an error should cause the error to disappear. OnPartialTranscription("Elephant tails average 4-5 feet long."); - EXPECT_FALSE(GetTitle()->GetVisible()); - EXPECT_FALSE(GetLabel()->GetVisible()); - EXPECT_TRUE(GetErrorMessage()->GetVisible()); + EXPECT_TRUE(GetTitle()->GetVisible()); + EXPECT_TRUE(GetLabel()->GetVisible()); + EXPECT_FALSE(GetErrorMessage()->GetVisible()); + + // Set the error again. + OnError(); // The error should not be visible on a new tab. InsertNewTab(); ActivateTabAt(1); - OnPartialTranscription("Elephants are vegetarians."); + OnPartialTranscription("Elephants are vegetarians.", 1); EXPECT_TRUE(GetTitle()->GetVisible()); EXPECT_TRUE(GetLabel()->GetVisible()); EXPECT_FALSE(GetErrorMessage()->GetVisible()); @@ -430,7 +445,7 @@ } IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, CloseButtonCloses) { - bool success = OnFinalTranscription("Elephants have 3-4 toenails per foot"); + bool success = OnPartialTranscription("Elephants have 3-4 toenails per foot"); EXPECT_TRUE(success); EXPECT_TRUE(GetCaptionWidget()); EXPECT_TRUE(IsWidgetVisible()); @@ -438,7 +453,7 @@ ClickButton(GetCloseButton()); EXPECT_TRUE(GetCaptionWidget()); EXPECT_FALSE(IsWidgetVisible()); - success = OnFinalTranscription( + success = OnPartialTranscription( "Elephants wander 35 miles a day in search of water"); EXPECT_FALSE(success); EXPECT_EQ("", GetLabelText()); @@ -763,21 +778,23 @@ for (int i = 10; i < 40; i++) { text += base::NumberToString(i) + line + " "; } + OnPartialTranscription(text); OnFinalTranscription(text); EXPECT_EQ(text.substr(10500, 15000), GetLabelText()); - EXPECT_EQ(9u, GetBubble()->GetNumLinesInLabel()); + EXPECT_EQ(9u, GetNumLinesInLabel()); OnPartialTranscription(text); EXPECT_EQ(text.substr(10500, 15000) + text, GetLabelText()); - EXPECT_EQ(39u, GetBubble()->GetNumLinesInLabel()); + EXPECT_EQ(39u, GetNumLinesInLabel()); OnFinalTranscription("a "); EXPECT_EQ(text.substr(11000, 15000) + "a ", GetLabelText()); - EXPECT_EQ(9u, GetBubble()->GetNumLinesInLabel()); + EXPECT_EQ(9u, GetNumLinesInLabel()); } IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, TabNavigation) { ui_test_utils::NavigateToURL(browser(), GURL("http://www.google.com")); content::WaitForLoadStop( browser()->tab_strip_model()->GetActiveWebContents()); + OnPartialTranscription("Elephant calves"); OnFinalTranscription("Elephant calves can stand within 20 minutes of birth"); EXPECT_TRUE(IsWidgetVisible()); EXPECT_EQ("Elephant calves can stand within 20 minutes of birth", @@ -879,7 +896,7 @@ ActivateTabAt(1); EXPECT_FALSE(IsWidgetVisible()); - OnPartialTranscription("Nearly all ants are female."); + OnPartialTranscription("Nearly all ants are female.", 1); EXPECT_TRUE(GetCollapseButton()->GetVisible()); EXPECT_FALSE(GetExpandButton()->GetVisible()); EXPECT_EQ(7 * line_height, GetLabel()->GetBoundsInScreen().height()); @@ -888,6 +905,17 @@ EXPECT_TRUE(GetExpandButton()->GetVisible()); EXPECT_FALSE(GetCollapseButton()->GetVisible()); EXPECT_EQ(line_height, GetLabel()->GetBoundsInScreen().height()); + + // The expand and collapse buttons are not visible when there is an error. + OnError(1); + EXPECT_FALSE(GetCollapseButton()->GetVisible()); + EXPECT_FALSE(GetExpandButton()->GetVisible()); + + // Clear the error message. The expand button should appear. + OnPartialTranscription("An ant can lift 20 times its own body weight.", 1); + EXPECT_TRUE(GetExpandButton()->GetVisible()); + EXPECT_FALSE(GetCollapseButton()->GetVisible()); + EXPECT_EQ(line_height, GetLabel()->GetBoundsInScreen().height()); } IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, NonAsciiCharacter) { @@ -902,21 +930,22 @@ AccessibleTextComputedWhenAccessibilityModeEnabled) { // If accessibility is disabled, virtual children aren't computed. content::BrowserAccessibilityState::GetInstance()->DisableAccessibility(); + OnPartialTranscription("A"); OnFinalTranscription("A dog's nose print"); - EXPECT_EQ(0u, GetVirtualChildrenText().size()); + EXPECT_EQ(0u, GetAXLineText().size()); // When accessibility is enabled, virtual children are computed. content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); OnFinalTranscription("is unique"); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("A dog's nose print is unique", GetVirtualChildrenText()[0]); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ("A dog's nose print is unique", GetAXLineText()[0]); // When accessibility is disabled, virtual children are no longer being // updated. content::BrowserAccessibilityState::GetInstance()->DisableAccessibility(); OnFinalTranscription("like a fingerprint"); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("A dog's nose print is unique", GetVirtualChildrenText()[0]); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ("A dog's nose print is unique", GetAXLineText()[0]); } IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, @@ -927,79 +956,55 @@ content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); OnPartialTranscription(line); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ(line, GetVirtualChildrenText()[0]); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ(line, GetAXLineText()[0]); OnPartialTranscription(line + line); - EXPECT_EQ(2u, GetVirtualChildrenText().size()); - EXPECT_EQ(line, GetVirtualChildrenText()[0]); - EXPECT_EQ(line, GetVirtualChildrenText()[1]); + EXPECT_EQ(2u, GetAXLineText().size()); + EXPECT_EQ(line, GetAXLineText()[0]); + EXPECT_EQ(line, GetAXLineText()[1]); OnPartialTranscription(line); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ(line, GetVirtualChildrenText()[0]); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ(line, GetAXLineText()[0]); } IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, AccessibleTextClearsWhenBubbleCloses) { content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); - OnFinalTranscription("Dogs' noses are wet to help them smell."); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("Dogs' noses are wet to help them smell.", - GetVirtualChildrenText()[0]); + OnPartialTranscription("Dogs' noses are wet to help them smell."); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ("Dogs' noses are wet to help them smell.", GetAXLineText()[0]); ClickButton(GetCloseButton()); - EXPECT_EQ(0u, GetVirtualChildrenText().size()); + EXPECT_EQ(0u, GetAXLineText().size()); } IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, AccessibleTextClearsWhenTabRefreshes) { content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); - OnFinalTranscription("Newfoundlands are amazing lifeguards."); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("Newfoundlands are amazing lifeguards.", - GetVirtualChildrenText()[0]); + OnPartialTranscription("Newfoundlands are amazing lifeguards."); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ("Newfoundlands are amazing lifeguards.", GetAXLineText()[0]); chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB); content::WaitForLoadStop( browser()->tab_strip_model()->GetActiveWebContents()); - EXPECT_EQ(0u, GetVirtualChildrenText().size()); + EXPECT_EQ(0u, GetAXLineText().size()); } IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, AccessibleTextChangesWhenTabChanges) { content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); - OnFinalTranscription("3 dogs survived the Titanic sinking."); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("3 dogs survived the Titanic sinking.", - GetVirtualChildrenText()[0]); + OnPartialTranscription("3 dogs survived the Titanic sinking."); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ("3 dogs survived the Titanic sinking.", GetAXLineText()[0]); InsertNewTab(); ActivateTabAt(1); OnFinalTranscription("30% of Dalmations are deaf in one ear.", 1); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("30% of Dalmations are deaf in one ear.", - GetVirtualChildrenText()[0]); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ("30% of Dalmations are deaf in one ear.", GetAXLineText()[0]); ActivateTabAt(0); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("3 dogs survived the Titanic sinking. ", - GetVirtualChildrenText()[0]); -} - -IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, - AccessibleTextClearsOnError) { - content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); - OnFinalTranscription("The Saluki is the oldest dog breed."); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("The Saluki is the oldest dog breed.", GetVirtualChildrenText()[0]); - OnError(); - EXPECT_EQ(0u, GetVirtualChildrenText().size()); - - // Clear the error by refreshing. - chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB); - content::WaitForLoadStop( - browser()->tab_strip_model()->GetActiveWebContents()); - - OnFinalTranscription("Chow Chows have black tongues."); - EXPECT_EQ(1u, GetVirtualChildrenText().size()); - EXPECT_EQ("Chow Chows have black tongues.", GetVirtualChildrenText()[0]); + EXPECT_EQ(1u, GetAXLineText().size()); + EXPECT_EQ("3 dogs survived the Titanic sinking.", GetAXLineText()[0]); } IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, @@ -1011,29 +1016,26 @@ text += base::NumberToString(i) + line + " "; } content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); + OnPartialTranscription(text); OnFinalTranscription(text); - EXPECT_EQ(9u, GetVirtualChildrenText().size()); + EXPECT_EQ(9u, GetAXLineText().size()); for (int i = 0; i < 9; i++) { - EXPECT_EQ(base::NumberToString(i + 31) + line + " ", - GetVirtualChildrenText()[i]); + EXPECT_EQ(base::NumberToString(i + 31) + line + " ", GetAXLineText()[i]); } OnPartialTranscription(text); - EXPECT_EQ(39u, GetVirtualChildrenText().size()); + EXPECT_EQ(39u, GetAXLineText().size()); for (int i = 0; i < 9; i++) { - EXPECT_EQ(base::NumberToString(i + 31) + line + " ", - GetVirtualChildrenText()[i]); + EXPECT_EQ(base::NumberToString(i + 31) + line + " ", GetAXLineText()[i]); } for (int i = 10; i < 40; i++) { - EXPECT_EQ(base::NumberToString(i) + line + " ", - GetVirtualChildrenText()[i - 1]); + EXPECT_EQ(base::NumberToString(i) + line + " ", GetAXLineText()[i - 1]); } OnFinalTranscription("a "); - EXPECT_EQ(9u, GetVirtualChildrenText().size()); + EXPECT_EQ(9u, GetAXLineText().size()); for (int i = 0; i < 8; i++) { - EXPECT_EQ(base::NumberToString(i + 32) + line + " ", - GetVirtualChildrenText()[i]); + EXPECT_EQ(base::NumberToString(i + 32) + line + " ", GetAXLineText()[i]); } - EXPECT_EQ("a ", GetVirtualChildrenText()[8]); + EXPECT_EQ("a ", GetAXLineText()[8]); } #if !defined(OS_MAC) @@ -1068,24 +1070,32 @@ // Caption bubble hides after 5 seconds without receiving a transcription. OnPartialTranscription("Bowhead whales can live for over 200 years."); EXPECT_TRUE(IsWidgetVisible()); + EXPECT_EQ("Bowhead whales can live for over 200 years.", GetLabelText()); ASSERT_TRUE(GetBubble()->GetInactivityTimerForTesting()->IsRunning()); test_task_runner->FastForwardBy(base::TimeDelta::FromSeconds(5)); EXPECT_FALSE(IsWidgetVisible()); + EXPECT_EQ("", GetLabelText()); // Caption bubble becomes visible when transcription is received, and stays // visible if transcriptions are received before 5 seconds have passed. OnPartialTranscription("Killer whales"); EXPECT_TRUE(IsWidgetVisible()); + EXPECT_EQ("Killer whales", GetLabelText()); test_task_runner->FastForwardBy(base::TimeDelta::FromSeconds(4)); EXPECT_TRUE(IsWidgetVisible()); OnPartialTranscription("Killer whales travel in matrifocal groups"); EXPECT_TRUE(IsWidgetVisible()); + EXPECT_EQ("Killer whales travel in matrifocal groups", GetLabelText()); test_task_runner->FastForwardBy(base::TimeDelta::FromSeconds(4)); EXPECT_TRUE(IsWidgetVisible()); OnFinalTranscription( "Killer whales travel in matrifocal groups--a family unit centered on " "the mother."); EXPECT_TRUE(IsWidgetVisible()); + EXPECT_EQ( + "Killer whales travel in matrifocal groups--a family unit centered on " + "the mother.", + GetLabelText()); test_task_runner->FastForwardBy(base::TimeDelta::FromSeconds(4)); EXPECT_TRUE(IsWidgetVisible()); @@ -1096,12 +1106,56 @@ EXPECT_TRUE(IsWidgetVisible()); test_task_runner->FastForwardBy(base::TimeDelta::FromSeconds(10)); EXPECT_TRUE(IsWidgetVisible()); + EXPECT_EQ( + "Killer whales travel in matrifocal groups--a family unit centered on " + "the mother.", + GetLabelText()); UnfocusCaptionWidget(); EXPECT_FALSE(GetBubble()->HasFocus()); + EXPECT_EQ( + "Killer whales travel in matrifocal groups--a family unit centered on " + "the mother.", + GetLabelText()); EXPECT_TRUE(IsWidgetVisible()); test_task_runner->FastForwardBy(base::TimeDelta::FromSeconds(5)); EXPECT_FALSE(IsWidgetVisible()); + EXPECT_EQ("", GetLabelText()); +} + +IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, + ClearsTextAfterInactivity) { + // Use a ScopedMockTimeMessageLoopTaskRunner to test the inactivity timer with + // a mock tick clock that replaces the default tick clock with mock time. + base::ScopedMockTimeMessageLoopTaskRunner test_task_runner; + SetTickClockForTesting(test_task_runner->GetMockTickClock()); + + // Caption bubble hides after 5 seconds without receiving a transcription. + OnPartialTranscription("Bowhead whales can live for over 200 years."); + EXPECT_TRUE(IsWidgetVisible()); + EXPECT_EQ("Bowhead whales can live for over 200 years.", GetLabelText()); + ASSERT_TRUE(GetBubble()->GetInactivityTimerForTesting()->IsRunning()); + test_task_runner->FastForwardBy(base::TimeDelta::FromSeconds(5)); + EXPECT_FALSE(IsWidgetVisible()); + EXPECT_EQ("", GetLabelText()); + + // Caption bubble stays hidden when receiving a final transcription. + OnFinalTranscription("Bowhead whales can live for over 200 years."); + EXPECT_FALSE(IsWidgetVisible()); + EXPECT_EQ("", GetLabelText()); + + // Caption bubble reappears when receiving a partial transcription. + OnPartialTranscription("Killer whales"); + EXPECT_TRUE(IsWidgetVisible()); + EXPECT_EQ("Killer whales", GetLabelText()); +} + +IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, + HasAccessibleWindowTitle) { + OnPartialTranscription("A turtle's shell is part of its skeleton."); + EXPECT_FALSE(GetAccessibleWindowTitle().empty()); + EXPECT_EQ(GetAccessibleWindowTitle(), + base::UTF16ToUTF8(GetTitle()->GetText())); } } // namespace captions
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_model.cc b/chrome/browser/ui/views/accessibility/caption_bubble_model.cc index 4aa8782a..70741417 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_model.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble_model.cc
@@ -46,13 +46,16 @@ void CaptionBubbleModel::SetPartialText(const std::string& partial_text) { partial_text_ = partial_text; OnTextChanged(); + if (has_error_) { + has_error_ = false; + if (observer_) + observer_->OnErrorChanged(); + } } void CaptionBubbleModel::Close() { - final_text_.clear(); - partial_text_.clear(); is_closed_ = true; - OnTextChanged(); + ClearText(); } void CaptionBubbleModel::OnError() { @@ -61,20 +64,23 @@ observer_->OnErrorChanged(); } +void CaptionBubbleModel::ClearText() { + partial_text_.clear(); + final_text_.clear(); + OnTextChanged(); +} + void CaptionBubbleModel::DidFinishNavigation( content::NavigationHandle* navigation_handle) { if (!navigation_handle->IsInMainFrame()) return; // Reset caption bubble to it's starting state. - final_text_.clear(); - partial_text_.clear(); is_closed_ = false; has_error_ = false; - if (observer_) { - observer_->OnTextChanged(); + ClearText(); + if (observer_) observer_->OnErrorChanged(); - } } void CaptionBubbleModel::CommitPartialText() {
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_model.h b/chrome/browser/ui/views/accessibility/caption_bubble_model.h index dedc492..8b1e6ef 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_model.h +++ b/chrome/browser/ui/views/accessibility/caption_bubble_model.h
@@ -57,6 +57,9 @@ // observer. void Close(); + // Clears the partial and final text and alerts the observer. + void ClearText(); + bool IsClosed() const { return is_closed_; } bool HasError() const { return has_error_; } std::string GetFullText() const { return final_text_ + partial_text_; }
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc index b13cd7e..ccfdddf 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -318,12 +318,12 @@ void ExtensionsToolbarContainer::PopOutAction( ToolbarActionViewController* action, bool is_sticky, - const base::RepeatingClosure& closure) { + base::OnceClosure closure) { // TODO(pbos): Highlight popout differently. DCHECK(!popped_out_action_); popped_out_action_ = action; UpdateIconVisibility(action->GetId()); - animating_layout_manager()->PostOrQueueAction(closure); + animating_layout_manager()->PostOrQueueAction(std::move(closure)); } bool ExtensionsToolbarContainer::ShowToolbarActionPopupForAPICall(
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h index ac6426b..abdbb5a 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
@@ -117,7 +117,7 @@ bool CloseOverflowMenuIfOpen() override; void PopOutAction(ToolbarActionViewController* action, bool is_sticky, - const base::RepeatingClosure& closure) override; + base::OnceClosure closure) override; bool ShowToolbarActionPopupForAPICall(const std::string& action_id) override; void ShowToolbarActionBubble( std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 9080154..f3284c11 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -2584,27 +2584,33 @@ if (!model()->CurrentTextIsURL()) return false; base::string16 text = GetText(); - url::Component scheme, host; - AutocompleteInput::ParseForEmphasizeComponents( - text, model()->client()->GetSchemeClassifier(), &scheme, &host); + url::Parsed parts; + base::string16 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 base::string16 url_host = text.substr(host.begin, host.len); + const base::string16 url_host = text.substr(parts.host.begin, parts.host.len); if (base::i18n::GetStringDirection(url_host) == base::i18n::TextDirection::UNKNOWN_DIRECTION) { return false; } - const base::string16 url_scheme = text.substr(scheme.begin, scheme.len); + // 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 (url_scheme == base::UTF8ToUTF16(url::kHttpScheme) || - url_scheme == base::UTF8ToUTF16(url::kHttpsScheme)) && - host.is_nonempty() && + return (scheme_str == base::UTF8ToUTF16(url::kHttpScheme) || + scheme_str == base::UTF8ToUTF16(url::kHttpsScheme)) && + !url_host.empty() && !net::HostStringIsLocalhost( - base::UTF16ToUTF8(text.substr(host.begin, host.len))); + base::UTF16ToUTF8(text.substr(parts.host.begin, parts.host.len))); } void OmniboxViewViews::ResetToHideOnInteraction() {
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 88894cf..0182d426 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -2842,6 +2842,9 @@ base::ASCIIToUTF16("javascript:alert(1)"), base::ASCIIToUTF16("data:text/html,hello"), base::ASCIIToUTF16("http://localhost:4000/foo"), + base::ASCIIToUTF16("blob:https://example.test/"), + base::ASCIIToUTF16("view-source:https://example.test/"), + base::ASCIIToUTF16("filesystem:https://example.test/a"), // A smoke test to check that the test code results in // the URL being elided properly when eligible. kSimplifiedDomainDisplayUrl,
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc index 95cd768..84f9e5c 100644 --- a/chrome/browser/ui/views/task_manager_view.cc +++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -105,6 +105,7 @@ window->SetProperty(ash::kShelfIDKey, shelf_id.Serialize()); window->SetProperty(ash::kAppIDKey, shelf_id.app_id); window->SetProperty<int>(ash::kShelfItemTypeKey, ash::TYPE_DIALOG); + window->SetTitle(l10n_util::GetStringUTF16(IDS_TASK_MANAGER_TITLE)); #endif return g_task_manager_view->table_model_.get(); } @@ -277,7 +278,10 @@ SetButtonLabel(ui::DIALOG_BUTTON_OK, l10n_util::GetStringUTF16(IDS_TASK_MANAGER_KILL)); SetHasWindowSizeControls(true); +#if !BUILDFLAG(IS_CHROMEOS_ASH) + // On Chrome OS, the widget's frame should not show the window title. SetTitle(IDS_TASK_MANAGER_TITLE); +#endif // Avoid calling Accept() when closing the dialog, since Accept() here means // "kill task" (!).
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc index 2420b070..bd6820d9 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
@@ -209,6 +209,6 @@ // ToolbarActionsBarBubbleDelegate. The ToolbarActionsBarBubbleDelegate is // an ExtensionMessageBubbleBridge, which owns the // ExtensionMessageBubbleController. - delegate_->OnBubbleShown(base::BindRepeating(&views::Widget::Close, - base::Unretained(GetWidget()))); + delegate_->OnBubbleShown( + base::BindOnce(&views::Widget::Close, base::Unretained(GetWidget()))); }
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 7918d21bf..f74356a1 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -226,6 +226,7 @@ #include "chromeos/services/multidevice_setup/multidevice_setup_service.h" #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h" #include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom.h" +#include "chromeos/services/network_health/public/mojom/network_health.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #endif @@ -439,6 +440,14 @@ chromeos::network_health::NetworkHealthService::GetInstance() ->BindDiagnosticsReceiver(std::move(receiver)); }), + /* BindNetworkHealthServiceCallback */ + base::BindRepeating( + [](mojo::PendingReceiver< + chromeos::network_health::mojom::NetworkHealthService> + receiver) { + chromeos::network_health::NetworkHealthService::GetInstance() + ->BindHealthReceiver(std::move(receiver)); + }), /* SendFeedbackReportCallback */ base::BindRepeating( &chrome::ShowFeedbackDialogForWebUI,
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc index 9ba04c3b..6e4fda6a 100644 --- a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
@@ -4,17 +4,20 @@ #include "chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.h" +#include "base/containers/span.h" +#include "base/feature_list.h" +#include "base/no_destructor.h" +#include "base/values.h" #include "chrome/browser/ui/webui/webui_util.h" #include "chrome/grit/generated_resources.h" +#include "chromeos/constants/chromeos_features.h" #include "components/login/localized_values_builder.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/web_ui_data_source.h" #include "ui/base/webui/web_ui_util.h" namespace chromeos { - namespace cellular_setup { - namespace { constexpr webui::LocalizedString kLocalizedStringsWithoutPlaceholders[] = { @@ -63,6 +66,21 @@ {"qrCodeRetry", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_RETRY}, {"scanQrCodeInvalid", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_INVALID}, {"profileListPageMessage", IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE}}; + +struct NamedBoolean { + const char* name; + bool value; +}; + +const std::vector<const NamedBoolean>& GetBooleanValues() { + static const base::NoDestructor<std::vector<const NamedBoolean>> named_bools({ + {"updatedCellularActivationUi", + base::FeatureList::IsEnabled( + chromeos::features::kUpdatedCellularActivationUi)}, + }); + return *named_bools; +} + } // namespace void AddLocalizedStrings(content::WebUIDataSource* html_source) { @@ -74,6 +92,15 @@ builder->Add(entry.name, entry.id); } -} // namespace cellular_setup +void AddNonStringLoadTimeData(content::WebUIDataSource* html_source) { + for (const auto& entry : GetBooleanValues()) + html_source->AddBoolean(entry.name, entry.value); +} +void AddNonStringLoadTimeDataToDict(base::DictionaryValue* dict) { + for (const auto& entry : GetBooleanValues()) + dict->SetBoolean(entry.name, entry.value); +} + +} // namespace cellular_setup } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.h b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.h index 6ab522f..5af2ed196 100644 --- a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.h +++ b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.h
@@ -5,16 +5,19 @@ #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_CELLULAR_SETUP_CELLULAR_SETUP_LOCALIZED_STRINGS_PROVIDER_H_ #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_CELLULAR_SETUP_CELLULAR_SETUP_LOCALIZED_STRINGS_PROVIDER_H_ +namespace base { +class DictionaryValue; +} // namespace base + namespace login { class LocalizedValuesBuilder; -} +} // namespace login namespace content { class WebUIDataSource; -} +} // namespace content namespace chromeos { - namespace cellular_setup { // Adds the strings needed for the cellular setup flow to |html_source|. @@ -23,8 +26,13 @@ // Same as AddLocalizedStrings() but for a LocalizedValuesBuilder. void AddLocalizedValuesToBuilder(::login::LocalizedValuesBuilder* builder); -} // namespace cellular_setup +// Adds non-string constants for loadTimeData consumption. +void AddNonStringLoadTimeData(content::WebUIDataSource* html_source); +// Same as AddNonStringLoadTimeData() but for a DictionaryValue. +void AddNonStringLoadTimeDataToDict(base::DictionaryValue* dict); + +} // namespace cellular_setup } // namespace chromeos #endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_CELLULAR_SETUP_CELLULAR_SETUP_LOCALIZED_STRINGS_PROVIDER_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc index 007078bc..9547e688 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h" #include "chrome/browser/chromeos/login/screens/network_screen.h" #include "chrome/browser/chromeos/login/startup_utils.h" +#include "chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.h" #include "chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h" #include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h" #include "chrome/grit/generated_resources.h" @@ -98,10 +99,12 @@ builder->Add("offlineDemoSetupListItemName", IDS_NETWORK_OFFLINE_DEMO_SETUP_LIST_ITEM_NAME); network_element::AddLocalizedValuesToBuilder(builder); + cellular_setup::AddLocalizedValuesToBuilder(builder); } void NetworkScreenHandler::GetAdditionalParameters( base::DictionaryValue* dict) { + cellular_setup::AddNonStringLoadTimeDataToDict(dict); } void NetworkScreenHandler::Initialize() {
diff --git a/chrome/browser/ui/webui/settings/chromeos/accessibility_section.cc b/chrome/browser/ui/webui/settings/chromeos/accessibility_section.cc index 7d77e1c..5ea3b9f8 100644 --- a/chrome/browser/ui/webui/settings/chromeos/accessibility_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/accessibility_section.cc
@@ -509,6 +509,14 @@ {"assignSelectSwitchLabel", IDS_SETTINGS_ASSIGN_SELECT_SWITCH_LABEL}, {"assignNextSwitchLabel", IDS_SETTINGS_ASSIGN_NEXT_SWITCH_LABEL}, {"assignPreviousSwitchLabel", IDS_SETTINGS_ASSIGN_PREVIOUS_SWITCH_LABEL}, + {"switchAccessActionAssignmentDialogAssignedIconLabel", + IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ASSIGNED_ICON_LABEL}, + {"switchAccessActionAssignmentDialogAddAssignmentIconLabel", + IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ADD_ASSIGNMENT_ICON_LABEL}, + {"switchAccessActionAssignmentDialogRemoveAssignmentIconLabel", + IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_REMOVE_ASSIGNMENT_ICON_LABEL}, + {"switchAccessActionAssignmentDialogErrorIconLabel", + IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_ERROR_ICON_LABEL}, {"switchAccessActionAssignmentDialogTitle", IDS_SETTINGS_SWITCH_ACCESS_ACTION_ASSIGNMENT_DIALOG_TITLE}, {"switchAccessActionAssignmentDialogWarnNotConfirmedPrompt",
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc index 04ba2aa..9ac8f2d 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -1257,7 +1257,7 @@ const GURL& server_url, bool should_fallback) { server_printers_fetcher_ = std::make_unique<ServerPrintersFetcher>( - server_url, "(from user)", + profile_, server_url, "(from user)", base::BindRepeating(&CupsPrintersHandler::OnQueryPrintServerCompleted, weak_factory_.GetWeakPtr(), callback_id, should_fallback));
diff --git a/chrome/browser/ui/webui/settings/chromeos/internet_section.cc b/chrome/browser/ui/webui/settings/chromeos/internet_section.cc index 2d184610..6fb832d 100644 --- a/chrome/browser/ui/webui/settings/chromeos/internet_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/internet_section.cc
@@ -734,6 +734,7 @@ network_element::AddDetailsLocalizedStrings(html_source); network_element::AddConfigLocalizedStrings(html_source); network_element::AddErrorLocalizedStrings(html_source); + cellular_setup::AddNonStringLoadTimeData(html_source); if (base::FeatureList::IsEnabled( chromeos::features::kUpdatedCellularActivationUi)) { cellular_setup::AddLocalizedStrings(html_source); @@ -747,10 +748,6 @@ html_source->AddString("networkGoogleNameserversLearnMoreUrl", chrome::kGoogleNameserversLearnMoreURL); - html_source->AddBoolean( - "updatedCellularActivationUi", - base::FeatureList::IsEnabled( - chromeos::features::kUpdatedCellularActivationUi)); html_source->AddString( "networkNotSynced",
diff --git a/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc b/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc index 4bff3c0..756ee38d 100644 --- a/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
@@ -20,6 +20,7 @@ #include "chrome/common/webui_url_constants.h" #include "chrome/grit/generated_resources.h" #include "chromeos/components/phonehub/phone_hub_manager.h" +#include "chromeos/components/phonehub/url_constants.h" #include "chromeos/constants/chromeos_features.h" #include "chromeos/services/multidevice_setup/public/cpp/prefs.h" #include "chromeos/services/multidevice_setup/public/cpp/url_provider.h" @@ -420,15 +421,11 @@ l10n_util::GetStringFUTF16( IDS_SETTINGS_MULTIDEVICE_PHONE_HUB_NOTIFICATIONS_SUMMARY, ui::GetChromeOSDeviceName())); - // TODO(https://crbug.com/1144053): Replace with updated URL. html_source->AddString( "multideviceNotificationAccessSetupAccessProhibitedSummary", l10n_util::GetStringFUTF16( IDS_SETTINGS_MULTIDEVICE_NOTIFICATION_ACCESS_SETUP_DIALOG_ACCESS_PROHIBITED_SUMMARY, - base::UTF8ToUTF16( - multidevice_setup:: - GetBoardSpecificBetterTogetherSuiteLearnMoreUrl() - .spec()))); + GetHelpUrlWithBoard(phonehub::kPhoneHubLearnMoreLink))); html_source->AddString( "multideviceWifiSyncItemSummary", l10n_util::GetStringFUTF16( @@ -443,7 +440,7 @@ "multidevicePhoneHubTaskContinuationDisabledSummary", l10n_util::GetStringFUTF16( IDS_SETTINGS_MULTIDEVICE_PHONE_HUB_TASK_CONTINUATION_DISABLED_SUMMARY, - GetHelpUrlWithBoard(chrome::kPhoneHubLearnMoreLink))); + GetHelpUrlWithBoard(phonehub::kPhoneHubLearnMoreLink))); AddEasyUnlockStrings(html_source); ::settings::AddNearbyShareData(html_source);
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc index 471701a..ba9b983 100644 --- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc +++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -209,6 +209,10 @@ "createProfile", base::BindRepeating(&ProfilePickerHandler::HandleCreateProfile, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "setProfileName", + base::BindRepeating(&ProfilePickerHandler::HandleSetProfileName, + base::Unretained(this))); } void ProfilePickerHandler::OnJavascriptAllowed() { @@ -447,6 +451,27 @@ profile, Profile::CREATE_STATUS_INITIALIZED); } +void ProfilePickerHandler::HandleSetProfileName(const base::ListValue* args) { + CHECK_EQ(2U, args->GetSize()); + const base::Value& profile_path_value = args->GetList()[0]; + base::Optional<base::FilePath> profile_path = + util::ValueToFilePath(profile_path_value); + + if (!profile_path) { + NOTREACHED(); + return; + } + base::string16 profile_name = + base::UTF8ToUTF16(args->GetList()[1].GetString()); + base::TrimWhitespace(profile_name, base::TRIM_ALL, &profile_name); + CHECK(!profile_name.empty()); + ProfileAttributesEntry* entry; + CHECK(g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetProfileAttributesWithPath(profile_path.value(), &entry)); + entry->SetLocalProfileName(profile_name); +} + void ProfilePickerHandler::HandleRemoveProfile(const base::ListValue* args) { CHECK_EQ(1U, args->GetSize()); const base::Value& profile_path_value = args->GetList()[0]; @@ -570,7 +595,8 @@ std::vector<ProfileAttributesEntry*> entries = g_browser_process->profile_manager() ->GetProfileAttributesStorage() - .GetAllProfilesAttributesSortedByName(); + .GetAllProfilesAttributesSortedByLocalProfilName(); + const int avatar_icon_size = kProfileCardAvatarSize * web_ui()->GetDeviceScaleFactor(); for (const ProfileAttributesEntry* entry : entries) {
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.h b/chrome/browser/ui/webui/signin/profile_picker_handler.h index 7b7af38c..ee3d40a3 100644 --- a/chrome/browser/ui/webui/signin/profile_picker_handler.h +++ b/chrome/browser/ui/webui/signin/profile_picker_handler.h
@@ -39,6 +39,7 @@ void HandleAskOnStartupChanged(const base::ListValue* args); void HandleRemoveProfile(const base::ListValue* args); void HandleGetProfileStatistics(const base::ListValue* args); + void HandleSetProfileName(const base::ListValue* args); // TODO(crbug.com/1115056): Move to new handler for profile creation. void HandleLoadSignInProfileCreationFlow(const base::ListValue* args);
diff --git a/chrome/browser/web_applications/pending_app_manager_impl_unittest.cc b/chrome/browser/web_applications/pending_app_manager_impl_unittest.cc index dafe4bf..66689dd 100644 --- a/chrome/browser/web_applications/pending_app_manager_impl_unittest.cc +++ b/chrome/browser/web_applications/pending_app_manager_impl_unittest.cc
@@ -122,14 +122,65 @@ return TestInstallFinalizer::GetAppIdForUrl(url); } +// Class to delay completion of TestPendingAppInstallTasks. +// +// Tests can call into this class to tell it to save install requests and to +// trigger running the saved requests. TestPendingAppInstallTasks call into this +// class with a OnceClosure. This class then decides if the closure should be +// run immediately or if it should be saved. +class TestPendingAppInstallTaskManager { + public: + TestPendingAppInstallTaskManager() = default; + TestPendingAppInstallTaskManager(const TestPendingAppInstallTaskManager&) = + delete; + TestPendingAppInstallTaskManager& operator=( + const TestPendingAppInstallTaskManager&) = delete; + ~TestPendingAppInstallTaskManager() = default; + + void SaveInstallRequests() { should_save_requests_ = true; } + + void RunOrSaveRequest(base::OnceClosure install_request) { + if (should_save_requests_) { + pending_install_requests_.push(std::move(install_request)); + return; + } + // Post a task to simulate tasks completing asynchronously. + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(install_request)); + } + + void ProcessSavedRequests() { + // Swap to avoid re-entrancy issues. + std::queue<base::OnceClosure> pending_install_requests; + pending_install_requests.swap(pending_install_requests_); + while (!pending_install_requests.empty()) { + base::OnceClosure request = std::move(pending_install_requests.front()); + pending_install_requests.pop(); + std::move(request).Run(); + } + } + + size_t num_pending_tasks() { return pending_install_requests_.size(); } + + private: + std::queue<base::OnceClosure> pending_install_requests_; + bool should_save_requests_ = false; +}; + class TestPendingAppManagerImpl : public PendingAppManagerImpl { public: - TestPendingAppManagerImpl(Profile* profile, - TestAppRegistrar* test_app_registrar, - TestWebAppUrlLoader* test_url_loader) + struct TestTaskResult { + InstallResultCode code; + bool did_install_placeholder; + }; + + TestPendingAppManagerImpl( + Profile* profile, + TestAppRegistrar* test_app_registrar, + TestPendingAppInstallTaskManager& test_install_task_manager) : PendingAppManagerImpl(profile), test_app_registrar_(test_app_registrar), - test_url_loader_(test_url_loader) {} + test_install_task_manager_(test_install_task_manager) {} ~TestPendingAppManagerImpl() override { DCHECK(next_installation_task_results_.empty()); @@ -150,9 +201,11 @@ } void SetNextInstallationTaskResult(const GURL& app_url, - InstallResultCode result_code) { + InstallResultCode result_code, + bool did_install_placeholder = false) { DCHECK(!base::Contains(next_installation_task_results_, app_url)); - next_installation_task_results_[app_url] = result_code; + next_installation_task_results_[app_url] = {result_code, + did_install_placeholder}; } void SetNextInstallationLaunchURL(const GURL& app_url, @@ -174,7 +227,8 @@ std::unique_ptr<PendingAppInstallTask> CreateInstallationTask( ExternalInstallOptions install_options) override { return std::make_unique<TestPendingAppInstallTask>( - this, profile(), test_url_loader_, std::move(install_options)); + this, profile(), &test_url_loader_, test_install_task_manager_, + std::move(install_options)); } std::unique_ptr<PendingAppRegistrationTaskBase> StartRegistration( @@ -189,7 +243,7 @@ install_options_list_.push_back(install_options); } - InstallResultCode GetNextInstallationTaskResult(const GURL& url) { + TestTaskResult GetNextInstallationTaskResult(const GURL& url) { DCHECK(base::Contains(next_installation_task_results_, url)); auto result = next_installation_task_results_.at(url); next_installation_task_results_.erase(url); @@ -240,6 +294,7 @@ TestPendingAppManagerImpl* pending_app_manager_impl, Profile* profile, TestWebAppUrlLoader* test_url_loader, + TestPendingAppInstallTaskManager& test_install_task_manager, ExternalInstallOptions install_options) : PendingAppInstallTask( profile, @@ -252,7 +307,7 @@ install_options), pending_app_manager_impl_(pending_app_manager_impl), externally_installed_app_prefs_(profile->GetPrefs()), - test_url_loader_(test_url_loader) {} + test_install_task_manager_(test_install_task_manager) {} TestPendingAppInstallTask(const TestPendingAppInstallTask&) = delete; TestPendingAppInstallTask& operator=(const TestPendingAppInstallTask&) = @@ -260,12 +315,11 @@ ~TestPendingAppInstallTask() override = default; void DoInstall(const GURL& install_url, - bool is_placeholder, ResultCallback callback) { - auto result_code = + auto result = pending_app_manager_impl_->GetNextInstallationTaskResult(install_url); base::Optional<AppId> app_id; - if (result_code == InstallResultCode::kSuccessNewInstall) { + if (result.code == InstallResultCode::kSuccessNewInstall) { app_id = GenerateFakeAppId(install_url); GURL launch_url = pending_app_manager_impl_->GetNextInstallationLaunchURL( @@ -275,41 +329,37 @@ *app_id, {install_url, install_source, launch_url}); externally_installed_app_prefs_.Insert(install_url, *app_id, install_source); - externally_installed_app_prefs_.SetIsPlaceholder(install_url, - is_placeholder); + externally_installed_app_prefs_.SetIsPlaceholder( + install_url, result.did_install_placeholder); } - std::move(callback).Run(app_id, {.code = result_code}); + std::move(callback).Run(app_id, {.code = result.code}); } void Install(content::WebContents* web_contents, ResultCallback callback) override { pending_app_manager_impl_->OnInstallCalled(install_options()); - const GURL& install_url = install_options().install_url; - test_url_loader_->LoadUrl( - install_url, web_contents, - WebAppUrlLoader::UrlComparison::kSameOrigin, - base::BindLambdaForTesting( - [&, callback = std::move(callback)]( - WebAppUrlLoader::Result load_url_result) mutable { - DoInstall( - install_url, - (load_url_result != WebAppUrlLoader::Result::kUrlLoaded), - std::move(callback)); - })); + const GURL install_url = install_options().install_url; + test_install_task_manager_.RunOrSaveRequest(base::BindLambdaForTesting( + [&, install_url, callback = std::move(callback)]() mutable { + DoInstall(install_url, std::move(callback)); + })); } void InstallFromInfo(ResultCallback callback) override { pending_app_manager_impl_->OnInstallCalled(install_options()); GURL install_url = install_options().app_info_factory.Run()->start_url; - DoInstall(install_url, false, std::move(callback)); + test_install_task_manager_.RunOrSaveRequest(base::BindLambdaForTesting( + [&, install_url, callback = std::move(callback)]() mutable { + DoInstall(install_url, std::move(callback)); + })); } private: TestPendingAppManagerImpl* pending_app_manager_impl_; ExternallyInstalledWebAppPrefs externally_installed_app_prefs_; - TestWebAppUrlLoader* test_url_loader_; + TestPendingAppInstallTaskManager& test_install_task_manager_; }; class TestPendingAppRegistrationTask : public PendingAppRegistrationTaskBase { @@ -346,14 +396,15 @@ }; TestAppRegistrar* test_app_registrar_; - TestWebAppUrlLoader* test_url_loader_; + TestWebAppUrlLoader test_url_loader_; + TestPendingAppInstallTaskManager& test_install_task_manager_; std::vector<ExternalInstallOptions> install_options_list_; GURL last_registered_install_url_; size_t install_run_count_ = 0; size_t registration_run_count_ = 0; - std::map<GURL, InstallResultCode> next_installation_task_results_; + std::map<GURL, TestTaskResult> next_installation_task_results_; std::map<GURL, GURL> next_installation_launch_urls_; base::Optional<base::OnceClosure> preempt_registration_callback_; base::OneShotEvent web_contents_released_event_; @@ -379,16 +430,11 @@ app_registrar_ = test_app_registrar.get(); provider->SetRegistrar(std::move(test_app_registrar)); - auto url_loader = std::make_unique<TestWebAppUrlLoader>(); - url_loader_ = url_loader.get(); - auto test_pending_app_manager = std::make_unique<TestPendingAppManagerImpl>( - profile(), app_registrar_, url_loader_); + profile(), app_registrar_, test_install_task_manager_); pending_app_manager_impl_ = test_pending_app_manager.get(); provider->SetPendingAppManager(std::move(test_pending_app_manager)); - pending_app_manager_impl_->SetUrlLoaderForTesting(std::move(url_loader)); - auto test_install_finalizer = std::make_unique<TestInstallFinalizer>(); install_finalizer_ = test_install_finalizer.get(); provider->SetInstallFinalizer(std::move(test_install_finalizer)); @@ -506,7 +552,9 @@ TestWebAppUiManager* ui_manager() { return ui_manager_; } - TestWebAppUrlLoader* url_loader() { return url_loader_; } + TestPendingAppInstallTaskManager& install_task_manager() { + return test_install_task_manager_; + } TestInstallFinalizer* install_finalizer() { return install_finalizer_; } @@ -515,7 +563,8 @@ TestPendingAppManagerImpl* pending_app_manager_impl_ = nullptr; TestInstallFinalizer* install_finalizer_ = nullptr; TestWebAppUiManager* ui_manager_ = nullptr; - TestWebAppUrlLoader* url_loader_ = nullptr; + + TestPendingAppInstallTaskManager test_install_task_manager_; }; TEST_F(PendingAppManagerImplTest, Install_Succeeds) { @@ -523,8 +572,7 @@ FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); pending_app_manager_impl()->SetNextInstallationLaunchURL(FooWebAppUrl(), FooLaunchUrl()); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); + base::Optional<GURL> url; base::Optional<InstallResultCode> code; std::tie(url, code) = @@ -548,8 +596,6 @@ FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); pending_app_manager_impl()->SetNextInstallationLaunchURL(FooWebAppUrl(), FooLaunchUrl()); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); { base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -571,8 +617,6 @@ BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); pending_app_manager_impl()->SetNextInstallationLaunchURL(BarWebAppUrl(), BarLaunchUrl()); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); { base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -598,12 +642,8 @@ TEST_F(PendingAppManagerImplTest, Install_ConcurrentCallsDifferentApps) { pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::RunLoop run_loop; pending_app_manager_impl()->Install( @@ -639,13 +679,9 @@ TEST_F(PendingAppManagerImplTest, Install_PendingSuccessfulTask) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); - url_loader()->SaveLoadUrlRequests(); + install_task_manager().SaveInstallRequests(); base::RunLoop foo_run_loop; base::RunLoop bar_run_loop; @@ -662,8 +698,10 @@ foo_run_loop.Quit(); })); - // Make sure the installation has started. + + // Make sure the installation has started and that it hasn't finished yet. base::RunLoop().RunUntilIdle(); + ASSERT_EQ(install_task_manager().num_pending_tasks(), 1u); pending_app_manager_impl()->Install( GetBarInstallOptions(), @@ -678,13 +716,13 @@ bar_run_loop.Quit(); })); - url_loader()->ProcessLoadUrlRequests(); + install_task_manager().ProcessSavedRequests(); foo_run_loop.Run(); // Make sure the second installation has started. base::RunLoop().RunUntilIdle(); - url_loader()->ProcessLoadUrlRequests(); + install_task_manager().ProcessSavedRequests(); bar_run_loop.Run(); } @@ -713,9 +751,6 @@ TEST_F(PendingAppManagerImplTest, InstallAppsWithWebAppInfoAndUrl_Multiple) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); @@ -776,13 +811,9 @@ TEST_F(PendingAppManagerImplTest, Install_PendingFailingTask) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kWebAppDisabled); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); - url_loader()->SaveLoadUrlRequests(); + install_task_manager().SaveInstallRequests(); base::RunLoop foo_run_loop; base::RunLoop bar_run_loop; @@ -798,8 +829,9 @@ foo_run_loop.Quit(); })); - // Make sure the installation has started. + // Make sure the installation has started and that it hasn't finished yet. base::RunLoop().RunUntilIdle(); + ASSERT_EQ(install_task_manager().num_pending_tasks(), 1u); pending_app_manager_impl()->Install( GetBarInstallOptions(), @@ -814,25 +846,21 @@ bar_run_loop.Quit(); })); - url_loader()->ProcessLoadUrlRequests(); + install_task_manager().ProcessSavedRequests(); foo_run_loop.Run(); // Make sure the second installation has started. base::RunLoop().RunUntilIdle(); - url_loader()->ProcessLoadUrlRequests(); + install_task_manager().ProcessSavedRequests(); bar_run_loop.Run(); } TEST_F(PendingAppManagerImplTest, Install_ReentrantCallback) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::RunLoop run_loop; auto final_callback = base::BindLambdaForTesting( @@ -865,9 +893,6 @@ TEST_F(PendingAppManagerImplTest, Install_SerialCallsSameApp) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); - { base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -898,8 +923,6 @@ TEST_F(PendingAppManagerImplTest, Install_ConcurrentCallsSameApp) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::RunLoop run_loop; bool first_callback_ran = false; @@ -942,8 +965,6 @@ TEST_F(PendingAppManagerImplTest, Install_AlwaysUpdate) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); auto get_force_reinstall_info = []() { ExternalInstallOptions options(FooWebAppUrl(), DisplayMode::kStandalone, @@ -967,8 +988,6 @@ pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); { base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -987,8 +1006,6 @@ TEST_F(PendingAppManagerImplTest, Install_InstallationFails) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kWebAppDisabled); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -1003,9 +1020,8 @@ TEST_F(PendingAppManagerImplTest, Install_PlaceholderApp) { pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult( - FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/true); auto install_options = GetFooInstallOptions(); install_options.install_placeholder = true; @@ -1025,8 +1041,6 @@ TEST_F(PendingAppManagerImplTest, InstallApps_Succeeds) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); std::vector<ExternalInstallOptions> apps_to_install; apps_to_install.push_back(GetFooInstallOptions()); @@ -1045,8 +1059,6 @@ TEST_F(PendingAppManagerImplTest, InstallApps_FailsInstallationFails) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kWebAppDisabled); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); std::vector<ExternalInstallOptions> apps_to_install; apps_to_install.push_back(GetFooInstallOptions()); @@ -1063,9 +1075,8 @@ TEST_F(PendingAppManagerImplTest, InstallApps_PlaceholderApp) { pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult( - FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/true); auto install_options = GetFooInstallOptions(); install_options.install_placeholder = true; @@ -1086,13 +1097,8 @@ TEST_F(PendingAppManagerImplTest, InstallApps_Multiple) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); std::vector<ExternalInstallOptions> apps_to_install; apps_to_install.push_back(GetFooInstallOptions()); @@ -1113,12 +1119,8 @@ TEST_F(PendingAppManagerImplTest, InstallApps_PendingInstallApps) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::RunLoop run_loop; { @@ -1162,20 +1164,14 @@ FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); pending_app_manager_impl()->SetNextInstallationLaunchURL(FooWebAppUrl(), FooLaunchUrl()); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); pending_app_manager_impl()->SetNextInstallationLaunchURL(BarWebAppUrl(), BarLaunchUrl()); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( QuxWebAppUrl(), InstallResultCode::kSuccessNewInstall); pending_app_manager_impl()->SetNextInstallationLaunchURL(QuxWebAppUrl(), QuxLaunchUrl()); - url_loader()->SetNextLoadUrlResult(QuxWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); std::vector<ExternalInstallOptions> apps_to_install; apps_to_install.push_back(GetFooInstallOptions()); @@ -1231,16 +1227,10 @@ TEST_F(PendingAppManagerImplTest, InstallApps_PendingInstall) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( BarWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(BarWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); pending_app_manager_impl()->SetNextInstallationTaskResult( QuxWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(QuxWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::RunLoop run_loop; @@ -1296,9 +1286,6 @@ TEST_F(PendingAppManagerImplTest, AppUninstalled) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); - { base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -1316,10 +1303,6 @@ { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(GURL(url::kAboutBlankURL), - WebAppUrlLoader::Result::kUrlLoaded); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -1335,9 +1318,6 @@ TEST_F(PendingAppManagerImplTest, ExternalAppUninstalled) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); - { base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -1373,8 +1353,6 @@ { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -1442,8 +1420,6 @@ TEST_F(PendingAppManagerImplTest, UninstallApps_PendingInstall) { pending_app_manager_impl()->SetNextInstallationTaskResult( FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::RunLoop run_loop; pending_app_manager_impl()->Install( @@ -1473,9 +1449,8 @@ { pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult( - FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/true); base::Optional<GURL> url; base::Optional<InstallResultCode> code; std::tie(url, code) = @@ -1488,9 +1463,8 @@ { install_options.reinstall_placeholder = true; pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/false); install_finalizer()->SetNextUninstallExternalWebAppResult(FooWebAppUrl(), true); @@ -1514,9 +1488,8 @@ { pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult( - FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/true); base::Optional<GURL> url; base::Optional<InstallResultCode> code; std::tie(url, code) = @@ -1529,9 +1502,8 @@ { install_options.reinstall_placeholder = true; pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult( - FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/true); base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -1556,9 +1528,8 @@ { pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult( - FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/true); base::Optional<GURL> url; base::Optional<InstallResultCode> code; std::tie(url, code) = @@ -1572,10 +1543,9 @@ install_options.reinstall_placeholder = true; install_options.wait_for_windows_closed = true; pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/false); ui_manager()->SetNumWindowsForApp(GenerateFakeAppId(FooWebAppUrl()), 0); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); base::Optional<GURL> url; base::Optional<InstallResultCode> code; @@ -1597,9 +1567,8 @@ { pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); - url_loader()->SetNextLoadUrlResult( - FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/true); base::Optional<GURL> url; base::Optional<InstallResultCode> code; std::tie(url, code) = @@ -1613,10 +1582,9 @@ install_options.reinstall_placeholder = true; install_options.wait_for_windows_closed = true; pending_app_manager_impl()->SetNextInstallationTaskResult( - FooWebAppUrl(), InstallResultCode::kSuccessNewInstall); + FooWebAppUrl(), InstallResultCode::kSuccessNewInstall, + /*did_install_placeholder=*/false); ui_manager()->SetNumWindowsForApp(GenerateFakeAppId(FooWebAppUrl()), 1); - url_loader()->SetNextLoadUrlResult(FooWebAppUrl(), - WebAppUrlLoader::Result::kUrlLoaded); install_finalizer()->SetNextUninstallExternalWebAppResult(FooWebAppUrl(), true); @@ -1643,8 +1611,6 @@ install_url, InstallResultCode::kSuccessNewInstall); pending_app_manager_impl()->SetNextInstallationLaunchURL( install_url, install_url.Resolve("launch_page")); - url_loader()->SetNextLoadUrlResult(install_url, - WebAppUrlLoader::Result::kUrlLoaded); ExternalInstallOptions install_option( install_url, DisplayMode::kStandalone, ExternalInstallSource::kSystemInstalled);
diff --git a/chrome/browser/webshare/win/show_share_ui_for_window_operation.cc b/chrome/browser/webshare/win/show_share_ui_for_window_operation.cc index 8fcccef..67225e3 100644 --- a/chrome/browser/webshare/win/show_share_ui_for_window_operation.cc +++ b/chrome/browser/webshare/win/show_share_ui_for_window_operation.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/webshare/win/show_share_ui_for_window_operation.h" +#include <EventToken.h> #include <shlobj.h> #include <windows.applicationmodel.datatransfer.h> #include <wrl/event.h> @@ -72,7 +73,6 @@ ShowShareUIForWindowOperation::ShowShareUIForWindowOperation(HWND hwnd) : hwnd_(hwnd) { - data_requested_token_.value = 0; } ShowShareUIForWindowOperation::~ShowShareUIForWindowOperation() { @@ -93,12 +93,13 @@ // Fetch the OS handles needed ComPtr<IDataTransferManagerInterop> data_transfer_manager_interop; + ComPtr<IDataTransferManager> data_transfer_manager; HRESULT hr = GetDataTransferManagerHandles( - hwnd_, &data_transfer_manager_interop, &data_transfer_manager_); + hwnd_, &data_transfer_manager_interop, &data_transfer_manager); if (FAILED(hr)) return Cancel(); - // Create and register a data request handler + // Create and register a data requested handler auto weak_ptr = weak_factory_.GetWeakPtr(); auto raw_data_requested_callback = Callback< ITypedEventHandler<DataTransferManager*, DataRequestedEventArgs*>>( @@ -113,59 +114,73 @@ // operation will fail gracefully with messaging to the user. return S_OK; }); - hr = data_transfer_manager_->add_DataRequested( - raw_data_requested_callback.Get(), &data_requested_token_); - if (FAILED(hr)) + EventRegistrationToken data_requested_token{}; + hr = data_transfer_manager->add_DataRequested( + raw_data_requested_callback.Get(), &data_requested_token); + + // Create a callback to clean up the data requested handler that doesn't rely + // on |this| so it can still be run even if |this| has been destroyed + auto remove_data_requested_listener = base::BindOnce( + [](ComPtr<IDataTransferManager> data_transfer_manager, + EventRegistrationToken data_requested_token) { + if (data_transfer_manager && data_requested_token.value) { + data_transfer_manager->remove_DataRequested(data_requested_token); + } + }, + data_transfer_manager, data_requested_token); + + // If the call to register the data requested handler failed, clean up + // listener and cancel the operation + if (FAILED(hr)) { + std::move(remove_data_requested_listener).Run(); return Cancel(); + } // Request showing the Share UI - show_share_ui_for_window_call_in_progress_ = true; hr = data_transfer_manager_interop->ShowShareUIForWindow(hwnd_); - show_share_ui_for_window_call_in_progress_ = false; - // If the call is expected to complete later, schedule a timeout to cover - // any cases where it fails (and therefore never comes) - if (SUCCEEDED(hr) && data_requested_callback_) { + // If the call is expected to complete later, save the clean-up callback for + // later use and schedule a timeout to cover any cases where it fails (and + // therefore never comes) + if (SUCCEEDED(hr) && weak_ptr && data_requested_callback_) { + remove_data_requested_listener_ = std::move(remove_data_requested_listener); if (!base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, - base::BindOnce(&ShowShareUIForWindowOperation::Cancel, - weak_factory_.GetWeakPtr()), + base::BindOnce(&ShowShareUIForWindowOperation::Cancel, weak_ptr), kMaxExecutionTime)) { return Cancel(); } } else { - RemoveDataRequestedListener(); + // In all other cases (i.e. failure or synchronous completion), remove the + // listener right away + std::move(remove_data_requested_listener).Run(); } } void ShowShareUIForWindowOperation::Cancel() { - RemoveDataRequestedListener(); - if (data_requested_callback_) { + if (remove_data_requested_listener_) + std::move(remove_data_requested_listener_).Run(); + + if (data_requested_callback_) std::move(data_requested_callback_).Run(nullptr); - } } void ShowShareUIForWindowOperation::OnDataRequested( IDataTransferManager* data_transfer_manager, IDataRequestedEventArgs* event_args) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK_EQ(data_transfer_manager, data_transfer_manager_.Get()); - // Remove the DataRequested handler if this is being invoked asynchronously. - // If this is an in-progress invocation the system APIs don't handle the - // event being unregistered while it is being executed, but we will unregister - // it after the ShowShareUIForWindow call completes. - if (!show_share_ui_for_window_call_in_progress_) - RemoveDataRequestedListener(); + // If the callback to remove the DataRequested listener has been stored on + // |this| (i.e. this function is being invoked asynchronously), invoke it now + // before invoking the |data_requested_callback_|, as that may result in + // |this| being destroyed. Note that the callback to remove the DataRequested + // listener will not have been set if this is being invoked synchronously as + // part of the ShowShareUIForWindow call, as the system APIs don't handle + // unregistering at that point. + if (remove_data_requested_listener_) + std::move(remove_data_requested_listener_).Run(); std::move(data_requested_callback_).Run(event_args); } -void ShowShareUIForWindowOperation::RemoveDataRequestedListener() { - if (data_transfer_manager_ && data_requested_token_.value) { - data_transfer_manager_->remove_DataRequested(data_requested_token_); - data_requested_token_.value = 0; - } -} - } // namespace webshare
diff --git a/chrome/browser/webshare/win/show_share_ui_for_window_operation.h b/chrome/browser/webshare/win/show_share_ui_for_window_operation.h index 220c0dd..0452dfd 100644 --- a/chrome/browser/webshare/win/show_share_ui_for_window_operation.h +++ b/chrome/browser/webshare/win/show_share_ui_for_window_operation.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_WEBSHARE_WIN_SHOW_SHARE_UI_FOR_WINDOW_OPERATION_H_ #define CHROME_BROWSER_WEBSHARE_WIN_SHOW_SHARE_UI_FOR_WINDOW_OPERATION_H_ -#include <EventToken.h> #include <wrl/client.h> #include "base/callback.h" @@ -71,15 +70,10 @@ data_transfer_manager, ABI::Windows::ApplicationModel::DataTransfer::IDataRequestedEventArgs* event_args); - void RemoveDataRequestedListener(); DataRequestedCallback data_requested_callback_; - EventRegistrationToken data_requested_token_; - Microsoft::WRL::ComPtr< - ABI::Windows::ApplicationModel::DataTransfer::IDataTransferManager> - data_transfer_manager_; const HWND hwnd_; - bool show_share_ui_for_window_call_in_progress_; + base::OnceClosure remove_data_requested_listener_; base::WeakPtrFactory<ShowShareUIForWindowOperation> weak_factory_{this}; };
diff --git a/chrome/browser/webshare/win/show_share_ui_for_window_operation_unittest.cc b/chrome/browser/webshare/win/show_share_ui_for_window_operation_unittest.cc index 64cb1d9..dc28e1d96 100644 --- a/chrome/browser/webshare/win/show_share_ui_for_window_operation_unittest.cc +++ b/chrome/browser/webshare/win/show_share_ui_for_window_operation_unittest.cc
@@ -48,6 +48,7 @@ if (!IsSupportedEnvironment()) return; ASSERT_NO_FATAL_FAILURE(scoped_interop_.SetUp()); + operation_ = std::make_unique<ShowShareUIForWindowOperation>(hwnd_); auto weak_ptr = weak_factory_.GetWeakPtr(); test_callback_ = base::BindOnce( [](base::WeakPtr<ShowShareUIForWindowOperationTest> weak_ptr, @@ -58,6 +59,9 @@ weak_ptr->test_callback_state_ = event_args ? TestCallbackState::RunWithValue : TestCallbackState::RunWithoutValue; + // Explicitly free the operation to validate it handles being + // destroyed as soon as it has invoked the callback + weak_ptr->operation_.reset(); } }, weak_ptr); @@ -75,6 +79,7 @@ } const HWND hwnd_ = reinterpret_cast<HWND>(1); + std::unique_ptr<ShowShareUIForWindowOperation> operation_; ScopedFakeDataTransferManagerInterop scoped_interop_; content::BrowserTaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; @@ -90,8 +95,7 @@ fake_interop().SetShowShareUIForWindowBehavior( ShowShareUIForWindowBehavior::SucceedWithoutAction); - ShowShareUIForWindowOperation operation{hwnd_}; - operation.Run(std::move(test_callback_)); + operation_->Run(std::move(test_callback_)); ASSERT_EQ(test_callback_state_, TestCallbackState::NotRun); auto data_requested_invoker = fake_interop().GetDataRequestedInvoker(hwnd_); @@ -106,8 +110,7 @@ fake_interop().SetShowShareUIForWindowBehavior( ShowShareUIForWindowBehavior::SucceedWithoutAction); - ShowShareUIForWindowOperation operation{hwnd_}; - operation.Run(std::move(test_callback_)); + operation_->Run(std::move(test_callback_)); ASSERT_EQ(test_callback_state_, TestCallbackState::NotRun); task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); @@ -125,12 +128,11 @@ fake_interop().SetShowShareUIForWindowBehavior( ShowShareUIForWindowBehavior::SucceedWithoutAction); - auto operation = std::make_unique<ShowShareUIForWindowOperation>(hwnd_); - operation->Run(std::move(test_callback_)); + operation_->Run(std::move(test_callback_)); ASSERT_EQ(test_callback_state_, TestCallbackState::NotRun); auto data_requested_invoker = fake_interop().GetDataRequestedInvoker(hwnd_); - ASSERT_NO_FATAL_FAILURE(operation.reset()); + ASSERT_NO_FATAL_FAILURE(operation_.reset()); ASSERT_EQ(test_callback_state_, TestCallbackState::RunWithoutValue); ASSERT_NO_FATAL_FAILURE(std::move(data_requested_invoker).Run()); } @@ -142,8 +144,7 @@ fake_interop().SetShowShareUIForWindowBehavior( ShowShareUIForWindowBehavior::InvokeEventSynchronously); - ShowShareUIForWindowOperation operation{hwnd_}; - operation.Run(std::move(test_callback_)); + operation_->Run(std::move(test_callback_)); ASSERT_EQ(test_callback_state_, TestCallbackState::RunWithValue); } @@ -154,8 +155,7 @@ fake_interop().SetShowShareUIForWindowBehavior( ShowShareUIForWindowBehavior::FailImmediately); - ShowShareUIForWindowOperation operation{hwnd_}; - operation.Run(std::move(test_callback_)); + operation_->Run(std::move(test_callback_)); ASSERT_EQ(test_callback_state_, TestCallbackState::NotRun); } @@ -166,8 +166,7 @@ fake_interop().SetShowShareUIForWindowBehavior( ShowShareUIForWindowBehavior::InvokeEventSynchronouslyAndReturnFailure); - ShowShareUIForWindowOperation operation{hwnd_}; - operation.Run(std::move(test_callback_)); + operation_->Run(std::move(test_callback_)); ASSERT_EQ(test_callback_state_, TestCallbackState::RunWithValue); } @@ -175,8 +174,7 @@ if (!IsSupportedEnvironment()) return; - auto operation = std::make_unique<ShowShareUIForWindowOperation>(hwnd_); - ASSERT_NO_FATAL_FAILURE(operation.reset()); + ASSERT_NO_FATAL_FAILURE(operation_.reset()); } } // namespace webshare
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index e666558..07f856e9 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-master-1609199712-7e463f0207d055b7b562c386dc767d4724824c2c.profdata +chrome-linux-master-1609351142-dd1a26699eab924687a810625409dd4ac7df6d3b.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 268c01f..b53ad9e 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-master-1609199712-53d931f587c8bfb3642e1d3559fa944b25ac41c0.profdata +chrome-mac-master-1609351142-4bcda9a45834f5931e4d67a63f18aec167e5f993.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index ab8ddd5..092e0a8d 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-master-1609077635-95cc21097bbc828eec82ee3506f035af36a6f657.profdata +chrome-win32-master-1609318697-39f3b7685bb8ed03702107ffb2254545e4613a9d.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index fc208a81..a44fd99 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1609124291-e7a0465f695fe158abf9ec0e9104d31fe42b886f.profdata +chrome-win64-master-1609351142-315cd693e0e48f1df55c05a88c4395bf724b17db.profdata
diff --git a/chrome/common/extensions/docs/server2/.gitignore b/chrome/common/extensions/docs/server2/.gitignore deleted file mode 100644 index ab971ca..0000000 --- a/chrome/common/extensions/docs/server2/.gitignore +++ /dev/null
@@ -1,2 +0,0 @@ -third_party/ -local_debug/
diff --git a/chrome/common/extensions/docs/server2/BUILD.gn b/chrome/common/extensions/docs/server2/BUILD.gn deleted file mode 100644 index 9da61847..0000000 --- a/chrome/common/extensions/docs/server2/BUILD.gn +++ /dev/null
@@ -1,43 +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. - -# The main target used to aggregate all python based unit tests for the -# Docserver. This is used to generate a complete isolate which can be pushed to -# bots to run the tests. -group("extension_docserver_python_unittests") { - testonly = true - - data = [ - "//testing/scripts/common.py", - "//testing/scripts/run_isolated_script_test.py", - "//testing/xvfb.py", - "//chrome/common/extensions/docs/server2/", - - # Files in these paths are used by tests. All deps must be declared to - # ensure the isolate created has all the necessary dependencies. Verify by - # running - # python tools/mb/mb.py run out/Default extension_docserver_python_unittests -- --isolated-script-test-output=a.json - "//chrome/browser/apps/platform_apps/api/", - "//chrome/browser/extensions/api/", - "//chrome/browser/extensions/OWNERS", - "//chrome/common/apps/platform_apps/api/", - "//chrome/common/extensions/api/", - "//chrome/common/extensions/docs/examples/", - "//chrome/common/extensions/docs/templates/", - "//extensions/browser/api/", - "//extensions/common/api/", - - # Dependencies used by server. See build_server.py - "//ppapi/generators/", - "//third_party/google_appengine_cloudstorage/cloudstorage/", - "//third_party/markdown/", - "//third_party/motemplate/", - "//third_party/ply/", - "//third_party/simplejson/", - "//tools/json_comment_eater/json_comment_eater.py", - "//tools/json_schema_compiler/", - ] - - data_deps = [ "//third_party/catapult/third_party/typ" ] -}
diff --git a/chrome/common/extensions/docs/server2/OWNERS b/chrome/common/extensions/docs/server2/OWNERS deleted file mode 100644 index b4f68bd..0000000 --- a/chrome/common/extensions/docs/server2/OWNERS +++ /dev/null
@@ -1,7 +0,0 @@ -lazyboy@chromium.org -rdevlin.cronin@chromium.org -rockot@google.com - -# Modifying app.yaml needs a corresponding push of the new version to AppEngine. -per-file app.yaml=set noparent -per-file app.yaml=file://extensions/common/api/API_OWNERS
diff --git a/chrome/common/extensions/docs/server2/PRESUBMIT.py b/chrome/common/extensions/docs/server2/PRESUBMIT.py deleted file mode 100644 index 59362d2..0000000 --- a/chrome/common/extensions/docs/server2/PRESUBMIT.py +++ /dev/null
@@ -1,50 +0,0 @@ -# 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. - -"""Presubmit script for changes affecting extensions docs server - -See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts -for more details about the presubmit API built into depot_tools. -""" - -import os - -def _WarnIfAppYamlHasntChanged(input_api, output_api): - app_yaml_path = os.path.join(input_api.PresubmitLocalPath(), 'app.yaml') - if app_yaml_path in input_api.AbsoluteLocalPaths(): - return [] - return [output_api.PresubmitPromptOrNotify(''' -************************************************** -CHANGE DETECTED IN SERVER2 WITHOUT APP.YAML UPDATE -************************************************** -Maybe this is ok? Follow this simple guide: - -Q: Does this change any data that might get stored? - * Did you add/remove/update a field to a data source? - * Did you add/remove/update some data that gets sent to templates? - * Is this change to support a new feature in the templates? - * Does this change include changes to templates? -Yes? Bump the middle version and zero out the end version, i.e. 2-5-2 -> 2-6-0. - THIS WILL CAUSE THE CURRENTLY RUNNING SERVER TO STOP UPDATING. - PUSH THE NEW VERSION ASAP. -No? Continue. -Q: Is this a non-trivial change to the server? -Yes? Bump the end version. - Unlike above, the server will *not* stop updating. -No? Are you sure? How much do you bet? This can't be rolled back... - -Q: Is this a spelling correction? New test? Better comments? -Yes? Ok fine. Ignore this warning. -No? I guess this presubmit check doesn't work. -''')] - -def _RunPresubmit(input_api, output_api): - # TODO(crbug.com/434363): Enable pylint for the docserver. - return _WarnIfAppYamlHasntChanged(input_api, output_api) - -def CheckChangeOnUpload(input_api, output_api): - return _RunPresubmit(input_api, output_api) - -def CheckChangeOnCommit(input_api, output_api): - return _RunPresubmit(input_api, output_api)
diff --git a/chrome/common/extensions/docs/server2/README b/chrome/common/extensions/docs/server2/README deleted file mode 100644 index a659ef0..0000000 --- a/chrome/common/extensions/docs/server2/README +++ /dev/null
@@ -1,314 +0,0 @@ -TODO(devlin): MD docs seem to be the new hotness; this should probably be -converted. - --------- -Overview - -This is a Google App Engine server which serves the documentation for Chrome -apps and extensions. At time of this writing, the primary URL is: -http://developer.chrome.com/. - - ---------------------- -Developing the Server - -You shouldn't need app engine locally to develop the server, preview.py should -be sufficient. If for some reason you want to test against the app engine SDK: - - 1. Download the python Google App Engine SDK from: - https://developers.google.com/appengine/downloads - - 2. Run './start_dev_server.py <path/to/dev_appserver.py>' - (dev_appserver.py is part of the App Engine) - - 3. View docs at http://localhost:8080/(apps|extensions)/<doc_name> - -NOTE: The dev server will not work right way: you need to populate its -Datastore. You will need a local datastore cache in the working directory where -you started the dev server, and you will need to manually instruct the dev -server to pull data from that file: - - 1. Run './update_cache.py --no-push --save-file=FOOCACHE'. This will take - a very long time (30-40 minutes). It is advisable that you keep a copy - of this file around if you plan use the dev server often. It can be - updated much faster (< 3 minutes) in that case by also including - --load-file=FOOCACHE on subsequent update_cache.py runs. - - You MUST have branch heads fetched in your local repo in order for your - local data set to be populated correctly. You can accomplish this by - running: - - gclient sync --with_branch_heads - git fetch origin - - You may also specify --commit=<commitish> when running update_cache.py in - order to update the cache from a specific commit. This may be a commit ID, - or a partial commit ID, or a local branch ref, etc. To test local changes, - you MUST commit them locally and use the local commit to update your cache. - - 2. Once you have a cache (e.g. FOOCACHE) in the working directory of your - dev server, visit the URL: - - http://localhost:8080/_update_cache/FOOCACHE - - If you see errors about the FOOCACHE file not existing, the server may be - looking for the file in the root chromium directory (under src/), even if - you launched the server from the server2 directory. Try moving the FOOCACHE - file there. - - The server should take about a minute to fully populate its Datastore - from the data in your FOOCACHE file. Now you have a working dev server! - - ------------------------------------------------------------- -Using Google Cloud Storage content providers with preview.py - - 1. create a directory "[...]/server2/local_debug/gcs/<bucketname>" for every - gcs bucket referenced in content_providers.json - - 2. copy files to the respective local bucket directories. Preview.py has - no access to the real Google Cloud Storage. - - --------------------- -Deploying the Server - -You will need to have access to the http://chrome-apps-doc.appspot.com app. -Contact rdevlin.cronin@chromium.org or another extensions team member to obtain -access. - -Once you have access: - -1. Increment the version in app.yaml so we can roll back if the update breaks. - -2. Land your patch in chromium. Resync/pull. - -3. Run build_server.py. This copies some depenencies from /third_party into the - server directory so that they get uploaded to App Engine. - -4. Run appcfg.py (supplied with the App Engine SDK) to upload the server code: - - appcfg.py update . - -5. When prompted for your credentials, enter the information for the account - that has access to the production app. - -Note: Steps 1 - 5 can be completed (mostly) synchronously. However, once the -version is pushed, the docserver will need to repopulate its cache, which runs -from a cron job. (Theoretically, this job runs a few times a day - in practice, -it has been observered to be late.) - -6. Go to http://www.appspot.com, select the docs project, click "versions" in - the sidebar. CHECK THE VERSION YOU DEPLOYED WORKS. You can do this by - clicking the version with the "popout" link, which should send you to a link - like "https://3-50-3-dot-chrome-apps-doc.appspot.com". This should work, and - you should be able to see documentation by going to /extensions, - /extensions/webRequest, /extensions/contentScripts, etc. If you see a - "Not found" error, this means the version does not work. Likely, this is - because the cache hasn't been fully updated. - - If the newly-deployed version works, migrate traffic to the new version. This - happens nearly instantly, so you should immediately double-check the live - site at developer.chrome.com/extensions. - - If you get an error about too many versions when deploying, go into this - view and delete the version which was deployed the longest time ago. Then - try to deploy again. - - ----------------------- -Updating the Datastore - -Even when the server code hasn't changed, new data is constantly flowing into -the chromium repo and some of that data includes changes to new or existing -content hosted by the server. In order for the front-end to reflect these -changes, new data must be pushed into the project's Datastore. - -This is done periodically by a Compute Engine instance running the -update_cache.py tool. While it is possible to push from other hosts if you -get all the right credentials in all the right places, it is strongly -discouraged and also therefore not documented. - -To force a push safely from the VM, navigate to the developer console under -Compute -> Compute Engine -> VM instances and open SSH for the "git-processor" -instance. From within the SSH session, first switch to user "git-processor": - - sudo su - git-processor - -You can run './update-docs-full.sh' from the home directory there. This will -automatically fetch any new objects from the upstream repository and then -perform a full update if there are pending changes. - -It's almost never necessary to use this tool. For one interesting example, -consider the case where no new commits are landing in the chrome repository -but a change was just pushed to one of the GCS providers (like say, the -chromedocs-multidevice bucket). In this case, you may want to force an update -of only the content_providers data. To do this run the update-docs-cloud.sh -script. This will safely do the push for you, ensuring that the automated job -does not collide with your own. - ----------------------- -Server architecture - -The server is composed of two parts: - -1) A compute engine VM instance which runs a cron job to periodicially pull the - chromium repo and uses the update_cache.py script to push the new data to the - cloud datastore and clear the existing memcache for the App engine instance - to ensure stale data is not served. All the keys in the cloud datastore are - indexed by the app version specified in app.yaml. - -2) A python app engine app which reads the data in the cloud datastore and - serves the website. - -Hence, even if we were to stop the compute engine VM instance, the website -should still keep running. But it won't update, since the cloud datastore won't -get updated. - ------------------------------------------------ -Updating Docs served from Google Cloud Storage. - -Some docs (e.g. webstore docs) are served using Google Cloud Storage buckets. To -update files in these docs, follow these steps: - -1) Go the project homepage and then to the Storage section. -2) Go to the relevant storage bucket. For example, to update webstore docs, go - to the page for "chromedocs-webstore". -3) Modify an existing file or upload a new file. Edit file permissions if - necessary to ensure these are accessible to Public. (Ideally these should be - only accessible to the cron job running on the compute engine VM instance.) -4) After the next cron job on the compute engine completes, the modifications - should be live. -5) In order to expedite 4), a manual datastore update can be performed by - running "./update-docs-cloud.sh on the VM instance. This only updates the - "content_providers" data source without fetching updates for the chromium - repository. - -Note: these steps shouldn't require a server version bump. If they do, please -file a bug. - ---------------------------------------- -VM: Some notes and troubleshooting tips - -Q1: How is the datastore populated in the VM? -A: /home/git-processor/update-docs-full.sh - This script is run every 2 hours through cron to sync the chromium git repo - in this machine. Once it has done so, it will populate docserver data store - and write that in /home/git-processor/.docserver_cache. Docserver uses this - file as data sources to populate its documentation. - -Q2: Is chromium repo in the VM in sync? -A: Check the git logs on the repo. - - $ sudo su git-processor - $ cd ~/chrome/src - $ git log - - Verify that chromium checkout is up-to-date by looking at the latest git log - results. - -Q3: Did the last run to populate .docserver_cache succeed? -A: Check the logs. - - Logs can be checked from the Cloud dashboard. Go to the project homepage and - select Logging > Logs. Choose the VM instance and "syslog" from the filter - options. - - Alternatively, run - $ sudo -s # You need to be root. - $ vi /var/log/user.log - -Jan 19 21:51:39 git-processor logger: Acquiring docserver update lock... -Jan 19 21:51:39 git-processor logger: INFO:root:Starting refresh from commit 1ee51d53b10f8d2688a225d6cbd33dfdf8965403... -... - Specifically you want to see some logs about writing keys to the - cache file, e.g.: -Jan 19 21:33:21 git-processor logger: INFO:root:Saved 644 keys to /home/git-processor/.docserver_cache. - -Q4: Docs stopped updating for a while, what to do? -A: Start by checking whether the appengine instance contains datastore *close* - to HEAD. You can do this by visiting - - https://developer.chrome.com/_query_commit/master - - Then check the commit hash. If the commit hash is behind by more than few - days from HEAD then this means that last run(s) to populate .docserver_cache - failed in the VM. An example of this happening can be found in: - https://crbug.com/682376. - - Start checking the logs (Q3). If you see that there are no logs after - "Acquiring docserver update lock..", then the script might have hung. The - script uses /var/lock/docserver-update.lock lock file with flock. The - process/script probably is still running (I don't know why that happens - yet). You'd need to verify that this is the case. - For example, I ran: - - $ ps -e -o lstart,pid,ppid,cmd | grep update-docs - -Sat Oct 1 15:00:00 2016 10230 10229 /bin/sh -c /usr/bin/env bash /home/git-processor/update-docs-full.sh 2>&1 | /usr/bin> -Sat Oct 1 15:00:00 2016 10231 10230 bash /home/git-processor/update-docs-full.sh -Wed Dec 14 19:50:01 2016 10744 10743 /bin/sh -c /usr/bin/env bash /home/git-processor/update-docs-full.sh 2>&1 | /usr/bin> -Wed Dec 14 19:50:01 2016 10745 10744 bash /home/git-processor/update-docs-full.sh - Once you're sure that one or more of these processes are running for a - while, you'd want to kill them, which should be "safe" (endorsed by rockot@) - in most of the cases. If that doesn't work, then delete the lock file. This - will let subsequent cron runs to update docserver. - - Also ensure that the App engine's current version is in sync with the - version specified in app.yaml on ToT. - - Some other miscellaneous debugging tips: - - Viewing updates made by last cron job - To view the contents of the data persisted by the last cron job, inspect - the .docserver_cache file on the Compute Engine instance. See - /home/git-processor/tools/dump_keys.py for an example of how to do so. - - - Viewing actual datastore entries - Go to the project homepage and then move to the "Datastore" section. From - the dropdowns, choose "Namespace" = [default], "Kind"= - "PersistentObjectStoreItem" and click on "Filter Entities" and then enter - the key to inspect. Example search: - Key(PersistentObjectStoreItem, 'class=APIListDataSource&category=LocalGitFileSystem@master&app_version=3-65-0/api_data') - The data here should be the same as the one in .docserver_cache. - - - Debugging live App Engine instance - Go the Project homepage, and head over to the "Debug" section. Using - Stackdriver debugging, it's possible to take live snapshots and inspect - the state of the live App Engine instance. E.g. it allows you to inspect - variables, see the stack trace etc. by setting a "logpoint". - - -Q5: How to migrate to a new VM instance? (Say to update the operating system). - ROUGH steps: - 1) Stop the old VM. - 2) Backup the cloud datastore to a cloud storage bucket (optional). - 3) Clone the persistent disk (not the boot disk) from the old VM. Else just - create a new disk and copy necessary data (in /home/git-processor) later. - 4) Create a new VM instance (Use configuration from the old VM) and attach - the new persistent disk to the new VM. Make sure that new VM has the same - API access scopes as the old one (for e.g. it can write to the cloud - datastore). - 5) Mount the persistent disk at /home/git-processor (Modify /etc/fstab so - that the disk is automatically mounted on restarts). - 6) Ensure the data in /home/git-processor is the same as the old VM (if you - had not cloned the disk, use some other tool to copy the data). - 7) Increment the app engine version in the chromium repo and commit the - change (so that we don't somehow affect the currently serving production - version). - 8) On the VM, fetch chrome in /home/git-processor with all the branch heads. - 9) Ensure app.yaml in the chrome repo has the new app version. - 10) Install any necessary dependencies. For e.g. /home/git-processor/gcd is - a python virtual environment used by update-docs-full.sh (which is run - as part of the cron job). Hence pip, virtualenv need to be installed and - it needs to be ensured that the virtualenv at /home/git-processor/gcd is - correctly configured. Requirements file generated by pip can be used for - this purpose. - 11) Run update-docs-full.sh and ensure it works fine. (After it runs, the - new app engine version should work fine and have the latest changes). - 12) If it does, add a cronjob for the git-processor user to regularly run - update-docs-full.sh. - 13) Ensure the cron job is running fine and serve all the traffic from the - new app engine version. - 14) Delete the old VM, persistent disk after some time. - 15) (Optional) Install logging agent on the VM so that the syslog from the - VM can be seen from the cloud dashboard.
diff --git a/chrome/common/extensions/docs/server2/admin_servlets.py b/chrome/common/extensions/docs/server2/admin_servlets.py deleted file mode 100644 index 4e0a838..0000000 --- a/chrome/common/extensions/docs/server2/admin_servlets.py +++ /dev/null
@@ -1,135 +0,0 @@ -# Copyright 2014 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 json -import logging - -from appengine_wrappers import memcache -from commit_tracker import CommitTracker -from environment import IsDevServer -from environment_wrappers import CreateUrlFetcher -from future import All -from object_store_creator import ObjectStoreCreator -from servlet import Servlet, Response - - -# This is the service account ID associated with the chrome-apps-doc project in -# the Google Developers Console. -_SERVICE_ACCOUNT_NAME = '636061184119-compute@developer.gserviceaccount.com' - -# This is Google's OAuth2 service for retrieving user information from an access -# token. It is used to authenticate an incoming access token in the metadata -# flush servlet, ensuring that only requests from the above service account are -# fulfilled. -_ACCOUNT_INFO_URL = ('https://www.googleapis.com/oauth2/v1/userinfo?' - 'access_token=%s') - - -class QueryCommitServlet(Servlet): - '''Provides read access to the commit ID cache within the server. For example: - - /_query_commit/master - - will return the commit ID stored under the commit key "master" within the - commit cache. Currently "master" is the only named commit we cache, and it - corresponds to the commit ID whose data currently populates the data cache - used by live instances. - ''' - def __init__(self, request): - Servlet.__init__(self, request) - - def Get(self): - object_store_creator = ObjectStoreCreator(start_empty=False) - commit_tracker = CommitTracker(object_store_creator) - - def generate_response(result): - commit_id, history = result - history_log = ''.join('%s: %s<br>' % (entry.datetime, entry.commit_id) - for entry in reversed(history)) - response = 'Current commit: %s<br><br>Most recent commits:<br>%s' % ( - commit_id, history_log) - return response - - commit_name = self._request.path - id_future = commit_tracker.Get(commit_name) - history_future = commit_tracker.GetHistory(commit_name) - return Response.Ok( - All((id_future, history_future)).Then(generate_response).Get()) - - -class FlushMemcacheServlet(Servlet): - '''Flushes the entire memcache. - - This requires an access token for the project's main service account. Without - said token, the request is considered invalid. - ''' - - class Delegate(object): - def IsAuthorized(self, access_token): - '''Verifies that a given access_token represents the main service account. - ''' - fetcher = CreateUrlFetcher() - response = fetcher.Fetch(_ACCOUNT_INFO_URL % access_token) - if response.status_code != 200: - return False - try: - info = json.loads(response.content) - except: - return False - return info['email'] == _SERVICE_ACCOUNT_NAME - - def __init__(self, request, delegate=Delegate()): - Servlet.__init__(self, request) - self._delegate = delegate - - def GetAccessToken(self): - auth_header = self._request.headers.get('Authorization') - if not auth_header: - return None - try: - method, token = auth_header.split(' ', 1) - except: - return None - if method != 'Bearer': - return None - return token - - def Get(self): - access_token = self.GetAccessToken() - if not access_token: - return Response.Unauthorized('Unauthorized', 'Bearer', 'update') - if not self._delegate.IsAuthorized(access_token): - return Response.Forbidden('Forbidden') - result = memcache.flush_all() - return Response.Ok('Flushed: %s' % result) - - -class UpdateCacheServlet(Servlet): - '''Devserver-only servlet for pushing local file data into the datastore. - This is useful if you've used update_cache.py to build a local datastore - for testing. Query: - - /_update_cache/FOO_DATA - - to make the devserver read FOO_DATA from its pwd and push all the data into - datastore. - ''' - def __init__(self, request): - Servlet.__init__(self, request) - - def Get(self): - if not IsDevServer(): - return Response.BadRequest('') - import cPickle - from persistent_object_store_appengine import PersistentObjectStoreAppengine - with open(self._request.path, 'r') as f: - data = cPickle.load(f) - for namespace, contents in data.iteritems(): - store = PersistentObjectStoreAppengine(namespace) - for k, v in cPickle.loads(contents).iteritems(): - try: - store.Set(k, v).Get() - except: - logging.warn('Skipping entry %s because of errors.' % k) - return Response.Ok('Data pushed!')
diff --git a/chrome/common/extensions/docs/server2/api_categorizer.py b/chrome/common/extensions/docs/server2/api_categorizer.py deleted file mode 100644 index 9b531e6..0000000 --- a/chrome/common/extensions/docs/server2/api_categorizer.py +++ /dev/null
@@ -1,58 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import posixpath - -from compiled_file_system import SingleFile -from extensions_paths import PUBLIC_TEMPLATES - - -class APICategorizer(object): - ''' This class gets api category from documented apis. - ''' - - def __init__(self, file_system, compiled_fs_factory, platform): - self._file_system = file_system - self._cache = compiled_fs_factory.Create(file_system, - self._CollectDocumentedAPIs, - APICategorizer) - self._platform = platform - - def _GenerateAPICategories(self): - return self._cache.GetFromFileListing( - posixpath.join(PUBLIC_TEMPLATES, self._platform) + '/').Get() - - @SingleFile - def _CollectDocumentedAPIs(self, base_dir, files): - public_templates = [] - for root, _, files in self._file_system.Walk(base_dir): - public_templates.extend(posixpath.join(root, name) for name in files) - template_names = set(os.path.splitext(name)[0].replace('_', '.') - for name in public_templates) - return template_names - - def GetCategory(self, api_name): - '''Returns the type of api: - "internal": Used by chrome internally. Never documented. - "private": APIs which are undocumented or are available to - whitelisted apps/extensions. - "experimental": Experimental APIs. - "chrome": Public APIs. - ''' - documented_apis = self._GenerateAPICategories() - if api_name.endswith('Internal'): - assert api_name not in documented_apis, \ - "Internal API %s on %s platform should not be documented" % ( - api_name, self._platform) - return 'internal' - if (api_name.endswith('Private') or - api_name not in documented_apis): - return 'private' - if api_name.startswith('experimental.'): - return 'experimental' - return 'chrome' - - def IsDocumented(self, api_name): - return (api_name in self._GenerateAPICategories())
diff --git a/chrome/common/extensions/docs/server2/api_categorizer_test.py b/chrome/common/extensions/docs/server2/api_categorizer_test.py deleted file mode 100755 index 69e3478..0000000 --- a/chrome/common/extensions/docs/server2/api_categorizer_test.py +++ /dev/null
@@ -1,82 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from api_categorizer import APICategorizer -from compiled_file_system import CompiledFileSystem -from extensions_paths import CHROME_EXTENSIONS -from object_store_creator import ObjectStoreCreator -from test_file_system import TestFileSystem - - -def _ToTestData(obj): - '''Transforms |obj| into test data by turning a list of files into an object - mapping that file to its contents (derived from its name). - ''' - return dict((name, name) for name in obj) - - -_TEST_DATA = { - 'api': { - '_api_features.json': '{}', - '_manifest_features.json': '{}', - '_permission_features.json': '{}', - }, - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': '{}', - 'manifest.json': '{}', - 'permissions.json': '{}', - }, - 'public': { - 'apps': _ToTestData([ - 'alarms.html', - 'app_window.html', - 'experimental_bluetooth.html', - 'experimental_power.html', - 'storage.html', - 'sockets_udp.html' - ]), - 'extensions': _ToTestData([ - 'alarms.html', - 'browserAction.html', - 'experimental_history.html', - 'experimental_power.html', - 'infobars.html', - 'storage.html', - 'sockets_udp.html' - ]), - }, - }, - } -} - - -class APICategorizerTest(unittest.TestCase): - def setUp(self): - self._test_file_system = TestFileSystem( - _TEST_DATA, relative_to=CHROME_EXTENSIONS) - self._compiled_file_system = CompiledFileSystem.Factory( - ObjectStoreCreator.ForTest()) - - def testGetAPICategory(self): - def assertGetEqual(expected, category, only_on=None): - for platform in ('apps', 'extensions'): - get_category = APICategorizer( - self._test_file_system, - self._compiled_file_system, - platform if only_on is None else only_on).GetCategory(category) - self.assertEqual(expected, get_category) - - assertGetEqual('chrome', 'alarms') - assertGetEqual('private', 'musicManagerPrivate') - assertGetEqual('private', 'notDocumentedApi') - assertGetEqual('experimental', 'experimental.bluetooth', only_on='apps') - assertGetEqual('experimental', 'experimental.history', only_on='extensions') - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/api_data_source.py b/chrome/common/extensions/docs/server2/api_data_source.py deleted file mode 100644 index 98cd2d2d..0000000 --- a/chrome/common/extensions/docs/server2/api_data_source.py +++ /dev/null
@@ -1,139 +0,0 @@ -# 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. - -import logging - -from data_source import DataSource -from docs_server_utils import StringIdentity -from environment import IsPreviewServer -from file_system import FileNotFoundError -from future import All, Future -from jsc_view import CreateJSCView, GetEventByNameFromEvents -from platform_util import GetPlatforms -from third_party.json_schema_compiler.model import CamelName - - -class APIDataSource(DataSource): - '''This class fetches and loads JSON APIs from the FileSystem passed in with - |compiled_fs_factory|, so the APIs can be plugged into templates. - ''' - def __init__(self, server_instance, request): - file_system = server_instance.host_file_system_provider.GetMaster() - self._json_cache = server_instance.compiled_fs_factory.ForJson(file_system) - self._template_cache = server_instance.compiled_fs_factory.ForTemplates( - file_system) - self._platform_bundle = server_instance.platform_bundle - self._view_cache = server_instance.object_store_creator.Create( - APIDataSource, - # Update the models when any of templates, APIs, or Features change. - category=StringIdentity(self._json_cache.GetIdentity(), - self._template_cache.GetIdentity(), - self._platform_bundle.GetIdentity())) - - # This caches the result of _LoadEventByName. - self._event_byname_futures = {} - self._request = request - - def _LoadEventByName(self, platform): - '''All events have some members in common. We source their description - from Event in events.json. - ''' - if platform not in self._event_byname_futures: - future = self._GetSchemaView(platform, 'events') - self._event_byname_futures[platform] = Future( - callback=lambda: GetEventByNameFromEvents(future.Get())) - return self._event_byname_futures[platform] - - def _GetSchemaView(self, platform, api_name): - object_store_key = '/'.join((platform, api_name)) - api_models = self._platform_bundle.GetAPIModels(platform) - jsc_view_future = self._view_cache.Get(object_store_key) - model_future = api_models.GetModel(api_name) - content_script_apis_future = api_models.GetContentScriptAPIs() - - # Parsing samples on the preview server takes forever, so disable it. - if IsPreviewServer(): - samples_future = Future(value=[]) - else: - samples_future = (self._platform_bundle.GetSamplesModel(platform) - .FilterSamples(api_name)) - - def resolve(): - jsc_view = jsc_view_future.Get() - if jsc_view is None: - jsc_view = CreateJSCView( - content_script_apis_future.Get(), - model_future.Get(), - self._platform_bundle.GetAvailabilityFinder(platform), - self._json_cache, - self._template_cache, - self._platform_bundle.GetFeaturesBundle(platform), - self._LoadEventByName(platform), - platform, - samples_future.Get(), - self._request) - self._view_cache.Set(object_store_key, jsc_view) - return jsc_view - return Future(callback=resolve) - - def _NormalizeTemplateAPIName(self, platform, api_name): - '''Normalizes the API name used in templates. - ''' - names = self._platform_bundle.GetAPIModels(platform).GetNames() - if api_name in names: - return api_name - - # API names should be in camel case but many templates use unix_style names. - # See if converting helps. - camel_case_api_name = CamelName(api_name) - if camel_case_api_name in names: - return camel_case_api_name - - # Some APIs e.g. devtools ones are specified like - # devtools/inspected_windows, devtools/network. Try changing them to their - # feature names like devtools.inspectedWindows. - camel_case_api_name = camel_case_api_name.replace('/', '.') - if camel_case_api_name in names: - return camel_case_api_name - - # Some others are used in templates as app_window but their feature name is - # app.window. - alternate_name = api_name.replace('_', '.') - if alternate_name in names: - return alternate_name - - # Else schema view for this |api_name| wasn't persisted to the datastore - # during Refresh by the Compute Engine datastore. We might serve stale data - # for this api without a version update. - logging.warning('%s not found in bundle API names.' % api_name) - return api_name - - def get(self, platform): - '''Return a getter object so that templates can perform lookups such - as apis.extensions.runtime. - ''' - getter = lambda: 0 - def lookup(api_name): - # TODO(karandeepb): We should update the template usages to ensure that - # normalizing is not needed. - api_name = self._NormalizeTemplateAPIName(platform, api_name) - return self._GetSchemaView(platform, api_name).Get() - getter.get = lookup - return getter - - def Refresh(self): - def get_api_schema(platform, api): - return self._GetSchemaView(platform, api) - - def get_platform_schemas(platform): - # Internal APIs are an internal implementation detail. Do not pass them to - # templates. - return All([get_api_schema(platform, api) - for api in self._platform_bundle.GetAPIModels(platform) - .GetNames() - if self._platform_bundle.GetAPICategorizer(platform) - .GetCategory(api) != 'internal'], - except_pass=FileNotFoundError) - - return All([get_platform_schemas(platform) for platform in GetPlatforms()])
diff --git a/chrome/common/extensions/docs/server2/api_data_source_test.py b/chrome/common/extensions/docs/server2/api_data_source_test.py deleted file mode 100755 index 43dda5ad..0000000 --- a/chrome/common/extensions/docs/server2/api_data_source_test.py +++ /dev/null
@@ -1,201 +0,0 @@ -#!/usr/bin/env python -# 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. - -import unittest - -from api_data_source import APIDataSource -from extensions_paths import CHROME_EXTENSIONS -from servlet import Request -from server_instance import ServerInstance -from test_data.api_data_source.canned_master_fs import CANNED_MASTER_FS_DATA -from test_file_system import TestFileSystem - - -class APIDataSourceTest(unittest.TestCase): - def setUp(self): - self.server_instance = ServerInstance.ForTest( - TestFileSystem(CANNED_MASTER_FS_DATA, relative_to=CHROME_EXTENSIONS)) - - def testGet(self): - api_ds = APIDataSource(self.server_instance, Request.ForTest('/')) - jsc_view = api_ds.get('extensions').get('tester') - funcs_arr = [{ - 'availability': None, - 'callback': { - 'name': 'callback', - 'optional': False, - 'parameters': [{ - 'array': { - 'availability': None, - 'description': None, - 'events': [], - 'functions': [], - 'id': 'type-results-resultsType', - 'is_object': False, - 'link': { - 'name': 'TypeA', - 'ref': 'tester.TypeA', - 'text': 'TypeA' - }, - 'name': 'resultsType', - 'properties': [] - }, - 'availability': None, - 'description': None, - 'functions': [], - 'id': 'property-callback-results', - 'is_object': False, - 'last': True, - 'name': 'results', - 'optional': None, - 'parameters': [], - 'parentName': 'callback', - 'properties': [], - 'returns': None - }], - 'simple_type': { - 'simple_type': 'function' - } - }, - 'description': 'Gets stuff.', - 'id': 'method-get', - 'name': 'get', - 'parameters': [{ - 'availability': None, - 'choices': [{ - 'availability': None, - 'description': None, - 'events': [], - 'functions': [], - 'id': 'type-a-string', - 'is_object': False, - 'name': 'string', - 'properties': [], - 'simple_type': 'string' - }, - { - 'array': { - 'availability': None, - 'description': None, - 'events': [], - 'functions': [], - 'id': 'type-strings-stringsType', - 'is_object': False, - 'name': 'stringsType', - 'properties': [], - 'simple_type': 'string' - }, - 'availability': None, - 'description': None, - 'events': [], - 'functions': [], - 'id': 'type-a-strings', - 'is_object': False, - 'last': True, - 'name': 'strings', - 'properties': [] - }], - 'description': 'a param', - 'functions': [], - 'id': 'property-get-a', - 'is_object': False, - 'name': 'a', - 'optional': None, - 'parameters': [], - 'parentName': 'get', - 'properties': [], - 'returns': None - }, - { - 'asFunction': { - 'name': 'callback', - 'optional': False, - 'parameters': [{ - 'array': { - 'availability': None, - 'description': None, - 'events': [], - 'functions': [], - 'id': 'type-results-resultsType', - 'is_object': False, - 'link': { - 'name': 'TypeA', - 'ref': 'tester.TypeA', - 'text': 'TypeA' - }, - 'name': 'resultsType', - 'properties': [] - }, - 'availability': None, - 'description': None, - 'functions': [], - 'id': 'property-callback-results', - 'is_object': False, - 'last': True, - 'name': 'results', - 'optional': None, - 'parameters': [], - 'parentName': 'callback', - 'properties': [], - 'returns': None - }], - 'simple_type': { - 'simple_type': 'function' - } - }, - 'description': None, - 'id': 'property-get-callback', - 'isCallback': True, - 'last': True, - 'name': 'callback', - 'optional': False, - 'parentName': 'get', - 'simple_type': 'function' - }], - 'returns': None - }] - self.assertEquals(funcs_arr, jsc_view['functions']) - types_arr = [{ - 'availability': None, - 'description': 'A cool thing.', - 'events': [], - 'functions': [], - 'id': 'type-TypeA', - 'is_object': True, - 'name': 'TypeA', - 'properties': [{ - 'array': { - 'availability': None, - 'description': None, - 'events': [], - 'functions': [], - 'id': 'type-b-bType', - 'is_object': False, - 'link': { - 'name': 'TypeA', - 'ref': 'tester.TypeA', - 'text': 'TypeA' - }, - 'name': 'bType', - 'properties': [] - }, - 'availability': None, - 'description': 'List of TypeA.', - 'functions': [], - 'id': 'property-TypeA-b', - 'is_object': False, - 'name': 'b', - 'optional': True, - 'parameters': [], - 'parentName': 'TypeA', - 'properties': [], - 'returns': None - }], - 'simple_type': 'object' - }] - self.assertEquals(types_arr, jsc_view['types']) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/api_list_data_source.py b/chrome/common/extensions/docs/server2/api_list_data_source.py deleted file mode 100644 index 009ad7fe..0000000 --- a/chrome/common/extensions/docs/server2/api_list_data_source.py +++ /dev/null
@@ -1,123 +0,0 @@ -# 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 data_source import DataSource -from future import Future -from operator import itemgetter -from platform_util import GetPlatforms - -from docs_server_utils import MarkFirstAndLast, MarkLast - -class APIListDataSource(DataSource): - """ This class creates a list of chrome.* APIs and chrome.experimental.* APIs - for extensions and apps that are used in the api_index.html, - experimental.html, and private_apis.html pages. - - An API is considered listable if it is listed in _api_features.json, - it has a corresponding HTML file in the public template path, and one of - the following conditions is met: - - It has no "dependencies" or "extension_types" properties in _api_features - - It has an "extension_types" property in _api_features with either/both - "extension"/"platform_app" values present. - - It has a dependency in _{api,manifest,permission}_features with an - "extension_types" property where either/both "extension"/"platform_app" - values are present. - """ - def __init__(self, server_instance, _): - self._platform_bundle = server_instance.platform_bundle - self._object_store = server_instance.object_store_creator.Create( - # Update the model when the API or Features model updates. - APIListDataSource, category=self._platform_bundle.GetIdentity()) - - def _GenerateAPIDict(self): - def make_list_for_content_scripts(): - def convert_to_list(content_script_apis): - content_script_apis_list = [csa.__dict__ for api_name, csa - in content_script_apis.iteritems() - if self._platform_bundle.GetAPICategorizer( - 'extensions').IsDocumented(api_name)] - content_script_apis_list.sort(key=itemgetter('name')) - for csa in content_script_apis_list: - restricted_nodes = csa['restrictedTo'] - if restricted_nodes: - restricted_nodes.sort(key=itemgetter('node')) - MarkFirstAndLast(restricted_nodes) - else: - del csa['restrictedTo'] - return content_script_apis_list - - return (self._platform_bundle.GetAPIModels('extensions') - .GetContentScriptAPIs() - .Then(convert_to_list)) - - def make_dict_for_platform(platform): - platform_dict = { - 'chrome': {'stable': [], 'beta': [], 'dev': [], 'master': []}, - } - private_apis = [] - experimental_apis = [] - all_apis = [] - for api_name, api_model in self._platform_bundle.GetAPIModels( - platform).IterModels(): - if not self._platform_bundle.GetAPICategorizer(platform).IsDocumented( - api_name): - continue - api = { - 'name': api_name, - 'description': api_model.description, - } - category = self._platform_bundle.GetAPICategorizer( - platform).GetCategory(api_name) - if category == 'chrome': - channel_info = self._platform_bundle.GetAvailabilityFinder( - platform).GetAPIAvailability(api_name).channel_info - channel = channel_info.channel - if channel == 'stable': - version = channel_info.version - api['version'] = version - platform_dict[category][channel].append(api) - all_apis.append(api) - elif category == 'experimental': - experimental_apis.append(api) - all_apis.append(api) - elif category == 'private': - private_apis.append(api) - - for channel, apis_by_channel in platform_dict['chrome'].iteritems(): - apis_by_channel.sort(key=itemgetter('name')) - MarkLast(apis_by_channel) - platform_dict['chrome'][channel] = apis_by_channel - - for key, apis in (('all', all_apis), - ('private', private_apis), - ('experimental', experimental_apis)): - apis.sort(key=itemgetter('name')) - MarkLast(apis) - platform_dict[key] = apis - - return platform_dict - - def make_api_dict(content_script_apis): - api_dict = dict((platform, make_dict_for_platform(platform)) - for platform in GetPlatforms()) - api_dict['contentScripts'] = content_script_apis - return api_dict - - return make_list_for_content_scripts().Then(make_api_dict) - - def _GetCachedAPIData(self): - def persist_and_return(data): - self._object_store.Set('api_data', data) - return data - def return_or_generate(data): - if data is None: - return self._GenerateAPIDict().Then(persist_and_return) - return data - return self._object_store.Get('api_data').Then(return_or_generate) - - def get(self, key): - return self._GetCachedAPIData().Get().get(key) - - def Refresh(self): - return self._GetCachedAPIData()
diff --git a/chrome/common/extensions/docs/server2/api_list_data_source_test.py b/chrome/common/extensions/docs/server2/api_list_data_source_test.py deleted file mode 100755 index 5ce8b39..0000000 --- a/chrome/common/extensions/docs/server2/api_list_data_source_test.py +++ /dev/null
@@ -1,261 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest -import json - -from api_list_data_source import APIListDataSource -from api_models import ContentScriptAPI -from extensions_paths import CHROME_EXTENSIONS -from server_instance import ServerInstance -from test_file_system import TestFileSystem - - -def _ToTestData(obj): - '''Transforms |obj| into test data by turning a list of files into an object - mapping that file to its contents (derived from its name). - ''' - return dict((name, name) for name in obj) - - -def _ToTestFeatures(names): - '''Transforms a list of strings into a minimal JSON features object. - ''' - def platforms_to_extension_types(platforms): - return ['platform_app' if platform == 'apps' else 'extension' - for platform in platforms] - features = dict((name, { - 'name': name, - 'extension_types': platforms_to_extension_types(platforms), - 'contexts': context - }) for name, platforms, context in names) - features['sockets.udp']['channel'] = 'dev' - return features - - -def _ToTestAPIData(names): - api_data = dict((name, [{'namespace': name, 'description': description}]) - for name, description in names) - return api_data - - -def _ToTestAPISchema(names, apis): - for name, json_file in names: - apis['api'][json_file] = json.dumps(_TEST_API_DATA[name]) - return apis - - -_TEST_API_FEATURES = _ToTestFeatures([ - ('alarms', ['apps', 'extensions'], ['content_script']), - ('app.window', ['apps'], []), - ('browserAction', ['extensions'], []), - ('experimental.bluetooth', ['apps'], []), - ('experimental.history', ['extensions'], []), - ('experimental.power', ['apps', 'extensions'], []), - ('extension', ['extensions'], ['content_script']), - ('extension.onRequest', ['extensions'], ['content_script']), - ('extension.sendNativeMessage', ['extensions'], []), - ('extension.sendRequest', ['extensions'], ['content_script']), - ('infobars', ['extensions'], []), - ('something_internal', ['apps'], []), - ('something_else_internal', ['extensions'], []), - ('storage', ['apps', 'extensions'], []), - ('sockets.udp', ['apps', 'extensions'], []) -]) - - -_TEST_API_DATA = _ToTestAPIData([ - ('alarms', u'<code>alarms</code>'), - ('app.window', u'<code>app.window</code>'), - ('browserAction', u'<code>browserAction</code>'), - ('experimental.bluetooth', u'<code>experimental.bluetooth</code>'), - ('experimental.history', u'<code>experimental.history</code>'), - ('experimental.power', u'<code>experimental.power</code>'), - ('extension', u'<code>extension</code>'), - ('infobars', u'<code>infobars</code>'), - ('something_internal', u'<code>something_internal</code>'), - ('something_else_internal', u'<code>something_else_internal</code>'), - ('storage', u'<code>storage</code>'), - ('sockets.udp', u'<code>sockets.udp</code>') -]) - - -_TEST_API_SCHEMA = [ - ('alarms', 'alarms.json'), - ('app.window', 'app_window.json'), - ('browserAction', 'browser_action.json'), - ('experimental.bluetooth', 'experimental_bluetooth.json'), - ('experimental.history', 'experimental_history.json'), - ('experimental.power', 'experimental_power.json'), - ('extension', 'extension.json'), - ('infobars', 'infobars.json'), - ('something_internal', 'something_internal.json'), - ('something_else_internal', 'something_else_internal.json'), - ('storage', 'storage.json'), - ('sockets.udp', 'sockets_udp.json') -] - - -_TEST_DATA = _ToTestAPISchema(_TEST_API_SCHEMA, { - 'api': { - '_api_features.json': json.dumps(_TEST_API_FEATURES), - '_manifest_features.json': '{}', - '_permission_features.json': '{}', - }, - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': '{}', - 'manifest.json': '{}', - 'permissions.json': '{}', - }, - 'public': { - 'apps': _ToTestData([ - 'alarms.html', - 'app_window.html', - 'experimental_bluetooth.html', - 'experimental_power.html', - 'storage.html', - 'sockets_udp.html' - ]), - 'extensions': _ToTestData([ - 'alarms.html', - 'browserAction.html', - 'experimental_history.html', - 'experimental_power.html', - 'extension.html', - 'infobars.html', - 'storage.html', - 'sockets_udp.html' - ]), - }, - }, - }, -}) - - -class APIListDataSourceTest(unittest.TestCase): - def setUp(self): - server_instance = ServerInstance.ForTest( - TestFileSystem(_TEST_DATA, relative_to=CHROME_EXTENSIONS)) - # APIListDataSource takes a request but doesn't use it, - # so put None - self._api_list = APIListDataSource(server_instance, None) - self.maxDiff = None - - def testApps(self): - self.assertEqual({ - 'stable': [ - { - 'name': 'alarms', - 'version': 5, - 'description': u'<code>alarms</code>' - }, - { - 'name': 'app.window', - # Availability logic will look for a camelCase format filename - # (i.e. 'app.window.html') at version 20 and below, but the - # unix_name format above won't be found at these versions. - 'version': 21, - 'description': u'<code>app.window</code>' - }, - { - 'name': 'storage', - 'last': True, - 'version': 5, - 'description': u'<code>storage</code>' - }], - 'dev': [ - { - 'name': 'sockets.udp', - 'last': True, - 'description': u'<code>sockets.udp</code>' - }], - 'beta': [], - 'master': [] - }, self._api_list.get('apps').get('chrome')) - - def testExperimentalApps(self): - self.assertEqual([ - { - 'name': 'experimental.bluetooth', - 'description': u'<code>experimental.bluetooth</code>' - }, - { - 'name': 'experimental.power', - 'last': True, - 'description': u'<code>experimental.power</code>' - }], self._api_list.get('apps').get('experimental')) - - def testExtensions(self): - self.assertEqual({ - 'stable': [ - { - 'name': 'alarms', - 'version': 5, - 'description': u'<code>alarms</code>' - }, - { - 'name': 'browserAction', - # See comment above for 'app.window'. - 'version': 21, - 'description': u'<code>browserAction</code>' - }, - { - 'name': 'extension', - 'version': 5, - 'description': u'<code>extension</code>' - }, - { - 'name': 'infobars', - 'version': 5, - 'description': u'<code>infobars</code>' - }, - { - 'name': 'storage', - 'last': True, - 'version': 5, - 'description': u'<code>storage</code>' - }], - 'dev': [ - { - 'name': 'sockets.udp', - 'last': True, - 'description': u'<code>sockets.udp</code>' - }], - 'beta': [], - 'master': [] - }, self._api_list.get('extensions').get('chrome')) - - def testExperimentalExtensions(self): - self.assertEqual([ - { - 'name': 'experimental.history', - 'description': u'<code>experimental.history</code>' - }, - { - 'name': 'experimental.power', - 'description': u'<code>experimental.power</code>', - 'last': True - }], self._api_list.get('extensions').get('experimental')) - - def testContentScripts(self): - self.assertEqual([{ - 'name': 'alarms', - }, - { - 'name': 'extension', - 'restrictedTo': [{ - 'node': 'onRequest', - 'first': True - }, - { - 'node': 'sendRequest', - 'last': True - }] - }], self._api_list.get('contentScripts')) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/api_models.py b/chrome/common/extensions/docs/server2/api_models.py deleted file mode 100644 index 31c8a075..0000000 --- a/chrome/common/extensions/docs/server2/api_models.py +++ /dev/null
@@ -1,187 +0,0 @@ -# Copyright 2013 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 posixpath - -from compiled_file_system import Cache, SingleFile, Unicode -from extensions_paths import API_PATHS -from features_bundle import HasParent, GetParentName -from file_system import FileNotFoundError -from future import All, Future, Race -from operator import itemgetter -from path_util import Join -from platform_util import PlatformToExtensionType -from schema_processor import SchemaProcessor, SchemaProcessorFactory -from third_party.json_schema_compiler.json_schema import DeleteNodes -from third_party.json_schema_compiler.model import Namespace, UnixName - - -def GetNodeCategories(): - '''Returns a tuple of the possible categories a node may belong to. - ''' - return ('types', 'functions', 'events', 'properties') - - -class ContentScriptAPI(object): - '''Represents an API available to content scripts. - - |name| is the name of the API or API node this object represents. - |restrictedTo| is a list of dictionaries representing the nodes - of this API that are available to content scripts, or None if the - entire API is available to content scripts. - ''' - def __init__(self, name): - self.name = name - self.restrictedTo = None - - def __eq__(self, o): - return self.name == o.name and self.restrictedTo == o.restrictedTo - - def __ne__(self, o): - return not (self == o) - - def __repr__(self): - return ('<ContentScriptAPI name=%s, restrictedTo=%s>' % - (self.name, self.restrictedTo)) - - def __str__(self): - return repr(self) - - -class APIModels(object): - '''Tracks APIs and their Models. - ''' - - def __init__(self, - features_bundle, - compiled_fs_factory, - file_system, - object_store_creator, - platform, - schema_processor_factory): - self._features_bundle = features_bundle - self._platform = PlatformToExtensionType(platform) - self._model_cache = compiled_fs_factory.Create( - file_system, self._CreateAPIModel, APIModels, category=self._platform) - self._object_store = object_store_creator.Create(APIModels) - self._schema_processor = Future(callback=lambda: - schema_processor_factory.Create(False)) - - @Cache - @SingleFile - @Unicode - def _CreateAPIModel(self, path, data): - def does_not_include_platform(node): - return ('extension_types' in node and - node['extension_types'] != 'all' and - self._platform not in node['extension_types']) - - schema = self._schema_processor.Get().Process(path, data)[0] - if not schema: - raise ValueError('No schema for %s' % path) - return Namespace(DeleteNodes( - schema, matcher=does_not_include_platform), path) - - def GetNames(self): - # API names appear alongside some of their methods/events/etc in the - # features file. APIs are those which either implicitly or explicitly have - # no parent feature (e.g. app, app.window, and devtools.inspectedWindow are - # APIs; runtime.onConnectNative is not). - api_features = self._features_bundle.GetAPIFeatures().Get() - return [name for name, feature in api_features.iteritems() - if not HasParent(name, feature, api_features)] - - def _GetPotentialPathsForModel(self, api_name): - '''Returns the list of file system paths that the model for |api_name| - might be located at. - ''' - # By default |api_name| is assumed to be given without a path or extension, - # so combinations of known paths and extension types will be searched. - api_extensions = ('.json', '.idl') - api_paths = API_PATHS - - # Callers sometimes include a file extension and/or prefix path with the - # |api_name| argument. We believe them and narrow the search space - # accordingly. - name, ext = posixpath.splitext(api_name) - if ext in api_extensions: - api_extensions = (ext,) - api_name = name - for api_path in api_paths: - if api_name.startswith(api_path): - api_name = api_name[len(api_path):] - api_paths = (api_path,) - break - - # API names are given as declarativeContent and app.window but file names - # will be declarative_content and app_window. - file_name = UnixName(api_name).replace('.', '_') - # Devtools APIs are in API/devtools/ not API/, and have their - # "devtools" names removed from the file names. - basename = posixpath.basename(file_name) - if 'devtools_' in basename: - file_name = posixpath.join( - 'devtools', file_name.replace(basename, - basename.replace('devtools_' , ''))) - - return [Join(path, file_name + ext) for ext in api_extensions - for path in api_paths] - - def GetModel(self, api_name): - futures = [self._model_cache.GetFromFile(path) - for path in self._GetPotentialPathsForModel(api_name)] - return Race(futures, except_pass=(FileNotFoundError, ValueError)) - - def GetContentScriptAPIs(self): - '''Creates a dict of APIs and nodes supported by content scripts in - this format: - - { - 'extension': '<ContentScriptAPI name='extension', - restrictedTo=[{'node': 'onRequest'}]>', - ... - } - ''' - content_script_apis_future = self._object_store.Get('content_script_apis') - api_features_future = self._features_bundle.GetAPIFeatures() - def resolve(): - content_script_apis = content_script_apis_future.Get() - if content_script_apis is not None: - return content_script_apis - - api_features = api_features_future.Get() - content_script_apis = {} - for name, feature in api_features.iteritems(): - if 'content_script' not in feature.get('contexts', ()): - continue - parent = GetParentName(name, feature, api_features) - if parent is None: - content_script_apis[name] = ContentScriptAPI(name) - else: - # Creates a dict for the individual node. - node = {'node': name[len(parent) + 1:]} - if parent not in content_script_apis: - content_script_apis[parent] = ContentScriptAPI(parent) - if content_script_apis[parent].restrictedTo: - content_script_apis[parent].restrictedTo.append(node) - else: - content_script_apis[parent].restrictedTo = [node] - - self._object_store.Set('content_script_apis', content_script_apis) - return content_script_apis - return Future(callback=resolve) - - def Refresh(self): - futures = [self.GetModel(name) for name in self.GetNames()] - return All(futures, except_pass=(FileNotFoundError, ValueError)) - - def IterModels(self): - future_models = [(name, self.GetModel(name)) for name in self.GetNames()] - for name, future_model in future_models: - try: - model = future_model.Get() - except FileNotFoundError: - continue - if model: - yield name, model
diff --git a/chrome/common/extensions/docs/server2/api_models_test.py b/chrome/common/extensions/docs/server2/api_models_test.py deleted file mode 100755 index 4d96632..0000000 --- a/chrome/common/extensions/docs/server2/api_models_test.py +++ /dev/null
@@ -1,160 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 json -import unittest - -from api_models import APIModels -from compiled_file_system import CompiledFileSystem -from extensions_paths import (API_PATHS, CHROME_API, CHROME_EXTENSIONS, - EXTENSIONS_API) -from features_bundle import FeaturesBundle -from file_system import FileNotFoundError -from mock_file_system import MockFileSystem -from object_store_creator import ObjectStoreCreator -from test_file_system import TestFileSystem -from test_util import ReadFile -from future import Future -from schema_processor import SchemaProcessorFactoryForTest - - -_TEST_DATA = { - 'api': { - 'devtools': { - 'inspected_window.json': ReadFile( - CHROME_API, 'devtools', 'inspected_window.json'), - }, - '_api_features.json': json.dumps({ - 'alarms': {}, - 'app': {}, - 'app.runtime': {'noparent': True}, - 'app.runtime.foo': {}, - 'declarativeWebRequest': {}, - 'devtools.inspectedWindow': {}, - 'input': {}, - 'input.ime': {}, - 'storage': {}, - }), - '_manifest_features.json': '{}', - '_permission_features.json': '{}', - 'alarms.idl': ReadFile(EXTENSIONS_API, 'alarms.idl'), - 'input_ime.json': ReadFile(CHROME_API, 'input_ime.json'), - 'page_action.json': ReadFile(CHROME_API, 'page_action.json'), - }, - 'docs': { - 'templates': { - 'json': { - 'manifest.json': '{}', - 'permissions.json': '{}', - } - } - }, -} - - -class APIModelsTest(unittest.TestCase): - def setUp(self): - object_store_creator = ObjectStoreCreator.ForTest() - compiled_fs_factory = CompiledFileSystem.Factory(object_store_creator) - self._mock_file_system = MockFileSystem( - TestFileSystem(_TEST_DATA, relative_to=CHROME_EXTENSIONS)) - features_bundle = FeaturesBundle(self._mock_file_system, - compiled_fs_factory, - object_store_creator, - 'extensions') - self._api_models = APIModels(features_bundle, - compiled_fs_factory, - self._mock_file_system, - object_store_creator, - 'extensions', - SchemaProcessorFactoryForTest()) - - def testGetNames(self): - # Both 'app' and 'app.runtime' appear here because 'app.runtime' has - # noparent:true, but 'app.runtime.foo' etc doesn't so it's a sub-feature of - # 'app.runtime' not a separate API. 'devtools.inspectedWindow' is an API - # because there is no 'devtools'. - self.assertEqual( - ['alarms', 'app', 'app.runtime', 'declarativeWebRequest', - 'devtools.inspectedWindow', 'input', 'storage'], - sorted(self._api_models.GetNames())) - - def testGetModel(self): - def get_model_name(api_name): - return self._api_models.GetModel(api_name).Get().name - self.assertEqual('devtools.inspectedWindow', - get_model_name('devtools.inspectedWindow')) - self.assertEqual('devtools.inspectedWindow', - get_model_name('devtools/inspected_window.json')) - self.assertEqual('devtools.inspectedWindow', - get_model_name(CHROME_API + - 'devtools/inspected_window.json')) - self.assertEqual('alarms', get_model_name('alarms')) - self.assertEqual('alarms', get_model_name('alarms.idl')) - self.assertEqual('alarms', get_model_name(CHROME_API + 'alarms.idl')) - self.assertEqual('input.ime', get_model_name('input.ime')) - self.assertEqual('input.ime', get_model_name('input_ime.json')) - self.assertEqual('input.ime', - get_model_name(CHROME_API + 'input_ime.json')) - self.assertEqual('pageAction', get_model_name('pageAction')) - self.assertEqual('pageAction', get_model_name('page_action.json')) - self.assertEqual('pageAction', get_model_name(CHROME_API + - 'page_action.json')) - - def testGetNonexistentModel(self): - self.assertRaises(FileNotFoundError, - self._api_models.GetModel('declarativeWebRequest').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel( - 'declarative_web_request.json').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel( - CHROME_API + 'declarative_web_request.json').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel('notfound').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel('notfound.json').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel(CHROME_API + - 'notfound.json').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel(CHROME_API + - 'alarms.json').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel('storage').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel(CHROME_API + - 'storage.json').Get) - self.assertRaises(FileNotFoundError, - self._api_models.GetModel(CHROME_API + - 'storage.idl').Get) - - def testSingleFile(self): - # 2 stats (1 for JSON and 1 for IDL) for each available API path. - # 1 read (for IDL file which existed). - future = self._api_models.GetModel('alarms') - self.assertTrue(*self._mock_file_system.CheckAndReset( - read_count=1, stat_count=len(API_PATHS)*2)) - - # 1 read-resolve (for the IDL file). - # - # The important part here and above is that it's only doing a single read; - # any more would break the contract that only a single file is accessed - - # see the SingleFile annotation in api_models._CreateAPIModel. - future.Get() - self.assertTrue(*self._mock_file_system.CheckAndReset( - read_resolve_count=1)) - - # 2 stats (1 for JSON and 1 for IDL) for each available API path. - # No reads (still cached). - future = self._api_models.GetModel('alarms') - self.assertTrue(*self._mock_file_system.CheckAndReset( - stat_count=len(API_PATHS)*2)) - future.Get() - self.assertTrue(*self._mock_file_system.CheckAndReset()) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/api_schema_graph.py b/chrome/common/extensions/docs/server2/api_schema_graph.py deleted file mode 100644 index 1ec5833..0000000 --- a/chrome/common/extensions/docs/server2/api_schema_graph.py +++ /dev/null
@@ -1,383 +0,0 @@ -# Copyright 2013 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 json -import logging - -from api_models import GetNodeCategories -from collections import Iterable, Mapping - -class LookupResult(object): - '''Returned from APISchemaGraph.Lookup(), and relays whether or not - some element was found and what annotation object was associated with it, - if any. - ''' - - def __init__(self, found=None, annotation=None): - assert found is not None, 'LookupResult was given None value for |found|.' - self.found = found - self.annotation = annotation - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - return not (self == other) - - def __repr__(self): - return '%s%s' % (type(self).__name__, repr(self.__dict__)) - - def __str__(self): - return repr(self) - - -class APINodeCursor(object): - '''An abstract representation of a node in an APISchemaGraph. - The current position in the graph is represented by a path into the - underlying dictionary. So if the APISchemaGraph is: - - { - 'tabs': { - 'types': { - 'Tab': { - 'properties': { - 'url': { - ... - } - } - } - } - } - } - - then the 'url' property would be represented by: - - ['tabs', 'types', 'Tab', 'properties', 'url'] - ''' - - def __init__(self, availability_finder, namespace_name): - self._lookup_path = [] - self._node_availabilities = availability_finder.GetAPINodeAvailability( - namespace_name) - self._namespace_name = namespace_name - self._ignored_categories = [] - - def _AssertIsValidCategory(self, category): - assert category in GetNodeCategories(), \ - '%s is not a valid category. Full path: %s' % (category, str(self)) - - def _GetParentPath(self): - '''Returns the path pointing to this node's parent. - ''' - assert len(self._lookup_path) > 1, \ - 'Tried to look up parent for the top-level node.' - - # lookup_path[-1] is the name of the current node. If this lookup_path - # describes a regular node, then lookup_path[-2] will be a node category. - # Otherwise, it's an event callback or a function parameter. - if self._lookup_path[-2] not in GetNodeCategories(): - if self._lookup_path[-1] == 'callback': - # This is an event callback, so lookup_path[-2] is the event - # node name, thus lookup_path[-3] must be 'events'. - assert self._lookup_path[-3] == 'events' , \ - 'Invalid lookup path: %s' % (self._lookup_path) - return self._lookup_path[:-1] - # This is a function parameter. - assert self._lookup_path[-2] == 'parameters' - return self._lookup_path[:-2] - # This is a regular node, so lookup_path[-2] should - # be a node category. - self._AssertIsValidCategory(self._lookup_path[-2]) - return self._lookup_path[:-2] - - def _LookupNodeAvailability(self, lookup_path): - '''Returns the ChannelInfo object for this node. - ''' - return self._node_availabilities.Lookup(self._namespace_name, - *lookup_path).annotation - - def _CheckNamespacePrefix(self, lookup_path): - '''API schemas may prepend the namespace name to top-level types - (e.g. declarativeWebRequest > types > declarativeWebRequest.IgnoreRules), - but just the base name (here, 'IgnoreRules') will be in the |lookup_path|. - Try creating an alternate |lookup_path| by adding the namespace name. - ''' - # lookup_path[0] is always the node category (e.g. types, functions, etc.). - # Thus, lookup_path[1] is always the top-level node name. - self._AssertIsValidCategory(lookup_path[0]) - base_name = lookup_path[1] - lookup_path[1] = '%s.%s' % (self._namespace_name, base_name) - try: - node_availability = self._LookupNodeAvailability(lookup_path) - if node_availability is not None: - return node_availability - finally: - # Restore lookup_path. - lookup_path[1] = base_name - return None - - def _CheckEventCallback(self, lookup_path): - '''Within API schemas, an event has a list of 'properties' that the event's - callback expects. The callback itself is not explicitly represented in the - schema. However, when creating an event node in JSCView, a callback node - is generated and acts as the parent for the event's properties. - Modify |lookup_path| to check the original schema format. - ''' - if 'events' in lookup_path: - assert 'callback' in lookup_path, self - callback_index = lookup_path.index('callback') - try: - lookup_path.pop(callback_index) - node_availability = self._LookupNodeAvailability(lookup_path) - finally: - lookup_path.insert(callback_index, 'callback') - return node_availability - return None - - def _LookupAvailability(self, lookup_path): - '''Runs all the lookup checks on |lookup_path| and - returns the node availability if found, None otherwise. - ''' - for lookup in (self._LookupNodeAvailability, - self._CheckEventCallback, - self._CheckNamespacePrefix): - node_availability = lookup(lookup_path) - if node_availability is not None: - return node_availability - return None - - def _GetCategory(self): - '''Returns the category this node belongs to. - ''' - if self._lookup_path[-2] in GetNodeCategories(): - return self._lookup_path[-2] - # If lookup_path[-2] is not a valid category and lookup_path[-1] is - # 'callback', then we know we have an event callback. - if self._lookup_path[-1] == 'callback': - return 'events' - if self._lookup_path[-2] == 'parameters': - # Function parameters are modelled as properties. - return 'properties' - if (self._lookup_path[-1].endswith('Type') and - (self._lookup_path[-1][:-len('Type')] == self._lookup_path[-2] or - self._lookup_path[-1][:-len('ReturnType')] == self._lookup_path[-2])): - # Array elements and function return objects have 'Type' and 'ReturnType' - # appended to their names, respectively, in model.py. This results in - # lookup paths like - # 'events > types > Rule > properties > tags > tagsType'. - # These nodes are treated as properties. - return 'properties' - if self._lookup_path[0] == 'events': - # HACK(ahernandez.miralles): This catches a few edge cases, - # such as 'webviewTag > events > consolemessage > level'. - return 'properties' - raise AssertionError('Could not classify node %s' % self) - - def GetDeprecated(self): - '''Returns when this node became deprecated, or None if it - is not deprecated. - ''' - deprecated_path = self._lookup_path + ['deprecated'] - for lookup in (self._LookupNodeAvailability, - self._CheckNamespacePrefix): - node_availability = lookup(deprecated_path) - if node_availability is not None: - return node_availability - if 'callback' in self._lookup_path: - return self._CheckEventCallback(deprecated_path) - return None - - def GetAvailability(self): - '''Returns availability information for this node. - ''' - if self._GetCategory() in self._ignored_categories: - return None - node_availability = self._LookupAvailability(self._lookup_path) - if node_availability is None: - logging.warning('No availability found for: %s' % self) - return None - - parent_node_availability = self._LookupAvailability(self._GetParentPath()) - # If the parent node availability couldn't be found, something - # is very wrong. - assert parent_node_availability is not None - - # Only render this node's availability if it differs from the parent - # node's availability. - if node_availability == parent_node_availability: - return None - return node_availability - - def Descend(self, *path, **kwargs): - '''Moves down the APISchemaGraph, following |path|. - |ignore| should be a tuple of category strings (e.g. ('types',)) - for which nodes should not have availability data generated. - ''' - ignore = kwargs.get('ignore') - class scope(object): - def __enter__(self2): - if ignore: - self._ignored_categories.extend(ignore) - if path: - self._lookup_path.extend(path) - - def __exit__(self2, _, __, ___): - if ignore: - self._ignored_categories[:] = self._ignored_categories[:-len(ignore)] - if path: - self._lookup_path[:] = self._lookup_path[:-len(path)] - return scope() - - def __str__(self): - return repr(self) - - def __repr__(self): - return '%s > %s' % (self._namespace_name, ' > '.join(self._lookup_path)) - - -class _GraphNode(dict): - '''Represents some element of an API schema, and allows extra information - about that element to be stored on the |_annotation| object. - ''' - - def __init__(self, *args, **kwargs): - # Use **kwargs here since Python is picky with ordering of default args - # and variadic args in the method signature. The only keyword arg we care - # about here is 'annotation'. Intentionally don't pass |**kwargs| into the - # superclass' __init__(). - dict.__init__(self, *args) - self._annotation = kwargs.get('annotation') - - def __eq__(self, other): - # _GraphNode inherits __eq__() from dict, which will not take annotation - # objects into account when comparing. - return dict.__eq__(self, other) - - def __ne__(self, other): - return not (self == other) - - def GetAnnotation(self): - return self._annotation - - def SetAnnotation(self, annotation): - self._annotation = annotation - - -def _NameForNode(node): - '''Creates a unique id for an object in an API schema, depending on - what type of attribute the object is a member of. - ''' - if 'namespace' in node: return node['namespace'] - if 'name' in node: return node['name'] - if 'id' in node: return node['id'] - if 'type' in node: return node['type'] - if '$ref' in node: return node['$ref'] - assert False, 'Problems with naming node: %s' % json.dumps(node, indent=3) - - -def _IsObjectList(value): - '''Determines whether or not |value| is a list made up entirely of - dict-like objects. - ''' - return (isinstance(value, Iterable) and - all(isinstance(node, Mapping) for node in value)) - - -def _CreateGraph(root): - '''Recursively moves through an API schema, replacing lists of objects - and non-object values with objects. - ''' - schema_graph = _GraphNode() - if _IsObjectList(root): - for node in root: - name = _NameForNode(node) - assert name not in schema_graph, 'Duplicate name in API schema graph.' - schema_graph[name] = _GraphNode((key, _CreateGraph(value)) for - key, value in node.iteritems()) - - elif isinstance(root, Mapping): - for name, node in root.iteritems(): - if not isinstance(node, Mapping): - schema_graph[name] = _GraphNode() - else: - schema_graph[name] = _GraphNode((key, _CreateGraph(value)) for - key, value in node.iteritems()) - return schema_graph - - -def _Subtract(minuend, subtrahend): - ''' A Set Difference adaptation for graphs. Returns a |difference|, - which contains key-value pairs found in |minuend| but not in - |subtrahend|. - ''' - difference = _GraphNode() - for key in minuend: - if key not in subtrahend: - # Record all of this key's children as being part of the difference. - difference[key] = _Subtract(minuend[key], {}) - else: - # Note that |minuend| and |subtrahend| are assumed to be graphs, and - # therefore should have no lists present, only keys and nodes. - rest = _Subtract(minuend[key], subtrahend[key]) - if rest: - # Record a difference if children of this key differed at some point. - difference[key] = rest - return difference - - -class APISchemaGraph(object): - '''Provides an interface for interacting with an API schema graph, a - nested dict structure that allows for simpler lookups of schema data. - ''' - - def __init__(self, api_schema=None, _graph=None): - self._graph = _graph if _graph is not None else _CreateGraph(api_schema) - - def __eq__(self, other): - return self._graph == other._graph - - def __ne__(self, other): - return not (self == other) - - def Subtract(self, other): - '''Returns an APISchemaGraph instance representing keys that are in - this graph but not in |other|. - ''' - return APISchemaGraph(_graph=_Subtract(self._graph, other._graph)) - - def Update(self, other, annotator): - '''Modifies this graph by adding keys from |other| that are not - already present in this graph. - ''' - def update(base, addend): - '''A Set Union adaptation for graphs. Returns a graph which contains - the key-value pairs from |base| combined with any key-value pairs - from |addend| that are not present in |base|. - ''' - for key in addend: - if key not in base: - # Add this key and the rest of its children. - base[key] = update(_GraphNode(annotation=annotator(key)), addend[key]) - else: - # The key is already in |base|, but check its children. - update(base[key], addend[key]) - return base - - update(self._graph, other._graph) - - def Lookup(self, *path): - '''Given a list of path components, |path|, checks if the - APISchemaGraph instance contains |path|. - ''' - node = self._graph - for path_piece in path: - node = node.get(path_piece) - if node is None: - return LookupResult(found=False, annotation=None) - return LookupResult(found=True, annotation=node._annotation) - - def IsEmpty(self): - '''Checks for an empty schema graph. - ''' - return not self._graph
diff --git a/chrome/common/extensions/docs/server2/api_schema_graph_test.py b/chrome/common/extensions/docs/server2/api_schema_graph_test.py deleted file mode 100755 index e6d65af4..0000000 --- a/chrome/common/extensions/docs/server2/api_schema_graph_test.py +++ /dev/null
@@ -1,448 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from api_schema_graph import APISchemaGraph, LookupResult - - -API_SCHEMA = [{ - 'namespace': 'tabs', - 'properties': { - 'lowercase': { - 'properties': { - 'one': { 'value': 1 }, - 'two': { 'description': 'just as bad as one' } - } - }, - 'TAB_PROPERTY_ONE': { 'value': 'magic' }, - 'TAB_PROPERTY_TWO': {} - }, - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'id': {}, - 'url': {} - } - } - ], - 'functions': [ - { - 'name': 'get', - 'parameters': [ { 'name': 'tab', - 'type': 'object', - 'description': 'gets stuff, never complains' - }, - { 'name': 'tabId' } - ] - } - ], - 'events': [ - { - 'name': 'onActivated', - 'parameters': [ {'name': 'activeInfo'} ] - }, - { - 'name': 'onUpdated', - 'parameters': [ {'name': 'updateInfo'} ] - } - ] -}] - - -class APISchemaGraphTest(unittest.TestCase): - - def testLookup(self): - self._testAPISchema(APISchemaGraph(API_SCHEMA)) - - def testIsEmpty(self): - # A few assertions to make sure that Lookup works on empty sets. - empty_graph = APISchemaGraph({}) - self.assertTrue(empty_graph.IsEmpty()) - self.assertEqual(LookupResult(False, None), - empty_graph.Lookup('tabs', 'properties', - 'TAB_PROPERTY_ONE')) - self.assertEqual(LookupResult(False, None), - empty_graph.Lookup('tabs', 'functions', 'get', - 'parameters', 'tab')) - self.assertEqual(LookupResult(False, None), - empty_graph.Lookup('tabs', 'functions', 'get', - 'parameters', 'tabId')) - self.assertEqual(LookupResult(False, None), - empty_graph.Lookup('tabs', 'events', 'onActivated', - 'parameters', 'activeInfo')) - self.assertEqual(LookupResult(False, None), - empty_graph.Lookup('tabs', 'events', 'onUpdated', - 'parameters', 'updateInfo')) - - def testSubtractEmpty(self): - self._testAPISchema( - APISchemaGraph(API_SCHEMA).Subtract(APISchemaGraph({}))) - - def _testAPISchema(self, api_schema_graph): - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'properties', - 'TAB_PROPERTY_ONE')) - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'types', 'Tab')) - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'functions', 'get', - 'parameters', 'tab')) - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'functions', 'get', - 'parameters', 'tabId')) - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'functions', 'get', - 'parameters', 'tab', 'type')) - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'events', - 'onActivated', 'parameters', - 'activeInfo')) - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'events', 'onUpdated', - 'parameters', 'updateInfo')) - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'properties', - 'lowercase', 'properties', - 'one', 'value')) - self.assertEqual(LookupResult(True, None), - api_schema_graph.Lookup('tabs', 'properties', - 'lowercase', 'properties', - 'two', 'description')) - self.assertEqual(LookupResult(False, None), - api_schema_graph.Lookup('windows')) - self.assertEqual(LookupResult(False, None), - api_schema_graph.Lookup('tabs', 'properties', - 'TAB_PROPERTY_DEUX')) - self.assertEqual(LookupResult(False, None), - api_schema_graph.Lookup('tabs', 'events', 'onActivated', - 'parameters', 'callback')) - self.assertEqual(LookupResult(False, None), - api_schema_graph.Lookup('tabs', 'functions', 'getById', - 'parameters', 'tab')) - self.assertEqual(LookupResult(False, None), - api_schema_graph.Lookup('tabs', 'functions', 'get', - 'parameters', 'type')) - self.assertEqual(LookupResult(False, None), - api_schema_graph.Lookup('tabs', 'properties', - 'lowercase', 'properties', - 'two', 'value')) - - def testSubtractSelf(self): - self.assertTrue( - APISchemaGraph(API_SCHEMA).Subtract(APISchemaGraph(API_SCHEMA)) - .IsEmpty()) - - - def testSubtractDisjointSet(self): - difference = APISchemaGraph(API_SCHEMA).Subtract(APISchemaGraph({ - 'contextMenus': { - 'properties': { - 'CONTEXT_MENU_PROPERTY_ONE': {} - }, - 'types': { - 'Menu': { - 'properties': { - 'id': {}, - 'width': {} - } - } - }, - 'functions': { - 'get': { - 'parameters': { - 'callback': {} - } - } - }, - 'events': { - 'onClicked': { - 'parameters': { - 'clickInfo': {} - } - }, - 'onUpdated': { - 'parameters': { - 'updateInfo': {} - } - } - } - } - })) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs', 'properties', - 'TAB_PROPERTY_ONE')) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs', 'functions', 'get', - 'parameters', 'tab')) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs', 'events', 'onUpdated', - 'parameters', 'updateInfo')) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs', 'functions', 'get', - 'parameters', 'tabId')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('contextMenus', 'properties', - 'CONTEXT_MENU_PROPERTY_ONE')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('contextMenus', 'types', 'Menu')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('contextMenus', 'types', 'Menu', - 'properties', 'id')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('contextMenus', 'functions')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('contextMenus', 'events', 'onClicked', - 'parameters', 'clickInfo')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('contextMenus', 'events', 'onUpdated', - 'parameters', 'updateInfo')) - - def testSubtractSubset(self): - difference = APISchemaGraph(API_SCHEMA).Subtract(APISchemaGraph({ - 'tabs': { - 'properties': { - 'TAB_PROPERTY_ONE': { 'value': {} } - }, - 'functions': { - 'get': { - 'parameters': { - 'tab': { 'name': {}, - 'type': {}, - 'description': {} - } - } - } - }, - 'events': { - 'onUpdated': { - 'parameters': { - 'updateInfo': { - 'name': {}, - 'properties': { - 'tabId': {} - } - } - } - } - } - } - })) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs')) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs', 'properties', - 'TAB_PROPERTY_TWO')) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs', 'properties', 'lowercase', - 'properties', 'two', 'description')) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs', 'types', 'Tab', 'properties', - 'url')) - self.assertEqual(LookupResult(True, None), - difference.Lookup('tabs', 'events', 'onActivated', - 'parameters', 'activeInfo')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'events', 'onUpdated', - 'parameters', 'updateInfo')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'properties', - 'TAB_PROPERTY_ONE')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'properties', - 'TAB_PROPERTY_ONE', 'value')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'functions', 'get', - 'parameters', 'tab')) - - def testSubtractSuperset(self): - difference = APISchemaGraph(API_SCHEMA).Subtract(APISchemaGraph({ - 'tabs': { - 'namespace': {}, - 'properties': { - 'lowercase': { - 'properties': { - 'one': { 'value': {} }, - 'two': { 'description': {} } - } - }, - 'TAB_PROPERTY_ONE': { 'value': {} }, - 'TAB_PROPERTY_TWO': {}, - 'TAB_PROPERTY_THREE': {} - }, - 'types': { - 'Tab': { - 'id': {}, - 'properties': { - 'id': {}, - 'url': {} - } - }, - 'UpdateInfo': {} - }, - 'functions': { - 'get': { - 'name': {}, - 'parameters': { - 'tab': { 'name': {}, - 'type': {}, - 'description': {} - }, - 'tabId': { 'name': {} } - } - }, - 'getById': { - 'parameters': { - 'tabId': {} - } - } - }, - 'events': { - 'onActivated': { - 'name': {}, - 'parameters': { - 'activeInfo': { 'name': {} } - } - }, - 'onUpdated': { - 'name': {}, - 'parameters': { - 'updateInfo': { 'name': {} } - } - }, - 'onClicked': { - 'name': {}, - 'parameters': { - 'clickInfo': {} - } - } - } - } - })) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'properties', - 'TAB_PROPERTY_TWO')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'properties')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'types', 'Tab', 'properties', - 'url')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'types', 'Tab', 'properties', - 'id')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'events', 'onUpdated', - 'parameters', 'updateInfo')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'properties', - 'TAB_PROPERTY_ONE')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('tabs', 'functions', 'get', - 'parameters', 'tabId')) - self.assertEqual(LookupResult(False, None), - difference.Lookup('events', 'onUpdated', 'parameters', - 'updateInfo')) - - def testUpdate(self): - result = APISchemaGraph(API_SCHEMA) - to_add = APISchemaGraph({ - 'tabs': { - 'properties': { - 'TAB_PROPERTY_THREE': { 'description': 'better than two' }, - 'TAB_PROPERTY_FOUR': { 'value': 4 } - }, - 'functions': { - 'get': { - 'name': {}, - 'parameters': { - 'tab': { - 'type': {}, - 'name': {}, - 'description': {}, - 'surprise': {} - } - } - }, - 'getAllInWindow': { - 'parameters': { - 'windowId': { 'type': 'object' } - } - } - } - } - }) - result.Update(to_add, lambda _: 'first') - # Looking up elements that were originally available in |result|. Because - # of this, no |annotation| object should be attached to the LookupResult - # object. - self.assertEqual(LookupResult(True, None), - result.Lookup('tabs')) - self.assertEqual(LookupResult(True, None), - result.Lookup('tabs', 'functions', 'get', - 'parameters')) - self.assertEqual(LookupResult(True, None), - result.Lookup('tabs', 'properties', - 'TAB_PROPERTY_ONE')) - self.assertEqual(LookupResult(True, None), - result.Lookup('tabs', 'properties', - 'TAB_PROPERTY_ONE')) - self.assertEqual(LookupResult(True, None), - result.Lookup('tabs', 'functions', 'get', - 'parameters', 'tabId')) - - # Looking up elements that were just added to |result|. - self.assertEqual(LookupResult(True, 'first'), - result.Lookup('tabs', 'properties', - 'TAB_PROPERTY_THREE')) - self.assertEqual(LookupResult(True, 'first'), - result.Lookup('tabs', 'properties', - 'TAB_PROPERTY_FOUR')) - self.assertEqual(LookupResult(True, 'first'), - result.Lookup('tabs', 'functions', 'getAllInWindow', - 'parameters', 'windowId')) - self.assertEqual(LookupResult(True, 'first'), - result.Lookup('tabs', 'functions', 'get', 'parameters', - 'tab', 'surprise')) - - to_add = APISchemaGraph({ - 'tabs': { - 'properties': { - 'TAB_PROPERTY_FIVE': { 'description': 'stayin\' alive' } - }, - 'functions': { - 'getAllInWindow': { - 'parameters': { - 'callback': { 'type': 'function' } - } - } - } - } - }) - result.Update(to_add, lambda _: 'second') - # Looking up the second group of elements added to |result|. - self.assertEqual(LookupResult(True, 'first'), - result.Lookup('tabs', 'properties', - 'TAB_PROPERTY_FOUR')) - self.assertEqual(LookupResult(True, 'second'), - result.Lookup('tabs', 'properties', - 'TAB_PROPERTY_FIVE')) - self.assertEqual(LookupResult(True, 'first'), - result.Lookup('tabs', 'functions', - 'getAllInWindow', 'parameters', - 'windowId')) - self.assertEqual(LookupResult(True, 'second'), - result.Lookup('tabs', 'functions', - 'getAllInWindow', 'parameters', - 'callback')) - self.assertEqual(LookupResult(True, 'first'), - result.Lookup('tabs', 'functions', - 'getAllInWindow')) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml deleted file mode 100644 index bfb80b7c..0000000 --- a/chrome/common/extensions/docs/server2/app.yaml +++ /dev/null
@@ -1,22 +0,0 @@ -application: chrome-apps-doc -version: 3-72-0 -runtime: python27 -api_version: 1 -threadsafe: false - -handlers: -- url: /robots\.txt - static_files: robots.txt - upload: robots.txt -- url: /favicon\.ico - static_files: chrome-32.ico - upload: chrome-32.ico -- url: /apple-touch-icon-precomposed\.png - static_files: chrome-128.png - upload: chrome-128.png -- url: /_flush_memcache/.* - script: appengine_main.py - secure: always -- url: /.* - script: appengine_main.py - secure: always
diff --git a/chrome/common/extensions/docs/server2/app_engine_handler.py b/chrome/common/extensions/docs/server2/app_engine_handler.py deleted file mode 100644 index 14bcdf3b..0000000 --- a/chrome/common/extensions/docs/server2/app_engine_handler.py +++ /dev/null
@@ -1,56 +0,0 @@ -# Copyright 2013 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 logging -import webapp2 - -from handler import Handler -from servlet import Request - - -class AppEngineHandler(webapp2.RequestHandler): - '''Top-level handler for AppEngine requests. Just converts them into our - internal Servlet architecture. - ''' - - def post(self): - self._HandleRequest() - - def get(self): - self._HandleRequest() - - def _HandleRequest(self): - profile_mode = self.request.get('profile') - if profile_mode: - import cProfile, pstats, StringIO - pr = cProfile.Profile() - pr.enable() - - try: - response = None - arguments = {} - for argument in self.request.arguments(): - arguments[argument] = self.request.get(argument) - request = Request(self.request.path, - self.request.host, - self.request.headers, - arguments) - response = Handler(request).Get() - except Exception as e: - logging.exception(e) - finally: - if profile_mode: - pr.disable() - s = StringIO.StringIO() - pstats.Stats(pr, stream=s).sort_stats(profile_mode).print_stats() - self.response.out.write(s.getvalue()) - self.response.headers['Content-Type'] = 'text/plain' - self.response.status = 200 - elif response: - self.response.out.write(response.content.ToString()) - self.response.headers.update(response.headers) - self.response.status = response.status - else: - self.response.out.write('Internal server error') - self.response.status = 500
diff --git a/chrome/common/extensions/docs/server2/app_yaml_helper.py b/chrome/common/extensions/docs/server2/app_yaml_helper.py deleted file mode 100644 index d965f96d..0000000 --- a/chrome/common/extensions/docs/server2/app_yaml_helper.py +++ /dev/null
@@ -1,127 +0,0 @@ -# Copyright 2013 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 logging - -from extensions_paths import APP_YAML - - -_APP_YAML_CONTAINER = ''' -application: chrome-apps-doc -version: %s -runtime: python27 -api_version: 1 -threadsafe: false -''' - - -class AppYamlHelper(object): - '''Parses the app.yaml file, and is able to step back in the host file - system's revision history to find when it changed to some given version. - ''' - def __init__(self, - object_store_creator, - host_file_system_provider): - self._store = object_store_creator.Create( - AppYamlHelper, - category=host_file_system_provider.GetMaster().GetIdentity(), - start_empty=False) - self._host_file_system_provider = host_file_system_provider - - @staticmethod - def ExtractVersion(app_yaml, key='version'): - '''Extracts the 'version' key from the contents of an app.yaml file. - Allow overriding the key to parse e.g. the cron file ('target'). - ''' - # We could properly parse this using a yaml library but Python doesn't have - # one built in so whatevs. - key_colon = '%s:' % key - versions = [line.strip()[len(key_colon):].strip() - for line in app_yaml.split('\n') - if line.strip().startswith(key_colon)] - if not versions: - raise ValueError('No versions found for %s in %s' % ( - key, app_yaml)) - if len(set(versions)) > 1: - raise ValueError('Inconsistent versions found for %s in %s: %s' % ( - key, app_yaml, versions)) - return versions[0] - - @staticmethod - def IsGreater(lhs, rhs): - '''Return whether the app.yaml version |lhs| > |rhs|. This is tricky - because versions are typically not numbers but rather 2-0-9, 2-0-12, - 2-1-0, etc - and 2-1-0 > 2-0-10 > 2-0-9. - ''' - lhs_parts = lhs.replace('-', '.').split('.') - rhs_parts = rhs.replace('-', '.').split('.') - while lhs_parts and rhs_parts: - lhs_msb = int(lhs_parts.pop(0)) - rhs_msb = int(rhs_parts.pop(0)) - if lhs_msb != rhs_msb: - return lhs_msb > rhs_msb - return len(lhs) > len(rhs) - - @staticmethod - def GenerateAppYaml(version): - '''Probably only useful for tests. - ''' - return _APP_YAML_CONTAINER % version - - def IsUpToDate(self, app_version): - '''Returns True if the |app_version| is up to date with respect to the one - checked into the host file system. - ''' - checked_in_app_version = AppYamlHelper.ExtractVersion( - self._host_file_system_provider.GetMaster().ReadSingle(APP_YAML).Get()) - if app_version == checked_in_app_version: - return True - if AppYamlHelper.IsGreater(app_version, checked_in_app_version): - logging.warning( - 'Server is too new! Checked in %s < currently running %s' % ( - checked_in_app_version, app_version)) - return True - return False - - def GetFirstRevisionGreaterThan(self, app_version): - '''Finds the first revision that the version in app.yaml was greater than - |app_version|. - - WARNING: if there is no such revision (e.g. the app is up to date, or - *oops* the app is even newer) then this will throw a ValueError. Use - IsUpToDate to validate the input before calling this method. - ''' - stored = self._store.Get(app_version).Get() - if stored is None: - stored = self._GetFirstRevisionGreaterThanImpl(app_version) - assert stored is not None - self._store.Set(app_version, stored) - return stored - - def _GetFirstRevisionGreaterThanImpl(self, app_version): - # XXX(ahernandez): Tricky. The 'version' of app.yaml coming from - # GitilesFileSystem is a blob ID. - def get_app_yaml_revision(file_system): - return int(file_system.Stat(APP_YAML).version) - - def has_greater_app_version(file_system): - app_version_in_file_system = AppYamlHelper.ExtractVersion( - file_system.ReadSingle(APP_YAML).Get()) - return AppYamlHelper.IsGreater(app_version_in_file_system, app_version) - - found = None - next_file_system = self._host_file_system_provider.GetMaster() - - while has_greater_app_version(next_file_system): - found = get_app_yaml_revision(next_file_system) - # Back up a revision then find when app.yaml was last updated before then. - if found == 0: - logging.warning('All revisions are greater than %s' % app_version) - return 0 - next_file_system = self._host_file_system_provider.GetMaster( - commit=next_file_system.GetPreviousCommitID().Get()) - - if found is None: - raise ValueError('All revisions are less than %s' % app_version) - return found
diff --git a/chrome/common/extensions/docs/server2/app_yaml_helper_test.py b/chrome/common/extensions/docs/server2/app_yaml_helper_test.py deleted file mode 100755 index 3e51f685..0000000 --- a/chrome/common/extensions/docs/server2/app_yaml_helper_test.py +++ /dev/null
@@ -1,179 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from app_yaml_helper import AppYamlHelper -from extensions_paths import SERVER2 -from host_file_system_provider import HostFileSystemProvider -from mock_file_system import MockFileSystem -from object_store_creator import ObjectStoreCreator -from test_file_system import MoveTo, TestFileSystem -from test_util import DisableLogging - -_ExtractVersion, _IsGreater, _GenerateAppYaml = ( - AppYamlHelper.ExtractVersion, - AppYamlHelper.IsGreater, - AppYamlHelper.GenerateAppYaml) - -class AppYamlHelperTest(unittest.TestCase): - def testExtractVersion(self): - def run_test(version): - self.assertEqual(version, _ExtractVersion(_GenerateAppYaml(version))) - run_test('0') - run_test('0-0') - run_test('0-0-0') - run_test('1') - run_test('1-0') - run_test('1-0-0') - run_test('1-0-1') - run_test('1-1-0') - run_test('1-1-1') - run_test('2-0-9') - run_test('2-0-12') - run_test('2-1') - run_test('2-1-0') - run_test('2-11-0') - run_test('3-1-0') - run_test('3-1-3') - run_test('3-12-0') - - def testIsGreater(self): - def assert_is_greater(lhs, rhs): - self.assertTrue(_IsGreater(lhs, rhs), '%s is not > %s' % (lhs, rhs)) - self.assertFalse(_IsGreater(rhs, lhs), - '%s should not be > %s' % (rhs, lhs)) - assert_is_greater('0-0', '0') - assert_is_greater('0-0-0', '0') - assert_is_greater('0-0-0', '0-0') - assert_is_greater('1', '0') - assert_is_greater('1', '0-0') - assert_is_greater('1', '0-0-0') - assert_is_greater('1-0', '0-0') - assert_is_greater('1-0-0-0', '0-0-0') - assert_is_greater('2-0-12', '2-0-9') - assert_is_greater('2-0-12', '2-0-9-0') - assert_is_greater('2-0-12-0', '2-0-9') - assert_is_greater('2-0-12-0', '2-0-9-0') - assert_is_greater('2-1', '2-0-9') - assert_is_greater('2-1', '2-0-12') - assert_is_greater('2-1-0', '2-0-9') - assert_is_greater('2-1-0', '2-0-12') - assert_is_greater('3-1-0', '2-1') - assert_is_greater('3-1-0', '2-1-0') - assert_is_greater('3-1-0', '2-11-0') - assert_is_greater('3-1-3', '3-1-0') - assert_is_greater('3-12-0', '3-1-0') - assert_is_greater('3-12-0', '3-1-3') - assert_is_greater('3-12-0', '3-1-3-0') - - @DisableLogging('warning') - def testInstanceMethods(self): - test_data = { - 'app.yaml': _GenerateAppYaml('1-0'), - 'app_yaml_helper.py': 'Copyright notice etc' - } - - updates = [] - # Pass a specific file system at head to the HostFileSystemProvider so that - # we know it's always going to be backed by a MockFileSystem. The Provider - # may decide to wrap it in caching etc. - file_system_at_head = MockFileSystem( - TestFileSystem(test_data, relative_to=SERVER2)) - - def apply_update(update): - update = MoveTo(SERVER2, update) - file_system_at_head.Update(update) - updates.append(update) - - def host_file_system_constructor(branch, commit=None): - self.assertEqual('master', branch) - self.assertTrue(commit is not None) - return MockFileSystem.Create( - TestFileSystem(test_data, relative_to=SERVER2), updates[:int(commit)]) - - object_store_creator = ObjectStoreCreator.ForTest() - host_file_system_provider = HostFileSystemProvider( - object_store_creator, - default_master_instance=file_system_at_head, - constructor_for_test=host_file_system_constructor) - helper = AppYamlHelper(object_store_creator, host_file_system_provider) - - def assert_is_up_to_date(version): - self.assertTrue(helper.IsUpToDate(version), - '%s is not up to date' % version) - self.assertRaises(ValueError, - helper.GetFirstRevisionGreaterThan, version) - - self.assertEqual(0, helper.GetFirstRevisionGreaterThan('0-5-0')) - assert_is_up_to_date('1-0-0') - assert_is_up_to_date('1-5-0') - - # Revision 1. - apply_update({ - 'app.yaml': _GenerateAppYaml('1-5-0') - }) - - self.assertEqual(0, helper.GetFirstRevisionGreaterThan('0-5-0')) - self.assertEqual(1, helper.GetFirstRevisionGreaterThan('1-0-0')) - assert_is_up_to_date('1-5-0') - assert_is_up_to_date('2-5-0') - - # Revision 2. - apply_update({ - 'app_yaml_helper.py': 'fixed a bug' - }) - - self.assertEqual(0, helper.GetFirstRevisionGreaterThan('0-5-0')) - self.assertEqual(1, helper.GetFirstRevisionGreaterThan('1-0-0')) - assert_is_up_to_date('1-5-0') - assert_is_up_to_date('2-5-0') - - # Revision 3. - apply_update({ - 'app.yaml': _GenerateAppYaml('1-6-0') - }) - - self.assertEqual(0, helper.GetFirstRevisionGreaterThan('0-5-0')) - self.assertEqual(1, helper.GetFirstRevisionGreaterThan('1-0-0')) - self.assertEqual(3, helper.GetFirstRevisionGreaterThan('1-5-0')) - assert_is_up_to_date('2-5-0') - - # Revision 4. - apply_update({ - 'app.yaml': _GenerateAppYaml('1-8-0') - }) - # Revision 5. - apply_update({ - 'app.yaml': _GenerateAppYaml('2-0-0') - }) - # Revision 6. - apply_update({ - 'app.yaml': _GenerateAppYaml('2-2-0') - }) - # Revision 7. - apply_update({ - 'app.yaml': _GenerateAppYaml('2-4-0') - }) - # Revision 8. - apply_update({ - 'app.yaml': _GenerateAppYaml('2-6-0') - }) - - self.assertEqual(0, helper.GetFirstRevisionGreaterThan('0-5-0')) - self.assertEqual(1, helper.GetFirstRevisionGreaterThan('1-0-0')) - self.assertEqual(3, helper.GetFirstRevisionGreaterThan('1-5-0')) - self.assertEqual(5, helper.GetFirstRevisionGreaterThan('1-8-0')) - self.assertEqual(6, helper.GetFirstRevisionGreaterThan('2-0-0')) - self.assertEqual(6, helper.GetFirstRevisionGreaterThan('2-1-0')) - self.assertEqual(7, helper.GetFirstRevisionGreaterThan('2-2-0')) - self.assertEqual(7, helper.GetFirstRevisionGreaterThan('2-3-0')) - self.assertEqual(8, helper.GetFirstRevisionGreaterThan('2-4-0')) - self.assertEqual(8, helper.GetFirstRevisionGreaterThan('2-5-0')) - assert_is_up_to_date('2-6-0') - assert_is_up_to_date('2-7-0') - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/appengine_blobstore.py b/chrome/common/extensions/docs/server2/appengine_blobstore.py deleted file mode 100644 index 6e35b162..0000000 --- a/chrome/common/extensions/docs/server2/appengine_blobstore.py +++ /dev/null
@@ -1,52 +0,0 @@ -# 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. - -import blob_reference_store as datastore -from blob_reference_store import BlobReferenceStore -from appengine_wrappers import blobstore -from appengine_wrappers import files - -# TODO(kalman): Re-write this class. -# - It uses BlobReader which is a synchronous method. We should be creating -# multiple async fetches, one for each partition, then exposing a Future -# interface which stitches them together. -# - It's very hard to reuse. - -class AppEngineBlobstore(object): - """A wrapper around the blobstore API, which stores the blob keys in - datastore. - """ - def __init__(self): - self._datastore = BlobReferenceStore() - - def Set(self, key, blob, namespace): - """Add a blob to the blobstore. |version| is used as part of the key so - multiple blobs with the same name can be differentiated. - """ - key = namespace + '.' + key - filename = files.blobstore.create() - with files.open(filename, 'a') as f: - f.write(blob) - files.finalize(filename) - blob_key = files.blobstore.get_blob_key(filename) - self._datastore.Set(datastore.BLOB_REFERENCE_BLOBSTORE, key, blob_key) - - def Get(self, key, namespace): - """Get a blob with version |version|. - """ - key = namespace + '.' + key - blob_key = self._datastore.Get(datastore.BLOB_REFERENCE_BLOBSTORE, key) - if blob_key is None: - return None - blob_reader = blobstore.BlobReader(blob_key) - return blob_reader.read() - - def Delete(self, key, namespace): - """Delete the blob with version |version| if it is found. - """ - key = namespace + '.' + key - blob_key = self._datastore.Delete(datastore.BLOB_REFERENCE_BLOBSTORE, key) - if blob_key is None: - return - blob_key.delete()
diff --git a/chrome/common/extensions/docs/server2/appengine_main.py b/chrome/common/extensions/docs/server2/appengine_main.py deleted file mode 100755 index fb9a817..0000000 --- a/chrome/common/extensions/docs/server2/appengine_main.py +++ /dev/null
@@ -1,23 +0,0 @@ -#!/usr/bin/env python -# 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. - -import os -import sys - -# Add the original server location to sys.path so we are able to import -# modules from there. -SERVER_PATH = 'chrome/common/extensions/docs/server2' -if os.path.abspath(SERVER_PATH) not in sys.path: - sys.path.append(os.path.abspath(SERVER_PATH)) - -import webapp2 - -from app_engine_handler import AppEngineHandler - -def main(): - webapp2.WSGIApplication([('/.*', AppEngineHandler)], debug=False).run() - -if __name__ == '__main__': - main()
diff --git a/chrome/common/extensions/docs/server2/appengine_url_fetcher.py b/chrome/common/extensions/docs/server2/appengine_url_fetcher.py deleted file mode 100644 index 8ed0494..0000000 --- a/chrome/common/extensions/docs/server2/appengine_url_fetcher.py +++ /dev/null
@@ -1,77 +0,0 @@ -# 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. - -import base64 -import logging -import posixpath -import time - -from appengine_wrappers import urlfetch -from environment import GetAppVersion -from future import Future - - -_MAX_RETRIES = 5 -_RETRY_DELAY_SECONDS = 30 - - -def _MakeHeaders(username, password, access_token): - headers = { - 'User-Agent': 'Chromium docserver %s' % GetAppVersion(), - 'Cache-Control': 'max-age=0', - } - if username is not None and password is not None: - headers['Authorization'] = 'Basic %s' % base64.b64encode( - '%s:%s' % (username, password)) - if access_token is not None: - headers['Authorization'] = 'OAuth %s' % access_token - return headers - - -class AppEngineUrlFetcher(object): - """A wrapper around the App Engine urlfetch module that allows for easy - async fetches. - """ - def __init__(self, base_path=None): - assert base_path is None or not base_path.endswith('/'), base_path - self._base_path = base_path - self._retries_left = _MAX_RETRIES - - def Fetch(self, url, username=None, password=None, access_token=None): - """Fetches a file synchronously. - """ - return urlfetch.fetch(self._FromBasePath(url), - deadline=20, - headers=_MakeHeaders(username, - password, - access_token)) - - def FetchAsync(self, url, username=None, password=None, access_token=None): - """Fetches a file asynchronously, and returns a Future with the result. - """ - def process_result(result): - if result.status_code == 429: - if self._retries_left == 0: - logging.error('Still throttled. Giving up.') - return result - self._retries_left -= 1 - logging.info('Throttled. Trying again in %s seconds.' % - _RETRY_DELAY_SECONDS) - time.sleep(_RETRY_DELAY_SECONDS) - return self.FetchAsync(url, username, password, access_token).Get() - return result - - rpc = urlfetch.create_rpc(deadline=20) - urlfetch.make_fetch_call(rpc, - self._FromBasePath(url), - headers=_MakeHeaders(username, - password, - access_token)) - return Future(callback=lambda: process_result(rpc.get_result())) - - def _FromBasePath(self, url): - assert not url.startswith('/'), url - if self._base_path is not None: - url = posixpath.join(self._base_path, url) if url else self._base_path - return url
diff --git a/chrome/common/extensions/docs/server2/appengine_wrappers.py b/chrome/common/extensions/docs/server2/appengine_wrappers.py deleted file mode 100644 index f477e53..0000000 --- a/chrome/common/extensions/docs/server2/appengine_wrappers.py +++ /dev/null
@@ -1,60 +0,0 @@ -# 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. - - -# This will attempt to import the actual App Engine modules, and if it fails, -# they will be replaced with fake modules. This is useful during testing. -try: - import google.appengine.api.memcache as memcache -except ImportError: - class _RPC(object): - def __init__(self, result=None): - self.result = result - - def get_result(self): - return self.result - - def wait(self): - pass - - - class InMemoryMemcache(object): - """An in-memory memcache implementation. - """ - def __init__(self): - self._namespaces = {} - - class Client(object): - def set_multi_async(self, mapping, namespace='', time=0): - return _RPC(result=dict( - (k, memcache.set(k, v, namespace=namespace, time=time)) - for k, v in mapping.iteritems())) - - def get_multi_async(self, keys, namespace='', time=0): - return _RPC(result=dict( - (k, memcache.get(k, namespace=namespace, time=time)) for k in keys)) - - def set(self, key, value, namespace='', time=0): - self._GetNamespace(namespace)[key] = value - - def get(self, key, namespace='', time=0): - return self._GetNamespace(namespace).get(key) - - def delete(self, key, namespace=''): - self._GetNamespace(namespace).pop(key, None) - - def delete_multi(self, keys, namespace=''): - for k in keys: - self.delete(k, namespace=namespace) - - def _GetNamespace(self, namespace): - if namespace not in self._namespaces: - self._namespaces[namespace] = {} - return self._namespaces[namespace] - - def flush_all(self): - self._namespaces = {} - return False - - memcache = InMemoryMemcache()
diff --git a/chrome/common/extensions/docs/server2/availability_finder.py b/chrome/common/extensions/docs/server2/availability_finder.py deleted file mode 100644 index 5134023..0000000 --- a/chrome/common/extensions/docs/server2/availability_finder.py +++ /dev/null
@@ -1,470 +0,0 @@ -# Copyright 2013 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 posixpath - -from api_models import GetNodeCategories -from api_schema_graph import APISchemaGraph -from branch_utility import BranchUtility, ChannelInfo -from compiled_file_system import Cache, CompiledFileSystem, SingleFile, Unicode -from extensions_paths import API_PATHS, JSON_TEMPLATES -from features_bundle import FeaturesBundle -from file_system import FileNotFoundError -from schema_processor import SchemaProcessor -from third_party.json_schema_compiler.memoize import memoize -from third_party.json_schema_compiler.model import UnixName - - -_DEVTOOLS_API = 'devtools_api.json' -_EXTENSION_API = 'extension_api.json' -# The version where api_features.json is first available. -_API_FEATURES_MIN_VERSION = 28 -# The version where permission_ and manifest_features.json are available and -# presented in the current format. -_ORIGINAL_FEATURES_MIN_VERSION = 20 -# API schemas are aggregated in extension_api.json up to this version. -_EXTENSION_API_MAX_VERSION = 17 -# The earliest version for which we have SVN data. -_SVN_MIN_VERSION = 5 - - -def _GetChannelFromFeatures(api_name, features): - '''Finds API channel information for |api_name| from |features|. - Returns None if channel information for the API cannot be located. - ''' - feature = features.Get().get(api_name) - channel = feature.get('channel') if feature else None - - # Change "trunk" to "master". Extension features use "trunk" while the - # Docserver uses "master". - return "master" if channel == "trunk" else channel - -def _GetChannelFromAPIFeatures(api_name, features_bundle): - return _GetChannelFromFeatures(api_name, features_bundle.GetAPIFeatures()) - - -def _GetChannelFromManifestFeatures(api_name, features_bundle): - # _manifest_features.json uses unix_style API names. - api_name = UnixName(api_name) - return _GetChannelFromFeatures(api_name, - features_bundle.GetManifestFeatures()) - - -def _GetChannelFromPermissionFeatures(api_name, features_bundle): - return _GetChannelFromFeatures(api_name, - features_bundle.GetPermissionFeatures()) - - -def _GetAPISchemaFilename(api_name, file_system, version): - '''Gets the name of the file which may contain the schema for |api_name| in - |file_system|, or None if the API is not found. Note that this may be the - single _EXTENSION_API file which all APIs share in older versions of Chrome, - in which case it is unknown whether the API actually exists there. - ''' - if version == 'master' or version > _ORIGINAL_FEATURES_MIN_VERSION: - # API schema filenames switch format to unix_hacker_style. - api_name = UnixName(api_name) - - # Devtools API names have 'devtools.' prepended to them. - # The corresponding filenames do not. - if 'devtools_' in api_name: - api_name = api_name.replace('devtools_', '') - - for api_path in API_PATHS: - try: - for base, _, filenames in file_system.Walk(api_path): - for ext in ('json', 'idl'): - filename = '%s.%s' % (api_name, ext) - if filename in filenames: - return posixpath.join(api_path, base, filename) - if _EXTENSION_API in filenames: - return posixpath.join(api_path, base, _EXTENSION_API) - except FileNotFoundError: - continue - return None - - -class AvailabilityInfo(object): - '''Represents availability data for an API. |scheduled| is a version number - specifying when dev and beta APIs will become stable, or None if that data - is unknown. - ''' - def __init__(self, channel_info, scheduled=None): - assert isinstance(channel_info, ChannelInfo) - assert isinstance(scheduled, int) or scheduled is None - self.channel_info = channel_info - self.scheduled = scheduled - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - return not (self == other) - - def __repr__(self): - return '%s%s' % (type(self).__name__, repr(self.__dict__)) - - def __str__(self): - return repr(self) - - -class AvailabilityFinder(object): - '''Generates availability information for APIs by looking at API schemas and - _features files over multiple release versions of Chrome. - ''' - - def __init__(self, - branch_utility, - compiled_fs_factory, - file_system_iterator, - host_file_system, - object_store_creator, - platform, - schema_processor_factory): - self._branch_utility = branch_utility - self._compiled_fs_factory = compiled_fs_factory - self._file_system_iterator = file_system_iterator - self._host_file_system = host_file_system - self._object_store_creator = object_store_creator - def create_object_store(category): - return object_store_creator.Create( - AvailabilityFinder, category='/'.join((platform, category))) - self._top_level_object_store = create_object_store('top_level') - self._node_level_object_store = create_object_store('node_level') - self._json_fs = compiled_fs_factory.ForJson(self._host_file_system) - self._platform = platform - # When processing the API schemas, we retain inlined types in the schema - # so that there are not missing nodes in the APISchemaGraphs when trying - # to lookup availability. - self._schema_processor = schema_processor_factory.Create(True) - - def _GetPredeterminedNodeAvailability(self, node_name): - '''Checks a configuration file for hardcoded (i.e. predetermined) - availability information for an API node. - ''' - node_info = self._json_fs.GetFromFile( - JSON_TEMPLATES + 'api_availabilities.json').Get().get(node_name) - if node_info is None: - return None - - channel_info = None - if node_info['channel'] == 'stable': - channel_info = self._branch_utility.GetStableChannelInfo( - node_info['version']) - else: - channel_info = self._branch_utility.GetChannelInfo(node_info['channel']) - return AvailabilityInfo(channel_info) if channel_info else None - - @memoize - def _CreateAPISchemaFileSystem(self, file_system): - '''Creates a CompiledFileSystem for parsing raw JSON or IDL API schema - data and formatting it so that it can be used to create APISchemaGraphs. - ''' - def process_schema(path, data): - return self._schema_processor.Process(path, data) - return self._compiled_fs_factory.Create( - file_system, - Cache(SingleFile(Unicode(process_schema))), - CompiledFileSystem, - category='api-schema') - - def _GetAPISchema(self, api_name, file_system, version): - '''Searches |file_system| for |api_name|'s API schema data, and processes - and returns it if found. - ''' - api_filename = _GetAPISchemaFilename(api_name, file_system, version) - if api_filename is None: - # No file for the API could be found in the given |file_system|. - return None - - schema_fs = self._CreateAPISchemaFileSystem(file_system) - api_schemas = schema_fs.GetFromFile(api_filename).Get() - matching_schemas = [api for api in api_schemas - if api and api['namespace'] == api_name] - # There should only be a single matching schema per file, or zero in the - # case of no API data being found in _EXTENSION_API. - assert len(matching_schemas) <= 1 - return matching_schemas or None - - def _HasAPISchema(self, api_name, file_system, version): - '''Whether or not an API schema for |api_name| exists in the given - |file_system|. - ''' - filename = _GetAPISchemaFilename(api_name, file_system, version) - if filename is None: - return False - if filename.endswith(_EXTENSION_API) or filename.endswith(_DEVTOOLS_API): - return self._GetAPISchema(api_name, file_system, version) is not None - return True - - def _CheckStableAvailability(self, - api_name, - file_system, - version, - earliest_version=None): - '''Checks for availability of an API, |api_name|, on the stable channel. - Considers several _features.json files, file system existence, and - extension_api.json depending on the given |version|. - |earliest_version| is the version of Chrome at which |api_name| first became - available. It should only be given when checking stable availability for - API nodes, so it can be used as an alternative to the check for filesystem - existence. - ''' - earliest_version = earliest_version or _SVN_MIN_VERSION - if version < earliest_version: - # SVN data isn't available below this version. - return False - features_bundle = self._CreateFeaturesBundle(file_system) - available_channel = None - if version >= _API_FEATURES_MIN_VERSION: - # The _api_features.json file first appears in version 28 and should be - # the most reliable for finding API availability. - available_channel = _GetChannelFromAPIFeatures(api_name, - features_bundle) - if version >= _ORIGINAL_FEATURES_MIN_VERSION: - # The _permission_features.json and _manifest_features.json files are - # present in Chrome 20 and onwards. Use these if no information could be - # found using _api_features.json. - available_channel = ( - available_channel or - _GetChannelFromPermissionFeatures(api_name, features_bundle) or - _GetChannelFromManifestFeatures(api_name, features_bundle)) - if available_channel is not None: - return available_channel == 'stable' - - # |earliest_version| == _SVN_MIN_VERSION implies we're dealing with an API. - # Fall back to a check for file system existence if the API is not - # stable in any of the _features.json files, or if the _features files - # do not exist (version 19 and earlier). - if earliest_version == _SVN_MIN_VERSION: - return self._HasAPISchema(api_name, file_system, version) - # For API nodes, assume it's available if |version| is greater than the - # version the node became available (which it is, because of the first - # check). - return True - - def _CheckChannelAvailability(self, api_name, file_system, channel_info): - '''Searches through the _features files in a given |file_system|, falling - back to checking the file system for API schema existence, to determine - whether or not an API is available on the given channel, |channel_info|. - ''' - features_bundle = self._CreateFeaturesBundle(file_system) - available_channel = ( - _GetChannelFromAPIFeatures(api_name, features_bundle) or - _GetChannelFromPermissionFeatures(api_name, features_bundle) or - _GetChannelFromManifestFeatures(api_name, features_bundle)) - if (available_channel is None and - self._HasAPISchema(api_name, file_system, channel_info.version)): - # If an API is not represented in any of the _features files, but exists - # in the filesystem, then assume it is available in this version. - # The chrome.windows API is an example of this. - available_channel = channel_info.channel - # If the channel we're checking is the same as or newer than the - # |available_channel| then the API is available at this channel. - newest = BranchUtility.NewestChannel((available_channel, - channel_info.channel)) - return available_channel is not None and newest == channel_info.channel - - def _CheckChannelAvailabilityForNode(self, - node_name, - file_system, - channel_info, - earliest_channel_info): - '''Searches through the _features files in a given |file_system| to - determine whether or not an API node is available on the given channel, - |channel_info|. |earliest_channel_info| is the earliest channel the node - was introduced. - ''' - features_bundle = self._CreateFeaturesBundle(file_system) - available_channel = None - # Only API nodes can have their availability overriden on a per-node basis, - # so we only need to check _api_features.json. - if channel_info.version >= _API_FEATURES_MIN_VERSION: - available_channel = _GetChannelFromAPIFeatures(node_name, features_bundle) - if (available_channel is None and - channel_info.version >= earliest_channel_info.version): - # Most API nodes inherit their availabiltity from their parent, so don't - # explicitly appear in _api_features.json. For example, "tabs.create" - # isn't listed; it inherits from "tabs". Assume these are available at - # |channel_info|. - available_channel = channel_info.channel - newest = BranchUtility.NewestChannel((available_channel, - channel_info.channel)) - return available_channel is not None and newest == channel_info.channel - - @memoize - def _CreateFeaturesBundle(self, file_system): - return FeaturesBundle(file_system, - self._compiled_fs_factory, - self._object_store_creator, - self._platform) - - def _CheckAPIAvailability(self, api_name, file_system, channel_info): - '''Determines the availability for an API at a certain version of Chrome. - Two branches of logic are used depending on whether or not the API is - determined to be 'stable' at the given version. - ''' - if channel_info.channel == 'stable': - return self._CheckStableAvailability(api_name, - file_system, - channel_info.version) - return self._CheckChannelAvailability(api_name, - file_system, - channel_info) - - def _FindScheduled(self, api_name, earliest_version=None): - '''Determines the earliest version of Chrome where the API is stable. - Unlike the code in GetAPIAvailability, this checks if the API is stable - even when Chrome is in dev or beta, which shows that the API is scheduled - to be stable in that verison of Chrome. |earliest_version| is the version - |api_name| became first available. Only use it when finding scheduled - availability for nodes. - ''' - def check_scheduled(file_system, channel_info): - return self._CheckStableAvailability(api_name, - file_system, - channel_info.version, - earliest_version=earliest_version) - - stable_channel = self._file_system_iterator.Descending( - self._branch_utility.GetChannelInfo('dev'), check_scheduled) - - return stable_channel.version if stable_channel else None - - def _CheckAPINodeAvailability(self, node_name, earliest_channel_info): - '''Gets availability data for a node by checking _features files. - ''' - # Check for predetermined availability and cache this information if found. - availability = self._GetPredeterminedNodeAvailability(node_name) - if availability is not None: - self._top_level_object_store.Set(node_name, availability) - return availability - - def check_node_availability(file_system, channel_info): - return self._CheckChannelAvailabilityForNode(node_name, - file_system, - channel_info, - earliest_channel_info) - channel_info = (self._file_system_iterator.Descending( - self._branch_utility.GetChannelInfo('dev'), check_node_availability) or - earliest_channel_info) - - if channel_info.channel == 'stable': - scheduled = None - else: - scheduled = self._FindScheduled( - node_name, - earliest_version=earliest_channel_info.version) - - return AvailabilityInfo(channel_info, scheduled=scheduled) - - def GetAPIAvailability(self, api_name): - '''Performs a search for an API's top-level availability by using a - HostFileSystemIterator instance to traverse multiple version of the - SVN filesystem. - ''' - availability = self._top_level_object_store.Get(api_name).Get() - if availability is not None: - return availability - - # Check for predetermined availability and cache this information if found. - availability = self._GetPredeterminedNodeAvailability(api_name) - if availability is not None: - self._top_level_object_store.Set(api_name, availability) - return availability - - def check_api_availability(file_system, channel_info): - return self._CheckAPIAvailability(api_name, file_system, channel_info) - - channel_info = self._file_system_iterator.Descending( - self._branch_utility.GetChannelInfo('dev'), - check_api_availability) - if channel_info is None: - # The API wasn't available on 'dev', so it must be a 'master'-only API. - channel_info = self._branch_utility.GetChannelInfo('master') - - # If the API is not stable, check when it will be scheduled to be stable. - if channel_info.channel == 'stable': - scheduled = None - else: - scheduled = self._FindScheduled(api_name) - - availability = AvailabilityInfo(channel_info, scheduled=scheduled) - - self._top_level_object_store.Set(api_name, availability) - return availability - - def GetAPINodeAvailability(self, api_name): - '''Returns an APISchemaGraph annotated with each node's availability (the - ChannelInfo at the oldest channel it's available in). - ''' - availability_graph = self._node_level_object_store.Get(api_name).Get() - if availability_graph is not None: - return availability_graph - - def assert_not_none(value): - assert value is not None - return value - - availability_graph = APISchemaGraph() - host_fs = self._host_file_system - master_stat = assert_not_none(host_fs.Stat(_GetAPISchemaFilename( - api_name, host_fs, 'master'))) - - # Weird object thing here because nonlocal is Python 3. - previous = type('previous', (object,), {'stat': None, 'graph': None}) - - def update_availability_graph(file_system, channel_info): - # If we can't find a filename, skip checking at this branch. - # For example, something could have a predetermined availability of 23, - # but it doesn't show up in the file system until 26. - # We know that the file will become available at some point. - # - # The problem with this is that at the first version where the API file - # exists, we'll get a huge chunk of new objects that don't match - # the predetermined API availability. - version_filename = _GetAPISchemaFilename(api_name, - file_system, - channel_info.version) - if version_filename is None: - # Continue the loop at the next version. - return True - - version_stat = assert_not_none(file_system.Stat(version_filename)) - - # Important optimisation: only re-parse the graph if the file changed in - # the last revision. Parsing the same schema and forming a graph on every - # iteration is really expensive. - if version_stat == previous.stat: - version_graph = previous.graph - else: - # Keep track of any new schema elements from this version by adding - # them to |availability_graph|. - # - # Calling |availability_graph|.Lookup() on the nodes being updated - # will return the |annotation| object -- the current |channel_info|. - version_graph = APISchemaGraph( - api_schema=self._GetAPISchema(api_name, - file_system, - channel_info.version)) - def annotator(node_name): - return self._CheckAPINodeAvailability('%s.%s' % (api_name, node_name), - channel_info) - - availability_graph.Update(version_graph.Subtract(availability_graph), - annotator) - - previous.stat = version_stat - previous.graph = version_graph - - # Continue looping until there are no longer differences between this - # version and master. - return version_stat != master_stat - - self._file_system_iterator.Ascending( - self.GetAPIAvailability(api_name).channel_info, - update_availability_graph) - - self._node_level_object_store.Set(api_name, availability_graph) - return availability_graph
diff --git a/chrome/common/extensions/docs/server2/availability_finder_test.py b/chrome/common/extensions/docs/server2/availability_finder_test.py deleted file mode 100755 index a1ec96a..0000000 --- a/chrome/common/extensions/docs/server2/availability_finder_test.py +++ /dev/null
@@ -1,307 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -import os -import sys -import unittest - -import api_schema_graph -from availability_finder import AvailabilityFinder, AvailabilityInfo -from branch_utility import BranchUtility, ChannelInfo -from compiled_file_system import CompiledFileSystem -from fake_host_file_system_provider import FakeHostFileSystemProvider -from fake_url_fetcher import FakeUrlFetcher -from host_file_system_iterator import HostFileSystemIterator -from mock_function import MockFunction -from object_store_creator import ObjectStoreCreator -from platform_util import GetPlatforms -from test_data.canned_data import (CANNED_API_FILE_SYSTEM_DATA, CANNED_BRANCHES) -from test_data.object_level_availability.tabs import TABS_SCHEMA_BRANCHES -from test_util import Server2Path -from schema_processor import SchemaProcessorFactoryForTest - - -TABS_UNMODIFIED_VERSIONS = (16, 20, 23, 24) - -class AvailabilityFinderTest(unittest.TestCase): - - def _create_availability_finder(self, - host_fs_creator, - host_fs_iterator, - platform): - test_object_store = ObjectStoreCreator.ForTest() - return AvailabilityFinder( - self._branch_utility, - CompiledFileSystem.Factory(test_object_store), - host_fs_iterator, - host_fs_creator.GetMaster(), - test_object_store, - platform, - SchemaProcessorFactoryForTest()) - - def setUp(self): - self._branch_utility = BranchUtility( - os.path.join('branch_utility', 'first.json'), - os.path.join('branch_utility', 'second.json'), - FakeUrlFetcher(Server2Path('test_data')), - ObjectStoreCreator.ForTest()) - self._api_fs_creator = FakeHostFileSystemProvider( - CANNED_API_FILE_SYSTEM_DATA) - self._node_fs_creator = FakeHostFileSystemProvider(TABS_SCHEMA_BRANCHES) - self._api_fs_iterator = HostFileSystemIterator(self._api_fs_creator, - self._branch_utility) - self._node_fs_iterator = HostFileSystemIterator(self._node_fs_creator, - self._branch_utility) - - # Imitate the actual SVN file system by incrementing the stats for paths - # where an API schema has changed. - last_stat = type('last_stat', (object,), {'val': 0}) - - def stat_paths(file_system, channel_info): - if channel_info.version not in TABS_UNMODIFIED_VERSIONS: - last_stat.val += 1 - # HACK: |file_system| is a MockFileSystem backed by a TestFileSystem. - # Increment the TestFileSystem stat count. - file_system._file_system.IncrementStat(by=last_stat.val) - # Continue looping. The iterator will stop after 'master' automatically. - return True - - # Use the HostFileSystemIterator created above to change global stat values - # for the TestFileSystems that it creates. - self._node_fs_iterator.Ascending( - # The earliest version represented with the tabs' test data is 13. - self._branch_utility.GetStableChannelInfo(13), - stat_paths) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGraphOptimization(self): - for platform in GetPlatforms(): - # Keep track of how many times the APISchemaGraph constructor is called. - original_constructor = api_schema_graph.APISchemaGraph - mock_constructor = MockFunction(original_constructor) - api_schema_graph.APISchemaGraph = mock_constructor - - node_avail_finder = self._create_availability_finder( - self._node_fs_creator, self._node_fs_iterator, platform) - try: - # The test data includes an extra branch where the API does not exist. - num_versions = len(TABS_SCHEMA_BRANCHES) - 1 - # We expect an APISchemaGraph to be created only when an API schema file - # has different stat data from the previous version's schema file. - num_graphs_created = num_versions - len(TABS_UNMODIFIED_VERSIONS) - - # Run the logic for object-level availability for an API. - node_avail_finder.GetAPINodeAvailability('tabs') - - self.assertTrue(*api_schema_graph.APISchemaGraph.CheckAndReset( - num_graphs_created)) - finally: - # Ensure that the APISchemaGraph constructor is reset to be the original - # constructor. - api_schema_graph.APISchemaGraph = original_constructor - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetAPIAvailability(self): - # Key: Using 'channel' (i.e. 'beta') to represent an availability listing - # for an API in a _features.json file, and using |channel| (i.e. |dev|) to - # represent the development channel, or phase of development, where an API's - # availability is being checked. - - def assertGet(ch_info, api, only_on=None, scheduled=None): - for platform in GetPlatforms(): - get_availability = self._create_availability_finder( - self._api_fs_creator, - self._api_fs_iterator, - platform if only_on is None else only_on).GetAPIAvailability - self.assertEqual(AvailabilityInfo(ch_info, scheduled=scheduled), - get_availability(api)) - - # Testing APIs with predetermined availability. - assertGet(ChannelInfo('master', 'master', 'master'), 'jsonMasterAPI') - assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'jsonDevAPI') - assertGet(ChannelInfo('beta', CANNED_BRANCHES[30], 30), 'jsonBetaAPI') - assertGet(ChannelInfo('stable', CANNED_BRANCHES[20], 20), 'jsonStableAPI') - - # Testing a whitelisted API. - assertGet(ChannelInfo('beta', CANNED_BRANCHES[30], 30), - 'declarativeWebRequest') - - # Testing APIs found only by checking file system existence. - assertGet(ChannelInfo('stable', CANNED_BRANCHES[23], 23), 'windows') - assertGet(ChannelInfo('stable', CANNED_BRANCHES[18], 18), 'tabs') - assertGet(ChannelInfo('stable', CANNED_BRANCHES[18], 18), 'input.ime') - - # Testing API channel existence for _api_features.json. - # Listed as 'dev' on |beta|, 'dev' on |dev|. - assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'systemInfo.stuff') - # Listed as 'stable' on |beta|. - assertGet(ChannelInfo('beta', CANNED_BRANCHES[30], 30), - 'systemInfo.cpu', - scheduled=31) - - # Testing API channel existence for _manifest_features.json. - # Listed as 'master' on all channels. - assertGet(ChannelInfo('master', 'master', 'master'), 'sync') - # Listed as 'trunk'. See crbug.com/883009. - assertGet(ChannelInfo('master', 'master', 'master'), - 'declarativeNetRequest') - # No records of API until |master|. - assertGet(ChannelInfo('master', 'master', 'master'), 'history') - # Listed as 'dev' on |dev|. - assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'storage') - # Stable in _manifest_features and into pre-18 versions. - assertGet(ChannelInfo('stable', CANNED_BRANCHES[8], 8), 'pageAction') - - # Testing API channel existence for _permission_features.json. - # Listed as 'beta' on |master|. - assertGet(ChannelInfo('master', 'master', 'master'), 'falseBetaAPI') - # Listed as 'master' on |master|. - assertGet(ChannelInfo('master', 'master', 'master'), 'masterAPI') - # Listed as 'master' on all development channels. - assertGet(ChannelInfo('master', 'master', 'master'), 'declarativeContent') - # Listed as 'dev' on all development channels. - assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'bluetooth') - # Listed as 'dev' on |dev|. - assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'cookies') - # Treated as 'stable' APIs. - assertGet(ChannelInfo('stable', CANNED_BRANCHES[24], 24), 'alarms') - assertGet(ChannelInfo('stable', CANNED_BRANCHES[21], 21), 'bookmarks') - - # Testing older API existence using extension_api.json. - assertGet(ChannelInfo('stable', CANNED_BRANCHES[6], 6), 'menus') - assertGet(ChannelInfo('stable', CANNED_BRANCHES[5], 5), 'idle') - - # Switches between _features.json files across branches. - # Listed as 'master' on all channels, in _api, _permission, or _manifest. - assertGet(ChannelInfo('master', 'master', 'master'), 'contextMenus') - # Moves between _permission and _manifest as file system is traversed. - assertGet(ChannelInfo('stable', CANNED_BRANCHES[23], 23), - 'systemInfo.display') - assertGet(ChannelInfo('stable', CANNED_BRANCHES[17], 17), 'webRequest') - - # Mid-upgrade cases: - # Listed as 'dev' on |beta| and 'beta' on |dev|. - assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'notifications') - # Listed as 'beta' on |stable|, 'dev' on |beta|...until |stable| on master. - assertGet(ChannelInfo('master', 'master', 'master'), 'events') - - # Check for differing availability across apps|extensions - assertGet(ChannelInfo('stable', CANNED_BRANCHES[26], 26), - 'appsFirst', - only_on='extensions') - assertGet(ChannelInfo('stable', CANNED_BRANCHES[25], 25), - 'appsFirst', - only_on='apps') - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetAPINodeAvailability(self): - def assertEquals(found, channel_info, actual, scheduled=None): - lookup_result = api_schema_graph.LookupResult - if channel_info is None: - self.assertEquals(lookup_result(found, None), actual) - else: - self.assertEquals(lookup_result(found, AvailabilityInfo(channel_info, - scheduled=scheduled)), actual) - - for platform in GetPlatforms(): - # Allow the LookupResult constructions below to take just one line. - avail_finder = self._create_availability_finder( - self._node_fs_creator, - self._node_fs_iterator, - platform) - tabs_graph = avail_finder.GetAPINodeAvailability('tabs') - fake_tabs_graph = avail_finder.GetAPINodeAvailability('fakeTabs') - - # Test an API node with predetermined availability. - assertEquals(True, self._branch_utility.GetStableChannelInfo(27), - tabs_graph.Lookup('tabs', 'properties', 'fakeTabsProperty4')) - - assertEquals(True, self._branch_utility.GetChannelInfo('master'), - tabs_graph.Lookup('tabs', 'properties', 'fakeTabsProperty3')) - assertEquals(True, self._branch_utility.GetChannelInfo('dev'), - tabs_graph.Lookup('tabs', 'events', 'onActivated', 'parameters', - 'activeInfo', 'properties', 'windowId'), scheduled=31) - assertEquals(True, self._branch_utility.GetChannelInfo('dev'), - tabs_graph.Lookup('tabs', 'events', 'onUpdated', 'parameters', 'tab'), - scheduled=31) - assertEquals(True, self._branch_utility.GetChannelInfo('beta'), - tabs_graph.Lookup('tabs', 'events', 'onActivated'), scheduled=30) - assertEquals(True, self._branch_utility.GetChannelInfo('beta'), - tabs_graph.Lookup('tabs', 'functions', 'get', 'parameters', 'tabId'), - scheduled=30) - assertEquals(True, self._branch_utility.GetChannelInfo('stable'), - tabs_graph.Lookup('tabs', 'types', 'InjectDetails', 'properties', - 'code')) - assertEquals(True, self._branch_utility.GetChannelInfo('stable'), - tabs_graph.Lookup('tabs', 'types', 'InjectDetails', 'properties', - 'file')) - assertEquals(True, self._branch_utility.GetStableChannelInfo(25), - tabs_graph.Lookup('tabs', 'types', 'InjectDetails')) - - # Test inlined type. - assertEquals(True, self._branch_utility.GetChannelInfo('master'), - tabs_graph.Lookup('tabs', 'types', 'InlinedType')) - - # Test implicitly inlined type. - assertEquals(True, self._branch_utility.GetStableChannelInfo(25), - fake_tabs_graph.Lookup('fakeTabs', 'types', - 'WasImplicitlyInlinedType')) - - # Test a node that was restricted to dev channel when it was introduced. - assertEquals(True, self._branch_utility.GetChannelInfo('beta'), - tabs_graph.Lookup('tabs', 'functions', 'restrictedFunc'), - scheduled=30) - - # Test an explicitly scheduled node. - assertEquals(True, self._branch_utility.GetChannelInfo('dev'), - tabs_graph.Lookup('tabs', 'functions', 'scheduledFunc'), - scheduled=31) - - # Nothing new in version 24 or 23. - - assertEquals(True, self._branch_utility.GetStableChannelInfo(22), - tabs_graph.Lookup('tabs', 'types', 'Tab', 'properties', 'windowId')) - assertEquals(True, self._branch_utility.GetStableChannelInfo(21), - tabs_graph.Lookup('tabs', 'types', 'Tab', 'properties', 'selected')) - - # Nothing new in version 20. - - assertEquals(True, self._branch_utility.GetStableChannelInfo(19), - tabs_graph.Lookup('tabs', 'functions', 'getCurrent')) - assertEquals(True, self._branch_utility.GetStableChannelInfo(18), - tabs_graph.Lookup('tabs', 'types', 'Tab', 'properties', 'index')) - assertEquals(True, self._branch_utility.GetStableChannelInfo(17), - tabs_graph.Lookup('tabs', 'events', 'onUpdated', 'parameters', - 'changeInfo')) - - # Nothing new in version 16. - - assertEquals(True, self._branch_utility.GetStableChannelInfo(15), - tabs_graph.Lookup('tabs', 'properties', 'fakeTabsProperty2')) - - # Everything else is available at the API's release, version 14 here. - assertEquals(True, self._branch_utility.GetStableChannelInfo(14), - tabs_graph.Lookup('tabs', 'types', 'Tab')) - assertEquals(True, self._branch_utility.GetStableChannelInfo(14), - tabs_graph.Lookup('tabs', 'types', 'Tab', 'properties', 'url')) - assertEquals(True, self._branch_utility.GetStableChannelInfo(14), - tabs_graph.Lookup('tabs', 'properties', 'fakeTabsProperty1')) - assertEquals(True, self._branch_utility.GetStableChannelInfo(14), - tabs_graph.Lookup('tabs', 'functions', 'get', 'parameters', - 'callback')) - assertEquals(True, self._branch_utility.GetStableChannelInfo(14), - tabs_graph.Lookup('tabs', 'events', 'onUpdated')) - - # Test things that aren't available. - assertEquals(False, None, tabs_graph.Lookup('tabs', 'types', - 'UpdateInfo')) - assertEquals(False, None, tabs_graph.Lookup('tabs', 'functions', 'get', - 'parameters', 'callback', 'parameters', 'tab', 'id')) - assertEquals(False, None, tabs_graph.Lookup('functions')) - assertEquals(False, None, tabs_graph.Lookup('events', 'onActivated', - 'parameters', 'activeInfo', 'tabId')) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/blob_reference_store.py b/chrome/common/extensions/docs/server2/blob_reference_store.py deleted file mode 100644 index 7edf5ee..0000000 --- a/chrome/common/extensions/docs/server2/blob_reference_store.py +++ /dev/null
@@ -1,38 +0,0 @@ -# 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 appengine_wrappers import db -from appengine_wrappers import BlobReferenceProperty - -BLOB_REFERENCE_BLOBSTORE = 'BlobReferenceBlobstore' - -class _Model(db.Model): - key_ = db.StringProperty() - value = BlobReferenceProperty() - -class BlobReferenceStore(object): - """A wrapper around the datastore API that can store blob keys. - """ - def _Query(self, namespace, key): - return _Model.gql('WHERE key_ = :1', self._MakeKey(namespace, key)).get() - - def _MakeKey(self, namespace, key): - return '.'.join((namespace, key)) - - def Set(self, namespace, key, value): - _Model(key_=self._MakeKey(namespace, key), value=value).put() - - def Get(self, namespace, key): - result = self._Query(namespace, key) - if not result: - return None - return result.value - - def Delete(self, namespace, key): - result = self._Query(namespace, key) - if not result: - return None - blob_key = result.value - result.delete() - return blob_key
diff --git a/chrome/common/extensions/docs/server2/branch_utility.py b/chrome/common/extensions/docs/server2/branch_utility.py deleted file mode 100644 index a3de42ae..0000000 --- a/chrome/common/extensions/docs/server2/branch_utility.py +++ /dev/null
@@ -1,245 +0,0 @@ -# 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. - -import json -import logging -import operator - -from environment_wrappers import CreateUrlFetcher -import url_constants - - -class ChannelInfo(object): - '''Represents a Chrome channel with three pieces of information. |channel| is - one of 'stable', 'beta', 'dev', or 'master'. |branch| and |version| correspond - with each other, and represent different releases of Chrome. Note that - |branch| and |version| can occasionally be the same for separate channels - (i.e. 'beta' and 'dev'), so all three fields are required to uniquely - identify a channel. - ''' - - def __init__(self, channel, branch, version): - assert isinstance(channel, basestring), channel - assert isinstance(branch, basestring), branch - # TODO(kalman): Assert that this is a string. One day Chromium will probably - # be served out of a git repository and the versions will no longer be ints. - assert isinstance(version, int) or version == 'master', version - self.channel = channel - self.branch = branch - self.version = version - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - return not (self == other) - - def __repr__(self): - return '%s%s' % (type(self).__name__, repr(self.__dict__)) - - def __str__(self): - return repr(self) - - -class BranchUtility(object): - '''Provides methods for working with Chrome channel, branch, and version - data served from OmahaProxy. - ''' - - def __init__(self, fetch_url, history_url, fetcher, object_store_creator): - self._fetcher = fetcher - def create_object_store(category): - return object_store_creator.Create(BranchUtility, category=category) - self._branch_object_store = create_object_store('branch') - self._version_object_store = create_object_store('version') - self._fetch_result = self._fetcher.FetchAsync(fetch_url) - self._history_result = self._fetcher.FetchAsync(history_url) - - @staticmethod - def Create(object_store_creator): - return BranchUtility(url_constants.OMAHA_PROXY_URL, - url_constants.OMAHA_DEV_HISTORY, - CreateUrlFetcher(), - object_store_creator) - - @staticmethod - def GetAllChannelNames(): - return ('stable', 'beta', 'dev', 'master') - - @staticmethod - def NewestChannel(channels): - channels = set(channels) - for channel in reversed(BranchUtility.GetAllChannelNames()): - if channel in channels: - return channel - - def Newer(self, channel_info): - '''Given a ChannelInfo object, returns a new ChannelInfo object - representing the next most recent Chrome version/branch combination. - ''' - if channel_info.channel == 'master': - return None - if channel_info.channel == 'stable': - stable_info = self.GetChannelInfo('stable') - if channel_info.version < stable_info.version: - return self.GetStableChannelInfo(channel_info.version + 1) - names = self.GetAllChannelNames() - return self.GetAllChannelInfo()[names.index(channel_info.channel) + 1] - - def Older(self, channel_info): - '''Given a ChannelInfo object, returns a new ChannelInfo object - representing the previous Chrome version/branch combination. - ''' - if channel_info.channel == 'stable': - return self.GetStableChannelInfo(channel_info.version - 1) - names = self.GetAllChannelNames() - return self.GetAllChannelInfo()[names.index(channel_info.channel) - 1] - - @staticmethod - def SplitChannelNameFromPath(path): - '''Splits the channel name out of |path|, returning the tuple - (channel_name, real_path). If the channel cannot be determined then returns - (None, path). - ''' - if '/' in path: - first, second = path.split('/', 1) - else: - first, second = (path, '') - if first in BranchUtility.GetAllChannelNames(): - return (first, second) - return (None, path) - - def GetAllBranches(self): - return tuple((channel, self.GetChannelInfo(channel).branch) - for channel in BranchUtility.GetAllChannelNames()) - - def GetAllVersions(self): - return tuple(self.GetChannelInfo(channel).version - for channel in BranchUtility.GetAllChannelNames()) - - def GetAllChannelInfo(self): - return tuple(self.GetChannelInfo(channel) - for channel in BranchUtility.GetAllChannelNames()) - - - def GetChannelInfo(self, channel): - version = self._ExtractFromVersionJson(channel, 'version') - if version != 'master': - version = int(version) - return ChannelInfo(channel, - self._ExtractFromVersionJson(channel, 'branch'), - version) - - def GetStableChannelInfo(self, version): - '''Given a |version| corresponding to a 'stable' version of Chrome, returns - a ChannelInfo object representing that version. - ''' - branch = self.GetBranchForVersion(version) - if branch is None: - return None - return ChannelInfo('stable', branch, version) - - def _ExtractFromVersionJson(self, channel_name, data_type): - '''Returns the branch or version number for a channel name. - ''' - if channel_name == 'master': - return 'master' - - if data_type == 'branch': - object_store = self._branch_object_store - elif data_type == 'version': - object_store = self._version_object_store - - data = object_store.Get(channel_name).Get() - if data is not None: - return data - - try: - version_json = json.loads(self._fetch_result.Get().content) - except Exception as e: - # This can happen if omahaproxy is misbehaving, which we've seen before. - # Quick hack fix: just serve from master until it's fixed. - logging.error('Failed to fetch or parse branch from omahaproxy: %s! ' - 'Falling back to "master".' % e) - return 'master' - - numbers = {} - for entry in version_json: - if entry['os'] not in ('win', 'linux', 'mac', 'cros'): - continue - for version in entry['versions']: - if version['channel'] != channel_name: - continue - if data_type == 'branch': - number = version['version'].split('.')[2] - elif data_type == 'version': - number = version['version'].split('.')[0] - if number not in numbers: - numbers[number] = 0 - else: - numbers[number] += 1 - - sorted_numbers = sorted(numbers.iteritems(), - key=operator.itemgetter(1), - reverse=True) - object_store.Set(channel_name, sorted_numbers[0][0]) - return sorted_numbers[0][0] - - def GetBranchForVersion(self, version): - '''Returns the most recent branch for a given chrome version number using - data stored on omahaproxy (see url_constants). - ''' - if version == 'master': - return 'master' - - branch = self._branch_object_store.Get(str(version)).Get() - if branch is not None: - return branch - - version_json = json.loads(self._history_result.Get().content) - for entry in version_json: - version_title = entry['version'].split('.') - # TODO(devlin): Is there a reason we don't cache all these values now? - if version_title[0] == str(version): - self._branch_object_store.Set(str(version), version_title[2]) - return version_title[2] - - # This can legitimately happen because - # https://omahaproxy.appspot.com/history.json?channel=dev&os=win&json=1 - # (where we get the branch data) has a maximum number of results. The - # assertion is a nasty hack to make sure that we're at least retrieving - # a reasonable number of version. Unfortunately, this is also doomed to - # need updating every five years or so. - # TODO(devlin): Really, this is awful. - assert(version < 40) - return None - - def GetChannelForVersion(self, version): - '''Returns the name of the development channel corresponding to a given - version number. - ''' - for channel_info in self.GetAllChannelInfo(): - if channel_info.channel == 'stable' and version <= channel_info.version: - return channel_info.channel - if version == channel_info.version: - return channel_info.channel - - def GetLatestVersionNumber(self): - '''Returns the most recent version number found using data stored on - omahaproxy. - ''' - latest_version = self._version_object_store.Get('latest').Get() - if latest_version is not None: - return latest_version - - version_json = json.loads(self._history_result.Get().content) - latest_version = 0 - for entry in version_json: - version_title = entry['version'].split('.') - version = int(version_title[0]) - if version > latest_version: - latest_version = version - - self._version_object_store.Set('latest', latest_version) - return latest_version
diff --git a/chrome/common/extensions/docs/server2/branch_utility_test.py b/chrome/common/extensions/docs/server2/branch_utility_test.py deleted file mode 100755 index 8a29403..0000000 --- a/chrome/common/extensions/docs/server2/branch_utility_test.py +++ /dev/null
@@ -1,184 +0,0 @@ -#!/usr/bin/env python -# 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. - -import os -import sys -import unittest - -from branch_utility import BranchUtility, ChannelInfo -from fake_url_fetcher import FakeUrlFetcher -from object_store_creator import ObjectStoreCreator -from test_util import Server2Path - - -class BranchUtilityTest(unittest.TestCase): - - def setUp(self): - self._branch_util = BranchUtility( - os.path.join('branch_utility', 'first.json'), - os.path.join('branch_utility', 'second.json'), - FakeUrlFetcher(Server2Path('test_data')), - ObjectStoreCreator.ForTest()) - - def testSplitChannelNameFromPath(self): - self.assertEquals(('stable', 'extensions/stuff.html'), - self._branch_util.SplitChannelNameFromPath( - 'stable/extensions/stuff.html')) - self.assertEquals(('dev', 'extensions/stuff.html'), - self._branch_util.SplitChannelNameFromPath( - 'dev/extensions/stuff.html')) - self.assertEquals(('beta', 'extensions/stuff.html'), - self._branch_util.SplitChannelNameFromPath( - 'beta/extensions/stuff.html')) - self.assertEquals(('master', 'extensions/stuff.html'), - self._branch_util.SplitChannelNameFromPath( - 'master/extensions/stuff.html')) - self.assertEquals((None, 'extensions/stuff.html'), - self._branch_util.SplitChannelNameFromPath( - 'extensions/stuff.html')) - self.assertEquals((None, 'apps/stuff.html'), - self._branch_util.SplitChannelNameFromPath( - 'apps/stuff.html')) - self.assertEquals((None, 'extensions/dev/stuff.html'), - self._branch_util.SplitChannelNameFromPath( - 'extensions/dev/stuff.html')) - self.assertEquals((None, 'stuff.html'), - self._branch_util.SplitChannelNameFromPath( - 'stuff.html')) - - def testNewestChannel(self): - self.assertEquals('master', - self._branch_util.NewestChannel(('master', 'dev', 'beta', 'stable'))) - self.assertEquals('master', - self._branch_util.NewestChannel(('stable', 'beta', 'dev', 'master'))) - self.assertEquals('dev', - self._branch_util.NewestChannel(('stable', 'beta', 'dev'))) - self.assertEquals('dev', - self._branch_util.NewestChannel(('dev', 'beta', 'stable'))) - self.assertEquals('beta', - self._branch_util.NewestChannel(('beta', 'stable'))) - self.assertEquals('beta', - self._branch_util.NewestChannel(('stable', 'beta'))) - self.assertEquals('stable', self._branch_util.NewestChannel(('stable',))) - self.assertEquals('beta', self._branch_util.NewestChannel(('beta',))) - self.assertEquals('dev', self._branch_util.NewestChannel(('dev',))) - self.assertEquals('master', self._branch_util.NewestChannel(('master',))) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testNewer(self): - oldest_stable_info = ChannelInfo('stable', '963', 17) - older_stable_info = ChannelInfo('stable', '1025', 18) - old_stable_info = ChannelInfo('stable', '1084', 19) - sort_of_old_stable_info = ChannelInfo('stable', '1500', 28) - stable_info = ChannelInfo('stable', '1547', 29) - beta_info = ChannelInfo('beta', '1599', 30) - dev_info = ChannelInfo('dev', '1612', 31) - master_info = ChannelInfo('master', 'master', 'master') - - self.assertEquals(older_stable_info, - self._branch_util.Newer(oldest_stable_info)) - self.assertEquals(old_stable_info, - self._branch_util.Newer(older_stable_info)) - self.assertEquals(stable_info, - self._branch_util.Newer(sort_of_old_stable_info)) - self.assertEquals(beta_info, self._branch_util.Newer(stable_info)) - self.assertEquals(dev_info, self._branch_util.Newer(beta_info)) - self.assertEquals(master_info, self._branch_util.Newer(dev_info)) - # Test the upper limit. - self.assertEquals(None, self._branch_util.Newer(master_info)) - - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testOlder(self): - master_info = ChannelInfo('master', 'master', 'master') - dev_info = ChannelInfo('dev', '1612', 31) - beta_info = ChannelInfo('beta', '1599', 30) - stable_info = ChannelInfo('stable', '1547', 29) - old_stable_info = ChannelInfo('stable', '1500', 28) - older_stable_info = ChannelInfo('stable', '1453', 27) - oldest_stable_info = ChannelInfo('stable', '396', 5) - - self.assertEquals(dev_info, self._branch_util.Older(master_info)) - self.assertEquals(beta_info, self._branch_util.Older(dev_info)) - self.assertEquals(stable_info, self._branch_util.Older(beta_info)) - self.assertEquals(old_stable_info, self._branch_util.Older(stable_info)) - self.assertEquals(older_stable_info, - self._branch_util.Older(old_stable_info)) - # Test the lower limit. - self.assertEquals(None, self._branch_util.Older(oldest_stable_info)) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetChannelInfo(self): - master_info = ChannelInfo('master', 'master', 'master') - self.assertEquals(master_info, self._branch_util.GetChannelInfo('master')) - - dev_info = ChannelInfo('dev', '1612', 31) - self.assertEquals(dev_info, self._branch_util.GetChannelInfo('dev')) - - beta_info = ChannelInfo('beta', '1599', 30) - self.assertEquals(beta_info, self._branch_util.GetChannelInfo('beta')) - - stable_info = ChannelInfo('stable', '1547', 29) - self.assertEquals(stable_info, self._branch_util.GetChannelInfo('stable')) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetLatestVersionNumber(self): - self.assertEquals(37, self._branch_util.GetLatestVersionNumber()) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetBranchForVersion(self): - self.assertEquals('1500', - self._branch_util.GetBranchForVersion(28)) - self.assertEquals('1453', - self._branch_util.GetBranchForVersion(27)) - self.assertEquals('1410', - self._branch_util.GetBranchForVersion(26)) - self.assertEquals('1364', - self._branch_util.GetBranchForVersion(25)) - self.assertEquals('1312', - self._branch_util.GetBranchForVersion(24)) - self.assertEquals('1271', - self._branch_util.GetBranchForVersion(23)) - self.assertEquals('1229', - self._branch_util.GetBranchForVersion(22)) - self.assertEquals('1180', - self._branch_util.GetBranchForVersion(21)) - self.assertEquals('1132', - self._branch_util.GetBranchForVersion(20)) - self.assertEquals('1084', - self._branch_util.GetBranchForVersion(19)) - self.assertEquals('1025', - self._branch_util.GetBranchForVersion(18)) - self.assertEquals('963', - self._branch_util.GetBranchForVersion(17)) - self.assertEquals('696', - self._branch_util.GetBranchForVersion(11)) - self.assertEquals('396', - self._branch_util.GetBranchForVersion(5)) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetChannelForVersion(self): - self.assertEquals('master', - self._branch_util.GetChannelForVersion('master')) - self.assertEquals('dev', - self._branch_util.GetChannelForVersion(31)) - self.assertEquals('beta', - self._branch_util.GetChannelForVersion(30)) - self.assertEquals('stable', - self._branch_util.GetChannelForVersion(26)) - self.assertEquals('stable', - self._branch_util.GetChannelForVersion(22)) - self.assertEquals('stable', - self._branch_util.GetChannelForVersion(18)) - self.assertEquals('stable', - self._branch_util.GetChannelForVersion(14)) - self.assertEquals(None, - self._branch_util.GetChannelForVersion(32)) - self.assertEquals(None, - self._branch_util.GetChannelForVersion(42)) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/build_server.py b/chrome/common/extensions/docs/server2/build_server.py deleted file mode 100755 index 86e315e..0000000 --- a/chrome/common/extensions/docs/server2/build_server.py +++ /dev/null
@@ -1,92 +0,0 @@ -#!/usr/bin/env python -# 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. - -# This script is used to copy all dependencies into the local directory. -# The package of files can then be uploaded to App Engine. -import os -import shutil -import stat -import sys - -SRC_DIR = os.path.join(sys.path[0], os.pardir, os.pardir, os.pardir, os.pardir, - os.pardir) -THIRD_PARTY_DIR = os.path.join(SRC_DIR, 'third_party') -LOCAL_THIRD_PARTY_DIR = os.path.join(sys.path[0], 'third_party') -TOOLS_DIR = os.path.join(SRC_DIR, 'tools') -SCHEMA_COMPILER_FILES = ['memoize.py', - 'model.py', - 'idl_schema.py', - 'schema_util.py', - 'json_parse.py', - 'json_schema.py'] - -def MakeInit(path): - path = os.path.join(path, '__init__.py') - with open(os.path.join(path), 'w') as f: - os.utime(os.path.join(path), None) - -def OnError(function, path, excinfo): - os.chmod(path, stat.S_IWUSR) - function(path) - -def CopyThirdParty(src, dest, files=None, make_init=True): - dest_path = os.path.join(LOCAL_THIRD_PARTY_DIR, dest) - if not files: - shutil.copytree(src, dest_path) - if make_init: - MakeInit(dest_path) - return - try: - os.makedirs(dest_path) - except Exception: - pass - if make_init: - MakeInit(dest_path) - for filename in files: - shutil.copy(os.path.join(src, filename), os.path.join(dest_path, filename)) - -def HasLocalThirdPartyDirectory(): - return os.path.isdir(LOCAL_THIRD_PARTY_DIR) - -def main(): - if HasLocalThirdPartyDirectory(): - try: - shutil.rmtree(LOCAL_THIRD_PARTY_DIR, False, OnError) - except OSError: - print('*-------------------------------------------------------------*\n' - '| If you are receiving an upload error, try removing |\n' - '| chrome/common/extensions/docs/server2/third_party manually. |\n' - '*-------------------------------------------------------------*\n') - - - CopyThirdParty(os.path.join(THIRD_PARTY_DIR, 'motemplate'), 'motemplate') - CopyThirdParty(os.path.join(THIRD_PARTY_DIR, 'markdown'), 'markdown', - make_init=False) - CopyThirdParty(os.path.join(SRC_DIR, 'ppapi', 'generators'), - 'json_schema_compiler') - CopyThirdParty(os.path.join(THIRD_PARTY_DIR, 'ply'), - os.path.join('json_schema_compiler', 'ply')) - CopyThirdParty(os.path.join(TOOLS_DIR, 'json_schema_compiler'), - 'json_schema_compiler', - SCHEMA_COMPILER_FILES) - CopyThirdParty(os.path.join(TOOLS_DIR, 'json_comment_eater'), - 'json_schema_compiler', - ['json_comment_eater.py']) - CopyThirdParty(os.path.join(THIRD_PARTY_DIR, 'simplejson'), - os.path.join('json_schema_compiler', 'simplejson'), - make_init=False) - MakeInit(LOCAL_THIRD_PARTY_DIR) - - CopyThirdParty(os.path.join(THIRD_PARTY_DIR, 'google_appengine_cloudstorage', - 'cloudstorage'), 'cloudstorage') - - # To be able to use the Motemplate class we need this import in __init__.py. - with open(os.path.join(LOCAL_THIRD_PARTY_DIR, - 'motemplate', - '__init__.py'), 'a') as f: - f.write('from motemplate import Motemplate\n') - -if __name__ == '__main__': - main()
diff --git a/chrome/common/extensions/docs/server2/cache_chain_object_store.py b/chrome/common/extensions/docs/server2/cache_chain_object_store.py deleted file mode 100644 index 6fba846..0000000 --- a/chrome/common/extensions/docs/server2/cache_chain_object_store.py +++ /dev/null
@@ -1,81 +0,0 @@ -# Copyright 2013 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 future import All, Future -from object_store import ObjectStore - - -class CacheChainObjectStore(ObjectStore): - '''Maintains an in-memory cache along with a chain of other object stores to - try for the same keys. This is useful for implementing a multi-layered cache. - The in-memory cache is inbuilt since it's synchronous, but the object store - interface is asynchronous. - The rules for the object store chain are: - - When setting (or deleting) items, all object stores in the hierarcy will - have that item set. - - When getting items, the behaviour depends on |start_empty|. - - If false, each object store is tried in order. The first object - store to find the item will trickle back up, setting it on all object - stores higher in the hierarchy. - - If true, only the first in-memory cache is checked, as though the store - had been initialized with no content as opposed to the union of its - delegate stores. - ''' - def __init__(self, object_stores, start_empty=False): - self._object_stores = object_stores - self._start_empty = start_empty - self._cache = {} - - def SetMulti(self, mapping): - self._cache.update(mapping) - return All([object_store.SetMulti(mapping) - for object_store in self._object_stores]) - - def GetMulti(self, keys): - missing_keys = list(keys) - cached_items = {} - for key in keys: - if key in self._cache: - cached_items[key] = self._cache.get(key) - missing_keys.remove(key) - if len(missing_keys) == 0 or self._start_empty: - return Future(value=cached_items) - object_store_futures = [(object_store, object_store.GetMulti(missing_keys)) - for object_store in self._object_stores] - def resolve(): - # Approach: - # - # Try each object store in order, until there are no more missing keys. - # Don't realise the Future value of an object store that we don't need to; - # this is important e.g. to avoid querying data store constantly. - # - # When a value is found, cache it in all object stores further up the - # chain, including the object-based cache on CacheChainObjectStore. - object_store_updates = [] - for object_store, object_store_future in object_store_futures: - if len(missing_keys) == 0: - break - result = object_store_future.Get() - for k, v in result.items(): # use items(); changes during iteration - if v is None or k not in missing_keys: - del result[k] - continue - self._cache[k] = v - cached_items[k] = v - missing_keys.remove(k) - for _, updates in object_store_updates: - updates.update(result) - object_store_updates.append((object_store, {})) - # Update the caches of all object stores that need it. - for object_store, updates in object_store_updates: - if updates: - object_store.SetMulti(updates) - return cached_items - return Future(callback=resolve) - - def DelMulti(self, keys): - for k in keys: - self._cache.pop(k, None) - for object_store in self._object_stores: - object_store.DelMulti(keys)
diff --git a/chrome/common/extensions/docs/server2/cache_chain_object_store_test.py b/chrome/common/extensions/docs/server2/cache_chain_object_store_test.py deleted file mode 100755 index 051d5601..0000000 --- a/chrome/common/extensions/docs/server2/cache_chain_object_store_test.py +++ /dev/null
@@ -1,184 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 cache_chain_object_store import CacheChainObjectStore -from test_object_store import TestObjectStore -import unittest - -class CacheChainObjectStoreTest(unittest.TestCase): - def setUp(self): - self._first = TestObjectStore('first', init={ - 'storage.html': 'storage', - }) - self._second = TestObjectStore('second', init={ - 'runtime.html': 'runtime', - 'storage.html': 'storage', - }) - self._third = TestObjectStore('third', init={ - 'commands.html': 'commands', - 'runtime.html': 'runtime', - 'storage.html': 'storage', - }) - self._store = CacheChainObjectStore( - (self._first, self._second, self._third)) - - def testGetFromFirstLayer(self): - self.assertEqual('storage', self._store.Get('storage.html').Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1)) - # Found in first layer, stop. - self.assertTrue(*self._second.CheckAndReset()) - self.assertTrue(*self._third.CheckAndReset()) - # Cached in memory, won't re-query. - self.assertEqual('storage', self._store.Get('storage.html').Get()) - self.assertTrue(*self._first.CheckAndReset()) - self.assertTrue(*self._second.CheckAndReset()) - self.assertTrue(*self._third.CheckAndReset()) - - def testGetFromSecondLayer(self): - self.assertEqual('runtime', self._store.Get('runtime.html').Get()) - # Not found in first layer but found in second. - self.assertTrue(*self._first.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1)) - self.assertTrue(*self._third.CheckAndReset()) - # First will now have it cached. - self.assertEqual('runtime', self._first.Get('runtime.html').Get()) - self._first.Reset() - # Cached in memory, won't re-query. - self.assertEqual('runtime', self._store.Get('runtime.html').Get()) - self.assertTrue(*self._first.CheckAndReset()) - self.assertTrue(*self._second.CheckAndReset()) - self.assertTrue(*self._third.CheckAndReset()) - - def testGetFromThirdLayer(self): - self.assertEqual('commands', self._store.Get('commands.html').Get()) - # As above but for third. - self.assertTrue(*self._first.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._third.CheckAndReset(get_count=1)) - # First and second will now have it cached. - self.assertEqual('commands', self._first.Get('commands.html').Get()) - self.assertEqual('commands', self._second.Get('commands.html').Get()) - self._first.Reset() - self._second.Reset() - # Cached in memory, won't re-query. - self.assertEqual('commands', self._store.Get('commands.html').Get()) - self.assertTrue(*self._first.CheckAndReset()) - self.assertTrue(*self._second.CheckAndReset()) - self.assertTrue(*self._third.CheckAndReset()) - - def testGetFromAllLayers(self): - self.assertEqual({ - 'commands.html': 'commands', - 'runtime.html': 'runtime', - 'storage.html': 'storage', - }, self._store.GetMulti(('commands.html', - 'runtime.html', - 'storage.html')).Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._third.CheckAndReset(get_count=1)) - # First and second will have it all cached. - self.assertEqual('runtime', self._first.Get('runtime.html').Get()) - self.assertEqual('commands', self._first.Get('commands.html').Get()) - self.assertEqual('commands', self._second.Get('commands.html').Get()) - self._first.Reset() - self._second.Reset() - # Cached in memory. - self.assertEqual({ - 'commands.html': 'commands', - 'runtime.html': 'runtime', - 'storage.html': 'storage', - }, self._store.GetMulti(('commands.html', - 'runtime.html', - 'storage.html')).Get()) - self.assertTrue(*self._first.CheckAndReset()) - self.assertTrue(*self._second.CheckAndReset()) - self.assertTrue(*self._third.CheckAndReset()) - - def testPartiallyCachedInMemory(self): - self.assertEqual({ - 'commands.html': 'commands', - 'storage.html': 'storage', - }, self._store.GetMulti(('commands.html', 'storage.html')).Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._third.CheckAndReset(get_count=1)) - # runtime wasn't cached in memory, so stores should still be queried. - self.assertEqual({ - 'commands.html': 'commands', - 'runtime.html': 'runtime', - }, self._store.GetMulti(('commands.html', 'runtime.html')).Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1)) - self.assertTrue(*self._third.CheckAndReset()) - - def testNotFound(self): - self.assertEqual(None, self._store.Get('notfound.html').Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1)) - self.assertTrue(*self._third.CheckAndReset(get_count=1)) - # Not-foundedness shouldn't be cached. - self.assertEqual(None, self._store.Get('notfound.html').Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1)) - self.assertTrue(*self._third.CheckAndReset(get_count=1)) - # Test some things not found, some things found. - self.assertEqual({ - 'runtime.html': 'runtime', - }, self._store.GetMulti(('runtime.html', 'notfound.html')).Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1, set_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1)) - self.assertTrue(*self._third.CheckAndReset(get_count=1)) - - def testSet(self): - self._store.Set('hello.html', 'hello') - self.assertTrue(*self._first.CheckAndReset(set_count=1)) - self.assertTrue(*self._second.CheckAndReset(set_count=1)) - self.assertTrue(*self._third.CheckAndReset(set_count=1)) - # Should have cached it. - self.assertEqual('hello', self._store.Get('hello.html').Get()) - self.assertTrue(*self._first.CheckAndReset()) - self.assertTrue(*self._second.CheckAndReset()) - self.assertTrue(*self._third.CheckAndReset()) - # Should have the new content. - self.assertEqual('hello', self._first.Get('hello.html').Get()) - self.assertEqual('hello', self._second.Get('hello.html').Get()) - self.assertEqual('hello', self._third.Get('hello.html').Get()) - - def testDel(self): - # Cache it. - self.assertEqual('storage', self._store.Get('storage.html').Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1)) - # Delete it. - self._store.Del('storage.html') - self.assertTrue(*self._first.CheckAndReset(del_count=1)) - self.assertTrue(*self._second.CheckAndReset(del_count=1)) - self.assertTrue(*self._third.CheckAndReset(del_count=1)) - # Not cached anymore. - self.assertEqual(None, self._store.Get('storage.html').Get()) - self.assertTrue(*self._first.CheckAndReset(get_count=1)) - self.assertTrue(*self._second.CheckAndReset(get_count=1)) - self.assertTrue(*self._third.CheckAndReset(get_count=1)) - - def testStartEmpty(self): - store = CacheChainObjectStore((self._first, self._second, self._third), - start_empty=True) - # Won't query delegate file systems because it starts empty. - self.assertEqual(None, store.Get('storage.html').Get()) - self.assertTrue(*self._first.CheckAndReset()) - self.assertTrue(*self._second.CheckAndReset()) - self.assertTrue(*self._third.CheckAndReset()) - # Setting values will set on all delegates, though. - store.Set('storage.html', 'new content') - self.assertEqual('new content', store.Get('storage.html').Get()) - self.assertTrue(*self._first.CheckAndReset(set_count=1)) - self.assertTrue(*self._second.CheckAndReset(set_count=1)) - self.assertTrue(*self._third.CheckAndReset(set_count=1)) - self.assertEqual('new content', self._first.Get('storage.html').Get()) - self.assertEqual('new content', self._second.Get('storage.html').Get()) - self.assertEqual('new content', self._third.Get('storage.html').Get()) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/caching_file_system.py b/chrome/common/extensions/docs/server2/caching_file_system.py deleted file mode 100644 index 227739f..0000000 --- a/chrome/common/extensions/docs/server2/caching_file_system.py +++ /dev/null
@@ -1,199 +0,0 @@ -# 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. - -import logging -import posixpath -import sys - -from file_system import FileSystem, StatInfo, FileNotFoundError -from future import All, Future -from path_util import AssertIsDirectory, IsDirectory, ToDirectory -from third_party.json_schema_compiler.memoize import memoize - - -class CachingFileSystem(FileSystem): - '''FileSystem which implements a caching layer on top of |file_system|. If - |fail_on_miss| is True then cache misses throw a FileNotFoundError rather than - falling back onto the underlying FileSystem. - ''' - def __init__(self, file_system, object_store_creator, fail_on_miss=False): - self._file_system = file_system - self._fail_on_miss = fail_on_miss - def create_object_store(category, start_empty=True): - return object_store_creator.Create( - CachingFileSystem, - category='%s/%s' % (file_system.GetIdentity(), category), - start_empty=start_empty) - # We only start the stat cache empty if |fail_on_miss| is False, i.e. if - # we're NOT running on a live instance and we can afford to fall back onto - # the underlying FileSystem impl. - self._stat_cache = create_object_store('stat', start_empty=not fail_on_miss) - self._read_cache = create_object_store('read', start_empty=False) - self._walk_cache = create_object_store('walk', start_empty=False) - - def Refresh(self): - return self._file_system.Refresh() - - def StatAsync(self, path): - '''Stats the directory given, or if a file is given, stats the file's parent - directory to get info about the file. - ''' - # Always stat the parent directory, since it will have the stat of the child - # anyway, and this gives us an entire directory's stat info at once. - dir_path, file_path = posixpath.split(path) - dir_path = ToDirectory(dir_path) - - def make_stat_info(dir_stat): - '''Converts a dir stat into the correct resulting StatInfo; if the Stat - was for a file, the StatInfo should just contain that file. - ''' - if path == dir_path: - return dir_stat - # Was a file stat. Extract that file. - file_version = dir_stat.child_versions.get(file_path) - if file_version is None: - raise FileNotFoundError('No stat found for %s in %s (found %s)' % - (path, dir_path, dir_stat.child_versions)) - return StatInfo(file_version) - - def raise_cache_miss(path): - raise FileNotFoundError('Got cache miss when trying to stat %s' % path) - - dir_stat = self._stat_cache.Get(dir_path).Get() - if dir_stat is not None: - return Future(callback=lambda: make_stat_info(dir_stat)) - - if self._fail_on_miss: - logging.warning('Bailing on stat cache miss for %s on %s' % - (dir_path, self.GetIdentity())) - return Future(callback=lambda: raise_cache_miss(dir_path)) - - def next(dir_stat): - assert dir_stat is not None # should have raised a FileNotFoundError - # We only ever need to cache the dir stat. - self._stat_cache.Set(dir_path, dir_stat) - return make_stat_info(dir_stat) - return self._MemoizedStatAsyncFromFileSystem(dir_path).Then(next) - - @memoize - def _MemoizedStatAsyncFromFileSystem(self, dir_path): - '''This is a simple wrapper to memoize Futures to directory stats, since - StatAsync makes heavy use of it. Only cache directories so that the - memoized cache doesn't blow up. - ''' - assert IsDirectory(dir_path) - return self._file_system.StatAsync(dir_path) - - def Read(self, paths, skip_not_found=False): - '''Reads a list of files. If a file is cached and it is not out of - date, it is returned. Otherwise, the file is retrieved from the file system. - ''' - # Files which aren't found are cached in the read object store as - # (path, None, None). This is to prevent re-reads of files we know - # do not exist. - cached_read_values = self._read_cache.GetMulti(paths).Get() - cached_stat_values = self._stat_cache.GetMulti(paths).Get() - - # Populate a map of paths to Futures to their stat. They may have already - # been cached in which case their Future will already have been constructed - # with a value. - stat_futures = {} - - def handle(error): - if isinstance(error, FileNotFoundError): - return None - raise error - - for path in paths: - stat_value = cached_stat_values.get(path) - if stat_value is None: - stat_future = self.StatAsync(path) - if skip_not_found: - stat_future = stat_future.Then(lambda x: x, handle) - else: - stat_future = Future(value=stat_value) - stat_futures[path] = stat_future - - # Filter only the cached data which is up to date by comparing to the latest - # stat. The cached read data includes the cached version. Remove it for - # the result returned to callers. |version| == None implies a non-existent - # file, so skip it. - up_to_date_data = dict( - (path, data) for path, (data, version) in cached_read_values.iteritems() - if version is not None and stat_futures[path].Get().version == version) - - if skip_not_found: - # Filter out paths which we know do not exist, i.e. if |path| is in - # |cached_read_values| *and* has a None version, then it doesn't exist. - # See the above declaration of |cached_read_values| for more information. - paths = [path for path in paths - if cached_read_values.get(path, (None, True))[1]] - - remaining_paths = set(paths) - set(up_to_date_data.iterkeys()) - if len(remaining_paths) == 0: - # Everything was cached and up to date. - return Future(value=up_to_date_data) - - def raise_cache_miss(paths): - raise FileNotFoundError('Got cache miss when trying to stat %s' % paths) - - if self._fail_on_miss: - # Ignore missing values and return anyway. - logging.warn('Read cache miss for %s on %s' % - (remaining_paths, self.GetIdentity())) - return Future(callback=lambda: raise_cache_miss(remaining_paths)) - - def next(new_results): - # Update the cache. This is a path -> (data, version) mapping. - self._read_cache.SetMulti( - dict((path, (new_result, stat_futures[path].Get().version)) - for path, new_result in new_results.iteritems())) - # Update the read cache to include files that weren't found, to prevent - # constantly trying to read a file we now know doesn't exist. - self._read_cache.SetMulti( - dict((path, (None, None)) for path in paths - if stat_futures[path].Get() is None)) - new_results.update(up_to_date_data) - return new_results - - # Read in the values that were uncached or old. - return self._file_system.Read(remaining_paths, - skip_not_found=skip_not_found).Then(next) - - def GetCommitID(self): - return self._file_system.GetCommitID() - - def GetPreviousCommitID(self): - return self._file_system.GetPreviousCommitID() - - def Walk(self, root, depth=-1): - '''Overrides FileSystem.Walk() to provide caching functionality. - ''' - def file_lister(root): - res, root_stat = All((self._walk_cache.Get(root), - self.StatAsync(root))).Get() - - if res and res[2] == root_stat.version: - dirs, files = res[0], res[1] - else: - # Wasn't cached, or not up to date. - dirs, files = [], [] - for f in self.ReadSingle(root).Get(): - if IsDirectory(f): - dirs.append(f) - else: - files.append(f) - # Update the cache. This is a root -> (dirs, files, version) mapping. - self._walk_cache.Set(root, (dirs, files, root_stat.version)) - return dirs, files - return self._file_system.Walk(root, depth=depth, file_lister=file_lister) - - def GetIdentity(self): - return self._file_system.GetIdentity() - - def GetVersion(self): - return self._file_system.GetVersion() - - def __repr__(self): - return '%s of <%s>' % (type(self).__name__, repr(self._file_system))
diff --git a/chrome/common/extensions/docs/server2/caching_file_system_test.py b/chrome/common/extensions/docs/server2/caching_file_system_test.py deleted file mode 100755 index 51d063c..0000000 --- a/chrome/common/extensions/docs/server2/caching_file_system_test.py +++ /dev/null
@@ -1,297 +0,0 @@ -#!/usr/bin/env python -# 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. - -import os -import sys -import unittest - -from caching_file_system import CachingFileSystem -from extensions_paths import SERVER2 -from file_system import FileNotFoundError, StatInfo -from local_file_system import LocalFileSystem -from mock_file_system import MockFileSystem -from object_store_creator import ObjectStoreCreator -from test_file_system import TestFileSystem -from test_object_store import TestObjectStore - - -def _CreateLocalFs(): - return LocalFileSystem.Create(SERVER2, 'test_data', 'file_system/') - - -class CachingFileSystemTest(unittest.TestCase): - def setUp(self): - # Use this to make sure that every time _CreateCachingFileSystem is called - # the underlying object store data is the same, within each test. - self._object_store_dbs = {} - - def _CreateCachingFileSystem(self, fs, start_empty=False): - def store_type_constructor(namespace, start_empty=False): - '''Returns an ObjectStore backed onto test-lifetime-persistent objects - in |_object_store_dbs|. - ''' - if namespace not in self._object_store_dbs: - self._object_store_dbs[namespace] = {} - db = self._object_store_dbs[namespace] - if start_empty: - db.clear() - return TestObjectStore(namespace, init=db) - object_store_creator = ObjectStoreCreator(start_empty=start_empty, - store_type=store_type_constructor) - return CachingFileSystem(fs, object_store_creator) - - def testReadFiles(self): - file_system = self._CreateCachingFileSystem( - _CreateLocalFs(), start_empty=False) - expected = { - './test1.txt': 'test1\n', - './test2.txt': 'test2\n', - './test3.txt': 'test3\n', - } - self.assertEqual( - expected, - file_system.Read(['./test1.txt', './test2.txt', './test3.txt']).Get()) - - def testListDir(self): - file_system = self._CreateCachingFileSystem( - _CreateLocalFs(), start_empty=False) - expected = ['dir/'] + ['file%d.html' % i for i in range(7)] - file_system._read_cache.Set( - 'list/', - (expected, file_system.Stat('list/').version)) - self.assertEqual(expected, sorted(file_system.ReadSingle('list/').Get())) - - expected.remove('file0.html') - file_system._read_cache.Set( - 'list/', - (expected, file_system.Stat('list/').version)) - self.assertEqual(expected, sorted(file_system.ReadSingle('list/').Get())) - - def testCaching(self): - test_fs = TestFileSystem({ - 'bob': { - 'bob0': 'bob/bob0 contents', - 'bob1': 'bob/bob1 contents', - 'bob2': 'bob/bob2 contents', - 'bob3': 'bob/bob3 contents', - } - }) - mock_fs = MockFileSystem(test_fs) - def create_empty_caching_fs(): - return self._CreateCachingFileSystem(mock_fs, start_empty=True) - - file_system = create_empty_caching_fs() - - # The stat/read should happen before resolving the Future, and resolving - # the future shouldn't do any additional work. - get_future = file_system.ReadSingle('bob/bob0') - self.assertTrue(*mock_fs.CheckAndReset(read_count=1)) - self.assertEqual('bob/bob0 contents', get_future.Get()) - self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1, stat_count=1)) - - # Resource has been cached, so test resource is not re-fetched. - self.assertEqual('bob/bob0 contents', - file_system.ReadSingle('bob/bob0').Get()) - self.assertTrue(*mock_fs.CheckAndReset()) - - # Test if the Stat version is the same the resource is not re-fetched. - file_system = create_empty_caching_fs() - self.assertEqual('bob/bob0 contents', - file_system.ReadSingle('bob/bob0').Get()) - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1)) - - # Test if there is a newer version, the resource is re-fetched. - file_system = create_empty_caching_fs() - test_fs.IncrementStat(); - future = file_system.ReadSingle('bob/bob0') - self.assertTrue(*mock_fs.CheckAndReset(read_count=1, stat_count=1)) - self.assertEqual('bob/bob0 contents', future.Get()) - self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1)) - - # Test directory and subdirectory stats are cached. - file_system = create_empty_caching_fs() - file_system._stat_cache.Del('bob/bob0') - file_system._read_cache.Del('bob/bob0') - file_system._stat_cache.Del('bob/bob1') - test_fs.IncrementStat(); - futures = (file_system.ReadSingle('bob/bob1'), - file_system.ReadSingle('bob/bob0')) - self.assertTrue(*mock_fs.CheckAndReset(read_count=2)) - self.assertEqual(('bob/bob1 contents', 'bob/bob0 contents'), - tuple(future.Get() for future in futures)) - self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=2, stat_count=1)) - self.assertEqual('bob/bob1 contents', - file_system.ReadSingle('bob/bob1').Get()) - self.assertTrue(*mock_fs.CheckAndReset()) - - # Test a more recent parent directory doesn't force a refetch of children. - file_system = create_empty_caching_fs() - file_system._read_cache.Del('bob/bob0') - file_system._read_cache.Del('bob/bob1') - futures = (file_system.ReadSingle('bob/bob1'), - file_system.ReadSingle('bob/bob2'), - file_system.ReadSingle('bob/bob3')) - self.assertTrue(*mock_fs.CheckAndReset(read_count=3)) - self.assertEqual( - ('bob/bob1 contents', 'bob/bob2 contents', 'bob/bob3 contents'), - tuple(future.Get() for future in futures)) - self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=3, stat_count=1)) - - test_fs.IncrementStat(path='bob/bob0') - file_system = create_empty_caching_fs() - self.assertEqual('bob/bob1 contents', - file_system.ReadSingle('bob/bob1').Get()) - self.assertEqual('bob/bob2 contents', - file_system.ReadSingle('bob/bob2').Get()) - self.assertEqual('bob/bob3 contents', - file_system.ReadSingle('bob/bob3').Get()) - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1)) - - file_system = create_empty_caching_fs() - file_system._stat_cache.Del('bob/bob0') - future = file_system.ReadSingle('bob/bob0') - self.assertTrue(*mock_fs.CheckAndReset(read_count=1)) - self.assertEqual('bob/bob0 contents', future.Get()) - self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1, stat_count=1)) - self.assertEqual('bob/bob0 contents', - file_system.ReadSingle('bob/bob0').Get()) - self.assertTrue(*mock_fs.CheckAndReset()) - - # Test skip_not_found caching behavior. - file_system = create_empty_caching_fs() - future = file_system.ReadSingle('bob/no_file', skip_not_found=True) - self.assertTrue(*mock_fs.CheckAndReset(read_count=1)) - self.assertEqual(None, future.Get()) - self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1, stat_count=1)) - future = file_system.ReadSingle('bob/no_file', skip_not_found=True) - # There shouldn't be another read/stat from the file system; - # we know the file is not there. - self.assertTrue(*mock_fs.CheckAndReset()) - future = file_system.ReadSingle('bob/no_file') - self.assertTrue(*mock_fs.CheckAndReset(read_count=1)) - # Even though we cached information about non-existent files, - # trying to read one without specifiying skip_not_found should - # still raise an error. - self.assertRaises(FileNotFoundError, future.Get) - - def testCachedStat(self): - test_fs = TestFileSystem({ - 'bob': { - 'bob0': 'bob/bob0 contents', - 'bob1': 'bob/bob1 contents' - } - }) - mock_fs = MockFileSystem(test_fs) - - file_system = self._CreateCachingFileSystem(mock_fs, start_empty=False) - - self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob0')) - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1)) - self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob0')) - self.assertTrue(*mock_fs.CheckAndReset()) - - # Caching happens on a directory basis, so reading other files from that - # directory won't result in a stat. - self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob1')) - self.assertEqual( - StatInfo('0', child_versions={'bob0': '0', 'bob1': '0'}), - file_system.Stat('bob/')) - self.assertTrue(*mock_fs.CheckAndReset()) - - # Even though the stat is bumped, the object store still has it cached so - # this won't update. - test_fs.IncrementStat() - self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob0')) - self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob1')) - self.assertEqual( - StatInfo('0', child_versions={'bob0': '0', 'bob1': '0'}), - file_system.Stat('bob/')) - self.assertTrue(*mock_fs.CheckAndReset()) - - def testFreshStat(self): - test_fs = TestFileSystem({ - 'bob': { - 'bob0': 'bob/bob0 contents', - 'bob1': 'bob/bob1 contents' - } - }) - mock_fs = MockFileSystem(test_fs) - - def run_expecting_stat(stat): - def run(): - file_system = self._CreateCachingFileSystem(mock_fs, start_empty=True) - self.assertEqual( - StatInfo(stat, child_versions={'bob0': stat, 'bob1': stat}), - file_system.Stat('bob/')) - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1)) - self.assertEqual(StatInfo(stat), file_system.Stat('bob/bob0')) - self.assertEqual(StatInfo(stat), file_system.Stat('bob/bob0')) - self.assertTrue(*mock_fs.CheckAndReset()) - run() - run() - - run_expecting_stat('0') - test_fs.IncrementStat() - run_expecting_stat('1') - - def testSkipNotFound(self): - caching_fs = self._CreateCachingFileSystem(TestFileSystem({ - 'bob': { - 'bob0': 'bob/bob0 contents', - 'bob1': 'bob/bob1 contents' - } - })) - def read_skip_not_found(paths): - return caching_fs.Read(paths, skip_not_found=True).Get() - self.assertEqual({}, read_skip_not_found(('grub',))) - self.assertEqual({}, read_skip_not_found(('bob/bob2',))) - self.assertEqual({ - 'bob/bob0': 'bob/bob0 contents', - }, read_skip_not_found(('bob/bob0', 'bob/bob2'))) - - def testWalkCaching(self): - test_fs = TestFileSystem({ - 'root': { - 'file1': 'file1', - 'file2': 'file2', - 'dir1': { - 'dir1_file1': 'dir1_file1', - 'dir2': {}, - 'dir3': { - 'dir3_file1': 'dir3_file1', - 'dir3_file2': 'dir3_file2' - } - } - } - }) - mock_fs = MockFileSystem(test_fs) - file_system = self._CreateCachingFileSystem(mock_fs, start_empty=True) - for walkinfo in file_system.Walk(''): - pass - self.assertTrue(*mock_fs.CheckAndReset( - read_resolve_count=5, read_count=5, stat_count=5)) - - all_dirs, all_files = [], [] - for root, dirs, files in file_system.Walk(''): - all_dirs.extend(dirs) - all_files.extend(files) - self.assertEqual(sorted(['root/', 'dir1/', 'dir2/', 'dir3/']), - sorted(all_dirs)) - self.assertEqual( - sorted(['file1', 'file2', 'dir1_file1', 'dir3_file1', 'dir3_file2']), - sorted(all_files)) - # All data should be cached. - self.assertTrue(*mock_fs.CheckAndReset()) - - # Starting from a different root should still pull cached data. - for walkinfo in file_system.Walk('root/dir1/'): - pass - self.assertTrue(*mock_fs.CheckAndReset()) - # TODO(ahernandez): Test with a new instance CachingFileSystem so a - # different object store is utilized. - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/caching_rietveld_patcher.py b/chrome/common/extensions/docs/server2/caching_rietveld_patcher.py deleted file mode 100644 index 8e7aab6..0000000 --- a/chrome/common/extensions/docs/server2/caching_rietveld_patcher.py +++ /dev/null
@@ -1,116 +0,0 @@ -# Copyright 2013 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 datetime import datetime, timedelta -from file_system import FileNotFoundError -from future import Future -from patcher import Patcher - -_VERSION_CACHE_MAXAGE = timedelta(seconds=5) - -''' Append @version for keys to distinguish between different patchsets of -an issue. -''' -def _MakeKey(path, version): - return '%s@%s' % (path, version) - -def _ToObjectStoreValue(raw_value, version): - return dict((_MakeKey(key, version), raw_value[key]) - for key in raw_value) - -def _FromObjectStoreValue(raw_value): - return dict((key[0:key.rfind('@')], raw_value[key]) for key in raw_value) - -class _AsyncUncachedFuture(object): - def __init__(self, - version, - paths, - cached_value, - missing_paths, - fetch_delegate, - object_store): - self._version = version - self._paths = paths - self._cached_value = cached_value - self._missing_paths = missing_paths - self._fetch_delegate = fetch_delegate - self._object_store = object_store - - def Get(self): - uncached_value = self._fetch_delegate.Get() - self._object_store.SetMulti(_ToObjectStoreValue(uncached_value, - self._version)) - - for path in self._missing_paths: - if uncached_value.get(path) is None: - raise FileNotFoundError('File %s was not found in the patch.' % path) - self._cached_value[path] = uncached_value[path] - - return self._cached_value - -class CachingRietveldPatcher(Patcher): - ''' CachingRietveldPatcher implements a caching layer on top of |patcher|. - In theory, it can be used with any class that implements Patcher. But this - class assumes that applying to all patched files at once is more efficient - than applying to individual files. - ''' - def __init__(self, - rietveld_patcher, - object_store_creator, - test_datetime=datetime): - self._patcher = rietveld_patcher - def create_object_store(category): - return object_store_creator.Create( - CachingRietveldPatcher, - category='%s/%s' % (rietveld_patcher.GetIdentity(), category)) - self._version_object_store = create_object_store('version') - self._list_object_store = create_object_store('list') - self._file_object_store = create_object_store('file') - self._datetime = test_datetime - - def GetVersion(self): - key = 'version' - value = self._version_object_store.Get(key).Get() - if value is not None: - version, time = value - if self._datetime.now() - time < _VERSION_CACHE_MAXAGE: - return version - - version = self._patcher.GetVersion() - self._version_object_store.Set(key, - (version, self._datetime.now())) - return version - - def GetPatchedFiles(self, version=None): - if version is None: - version = self.GetVersion() - patched_files = self._list_object_store.Get(version).Get() - if patched_files is not None: - return patched_files - - patched_files = self._patcher.GetPatchedFiles(version) - self._list_object_store.Set(version, patched_files) - return patched_files - - def Apply(self, paths, file_system, version=None): - if version is None: - version = self.GetVersion() - added, deleted, modified = self.GetPatchedFiles(version) - cached_value = _FromObjectStoreValue(self._file_object_store. - GetMulti([_MakeKey(path, version) for path in paths]).Get()) - missing_paths = list(set(paths) - set(cached_value.keys())) - if len(missing_paths) == 0: - return Future(value=cached_value) - - return _AsyncUncachedFuture(version, - paths, - cached_value, - missing_paths, - self._patcher.Apply(set(added) | set(modified), - None, - version), - self._file_object_store) - - def GetIdentity(self): - return self._patcher.GetIdentity()
diff --git a/chrome/common/extensions/docs/server2/caching_rietveld_patcher_test.py b/chrome/common/extensions/docs/server2/caching_rietveld_patcher_test.py deleted file mode 100755 index a147a9e3..0000000 --- a/chrome/common/extensions/docs/server2/caching_rietveld_patcher_test.py +++ /dev/null
@@ -1,70 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest -from caching_rietveld_patcher import (CachingRietveldPatcher, - _VERSION_CACHE_MAXAGE) -from datetime import datetime -from object_store_creator import ObjectStoreCreator -from test_patcher import TestPatcher - -_TEST_PATCH_VERSION = '1' -_TEST_PATCH_FILES = (['add.txt'], ['del.txt'], ['modify.txt']) -_TEST_PATCH_DATA = { - 'add.txt': 'add', - 'modify.txt': 'modify', -} - -class FakeDateTime(object): - def __init__(self, time=datetime.now()): - self.time = time - - def now(self): - return self.time - -class CachingRietveldPatcherTest(unittest.TestCase): - def setUp(self): - self._datetime = FakeDateTime() - self._test_patcher = TestPatcher(_TEST_PATCH_VERSION, - _TEST_PATCH_FILES, - _TEST_PATCH_DATA) - self._patcher = CachingRietveldPatcher( - self._test_patcher, - ObjectStoreCreator(start_empty=False), - self._datetime) - - def testGetVersion(self): - # Invalidate cache. - self._datetime.time += _VERSION_CACHE_MAXAGE - # Fill cache. - self._patcher.GetVersion() - count = self._test_patcher.get_version_count - # Should read from cache. - self._patcher.GetVersion() - self.assertEqual(count, self._test_patcher.get_version_count) - # Invalidate cache. - self._datetime.time += _VERSION_CACHE_MAXAGE - # Should fetch version. - self._patcher.GetVersion() - self.assertEqual(count + 1, self._test_patcher.get_version_count) - - def testGetPatchedFiles(self): - # Fill cache. - self._patcher.GetPatchedFiles() - count = self._test_patcher.get_patched_files_count - # Should read from cache. - self._patcher.GetPatchedFiles() - self.assertEqual(count, self._test_patcher.get_patched_files_count) - - def testApply(self): - # Fill cache. - self._patcher.Apply(['add.txt'], None).Get() - count = self._test_patcher.apply_count - # Should read from cache even though it's reading another file. - self._patcher.Apply(['modify.txt'], None).Get() - self.assertEqual(count, self._test_patcher.apply_count) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/chained_compiled_file_system.py b/chrome/common/extensions/docs/server2/chained_compiled_file_system.py deleted file mode 100644 index 2f61dd3..0000000 --- a/chrome/common/extensions/docs/server2/chained_compiled_file_system.py +++ /dev/null
@@ -1,94 +0,0 @@ -# Copyright 2013 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 compiled_file_system import CompiledFileSystem -from docs_server_utils import StringIdentity -from file_system import FileNotFoundError -from future import Future -from path_util import ToDirectory - - -class ChainedCompiledFileSystem(object): - '''A CompiledFileSystem implementation that fetches data from a chain of - possible FileSystems. The chain consists of some number of FileSystems which - may have cached data for their CompiledFileSystem instances (injected on - Factory construction) + the main FileSystem (injected at Creation time). - - The expected configuration is that the main FileSystem is a PatchedFileSystem - and the chain the FileSystem which it patches, but with file systems - constructed via the HostFileSystemIterator the main FileSystems could be - anything. - - This slightly unusual configuration is primarily needed to avoid re-compiling - data for PatchedFileSystems, which are very similar to the FileSystem which - they patch. Re-compiling data is expensive and a waste of memory resources. - ChainedCompiledFileSystem shares the data. - ''' - class Factory(CompiledFileSystem.Factory): - def __init__(self, file_system_chain, object_store): - self._file_system_chain = file_system_chain - self._object_store = object_store - - def Create(self, file_system, populate_function, cls, category=None): - return ChainedCompiledFileSystem( - # Chain of CompiledFileSystem instances. - tuple(CompiledFileSystem.Factory(self._object_store).Create( - fs, populate_function, cls, category=category) - for fs in [file_system] + self._file_system_chain), - # Identity, as computed by all file systems. - StringIdentity(*(fs.GetIdentity() for fs in self._file_system_chain))) - - def __init__(self, compiled_fs_chain, identity): - '''|compiled_fs_chain| is a list of tuples (compiled_fs, file_system). - ''' - assert len(compiled_fs_chain) > 0 - self._compiled_fs_chain = compiled_fs_chain - self._identity = identity - - def GetFromFile(self, path, skip_not_found=False): - return self._GetImpl( - path, - lambda cfs: cfs.GetFromFile(path, skip_not_found=skip_not_found), - lambda cfs: cfs._GetFileVersionFromCache(path)) - - def GetFromFileListing(self, path): - path = ToDirectory(path) - return self._GetImpl( - path, - lambda compiled_fs: compiled_fs.GetFromFileListing(path), - lambda compiled_fs: compiled_fs._GetFileListingVersionFromCache(path)) - - def _GetImpl(self, path, reader, version_getter): - # Strategy: Get the current version of |path| in main FileSystem, then run - # through |_compiled_fs_chain| in *reverse* to find the "oldest" FileSystem - # with an up-to-date version of that file. - # - # Obviously, if files have been added in the main FileSystem then none of - # the older FileSystems will be able to find it. - read_and_version_futures = [(reader(fs), version_getter(fs), fs) - for fs in self._compiled_fs_chain] - - def resolve(): - try: - # The first file system contains both files of a newer version and - # files shared with other compiled file systems. We are going to try - # each compiled file system in the reverse order and return the data - # when version matches. Data cached in other compiled file system will - # be reused whenever possible so that we don't need to recompile things - # that are not changed across these file systems. - first_version = read_and_version_futures[0][1].Get() - for (read_future, - version_future, - compiled_fs) in reversed(read_and_version_futures): - if version_future.Get() == first_version: - return read_future.Get() - except FileNotFoundError: - pass - # Try an arbitrary operation again to generate a realistic stack trace. - return read_and_version_futures[0][0].Get() - - return Future(callback=resolve) - - def GetIdentity(self): - return self._identity
diff --git a/chrome/common/extensions/docs/server2/chained_compiled_file_system_test.py b/chrome/common/extensions/docs/server2/chained_compiled_file_system_test.py deleted file mode 100755 index 33fd91c..0000000 --- a/chrome/common/extensions/docs/server2/chained_compiled_file_system_test.py +++ /dev/null
@@ -1,70 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from chained_compiled_file_system import ChainedCompiledFileSystem -from compiled_file_system import CompiledFileSystem -from object_store_creator import ObjectStoreCreator -from test_file_system import TestFileSystem - -_TEST_DATA_BASE = { - 'a.txt': 'base a.txt', - 'dir': { - 'b.txt': 'base b.txt' - }, -} - -_TEST_DATA_NEW = { - 'a.txt': 'new a.txt', - 'new.txt': 'a new file', - 'dir': { - 'b.txt': 'new b.txt', - 'new.txt': 'new file in dir', - }, -} - -identity = lambda _, x: x - -class ChainedCompiledFileSystemTest(unittest.TestCase): - def setUp(self): - object_store_creator = ObjectStoreCreator(start_empty=False) - base_file_system = TestFileSystem(_TEST_DATA_BASE, identity='base') - self._base_compiled_fs = CompiledFileSystem.Factory( - object_store_creator).Create(base_file_system, - identity, - ChainedCompiledFileSystemTest) - chained_factory = ChainedCompiledFileSystem.Factory([base_file_system], - object_store_creator) - self._new_file_system = TestFileSystem(_TEST_DATA_NEW, identity='new') - self._chained_compiled_fs = chained_factory.Create( - self._new_file_system, identity, ChainedCompiledFileSystemTest) - - def testGetFromFile(self): - self.assertEqual(self._chained_compiled_fs.GetFromFile('a.txt').Get(), - self._base_compiled_fs.GetFromFile('a.txt').Get()) - self.assertEqual(self._chained_compiled_fs.GetFromFile('new.txt').Get(), - 'a new file') - self.assertEqual(self._chained_compiled_fs.GetFromFile('dir/new.txt').Get(), - 'new file in dir') - self._new_file_system.IncrementStat('a.txt') - self.assertNotEqual(self._chained_compiled_fs.GetFromFile('a.txt').Get(), - self._base_compiled_fs.GetFromFile('a.txt').Get()) - self.assertEqual(self._chained_compiled_fs.GetFromFile('a.txt').Get(), - self._new_file_system.ReadSingle('a.txt').Get()) - - def testGetFromFileListing(self): - self.assertEqual(self._chained_compiled_fs.GetFromFileListing('dir/').Get(), - self._base_compiled_fs.GetFromFileListing('dir/').Get()) - self._new_file_system.IncrementStat('dir/new.txt') - self.assertNotEqual( - self._chained_compiled_fs.GetFromFileListing('dir/').Get(), - self._base_compiled_fs.GetFromFileListing('dir/').Get()) - self.assertEqual( - self._chained_compiled_fs.GetFromFileListing('dir/').Get(), - self._new_file_system.ReadSingle('dir/').Get()) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/chrome-128.png b/chrome/common/extensions/docs/server2/chrome-128.png deleted file mode 100644 index 78ecb56..0000000 --- a/chrome/common/extensions/docs/server2/chrome-128.png +++ /dev/null Binary files differ
diff --git a/chrome/common/extensions/docs/server2/chrome-32.ico b/chrome/common/extensions/docs/server2/chrome-32.ico deleted file mode 100644 index 3c1023b..0000000 --- a/chrome/common/extensions/docs/server2/chrome-32.ico +++ /dev/null Binary files differ
diff --git a/chrome/common/extensions/docs/server2/chroot_file_system.py b/chrome/common/extensions/docs/server2/chroot_file_system.py deleted file mode 100644 index 2ed612f..0000000 --- a/chrome/common/extensions/docs/server2/chroot_file_system.py +++ /dev/null
@@ -1,53 +0,0 @@ -# Copyright 2013 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 posixpath - -from docs_server_utils import StringIdentity -from file_system import FileSystem -from future import Future - - -class ChrootFileSystem(FileSystem): - '''ChrootFileSystem(fs, path) exposes a FileSystem whose root is |path| inside - |fs|, so ChrootFileSystem(fs, 'hello').Read(['world']) is equivalent to - fs.Read(['hello/world']) with the 'hello' prefix stripped from the result. - ''' - - def __init__(self, file_system, root): - '''Parameters: - |file_system| The FileSystem instance to transpose paths of. - |root| The path to transpose all Read/Stat calls by. - ''' - self._file_system = file_system - self._root = root.strip('/') - - def Read(self, paths, skip_not_found=False): - # Maintain reverse mapping so the result can be mapped to the original - # paths given (the result from |file_system| will include |root| in the - # result, which would be wrong). - prefixed_paths = {} - def prefix(path): - prefixed = posixpath.join(self._root, path) - prefixed_paths[prefixed] = path - return prefixed - def next(results): - return dict((prefixed_paths[path], content) - for path, content in results.iteritems()) - return self._file_system.Read(tuple(prefix(path) for path in paths), - skip_not_found-skip_not_found).Then(next) - - def Refresh(self): - return self._file_system.Refresh() - - def Stat(self, path): - return self._file_system.Stat(posixpath.join(self._root, path)) - - def GetIdentity(self): - return StringIdentity( - '%s/%s' % (self._file_system.GetIdentity(), self._root)) - - def __repr__(self): - return 'ChrootFileSystem(%s, %s)' % ( - self._root, repr(self._file_system))
diff --git a/chrome/common/extensions/docs/server2/chroot_file_system_test.py b/chrome/common/extensions/docs/server2/chroot_file_system_test.py deleted file mode 100755 index 24160ea..0000000 --- a/chrome/common/extensions/docs/server2/chroot_file_system_test.py +++ /dev/null
@@ -1,102 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from chroot_file_system import ChrootFileSystem -from file_system import StatInfo -from test_file_system import TestFileSystem - - -def _SortListValues(dict_): - for value in dict_.itervalues(): - if isinstance(value, list): - value.sort() - return dict_ - - -class ChrootFileSystemTest(unittest.TestCase): - - def setUp(self): - self._test_fs = TestFileSystem({ - '404.html': '404.html contents', - 'apps': { - 'a11y.html': 'a11y.html contents', - 'about_apps.html': 'about_apps.html contents', - 'fakedir': { - 'file.html': 'file.html contents', - }, - }, - 'extensions': { - 'activeTab.html': 'activeTab.html contents', - 'alarms.html': 'alarms.html contents', - 'manifest': { - 'moremanifest': { - 'csp.html': 'csp.html contents', - 'usb.html': 'usb.html contents', - }, - 'sockets.html': 'sockets.html contents', - }, - }, - }) - - def testRead(self): - for prefix in ('', '/'): - for suffix in ('', '/'): - chroot_fs = ChrootFileSystem(self._test_fs, - prefix + 'extensions/manifest' + suffix) - self.assertEqual({ - 'moremanifest/usb.html': 'usb.html contents', - '': ['moremanifest/', 'sockets.html', ], - 'moremanifest/': ['csp.html', 'usb.html'], - 'sockets.html': 'sockets.html contents', - }, _SortListValues(chroot_fs.Read( - ('moremanifest/usb.html', '', 'moremanifest/', 'sockets.html') - ).Get())) - - def testEmptyRoot(self): - chroot_fs = ChrootFileSystem(self._test_fs, '') - self.assertEqual('404.html contents', - chroot_fs.ReadSingle('404.html').Get()) - - def testStat(self): - self._test_fs.IncrementStat('extensions/manifest/sockets.html', by=2) - self._test_fs.IncrementStat('extensions/manifest/moremanifest/csp.html') - for prefix in ('', '/'): - for suffix in ('', '/'): - chroot_fs = ChrootFileSystem(self._test_fs, - prefix + 'extensions' + suffix) - self.assertEqual(StatInfo('2', child_versions={ - 'activeTab.html': '0', - 'alarms.html': '0', - 'manifest/': '2', - }), chroot_fs.Stat('')) - self.assertEqual(StatInfo('0'), chroot_fs.Stat('activeTab.html')) - self.assertEqual(StatInfo('2', child_versions={ - 'moremanifest/': '1', - 'sockets.html': '2', - }), chroot_fs.Stat('manifest/')) - self.assertEqual(StatInfo('2'), chroot_fs.Stat('manifest/sockets.html')) - self.assertEqual(StatInfo('1', child_versions={ - 'csp.html': '1', - 'usb.html': '0', - }), chroot_fs.Stat('manifest/moremanifest/')) - self.assertEqual(StatInfo('1'), - chroot_fs.Stat('manifest/moremanifest/csp.html')) - self.assertEqual(StatInfo('0'), - chroot_fs.Stat('manifest/moremanifest/usb.html')) - - def testIdentity(self): - chroot_fs1 = ChrootFileSystem(self._test_fs, '1') - chroot_fs1b = ChrootFileSystem(self._test_fs, '1') - chroot_fs2 = ChrootFileSystem(self._test_fs, '2') - self.assertNotEqual(self._test_fs.GetIdentity(), chroot_fs1.GetIdentity()) - self.assertNotEqual(self._test_fs.GetIdentity(), chroot_fs2.GetIdentity()) - self.assertNotEqual(chroot_fs1.GetIdentity(), chroot_fs2.GetIdentity()) - self.assertEqual(chroot_fs1.GetIdentity(), chroot_fs1b.GetIdentity()) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/commit_tracker.py b/chrome/common/extensions/docs/server2/commit_tracker.py deleted file mode 100644 index 874c4b7b..0000000 --- a/chrome/common/extensions/docs/server2/commit_tracker.py +++ /dev/null
@@ -1,56 +0,0 @@ -# Copyright 2014 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 collections -import datetime - -from object_store_creator import ObjectStoreCreator -from future import Future - - -# The maximum number of commit IDs to retain in a named commit's history deque. -_MAX_COMMIT_HISTORY_LENGTH = 50 - - -class CachedCommit(object): - '''Object type which is stored for each entry in a named commit's history. - |datetime| is used as a timestamp for when the commit cache was completed, - and is only meant to provide a loose ordering of commits for administrative - servlets to display.''' - def __init__(self, commit_id, datetime): - self.commit_id = commit_id - self.datetime = datetime - - -class CommitTracker(object): - '''Utility class for managing and querying the storage of various named commit - IDs.''' - def __init__(self, object_store_creator): - # The object stores should never be created empty since the sole purpose of - # this tracker is to persist named commit data across requests. - self._store = object_store_creator.Create(CommitTracker, start_empty=False) - self._history_store = object_store_creator.Create(CommitTracker, - category='history', start_empty=False) - - def Get(self, key): - return self._store.Get(key) - - def Set(self, key, commit): - return (self._store.Set(key, commit) - .Then(lambda _: self._UpdateHistory(key, commit))) - - def GetHistory(self, key): - '''Fetches the commit ID history for a named commit. If the commit has no - history, this will return an empty collection.''' - return (self._history_store.Get(key) - .Then(lambda history: () if history is None else history)) - - def _UpdateHistory(self, key, commit): - '''Appends a commit ID to a named commit's tracked history.''' - def create_or_amend_history(history): - if history is None: - history = collections.deque([], maxlen=50) - history.append(CachedCommit(commit, datetime.datetime.now())) - return self._history_store.Set(key, history) - return self._history_store.Get(key).Then(create_or_amend_history)
diff --git a/chrome/common/extensions/docs/server2/compiled_file_system.py b/chrome/common/extensions/docs/server2/compiled_file_system.py deleted file mode 100644 index c8aada5..0000000 --- a/chrome/common/extensions/docs/server2/compiled_file_system.py +++ /dev/null
@@ -1,286 +0,0 @@ -# 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. - -import sys - -from docs_server_utils import ToUnicode -from file_system import FileNotFoundError -from future import Future -from path_util import AssertIsDirectory, AssertIsFile, ToDirectory -from third_party.json_schema_compiler import json_parse -from third_party.json_schema_compiler.memoize import memoize -from third_party.motemplate import Motemplate - - -_CACHEABLE_FUNCTIONS = set() -_SINGLE_FILE_FUNCTIONS = set() - - -def _GetUnboundFunction(fn): - '''Functions bound to an object are separate from the unbound - defintion. This causes issues when checking for cache membership, - so always get the unbound function, if possible. - ''' - return getattr(fn, 'im_func', fn) - - -def Cache(fn): - '''A decorator which can be applied to the compilation function - passed to CompiledFileSystem.Create, indicating that file/list data - should be cached. - - This decorator should be listed first in any list of decorators, along - with the SingleFile decorator below. - ''' - _CACHEABLE_FUNCTIONS.add(_GetUnboundFunction(fn)) - return fn - - -def SingleFile(fn): - '''A decorator which can be optionally applied to the compilation function - passed to CompiledFileSystem.Create, indicating that the function only - needs access to the file which is given in the function's callback. When - this is the case some optimisations can be done. - - Note that this decorator must be listed first in any list of decorators to - have any effect. - ''' - _SINGLE_FILE_FUNCTIONS.add(_GetUnboundFunction(fn)) - return fn - - -def Unicode(fn): - '''A decorator which can be optionally applied to the compilation function - passed to CompiledFileSystem.Create, indicating that the function processes - the file's data as Unicode text. - ''' - - # The arguments passed to fn can be (self, path, data) or (path, data). In - # either case the last argument is |data|, which should be converted to - # Unicode. - def convert_args(args): - args = list(args) - args[-1] = ToUnicode(args[-1]) - return args - - return lambda *args: fn(*convert_args(args)) - - -class _CacheEntry(object): - def __init__(self, cache_data, version): - - self.cache_data = cache_data - self.version = version - - -class CompiledFileSystem(object): - '''This class caches FileSystem data that has been processed. - ''' - - class Factory(object): - '''A class to build a CompiledFileSystem backed by |file_system|. - ''' - - def __init__(self, object_store_creator): - self._object_store_creator = object_store_creator - - def Create(self, file_system, compilation_function, cls, category=None): - '''Creates a CompiledFileSystem view over |file_system| that populates - its cache by calling |compilation_function| with (path, data), where - |data| is the data that was fetched from |path| in |file_system|. - - The namespace for the compiled file system is derived similar to - ObjectStoreCreator: from |cls| along with an optional |category|. - ''' - assert isinstance(cls, type) - assert not cls.__name__[0].islower() # guard against non-class types - full_name = [cls.__name__, file_system.GetIdentity()] - if category is not None: - full_name.append(category) - def create_object_store(my_category): - # The read caches can start populated (start_empty=False) because file - # updates are picked up by the stat - but only if the compilation - # function is affected by a single file. If the compilation function is - # affected by other files (e.g. compiling a list of APIs available to - # extensions may be affected by both a features file and the list of - # files in the API directory) then this optimisation won't work. - return self._object_store_creator.Create( - CompiledFileSystem, - category='/'.join(full_name + [my_category]), - start_empty=compilation_function not in _SINGLE_FILE_FUNCTIONS) - return CompiledFileSystem(file_system, - compilation_function, - create_object_store('file'), - create_object_store('list')) - - @memoize - def ForJson(self, file_system): - '''A CompiledFileSystem specifically for parsing JSON configuration data. - These are memoized over file systems tied to different branches. - ''' - return self.Create(file_system, - Cache(SingleFile(lambda _, data: - json_parse.Parse(ToUnicode(data)))), - CompiledFileSystem, - category='json') - - @memoize - def ForTemplates(self, file_system): - '''Creates a CompiledFileSystem for parsing templates. - ''' - return self.Create( - file_system, - Cache(SingleFile(lambda path, text: - Motemplate(ToUnicode(text), name=path))), - CompiledFileSystem) - - @memoize - def ForUnicode(self, file_system): - '''Creates a CompiledFileSystem for Unicode text processing. - ''' - return self.Create( - file_system, - SingleFile(lambda _, text: ToUnicode(text)), - CompiledFileSystem, - category='text') - - def __init__(self, - file_system, - compilation_function, - file_object_store, - list_object_store): - self._file_system = file_system - self._compilation_function = compilation_function - self._file_object_store = file_object_store - self._list_object_store = list_object_store - - def _Get(self, store, key): - if _GetUnboundFunction(self._compilation_function) in _CACHEABLE_FUNCTIONS: - return store.Get(key) - return Future(value=None) - - def _Set(self, store, key, value): - if _GetUnboundFunction(self._compilation_function) in _CACHEABLE_FUNCTIONS: - store.Set(key, value) - - def _RecursiveList(self, path): - '''Returns a Future containing the recursive directory listing of |path| as - a flat list of paths. - ''' - def split_dirs_from_files(paths): - '''Returns a tuple (dirs, files) where |dirs| contains the directory - names in |paths| and |files| contains the files. - ''' - result = [], [] - for path in paths: - result[0 if path.endswith('/') else 1].append(path) - return result - - def add_prefix(prefix, paths): - return [prefix + path for path in paths] - - # Read in the initial list of files. Do this eagerly (i.e. not part of the - # asynchronous Future contract) because there's a greater chance to - # parallelise fetching with the second layer (can fetch multiple paths). - try: - first_layer_dirs, first_layer_files = split_dirs_from_files( - self._file_system.ReadSingle(path).Get()) - except FileNotFoundError: - return Future(exc_info=sys.exc_info()) - - if not first_layer_dirs: - return Future(value=first_layer_files) - - def get_from_future_listing(listings): - '''Recursively lists files from directory listing |futures|. - ''' - dirs, files = [], [] - for dir_name, listing in listings.iteritems(): - new_dirs, new_files = split_dirs_from_files(listing) - # |dirs| are paths for reading. Add the full prefix relative to - # |path| so that |file_system| can find the files. - dirs += add_prefix(dir_name, new_dirs) - # |files| are not for reading, they are for returning to the caller. - # This entire function set (i.e. GetFromFileListing) is defined to - # not include the fetched-path in the result, however, |dir_name| - # will be prefixed with |path|. Strip it. - assert dir_name.startswith(path) - files += add_prefix(dir_name[len(path):], new_files) - if dirs: - files += self._file_system.Read(dirs).Then( - get_from_future_listing).Get() - return files - - return self._file_system.Read(add_prefix(path, first_layer_dirs)).Then( - lambda results: first_layer_files + get_from_future_listing(results)) - - def GetFromFile(self, path, skip_not_found=False): - '''Calls |compilation_function| on the contents of the file at |path|. - If |skip_not_found| is True, then None is passed to |compilation_function|. - ''' - AssertIsFile(path) - - try: - version = self._file_system.Stat(path).version - except FileNotFoundError: - if skip_not_found: - version = None - else: - return Future(exc_info=sys.exc_info()) - - cache_entry = self._Get(self._file_object_store, path).Get() - if (cache_entry is not None) and (version == cache_entry.version): - return Future(value=cache_entry.cache_data) - - def compile_(files): - cache_data = self._compilation_function(path, files) - self._Set(self._file_object_store, path, _CacheEntry(cache_data, version)) - return cache_data - - return self._file_system.ReadSingle( - path, skip_not_found=skip_not_found).Then(compile_) - - def GetFromFileListing(self, path): - '''Calls |compilation_function| on the listing of the files at |path|. - Assumes that the path given is to a directory. - ''' - AssertIsDirectory(path) - - try: - version = self._file_system.Stat(path).version - except FileNotFoundError: - return Future(exc_info=sys.exc_info()) - - cache_entry = self._Get(self._list_object_store, path).Get() - if (cache_entry is not None) and (version == cache_entry.version): - return Future(value=cache_entry.cache_data) - - def compile_(files): - cache_data = self._compilation_function(path, files) - self._Set(self._list_object_store, path, _CacheEntry(cache_data, version)) - return cache_data - return self._RecursiveList(path).Then(compile_) - - # _GetFileVersionFromCache and _GetFileListingVersionFromCache are exposed - # *only* so that ChainedCompiledFileSystem can optimise its caches. *Do not* - # use these methods otherwise, they don't do what you want. Use - # FileSystem.Stat on the FileSystem that this CompiledFileSystem uses. - - def _GetFileVersionFromCache(self, path): - cache_entry = self._Get(self._file_object_store, path).Get() - if cache_entry is not None: - return Future(value=cache_entry.version) - stat_future = self._file_system.StatAsync(path) - return Future(callback=lambda: stat_future.Get().version) - - def _GetFileListingVersionFromCache(self, path): - path = ToDirectory(path) - cache_entry = self._Get(self._list_object_store, path).Get() - if cache_entry is not None: - return Future(value=cache_entry.version) - stat_future = self._file_system.StatAsync(path) - return Future(callback=lambda: stat_future.Get().version) - - def GetIdentity(self): - return self._file_system.GetIdentity()
diff --git a/chrome/common/extensions/docs/server2/compiled_file_system_test.py b/chrome/common/extensions/docs/server2/compiled_file_system_test.py deleted file mode 100755 index 6564a434..0000000 --- a/chrome/common/extensions/docs/server2/compiled_file_system_test.py +++ /dev/null
@@ -1,225 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 functools -import os - -from compiled_file_system import Cache, CompiledFileSystem -from copy import deepcopy -from environment import GetAppVersion -from file_system import FileNotFoundError -from mock_file_system import MockFileSystem -from object_store_creator import ObjectStoreCreator -from test_file_system import TestFileSystem -from test_object_store import TestObjectStore -import unittest - -_TEST_DATA = { - '404.html': '404.html contents', - 'apps': { - 'a11y.html': 'a11y.html contents', - 'about_apps.html': 'about_apps.html contents', - 'fakedir': { - 'file.html': 'file.html contents' - }, - 'deepdir': { - 'deepfile.html': 'deepfile.html contents', - 'deeper': { - 'deepest.html': 'deepest.html contents', - }, - } - }, - 'extensions': { - 'activeTab.html': 'activeTab.html contents', - 'alarms.html': 'alarms.html contents' - } -} - -identity = lambda _, x: x - -def _GetTestCompiledFsCreator(): - '''Returns a function which creates CompiledFileSystem views of - TestFileSystems backed by _TEST_DATA. - ''' - return functools.partial( - CompiledFileSystem.Factory( - ObjectStoreCreator(start_empty=False, - store_type=TestObjectStore, - disable_wrappers=True), - ).Create, - TestFileSystem(deepcopy(_TEST_DATA))) - -class CompiledFileSystemTest(unittest.TestCase): - def testPopulateNamespace(self): - def CheckNamespace(expected_file, expected_list, fs): - self.assertEqual(expected_file, fs._file_object_store.namespace) - self.assertEqual(expected_list, fs._list_object_store.namespace) - compiled_fs_creator = _GetTestCompiledFsCreator() - f = lambda x: x - CheckNamespace( - 'class=CompiledFileSystem&' - 'category=CompiledFileSystemTest/TestFileSystem/file&' - 'app_version=%s' % GetAppVersion(), - 'class=CompiledFileSystem&' - 'category=CompiledFileSystemTest/TestFileSystem/list&' - 'app_version=%s' % GetAppVersion(), - compiled_fs_creator(f, CompiledFileSystemTest)) - CheckNamespace( - 'class=CompiledFileSystem&' - 'category=CompiledFileSystemTest/TestFileSystem/foo/file&' - 'app_version=%s' % GetAppVersion(), - 'class=CompiledFileSystem&' - 'category=CompiledFileSystemTest/TestFileSystem/foo/list&' - 'app_version=%s' % GetAppVersion(), - compiled_fs_creator(f, CompiledFileSystemTest, category='foo')) - - def testPopulateFromFile(self): - def Sleepy(key, val): - return '%s%s' % ('Z' * len(key), 'z' * len(val)) - compiled_fs = _GetTestCompiledFsCreator()(Sleepy, CompiledFileSystemTest) - self.assertEqual('ZZZZZZZZzzzzzzzzzzzzzzzzz', - compiled_fs.GetFromFile('404.html').Get()) - self.assertEqual('ZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzz', - compiled_fs.GetFromFile('apps/a11y.html').Get()) - self.assertEqual('ZZZZZZZZZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzz', - compiled_fs.GetFromFile('apps/fakedir/file.html').Get()) - - def testPopulateFromFileListing(self): - def strip_ext(_, files): - return [os.path.splitext(f)[0] for f in files] - compiled_fs = _GetTestCompiledFsCreator()(strip_ext, CompiledFileSystemTest) - expected_top_listing = [ - '404', - 'apps/a11y', - 'apps/about_apps', - 'apps/deepdir/deeper/deepest', - 'apps/deepdir/deepfile', - 'apps/fakedir/file', - 'extensions/activeTab', - 'extensions/alarms' - ] - self.assertEqual(expected_top_listing, - sorted(compiled_fs.GetFromFileListing('').Get())) - expected_apps_listing = [ - 'a11y', - 'about_apps', - 'deepdir/deeper/deepest', - 'deepdir/deepfile', - 'fakedir/file', - ] - self.assertEqual(expected_apps_listing, - sorted(compiled_fs.GetFromFileListing('apps/').Get())) - self.assertEqual(['file',], - compiled_fs.GetFromFileListing('apps/fakedir/').Get()) - self.assertEqual(['deeper/deepest', 'deepfile'], - sorted(compiled_fs.GetFromFileListing( - 'apps/deepdir/').Get())) - self.assertEqual(['deepest'], - compiled_fs.GetFromFileListing( - 'apps/deepdir/deeper/').Get()) - - def testCaching(self): - compiled_fs = _GetTestCompiledFsCreator()(Cache(identity), - CompiledFileSystemTest) - self.assertEqual('404.html contents', - compiled_fs.GetFromFile('404.html').Get()) - self.assertEqual(set(('file.html',)), - set(compiled_fs.GetFromFileListing('apps/fakedir/').Get())) - - compiled_fs._file_system._path_values['404.html'] = 'boom' - compiled_fs._file_system._path_values['apps/fakedir/'] = [ - 'file.html', 'boom.html'] - self.assertEqual('404.html contents', - compiled_fs.GetFromFile('404.html').Get()) - self.assertEqual(set(('file.html',)), - set(compiled_fs.GetFromFileListing('apps/fakedir/').Get())) - - compiled_fs._file_system.IncrementStat() - self.assertEqual('boom', compiled_fs.GetFromFile('404.html').Get()) - self.assertEqual(set(('file.html', 'boom.html')), - set(compiled_fs.GetFromFileListing('apps/fakedir/').Get())) - - def testFailures(self): - compiled_fs = _GetTestCompiledFsCreator()(identity, CompiledFileSystemTest) - self.assertRaises(FileNotFoundError, - compiled_fs.GetFromFile('405.html').Get) - # TODO(kalman): would be nice to test this fails since apps/ is a dir. - compiled_fs.GetFromFile('apps') - #self.assertRaises(SomeError, compiled_fs.GetFromFile, 'apps/') - self.assertRaises(FileNotFoundError, - compiled_fs.GetFromFileListing('nodir/').Get) - # TODO(kalman): likewise, not a FileNotFoundError. - self.assertRaises(FileNotFoundError, - compiled_fs.GetFromFileListing('404.html/').Get) - - def testCorrectFutureBehaviour(self): - # Tests that the underlying FileSystem's Read Future has had Get() called - # on it before the Future is resolved, but the underlying Future isn't - # resolved until Get is. - mock_fs = MockFileSystem(TestFileSystem(_TEST_DATA)) - compiled_fs = CompiledFileSystem.Factory( - ObjectStoreCreator.ForTest()).Create( - mock_fs, lambda path, contents: contents, type(self)) - - self.assertTrue(*mock_fs.CheckAndReset()) - future = compiled_fs.GetFromFile('404.html') - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, read_count=1)) - future.Get() - self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1)) - - future = compiled_fs.GetFromFileListing('apps/') - # Current behaviour is to have read=2 and read_resolve=1 because the first - # level is read eagerly, then all of the second is read (in parallel). If - # it weren't eager (and it may be worth experimenting with that) then it'd - # be read=1 and read_resolve=0. - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, - read_count=2, - read_resolve_count=1)) - future.Get() - # It's doing 1 more level 'deeper' (already read 'fakedir' and 'deepdir' - # though not resolved), so that's 1 more read/resolve + the resolve from - # the first read. - self.assertTrue(*mock_fs.CheckAndReset(read_count=1, read_resolve_count=2)) - - # Even though the directory is 1 layer deep the caller has no way of - # determining that ahead of time (though perhaps the API could give some - # kind of clue, if we really cared). - future = compiled_fs.GetFromFileListing('extensions/') - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, - read_count=1, - read_resolve_count=1)) - future.Get() - self.assertTrue(*mock_fs.CheckAndReset()) - - # Similar configuration to the 'apps/' case but deeper. - future = compiled_fs.GetFromFileListing('') - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, - read_count=2, - read_resolve_count=1)) - future.Get() - self.assertTrue(*mock_fs.CheckAndReset(read_count=2, read_resolve_count=3)) - - def testSkipNotFound(self): - mock_fs = MockFileSystem(TestFileSystem(_TEST_DATA)) - compiled_fs = CompiledFileSystem.Factory( - ObjectStoreCreator.ForTest()).Create( - mock_fs, Cache(lambda path, contents: contents), type(self)) - - future = compiled_fs.GetFromFile('no_file', skip_not_found=True) - # If the file doesn't exist, then the file system is not read. - self.assertTrue(*mock_fs.CheckAndReset(read_count=1, stat_count=1)) - self.assertEqual(None, future.Get()) - self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1)) - future = compiled_fs.GetFromFile('no_file', skip_not_found=True) - self.assertTrue(*mock_fs.CheckAndReset(stat_count=1)) - self.assertEqual(None, future.Get()) - # The result for a non-existent file should still be cached. - self.assertTrue(*mock_fs.CheckAndReset()) - future = compiled_fs.GetFromFile('no_file') - self.assertRaises(FileNotFoundError, future.Get) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/content_provider.py b/chrome/common/extensions/docs/server2/content_provider.py deleted file mode 100644 index baa779c..0000000 --- a/chrome/common/extensions/docs/server2/content_provider.py +++ /dev/null
@@ -1,216 +0,0 @@ -# Copyright 2013 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 logging -import mimetypes -import posixpath -import traceback - -from compiled_file_system import SingleFile -from directory_zipper import DirectoryZipper -from docs_server_utils import ToUnicode -from file_system import FileNotFoundError -from future import All, Future -from path_canonicalizer import PathCanonicalizer -from path_util import AssertIsValid, IsDirectory, Join, ToDirectory -from special_paths import SITE_VERIFICATION_FILE -from third_party.markdown import markdown -from third_party.motemplate import Motemplate - - -_MIMETYPE_OVERRIDES = { - # SVG is not supported by mimetypes.guess_type on AppEngine. - '.svg': 'image/svg+xml', -} - - -class ContentAndType(object): - '''Return value from ContentProvider.GetContentAndType. - ''' - - def __init__(self, content, content_type, version): - self.content = content - self.content_type = content_type - self.version = version - - -class ContentProvider(object): - '''Returns file contents correctly typed for their content-types (in the HTTP - sense). Content-type is determined from Python's mimetype library which - guesses based on the file extension. - - Typically the file contents will be either str (for binary content) or - unicode (for text content). However, HTML files *may* be returned as - Motemplate templates (if |supports_templates| is True on construction), in - which case the caller will presumably want to Render them. - - Zip file are automatically created and returned for .zip file extensions if - |supports_zip| is True. - - |default_extensions| is a list of file extensions which are queried when no - file extension is given to GetCanonicalPath/GetContentAndType. Typically - this will include .html. - ''' - - def __init__(self, - name, - compiled_fs_factory, - file_system, - object_store_creator, - default_extensions=(), - supports_templates=False, - supports_zip=False): - # Public. - self.name = name - self.file_system = file_system - # Private. - self._content_cache = compiled_fs_factory.Create(file_system, - self._CompileContent, - ContentProvider) - self._path_canonicalizer = PathCanonicalizer(file_system, - object_store_creator, - default_extensions) - self._default_extensions = default_extensions - self._supports_templates = supports_templates - if supports_zip: - self._directory_zipper = DirectoryZipper(compiled_fs_factory, file_system) - else: - self._directory_zipper = None - - @SingleFile - def _CompileContent(self, path, text): - assert text is not None, path - try: - _, ext = posixpath.splitext(path) - mimetype = _MIMETYPE_OVERRIDES.get(ext, mimetypes.guess_type(path)[0]) - if ext == '.md': - # See http://pythonhosted.org/Markdown/extensions - # for details on "extensions=". - content = markdown(ToUnicode(text), - extensions=('extra', 'headerid', 'sane_lists')) - mimetype = 'text/html' - if self._supports_templates: - content = Motemplate(content, name=path) - elif mimetype is None: - content = text - mimetype = 'text/plain' - elif mimetype == 'text/html': - content = ToUnicode(text) - if self._supports_templates: - content = Motemplate(content, name=path) - elif (mimetype.startswith('text/') or - mimetype in ('application/javascript', 'application/json')): - content = ToUnicode(text) - else: - content = text - return ContentAndType(content, - mimetype, - self.file_system.Stat(path).version) - except Exception as e: - logging.warn('In file %s: %s' % (path, e.message)) - return ContentAndType('', mimetype, self.file_system.Stat(path).version) - - def GetCanonicalPath(self, path): - '''Gets the canonical location of |path|. This class is tolerant of - spelling errors and missing files that are in other directories, and this - returns the correct/canonical path for those. - - For example, the canonical path of "browseraction" is probably - "extensions/browserAction.html". - - Note that the canonical path is relative to this content provider i.e. - given relative to |path|. It does not add the "serveFrom" prefix which - would have been pulled out in ContentProviders, callers must do that - themselves. - ''' - AssertIsValid(path) - base, ext = posixpath.splitext(path) - if self._directory_zipper and ext == '.zip': - # The canonical location of zip files is the canonical location of the - # directory to zip + '.zip'. - return self._path_canonicalizer.Canonicalize(base + '/').rstrip('/') + ext - return self._path_canonicalizer.Canonicalize(path) - - def GetContentAndType(self, path): - '''Returns a Future to the ContentAndType of the file at |path|. - ''' - AssertIsValid(path) - base, ext = posixpath.splitext(path) - if self._directory_zipper and ext == '.zip': - return (self._directory_zipper.Zip(ToDirectory(base)) - .Then(lambda zipped: ContentAndType(zipped, - 'application/zip', - None))) - return self._FindFileForPath(path).Then(self._content_cache.GetFromFile) - - def GetVersion(self, path): - '''Returns a Future to the version of the file at |path|. - ''' - AssertIsValid(path) - base, ext = posixpath.splitext(path) - if self._directory_zipper and ext == '.zip': - stat_future = self.file_system.StatAsync(ToDirectory(base)) - else: - stat_future = self._FindFileForPath(path).Then(self.file_system.StatAsync) - return stat_future.Then(lambda stat: stat.version) - - def _FindFileForPath(self, path): - '''Finds the real file backing |path|. This may require looking for the - correct file extension, or looking for an 'index' file if it's a directory. - Returns None if no path is found. - ''' - AssertIsValid(path) - _, ext = posixpath.splitext(path) - - if ext: - # There was already an extension, trust that it's a path. Elsewhere - # up the stack this will be caught if it's not. - return Future(value=path) - - def find_file_with_name(name): - '''Tries to find a file in the file system called |name| with one of the - default extensions of this content provider. - If none is found, returns None. - ''' - paths = [name + ext for ext in self._default_extensions] - def get_first_path_which_exists(existence): - for exists, path in zip(existence, paths): - if exists: - return path - return None - return (All(self.file_system.Exists(path) for path in paths) - .Then(get_first_path_which_exists)) - - def find_index_file(): - '''Tries to find an index file in |path|, if |path| is a directory. - If not, or if there is no index file, returns None. - ''' - def get_index_if_directory_exists(directory_exists): - if not directory_exists: - return None - return find_file_with_name(Join(path, 'index')) - return (self.file_system.Exists(ToDirectory(path)) - .Then(get_index_if_directory_exists)) - - # Try to find a file with the right name. If not, and it's a directory, - # look for an index file in that directory. If nothing at all is found, - # return the original |path| - its nonexistence will be caught up the stack. - return (find_file_with_name(path) - .Then(lambda found: found or find_index_file()) - .Then(lambda found: found or path)) - - def Refresh(self): - futures = [self._path_canonicalizer.Refresh()] - for root, _, files in self.file_system.Walk(''): - for f in files: - futures.append(self.GetContentAndType(Join(root, f))) - # Also cache the extension-less version of the file if needed. - base, ext = posixpath.splitext(f) - if f != SITE_VERIFICATION_FILE and ext in self._default_extensions: - futures.append(self.GetContentAndType(Join(root, base))) - # TODO(kalman): Cache .zip files for each directory (if supported). - return All(futures, except_pass=Exception, except_pass_log=True) - - def __repr__(self): - return 'ContentProvider of <%s>' % repr(self.file_system)
diff --git a/chrome/common/extensions/docs/server2/content_provider_test.py b/chrome/common/extensions/docs/server2/content_provider_test.py deleted file mode 100755 index e5027ec..0000000 --- a/chrome/common/extensions/docs/server2/content_provider_test.py +++ /dev/null
@@ -1,214 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 cStringIO import StringIO -import json -import os -import unittest -from zipfile import ZipFile - -from compiled_file_system import CompiledFileSystem -from content_provider import ContentProvider -from file_system import FileNotFoundError -from object_store_creator import ObjectStoreCreator -from path_canonicalizer import PathCanonicalizer -from test_file_system import TestFileSystem -from third_party.motemplate import Motemplate - -_REDIRECTS_JSON = json.dumps({ - 'oldfile.html': 'storage.html', - 'index.html': 'https://developers.google.com/chrome', -}) - - -_MARKDOWN_CONTENT = ( - ('# Header 1 #', u'<h1 id="header-1">Header 1</h1>'), - ('1. Foo\n', u'<ol>\n<li>Foo</li>\n</ol>'), - ('\n', - '<p><img alt="alt text" src="/path/img.jpg" title="Title" /></p>'), - ('* Unordered item 1', u'<ul>\n<li>Unordered item 1</li>\n</ul>') -) - -# Test file system data which exercises many different mimetypes. -_TEST_DATA = { - 'dir': { - 'a.txt': 'a.txt content', - 'b.txt': 'b.txt content', - 'c': { - 'd.txt': 'd.txt content', - }, - }, - 'dir2': { - 'dir3': { - 'a.txt': 'a.txt content', - 'b.txt': 'b.txt content', - 'c': { - 'd.txt': 'd.txt content', - }, - }, - }, - 'dir4': { - 'index.html': 'index.html content 1' - }, - 'dir5': { - 'index.html': 'index.html content 2' - }, - 'dir6': { - 'notindex.html': 'notindex.html content' - }, - 'dir7': { - 'index.md': '\n'.join(text[0] for text in _MARKDOWN_CONTENT) - }, - 'dir.txt': 'dir.txt content', - 'dir5.html': 'dir5.html content', - 'img.png': 'img.png content', - 'index.html': 'index.html content', - 'read.txt': 'read.txt content', - 'redirects.json': _REDIRECTS_JSON, - 'noextension': 'noextension content', - 'run.js': 'run.js content', - 'site.css': 'site.css content', - 'storage.html': 'storage.html content', - 'markdown.md': '\n'.join(text[0] for text in _MARKDOWN_CONTENT) -} - - -class ContentProviderUnittest(unittest.TestCase): - def setUp(self): - self._test_file_system = TestFileSystem(_TEST_DATA) - self._content_provider = self._CreateContentProvider() - - def _CreateContentProvider(self, supports_zip=False): - object_store_creator = ObjectStoreCreator.ForTest() - return ContentProvider( - 'foo', - CompiledFileSystem.Factory(object_store_creator), - self._test_file_system, - object_store_creator, - default_extensions=('.html', '.md'), - # TODO(kalman): Test supports_templates=False. - supports_templates=True, - supports_zip=supports_zip) - - def _assertContent(self, content, content_type, content_and_type): - # Assert type so that str is differentiated from unicode. - self.assertEqual(type(content), type(content_and_type.content)) - self.assertEqual(content, content_and_type.content) - self.assertEqual(content_type, content_and_type.content_type) - - def _assertTemplateContent(self, content, path, version): - content_and_type = self._content_provider.GetContentAndType(path).Get() - self.assertEqual(Motemplate, type(content_and_type.content)) - content_and_type.content = content_and_type.content.source - self._assertContent(content, 'text/html', content_and_type) - self.assertEqual(version, self._content_provider.GetVersion(path).Get()) - - def _assertMarkdownContent(self, content, path, version): - content_and_type = self._content_provider.GetContentAndType(path).Get() - content_and_type.content = content_and_type.content.source - self._assertContent(content, 'text/html', content_and_type) - self.assertEqual(version, self._content_provider.GetVersion(path).Get()) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testPlainText(self): - self._assertContent( - u'a.txt content', 'text/plain', - self._content_provider.GetContentAndType('dir/a.txt').Get()) - self._assertContent( - u'd.txt content', 'text/plain', - self._content_provider.GetContentAndType('dir/c/d.txt').Get()) - self._assertContent( - u'read.txt content', 'text/plain', - self._content_provider.GetContentAndType('read.txt').Get()) - self._assertContent( - unicode(_REDIRECTS_JSON, 'utf-8'), 'application/json', - self._content_provider.GetContentAndType('redirects.json').Get()) - self._assertContent( - u'run.js content', 'application/javascript', - self._content_provider.GetContentAndType('run.js').Get()) - self._assertContent( - u'site.css content', 'text/css', - self._content_provider.GetContentAndType('site.css').Get()) - - def testTemplate(self): - self._assertTemplateContent(u'storage.html content', 'storage.html', '0') - self._test_file_system.IncrementStat('storage.html') - self._assertTemplateContent(u'storage.html content', 'storage.html', '1') - - def testImage(self): - self._assertContent( - 'img.png content', 'image/png', - self._content_provider.GetContentAndType('img.png').Get()) - - def testZipTopLevel(self): - zip_content_provider = self._CreateContentProvider(supports_zip=True) - content_and_type = zip_content_provider.GetContentAndType('dir.zip').Get() - zipfile = ZipFile(StringIO(content_and_type.content)) - content_and_type.content = zipfile.namelist() - self._assertContent( - ['dir/a.txt', 'dir/b.txt', 'dir/c/d.txt'], 'application/zip', - content_and_type) - - def testZip2ndLevel(self): - zip_content_provider = self._CreateContentProvider(supports_zip=True) - content_and_type = zip_content_provider.GetContentAndType( - 'dir2/dir3.zip').Get() - zipfile = ZipFile(StringIO(content_and_type.content)) - content_and_type.content = zipfile.namelist() - self._assertContent( - ['dir3/a.txt', 'dir3/b.txt', 'dir3/c/d.txt'], 'application/zip', - content_and_type) - - def testCanonicalZipPaths(self): - # Without supports_zip the path is canonicalized as a file. - self.assertEqual( - 'dir.txt', - self._content_provider.GetCanonicalPath('dir.zip')) - self.assertEqual( - 'dir.txt', - self._content_provider.GetCanonicalPath('diR.zip')) - # With supports_zip the path is canonicalized as the zip file which - # corresponds to the canonical directory. - zip_content_provider = self._CreateContentProvider(supports_zip=True) - self.assertEqual( - 'dir.zip', - zip_content_provider.GetCanonicalPath('dir.zip')) - self.assertEqual( - 'dir.zip', - zip_content_provider.GetCanonicalPath('diR.zip')) - - def testMarkdown(self): - expected_content = '\n'.join(text[1] for text in _MARKDOWN_CONTENT) - self._assertMarkdownContent(expected_content, 'markdown', '0') - self._test_file_system.IncrementStat('markdown.md') - self._assertMarkdownContent(expected_content, 'markdown', '1') - - def testNotFound(self): - self.assertRaises( - FileNotFoundError, - self._content_provider.GetContentAndType('oops').Get) - - def testIndexRedirect(self): - self._assertTemplateContent(u'index.html content', '', '0') - self._assertTemplateContent(u'index.html content 1', 'dir4', '0') - self._assertTemplateContent(u'dir5.html content', 'dir5', '0') - self._assertMarkdownContent( - '\n'.join(text[1] for text in _MARKDOWN_CONTENT), - 'dir7', - '0') - self._assertContent( - 'noextension content', 'text/plain', - self._content_provider.GetContentAndType('noextension').Get()) - self.assertRaises( - FileNotFoundError, - self._content_provider.GetContentAndType('dir6').Get) - - def testRefresh(self): - # Not entirely sure what to test here, but get some code coverage. - self._content_provider.Refresh().Get() - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/content_providers.py b/chrome/common/extensions/docs/server2/content_providers.py deleted file mode 100644 index f06f3ee9..0000000 --- a/chrome/common/extensions/docs/server2/content_providers.py +++ /dev/null
@@ -1,175 +0,0 @@ -# Copyright 2013 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 logging -import os -import traceback - -from chroot_file_system import ChrootFileSystem -from content_provider import ContentProvider -import environment -from extensions_paths import CONTENT_PROVIDERS, LOCAL_DEBUG_DIR -from future import All, Future -from local_file_system import LocalFileSystem -from third_party.json_schema_compiler.memoize import memoize - - -_IGNORE_MISSING_CONTENT_PROVIDERS = [False] - - -def IgnoreMissingContentProviders(fn): - '''Decorates |fn| to ignore missing content providers during its run. - ''' - def run(*args, **optargs): - saved = _IGNORE_MISSING_CONTENT_PROVIDERS[0] - _IGNORE_MISSING_CONTENT_PROVIDERS[0] = True - try: - return fn(*args, **optargs) - finally: - _IGNORE_MISSING_CONTENT_PROVIDERS[0] = saved - return run - - -class ContentProviders(object): - '''Implements the content_providers.json configuration; see - chrome/common/extensions/docs/templates/json/content_providers.json for its - current state and a description of the format. - - Returns ContentProvider instances based on how they're configured there. - ''' - - def __init__(self, - object_store_creator, - compiled_fs_factory, - host_file_system, - gcs_file_system_provider): - self._object_store_creator = object_store_creator - self._compiled_fs_factory = compiled_fs_factory - self._host_file_system = host_file_system - self._gcs_file_system_provider = gcs_file_system_provider - self._cache = None - - # If running the devserver and there is a LOCAL_DEBUG_DIR, we - # will read the content_provider configuration from there instead - # of fetching it from Gitiles or patch. - if environment.IsDevServer() and os.path.exists(LOCAL_DEBUG_DIR): - local_fs = LocalFileSystem(LOCAL_DEBUG_DIR) - conf_stat = None - try: - conf_stat = local_fs.Stat(CONTENT_PROVIDERS) - except: - pass - - if conf_stat: - logging.warn(("Using local debug folder (%s) for " - "content_provider.json configuration") % LOCAL_DEBUG_DIR) - self._cache = compiled_fs_factory.ForJson(local_fs) - - if not self._cache: - self._cache = compiled_fs_factory.ForJson(host_file_system) - - @memoize - def GetByName(self, name): - '''Gets the ContentProvider keyed by |name| in content_providers.json, or - None of there is no such content provider. - ''' - config = self._GetConfig().get(name) - if config is None: - logging.error('No content provider found with name "%s"' % name) - return None - return self._CreateContentProvider(name, config) - - @memoize - def GetByServeFrom(self, path): - '''Gets a (content_provider, serve_from, path_in_content_provider) tuple, - where content_provider is the ContentProvider with the longest "serveFrom" - property that is a subpath of |path|, serve_from is that property, and - path_in_content_provider is the remainder of |path|. - - For example, if content provider A serves from "foo" and content provider B - serves from "foo/bar", GetByServeFrom("foo/bar/baz") will return (B, - "foo/bar", "baz"). - - Returns (None, '', |path|) if no ContentProvider serves from |path|. - ''' - serve_from_to_config = dict( - (config['serveFrom'], (name, config)) - for name, config in self._GetConfig().iteritems()) - path_parts = path.split('/') - for i in xrange(len(path_parts), -1, -1): - name_and_config = serve_from_to_config.get('/'.join(path_parts[:i])) - if name_and_config is not None: - return (self._CreateContentProvider(name_and_config[0], - name_and_config[1]), - '/'.join(path_parts[:i]), - '/'.join(path_parts[i:])) - return None, '', path - - def _GetConfig(self): - return self._cache.GetFromFile(CONTENT_PROVIDERS).Get() - - def _CreateContentProvider(self, name, config): - default_extensions = config.get('defaultExtensions', ()) - supports_templates = config.get('supportsTemplates', False) - supports_zip = config.get('supportsZip', False) - - if 'chromium' in config: - chromium_config = config['chromium'] - if 'dir' not in chromium_config: - logging.error('%s: "chromium" must have a "dir" property' % name) - return None - file_system = ChrootFileSystem(self._host_file_system, - - chromium_config['dir']) - elif 'gcs' in config: - gcs_config = config['gcs'] - if 'bucket' not in gcs_config: - logging.error('%s: "gcs" must have a "bucket" property' % name) - return None - bucket = gcs_config['bucket'] - if not bucket.startswith('gs://'): - logging.error('%s: bucket %s should start with gs://' % (name, bucket)) - return None - bucket = bucket[len('gs://'):] - file_system = self._gcs_file_system_provider.Create(bucket) - if 'dir' in gcs_config: - file_system = ChrootFileSystem(file_system, gcs_config['dir']) - - else: - logging.error('%s: content provider type not supported' % name) - return None - - return ContentProvider(name, - self._compiled_fs_factory, - file_system, - self._object_store_creator, - default_extensions=default_extensions, - supports_templates=supports_templates, - supports_zip=supports_zip) - - def Refresh(self): - def safe(name, action, callback): - '''Safely runs |callback| for a ContentProvider called |name| by - swallowing exceptions and turning them into a None return value. It's - important to run all ContentProvider Refreshes even if some of them fail. - ''' - try: - return callback() - except: - if not _IGNORE_MISSING_CONTENT_PROVIDERS[0]: - logging.error('Error %s Refresh for ContentProvider "%s":\n%s' % - (action, name, traceback.format_exc())) - return None - - def refresh_provider(path, config): - provider = self._CreateContentProvider(path, config) - future = safe(path, - 'initializing', - self._CreateContentProvider(path, config).Refresh) - if future is None: - return Future(callback=lambda: True) - return Future(callback=lambda: safe(path, 'resolving', future.Get)) - - return All(refresh_provider(path, config) - for path, config in self._GetConfig().iteritems())
diff --git a/chrome/common/extensions/docs/server2/content_providers_test.py b/chrome/common/extensions/docs/server2/content_providers_test.py deleted file mode 100755 index eaa39d5..0000000 --- a/chrome/common/extensions/docs/server2/content_providers_test.py +++ /dev/null
@@ -1,149 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 json -import unittest - -from compiled_file_system import CompiledFileSystem -from content_providers import ContentProviders -from extensions_paths import CHROME_EXTENSIONS -from gcs_file_system_provider import CloudStorageFileSystemProvider -from object_store_creator import ObjectStoreCreator -from test_file_system import TestFileSystem -from test_util import DisableLogging - - -_CONTENT_PROVIDERS = { - 'apples': { - 'chromium': { - 'dir': 'chrome/common/extensions/apples' - }, - 'serveFrom': 'apples-dir', - }, - 'bananas': { - 'serveFrom': '', - 'chromium': { - 'dir': 'chrome/common/extensions' - }, - }, - 'tomatoes': { - 'serveFrom': 'tomatoes-dir/are/a', - 'chromium': { - 'dir': 'chrome/common/extensions/tomatoes/are/a' - }, - }, -} - - -_FILE_SYSTEM_DATA = { - 'docs': { - 'templates': { - 'json': { - 'content_providers.json': json.dumps(_CONTENT_PROVIDERS), - }, - }, - }, - 'apples': { - 'gala.txt': 'gala apples', - 'green': { - 'granny smith.txt': 'granny smith apples', - }, - }, - 'tomatoes': { - 'are': { - 'a': { - 'vegetable.txt': 'no they aren\'t', - 'fruit': { - 'cherry.txt': 'cherry tomatoes', - }, - }, - }, - }, -} - -class ContentProvidersTest(unittest.TestCase): - def setUp(self): - object_store_creator = ObjectStoreCreator.ForTest() - test_file_system = TestFileSystem(_FILE_SYSTEM_DATA, - relative_to=CHROME_EXTENSIONS) - object_store_creator = ObjectStoreCreator.ForTest() - # TODO(mangini): create tests for GCS - self._gcs_fs_provider = CloudStorageFileSystemProvider(object_store_creator) - self._content_providers = ContentProviders( - object_store_creator, - CompiledFileSystem.Factory(object_store_creator), - test_file_system, - self._gcs_fs_provider) - - def testSimpleRootPath(self): - provider = self._content_providers.GetByName('apples') - self.assertEqual( - 'gala apples', - provider.GetContentAndType('gala.txt').Get().content) - self.assertEqual( - 'granny smith apples', - provider.GetContentAndType('green/granny smith.txt').Get().content) - - def testComplexRootPath(self): - provider = self._content_providers.GetByName('tomatoes') - self.assertEqual( - 'no they aren\'t', - provider.GetContentAndType('vegetable.txt').Get().content) - self.assertEqual( - 'cherry tomatoes', - provider.GetContentAndType('fruit/cherry.txt').Get().content) - - def testParentRootPath(self): - provider = self._content_providers.GetByName('bananas') - self.assertEqual( - 'gala apples', - provider.GetContentAndType('apples/gala.txt').Get().content) - - def testSimpleServlet(self): - provider, serve_from, path = self._content_providers.GetByServeFrom( - 'apples-dir') - self.assertEqual('apples', provider.name) - self.assertEqual('apples-dir', serve_from) - self.assertEqual('', path) - provider, serve_from, path = self._content_providers.GetByServeFrom( - 'apples-dir/') - self.assertEqual('apples', provider.name) - self.assertEqual('apples-dir', serve_from) - self.assertEqual('', path) - provider, serve_from, path = self._content_providers.GetByServeFrom( - 'apples-dir/are/forever') - self.assertEqual('apples', provider.name) - self.assertEqual('apples-dir', serve_from) - self.assertEqual('are/forever', path) - - def testComplexServlet(self): - provider, serve_from, path = self._content_providers.GetByServeFrom( - 'tomatoes-dir/are/a') - self.assertEqual('tomatoes', provider.name) - self.assertEqual('tomatoes-dir/are/a', serve_from) - self.assertEqual('', path) - provider, serve_from, path = self._content_providers.GetByServeFrom( - 'tomatoes-dir/are/a/fruit/they/are') - self.assertEqual('tomatoes', provider.name) - self.assertEqual('tomatoes-dir/are/a', serve_from) - self.assertEqual('fruit/they/are', path) - - def testEmptyStringServlet(self): - provider, serve_from, path = self._content_providers.GetByServeFrom( - 'tomatoes-dir/are') - self.assertEqual('bananas', provider.name) - self.assertEqual('', serve_from) - self.assertEqual('tomatoes-dir/are', path) - provider, serve_from, path = self._content_providers.GetByServeFrom('') - self.assertEqual('bananas', provider.name) - self.assertEqual('', serve_from) - self.assertEqual('', path) - - @DisableLogging('error') - def testProviderNotFound(self): - self.assertEqual(None, self._content_providers.GetByName('cabbages')) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/converter_html_parser.py b/chrome/common/extensions/docs/server2/converter_html_parser.py deleted file mode 100644 index 9e0db14..0000000 --- a/chrome/common/extensions/docs/server2/converter_html_parser.py +++ /dev/null
@@ -1,58 +0,0 @@ -# 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 HTMLParser import HTMLParser -from StringIO import StringIO - -class _ConverterHTMLParser(HTMLParser): - def __init__(self, io): - HTMLParser.__init__(self) - self._io = io - self._tag_stack = [] - - def handle_starttag(self, tag, attrs): - attrs_dict = dict(attrs) - self._tag_stack.append({'tag': tag}) - class_attr = dict(attrs).get('class', None) - if class_attr is not None: - if class_attr == 'doc-family extensions': - self._io.write('{{^is_apps}}\n') - self._tag_stack[-1]['close'] = True - if class_attr == 'doc-family apps': - self._io.write('{{?is_apps}}\n') - self._tag_stack[-1]['close'] = True - self._io.write(self.get_starttag_text()) - - def handle_startendtag(self, tag, attrs): - self._io.write(self.get_starttag_text()) - - def handle_endtag(self, tag): - self._io.write('</' + tag + '>') - if len(self._tag_stack) == 0: - return - if self._tag_stack[-1]['tag'] == tag: - if self._tag_stack[-1].get('close', False): - self._io.write('\n{{/is_apps}}') - self._tag_stack.pop() - - def handle_data(self, data): - self._io.write(data) - - def handle_comment(self, data): - self._io.write('<!--' + data + '-->') - - def handle_entityref(self, name): - self._io.write('&' + name + ';') - - def handle_charref(self, name): - self._io.write('&#' + name + ';') - - def handle_decl(self, data): - self._io.write('<!' + data + '>') - -def HandleDocFamily(html): - output = StringIO() - parser = _ConverterHTMLParser(output) - parser.feed(html) - return output.getvalue()
diff --git a/chrome/common/extensions/docs/server2/custom_logger.py b/chrome/common/extensions/docs/server2/custom_logger.py deleted file mode 100644 index d651612b..0000000 --- a/chrome/common/extensions/docs/server2/custom_logger.py +++ /dev/null
@@ -1,34 +0,0 @@ -# Copyright 2014 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 logging - -from environment import IsAppEngine - - -class CustomLogger(object): - '''Wraps logging methods to include a prefix and flush immediately. - The flushing is important because logging is often done from jobs - which may time out, thus losing unflushed logs. - ''' - def __init__(self, prefix): - self._prefix = prefix - - def info(self, msg, *args): self._log(logging.info, msg, args) - def warning(self, msg, *args): self._log(logging.warning, msg, args) - def error(self, msg, *args): self._log(logging.error, msg, args) - - def _log(self, logfn, msg, args): - try: - logfn('%s: %s' % (self._prefix, msg), *args) - finally: - self.flush() - - if IsAppEngine(): - from google.appengine.api.logservice import logservice - def flush(self): - logservice.flush() - else: - def flush(self): - pass
diff --git a/chrome/common/extensions/docs/server2/data_source.py b/chrome/common/extensions/docs/server2/data_source.py deleted file mode 100644 index a503655..0000000 --- a/chrome/common/extensions/docs/server2/data_source.py +++ /dev/null
@@ -1,33 +0,0 @@ -# Copyright 2013 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. - - -class DataSource(object): - ''' - Defines an abstraction for all DataSources. - - DataSources must have two public methods, get and Refresh. A DataSource is - initialized with a ServerInstance and a Request (defined in servlet.py). - Anything in the ServerInstance can be used by the DataSource. Request is None - when DataSources are created for Refresh. - - DataSources are used to provide templates with access to data. DataSources may - not access other DataSources and any logic or data that is useful to other - DataSources must be moved to a different class. - ''' - def __init__(self, server_instance, request): - pass - - def Refresh(self): - '''Refreshes the cache of data this source provides. Should return a Future - which resolves to a boolean indicating the success or failure of the - refresh. - ''' - raise NotImplementedError(self.__class__) - - def get(self, key): - '''Returns a dictionary or list that can be consumed by a template. Called - on an offline file system and can only access files in the cache. - ''' - raise NotImplementedError(self.__class__)
diff --git a/chrome/common/extensions/docs/server2/data_source_registry.py b/chrome/common/extensions/docs/server2/data_source_registry.py deleted file mode 100644 index 43161e3..0000000 --- a/chrome/common/extensions/docs/server2/data_source_registry.py +++ /dev/null
@@ -1,58 +0,0 @@ -# Copyright 2013 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 api_data_source import APIDataSource -from api_list_data_source import APIListDataSource -from data_source import DataSource -from manifest_data_source import ManifestDataSource -from owners_data_source import OwnersDataSource -from permissions_data_source import PermissionsDataSource -from samples_data_source import SamplesDataSource -from sidenav_data_source import SidenavDataSource -from strings_data_source import StringsDataSource -from template_data_source import ( - ArticleDataSource, IntroDataSource, PartialDataSource) -from whats_new_data_source import WhatsNewDataSource - - -_all_data_sources = { - 'apis': APIDataSource, - 'api_list': APIListDataSource, - 'articles': ArticleDataSource, - 'intros': IntroDataSource, - 'manifest_source': ManifestDataSource, - 'owners': OwnersDataSource, - 'partials': PartialDataSource, - 'permissions': PermissionsDataSource, - 'samples': SamplesDataSource, - 'sidenavs': SidenavDataSource, - 'strings': StringsDataSource, - 'whatsNew' : WhatsNewDataSource -} - - -assert all(issubclass(cls, DataSource) - for cls in _all_data_sources.itervalues()) - - -def GetDataSourceNames(): - return _all_data_sources.keys() - - -def CreateDataSource(name, server_instance, request=None): - '''Create a single DataSource by name.''' - assert name in _all_data_sources - return _all_data_sources[name](server_instance, request) - - -def CreateDataSources(server_instance, request=None): - '''Create a dictionary of initialized DataSources. DataSources are - initialized with |server_instance| and |request|. If the DataSources are - going to be used for Refresh, |request| should be omitted. - - The key of each DataSource is the name the template system will use to access - the DataSource. - ''' - return dict((name, cls(server_instance, request)) - for name, cls in _all_data_sources.iteritems())
diff --git a/chrome/common/extensions/docs/server2/datastore_models.py b/chrome/common/extensions/docs/server2/datastore_models.py deleted file mode 100644 index eaa8cab..0000000 --- a/chrome/common/extensions/docs/server2/datastore_models.py +++ /dev/null
@@ -1,44 +0,0 @@ -# Copyright 2013 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 cPickle -import google.appengine.ext.db as db -import logging -import traceback - - -_MAX_ENTITY_SIZE = 1024*1024 - - -# A collection of the data store models used throughout the server. -# These values are global within datastore. - -class PersistentObjectStoreItem(db.Model): - pickled_value = db.BlobProperty() - - @classmethod - def CreateKey(cls, namespace, key): - path = '%s/%s' % (namespace, key) - try: - return db.Key.from_path(cls.__name__, path) - except Exception: - # Probably AppEngine's BadValueError for the name being too long, but - # it's not documented which errors can actually be thrown here, so catch - # 'em all. - raise ValueError( - 'Exception thrown when trying to create db.Key from path %s: %s' % ( - path, traceback.format_exc())) - - @classmethod - def CreateItem(cls, namespace, key, value): - pickled_value = cPickle.dumps(value) - if len(pickled_value) > _MAX_ENTITY_SIZE: - logging.warn('Refusing to create entity greater than 1 MB in size: %s/%s' - % (namespace, key)) - return None - return PersistentObjectStoreItem(key=cls.CreateKey(namespace, key), - pickled_value=pickled_value) - - def GetValue(self): - return cPickle.loads(self.pickled_value)
diff --git a/chrome/common/extensions/docs/server2/datastore_util.py b/chrome/common/extensions/docs/server2/datastore_util.py deleted file mode 100644 index 21464363..0000000 --- a/chrome/common/extensions/docs/server2/datastore_util.py +++ /dev/null
@@ -1,131 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import cPickle -import logging - -from future import Future -from gcloud import datastore - -# N.B.: In order to use this module you should have a working cloud development -# environment configured with the googledatastore module installed. -# -# Please see https://cloud.google.com/datastore/docs/getstarted/start_python/ - - -_PROJECT_NAME = 'chrome-apps-doc' -_PERSISTENT_OBJECT_KIND = 'PersistentObjectStoreItem' -_VALUE_PROPERTY_NAME = 'pickled_value' - -# The max number of entities to include in a single request. This is capped at -# 500 by the service. In practice we may send fewer due to _MAX_REQUEST_SIZE -_MAX_BATCH_SIZE = 500 - - -# The maximum entity size allowed by Datastore. -_MAX_ENTITY_SIZE = 1024*1024 - - -# The maximum request size (in bytes) to send Datastore. This is an approximate -# size based on the sum of entity blob_value sizes. -_MAX_REQUEST_SIZE = 5*1024*1024 - - -def _CreateEntity(client, name, value): - key = client.key(_PERSISTENT_OBJECT_KIND, name) - entity = datastore.Entity( - key=key, exclude_from_indexes=[_VALUE_PROPERTY_NAME]) - entity[_VALUE_PROPERTY_NAME] = value - return entity - - -def _CreateBatches(client, data): - '''Constructs batches of at most _MAX_BATCH_SIZE entities to cover all - entities defined in |data| without exceeding the transaction size limit. - This is a generator emitting lists of entities. - ''' - def get_size(entity): - return len(entity[_VALUE_PROPERTY_NAME]) - - entities = [_CreateEntity(client, name, value) - for name, value in data.iteritems()] - batch_start = 0 - batch_end = 1 - batch_size = get_size(entities[0]) - while batch_end < len(entities): - next_size = get_size(entities[batch_end]) - if (batch_size + next_size > _MAX_REQUEST_SIZE or - batch_end - batch_start >= _MAX_BATCH_SIZE): - yield entities[batch_start:batch_end], batch_end, len(entities) - batch_start = batch_end - batch_size = 0 - else: - batch_size += next_size - batch_end = batch_end + 1 - if batch_end > batch_start and batch_start < len(entities): - yield entities[batch_start:batch_end], batch_end, len(entities) - - -def PushData(data, original_data={}): - '''Pushes a bunch of data into the datastore. The data should be a dict. Each - key is treated as a namespace, and each value is also a dict. A new datastore - entry is upserted for every inner key, with the value pickled into the - |pickled_value| field. - - For example, if given the dictionary: - - { - 'fruit': { - 'apple': 1234, - 'banana': 'yellow', - 'trolling carrot': { 'arbitrarily complex': ['value', 'goes', 'here'] } - }, - 'animal': { - 'sheep': 'baaah', - 'dog': 'woof', - 'trolling cat': 'moo' - } - } - - this would result in a push of 6 keys in total, with the following IDs: - - Key('PersistentObjectStoreItem', 'fruit/apple') - Key('PersistentObjectStoreItem', 'fruit/banana') - Key('PersistentObjectStoreItem', 'fruit/trolling carrot') - Key('PersistentObjectStoreItem', 'animal/sheep') - Key('PersistentObjectStoreItem', 'animal/dog') - Key('PersistentObjectStoreItem', 'animal/trolling cat') - - If given |original_data|, this will only push key-value pairs for entries that - are either new or have changed from their original (pickled) value. - - Caveat: Pickling and unpickling a dictionary can (but does not always) change - its key order. This means that objects will often be seen as changed even when - they haven't changed. - ''' - client = datastore.Client(_PROJECT_NAME) - - def flatten(dataset): - flat = {} - for namespace, items in dataset.iteritems(): - for k, v in items.iteritems(): - flat['%s/%s' % (namespace, k)] = cPickle.dumps(v) - return flat - - logging.info('Flattening data sets...') - data = flatten(data) - original_data = flatten(original_data) - - logging.info('Culling new data...') - for k in data.keys(): - if ((k in original_data and original_data[k] == data[k]) or - (len(data[k]) > _MAX_ENTITY_SIZE)): - del data[k] - - for entities, n, total in _CreateBatches(client, data): - batch = client.batch() - for e in entities: - batch.put(e) - logging.info('Committing %s/%s entities...' % (n, total)) - batch.commit()
diff --git a/chrome/common/extensions/docs/server2/directory_zipper.py b/chrome/common/extensions/docs/server2/directory_zipper.py deleted file mode 100644 index 6d16225..0000000 --- a/chrome/common/extensions/docs/server2/directory_zipper.py +++ /dev/null
@@ -1,54 +0,0 @@ -# Copyright 2013 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 io import BytesIO -import posixpath -from zipfile import ZipFile - -from compiled_file_system import SingleFile - - -class DirectoryZipper(object): - '''Creates zip files of whole directories. - ''' - - def __init__(self, compiled_fs_factory, file_system): - self._file_system = file_system - self._zip_cache = compiled_fs_factory.Create(file_system, - self._MakeZipFile, - DirectoryZipper) - - # NOTE: It's ok to specify SingleFile here even though this method reads - # multiple files. All files are underneath |base_dir|. If any file changes its - # stat will change, so the stat of |base_dir| will also change. - @SingleFile - def _MakeZipFile(self, base_dir, files): - base_dir = base_dir.strip('/') - zip_bytes = BytesIO() - with ZipFile(zip_bytes, mode='w') as zip_file: - futures_with_name = [ - (file_name, - self._file_system.ReadSingle(posixpath.join(base_dir, file_name))) - for file_name in files] - for file_name, future in futures_with_name: - file_contents = future.Get() - if isinstance(file_contents, unicode): - # Data is sometimes already cached as unicode. - file_contents = file_contents.encode('utf8') - # We want e.g. basic.zip to expand to basic/manifest.json etc, not - # chrome/common/extensions/.../basic/manifest.json, so only use the - # end of the path component when writing into the zip file. - dir_name = posixpath.basename(base_dir) - zip_file.writestr(posixpath.join(dir_name, file_name), file_contents) - return zip_bytes.getvalue() - - def Zip(self, path): - '''Creates a new zip file from the recursive contents of |path| as returned - by |_zip_cache|. - - Paths within the zip file will be relative to and include the last - component of |path|, such that when zipping foo/bar containing baf.txt and - qux.txt will return a zip file which unzips to bar/baz.txt and bar/qux.txt. - ''' - return self._zip_cache.GetFromFileListing(path)
diff --git a/chrome/common/extensions/docs/server2/directory_zipper_test.py b/chrome/common/extensions/docs/server2/directory_zipper_test.py deleted file mode 100755 index 040bd43e..0000000 --- a/chrome/common/extensions/docs/server2/directory_zipper_test.py +++ /dev/null
@@ -1,55 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest -from cStringIO import StringIO -from zipfile import ZipFile - -from compiled_file_system import CompiledFileSystem -from directory_zipper import DirectoryZipper -from file_system import FileNotFoundError -from test_file_system import TestFileSystem -from object_store_creator import ObjectStoreCreator - - -_TEST_DATA = { - 'top': { - 'one.txt': 'one.txt contents', - 'two': { - 'three.txt': 'three.txt contents', - 'four.txt': 'four.txt contents', - }, - } -} - - -class DirectoryZipperTest(unittest.TestCase): - def setUp(self): - self._directory_zipper = DirectoryZipper( - CompiledFileSystem.Factory(ObjectStoreCreator.ForTest()), - TestFileSystem(_TEST_DATA)) - - def testTopZip(self): - top_zip = ZipFile(StringIO(self._directory_zipper.Zip('top/').Get())) - self.assertEqual(['top/one.txt', 'top/two/four.txt', 'top/two/three.txt'], - sorted(top_zip.namelist())) - self.assertEqual('one.txt contents', top_zip.read('top/one.txt')) - self.assertEqual('three.txt contents', top_zip.read('top/two/three.txt')) - self.assertEqual('four.txt contents', top_zip.read('top/two/four.txt')) - - def testTwoZip(self): - two_zip = ZipFile(StringIO(self._directory_zipper.Zip('top/two/').Get())) - self.assertEqual(['two/four.txt', 'two/three.txt'], - sorted(two_zip.namelist())) - self.assertEqual('three.txt contents', two_zip.read('two/three.txt')) - self.assertEqual('four.txt contents', two_zip.read('two/four.txt')) - - def testNotFound(self): - self.assertRaises(FileNotFoundError, - self._directory_zipper.Zip('notfound/').Get) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/docs_server_utils.py b/chrome/common/extensions/docs/server2/docs_server_utils.py deleted file mode 100644 index 7fe962e..0000000 --- a/chrome/common/extensions/docs/server2/docs_server_utils.py +++ /dev/null
@@ -1,61 +0,0 @@ -# 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 base64 import b64encode -from hashlib import sha1 -import os - -def FormatKey(key): - '''Normalize a key by making sure it has a .html extension, and convert any - '.'s to '_'s. - ''' - if key.endswith('.html'): - key = key[:-len('.html')] - safe_key = key.replace('.', '_') - return '%s.html' % safe_key - -def SanitizeAPIName(name): - '''Sanitizes API filenames that are in subdirectories. - ''' - filename = os.path.splitext(name)[0].replace(os.sep, '_') - if 'experimental' in filename: - filename = 'experimental_' + filename.replace('experimental_', '') - return filename - -def StringIdentity(first, *more): - '''Creates a small hash of a string. - ''' - def encode(string): - return b64encode(sha1(string).digest()) - identity = encode(first) - for m in more: - identity = encode(identity + m) - return identity[:8] - -def MarkFirst(dicts): - '''Adds a property 'first' == True to the first element in a list of dicts. - ''' - if len(dicts) > 0: - dicts[0]['first'] = True - -def MarkLast(dicts): - '''Adds a property 'last' == True to the last element in a list of dicts. - ''' - if len(dicts) > 0: - dicts[-1]['last'] = True - -def MarkFirstAndLast(dicts): - '''Marks the first and last element in a list of dicts. - ''' - MarkFirst(dicts) - MarkLast(dicts) - -def ToUnicode(data): - '''Returns the str |data| as a unicode object. It's expected to be utf8, but - there are also latin-1 encodings in there for some reason. Fall back to that. - ''' - try: - return unicode(data, 'utf-8') - except: - return unicode(data, 'latin-1')
diff --git a/chrome/common/extensions/docs/server2/docs_server_utils_test.py b/chrome/common/extensions/docs/server2/docs_server_utils_test.py deleted file mode 100755 index fd4539c3..0000000 --- a/chrome/common/extensions/docs/server2/docs_server_utils_test.py +++ /dev/null
@@ -1,29 +0,0 @@ -#!/usr/bin/env python -# Copyright 2014 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 unittest - -from docs_server_utils import StringIdentity - - -class DocsServerUtilsTest(unittest.TestCase): - '''Tests for methods in docs_server_utils. - ''' - - # TODO(kalman): There are a bunch of methods in docs_server_utils. - # Test them all. - - def testStringIdentity(self): - # The important part really is that these are all different. - self.assertEqual('C+7Hteo/', StringIdentity('foo')) - self.assertEqual('Ys23Ag/5', StringIdentity('bar')) - self.assertEqual('T5FOBOjX', StringIdentity('foo', 'bar')) - self.assertEqual('K7XzI1GD', StringIdentity('bar', 'foo')) - self.assertEqual('CXypceHn', StringIdentity('foo', 'bar', 'baz')) - self.assertEqual('gGo0GTF6', StringIdentity('foo', 'baz', 'bar')) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/document_parser.py b/chrome/common/extensions/docs/server2/document_parser.py deleted file mode 100644 index bfd88e7..0000000 --- a/chrome/common/extensions/docs/server2/document_parser.py +++ /dev/null
@@ -1,221 +0,0 @@ -# Copyright 2013 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 HTMLParser import HTMLParser - - -class ParseResult(object): - '''The result of |ParseDocument|: - |title| The title of the page, as pulled from the first <h1>. - |title_attributes| The attributes of the <h1> tag the title is derived from. - |sections| The list of Sections within this document. - |warnings| Any warnings while parsing the document. - ''' - - def __init__(self, title, title_attributes, sections, warnings): - self.title = title - self.title_attributes = title_attributes - self.sections = sections - self.warnings = warnings - - -class DocumentSection(object): - '''A section of the document as grouped by <section>...</section>. Any content - not within section tags is considered an implicit section, so: - "Foo <section>Bar</section> Baz" is 3 sections. - |structure| A list of DocumentStructureEntry for each top-level heading. - ''' - - def __init__(self): - self.structure = [] - - -class DocumentStructureEntry(object): - '''An entry in the document structure. - |attributes| The attributes of the header tag this entry is derived from. - |name| The name of this entry, as pulled from the header tag this entry - is derived from. - |entries| A list of child DocumentStructureEntry items. - ''' - - def __init__(self, tag, attributes): - self.attributes = attributes - self.name = '' - self.entries = [] - # Callers shouldn't care about the tag, but we need it for sanity checking, - # so make it private. In particular we pretend that anything but the first - # h1 is an h2, and it'd be odd to expose that. - self._tag = tag - # Documents can override the name of the entry using title="". - self._has_explicit_name = False - - def __repr__(self): - return '<%s>%s</%s>' % (self._tag, self.name, self._tag) - - def __str__(self): - return repr(self) - - -def ParseDocument(document, expect_title=False): - '''Parses the title and a document structure form |document| and returns a - ParseResult. - ''' - parser = _DocumentParser(expect_title) - parser.feed(document) - parser.close() - return parser.parse_result - - -def RemoveTitle(document): - '''Removes the first <h1>..</h1> tag found in |document| and returns a - (result, warning) tuple. - - If no title is found or |document| is malformed in some way, returns the - original document and a warning message. Otherwise, returns the result of - removing the title from |document| with a None warning message. - ''' - - def min_index(lhs, rhs): - lhs_index, rhs_index = document.find(lhs), document.find(rhs) - if lhs_index == -1: return rhs_index - if rhs_index == -1: return lhs_index - return min(lhs_index, rhs_index) - - title_start = min_index('<h1', '<H1') - if title_start == -1: - return document, 'No opening <h1> was found' - title_end = min_index('/h1>', '/H1>') - if title_end == -1: - return document, 'No closing </h1> was found' - if title_end < title_start: - return document, 'The </h1> appeared before the <h1>' - - return (document[:title_start] + document[title_end + 4:], None) - - -_HEADER_TAGS = ['h2', 'h3', 'h4'] - - -class _DocumentParser(HTMLParser): - '''HTMLParser for ParseDocument. - ''' - - def __init__(self, expect_title): - HTMLParser.__init__(self) - # Public. - self.parse_result = None - # Private. - self._expect_title = expect_title - self._title_entry = None - self._sections = [] - self._processing_section = DocumentSection() - self._processing_entry = None - self._warnings = [] - - def handle_starttag(self, tag, attrs): - if tag == 'section': - self._OnSectionBoundary() - return - - if tag != 'h1' and tag not in _HEADER_TAGS: - return - - if self._processing_entry is not None: - self._WarnWithPosition('Found <%s> in the middle of processing a <%s>' % - (tag, self._processing_entry._tag)) - return - - attrs_dict = dict(attrs) - self._processing_entry = DocumentStructureEntry(tag, attrs_dict) - - explicit_name = attrs_dict.pop('title', None) - if explicit_name == '': - # Don't create a TOC entry at all if the tag has specified title="". - return - if explicit_name is not None: - self._processing_entry.name = explicit_name - self._processing_entry._has_explicit_name = True - - if tag == 'h1' and self._title_entry is not None: - self._WarnWithPosition('Found multiple <h1> tags. Subsequent <h1> tags ' - 'will be classified as <h2> for the purpose of ' - 'the structure') - tag = 'h2' - - if tag == 'h1': - self._title_entry = self._processing_entry - else: - belongs_to = self._processing_section.structure - for header in _HEADER_TAGS[:_HEADER_TAGS.index(tag)]: - if len(belongs_to) == 0: - # TODO(kalman): Re-enable this warning once the reference pages have - # their references fixed. - #self._WarnWithPosition('Found <%s> without any preceding <%s>' % - # (tag, header)) - break - belongs_to = belongs_to[-1].entries - belongs_to.append(self._processing_entry) - - def handle_endtag(self, tag): - if tag == 'section': - self._OnSectionBoundary() - return - - if tag != 'h1' and tag not in _HEADER_TAGS: - return - - if self._processing_entry is None: - self._WarnWithPosition('Found closing </%s> without an opening <%s>' % - (tag, tag)) - return - - if self._processing_entry._tag != tag: - self._WarnWithPosition('Found closing </%s> while processing a <%s>' % - (tag, self._processing_entry._tag)) - # Note: no early return, it's more likely that the mismatched header was - # a typo rather than a misplaced closing header tag. - - self._processing_entry = None - - def handle_data(self, data): - if (self._processing_entry is not None and - not self._processing_entry._has_explicit_name): - # += is inefficient, but probably fine here because the chances of a - # large number of nested tags within header tags is pretty low. - self._processing_entry.name += data - - def close(self): - HTMLParser.close(self) - - self._OnSectionBoundary() - - if self._processing_entry is not None: - self._warnings.append('Finished parsing while still processing a <%s>' % - parser._processing_entry._tag) - - if self._expect_title: - if not self._title_entry: - self._warnings.append('Expected a title') - title, title_attributes = '', {} - else: - title, title_attributes = ( - self._title_entry.name, self._title_entry.attributes) - else: - if self._title_entry: - self._warnings.append('Found unexpected title "%s"' % - self._title_entry.name) - title, title_attributes = None, None - - self.parse_result = ParseResult( - title, title_attributes, self._sections, self._warnings) - - def _OnSectionBoundary(self): - # Only start a new section if the previous section was non-empty. - if self._processing_section.structure: - self._sections.append(self._processing_section) - self._processing_section = DocumentSection() - - def _WarnWithPosition(self, message): - line, col = self.getpos() - self._warnings.append('%s (line %s, column %s)' % (message, line, col + 1))
diff --git a/chrome/common/extensions/docs/server2/document_parser_test.py b/chrome/common/extensions/docs/server2/document_parser_test.py deleted file mode 100755 index 855561a..0000000 --- a/chrome/common/extensions/docs/server2/document_parser_test.py +++ /dev/null
@@ -1,257 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from document_parser import ParseDocument, RemoveTitle - - -_WHOLE_DOCUMENT = ''' -Preamble before heading. - -<h1 id='main' class='header'>Main header</h1> -Some intro to the content. - -<h2 id='banana' class='header' title=''>Bananas</h2> -Something about bananas. - -<h2 id='orange' title='hello'>Oranges</h2> -Something about oranges. - -<h3 id='valencia'>Valencia Oranges</h3> -A description of valencia oranges. - -<h3 id='seville'>Seville Oranges</h3> -A description of seville oranges. - -<h2>Grapefruit</h3> -Grapefruit closed a h2 with a h3. This should be a warning. - -<h1 id='not-main'>Not the main header</h1> -But it should still show up in the TOC as though it were an h2. - -<h2>Not <h3>a banana</h2> -The embedded h3 should be ignored. - -<h4>It's a h4</h4> -h4 are part of the document structure, but this is not inside a h3. - -<h3>Plantains</h3> -Now I'm just getting lazy. - -<h4>Another h4</h4> -This h4 is inside a h3 so will show up. - -<h5>Header 5</h5> -Header 5s are not parsed. -''' - - -_WHOLE_DOCUMENT_WITHOUT_TITLE = ''' -Preamble before heading. - - -Some intro to the content. - -<h2 id='banana' class='header' title=''>Bananas</h2> -Something about bananas. - -<h2 id='orange' title='hello'>Oranges</h2> -Something about oranges. - -<h3 id='valencia'>Valencia Oranges</h3> -A description of valencia oranges. - -<h3 id='seville'>Seville Oranges</h3> -A description of seville oranges. - -<h2>Grapefruit</h3> -Grapefruit closed a h2 with a h3. This should be a warning. - -<h1 id='not-main'>Not the main header</h1> -But it should still show up in the TOC as though it were an h2. - -<h2>Not <h3>a banana</h2> -The embedded h3 should be ignored. - -<h4>It's a h4</h4> -h4 are part of the document structure, but this is not inside a h3. - -<h3>Plantains</h3> -Now I'm just getting lazy. - -<h4>Another h4</h4> -This h4 is inside a h3 so will show up. - -<h5>Header 5</h5> -Header 5s are not parsed. -''' - - -class DocumentParserUnittest(unittest.TestCase): - - def testEmptyDocument(self): - self.assertEqual(('', 'No opening <h1> was found'), RemoveTitle('')) - - result = ParseDocument('') - self.assertEqual(None, result.title) - self.assertEqual(None, result.title_attributes) - self.assertEqual([], result.sections) - self.assertEqual([], result.warnings) - - result = ParseDocument('', expect_title=True) - self.assertEqual('', result.title) - self.assertEqual({}, result.title_attributes) - self.assertEqual([], result.sections) - self.assertEqual(['Expected a title'], result.warnings) - - def testRemoveTitle(self): - no_closing_tag = '<h1>No closing tag' - self.assertEqual((no_closing_tag, 'No closing </h1> was found'), - RemoveTitle(no_closing_tag)) - - no_opening_tag = 'No opening tag</h1>' - self.assertEqual((no_opening_tag, 'No opening <h1> was found'), - RemoveTitle(no_opening_tag)) - - tags_wrong_order = '</h1>Tags in wrong order<h1>' - self.assertEqual((tags_wrong_order, 'The </h1> appeared before the <h1>'), - RemoveTitle(tags_wrong_order)) - - multiple_titles = '<h1>First header</h1> and <h1>Second header</h1>' - self.assertEqual((' and <h1>Second header</h1>', None), - RemoveTitle(multiple_titles)) - - upper_case = '<H1>Upper case header tag</H1> hi' - self.assertEqual((' hi', None), RemoveTitle(upper_case)) - mixed_case = '<H1>Mixed case header tag</h1> hi' - self.assertEqual((' hi', None), RemoveTitle(mixed_case)) - - def testOnlyTitleDocument(self): - document = '<h1 id="header">heading</h1>' - self.assertEqual(('', None), RemoveTitle(document)) - - result = ParseDocument(document) - self.assertEqual(None, result.title) - self.assertEqual(None, result.title_attributes) - self.assertEqual([], result.sections) - self.assertEqual(['Found unexpected title "heading"'], result.warnings) - - result = ParseDocument(document, expect_title=True) - self.assertEqual('heading', result.title) - self.assertEqual({'id': 'header'}, result.title_attributes) - self.assertEqual([], result.sections) - self.assertEqual([], result.warnings) - - def testWholeDocument(self): - self.assertEqual((_WHOLE_DOCUMENT_WITHOUT_TITLE, None), - RemoveTitle(_WHOLE_DOCUMENT)) - result = ParseDocument(_WHOLE_DOCUMENT, expect_title=True) - self.assertEqual('Main header', result.title) - self.assertEqual({'id': 'main', 'class': 'header'}, result.title_attributes) - self.assertEqual([ - 'Found closing </h3> while processing a <h2> (line 19, column 15)', - 'Found multiple <h1> tags. Subsequent <h1> tags will be classified as ' - '<h2> for the purpose of the structure (line 22, column 1)', - 'Found <h3> in the middle of processing a <h2> (line 25, column 9)', - # TODO(kalman): Re-enable this warning once the reference pages have - # their references fixed. - #'Found <h4> without any preceding <h3> (line 28, column 1)', - ], result.warnings) - - # The non-trivial table of contents assertions... - self.assertEqual(1, len(result.sections)) - entries = result.sections[0].structure - - self.assertEqual(4, len(entries), entries) - entry0, entry1, entry2, entry3 = entries - - self.assertEqual('hello', entry0.name) - self.assertEqual({'id': 'orange'}, entry0.attributes) - self.assertEqual(2, len(entry0.entries)) - entry0_0, entry0_1 = entry0.entries - - self.assertEqual('Valencia Oranges', entry0_0.name) - self.assertEqual({'id': 'valencia'}, entry0_0.attributes) - self.assertEqual([], entry0_0.entries) - self.assertEqual('Seville Oranges', entry0_1.name) - self.assertEqual({'id': 'seville'}, entry0_1.attributes) - self.assertEqual([], entry0_1.entries) - - self.assertEqual('Grapefruit', entry1.name) - self.assertEqual({}, entry1.attributes) - self.assertEqual([], entry1.entries) - - self.assertEqual('Not the main header', entry2.name) - self.assertEqual({'id': 'not-main'}, entry2.attributes) - self.assertEqual([], entry2.entries) - - self.assertEqual('Not a banana', entry3.name) - self.assertEqual({}, entry3.attributes) - self.assertEqual(2, len(entry3.entries)) - entry3_1, entry3_2 = entry3.entries - - self.assertEqual('It\'s a h4', entry3_1.name) - self.assertEqual({}, entry3_1.attributes) - self.assertEqual([], entry3_1.entries) - - self.assertEqual('Plantains', entry3_2.name) - self.assertEqual({}, entry3_2.attributes) - self.assertEqual(1, len(entry3_2.entries)) - entry3_2_1, = entry3_2.entries - - self.assertEqual('Another h4', entry3_2_1.name) - self.assertEqual({}, entry3_2_1.attributes) - self.assertEqual([], entry3_2_1.entries) - - def testSingleExplicitSection(self): - def test(document): - result = ParseDocument(document, expect_title=True) - self.assertEqual([], result.warnings) - self.assertEqual('Header', result.title) - self.assertEqual(1, len(result.sections)) - section0, = result.sections - entry0, = section0.structure - self.assertEqual('An inner header', entry0.name) - # A single section, one with the title inside the section, the other out. - test('<h1>Header</h1>' - '<section>' - 'Just a single section here.' - '<h2>An inner header</h2>' - '</section>') - test('<section>' - 'Another single section here.' - '<h1>Header</h1>' - '<h2>An inner header</h2>' - '</section>') - - def testMultipleSections(self): - result = ParseDocument( - '<h1>Header</h1>' - '<h2>First header</h2>' - 'This content outside a section is the first section.' - '<section>' - 'Second section' - '<h2>Second header</h2>' - '</section>' - '<section>' - 'Third section' - '<h2>Third header</h2>' - '</section>', - expect_title=True) - self.assertEqual([], result.warnings) - self.assertEqual('Header', result.title) - self.assertEqual(3, len(result.sections)) - section0, section1, section2 = result.sections - def assert_single_header(section, name): - self.assertEqual(1, len(section.structure)) - self.assertEqual(name, section.structure[0].name) - assert_single_header(section0, 'First header') - assert_single_header(section1, 'Second header') - assert_single_header(section2, 'Third header') - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/document_renderer.py b/chrome/common/extensions/docs/server2/document_renderer.py deleted file mode 100644 index 2e3556f..0000000 --- a/chrome/common/extensions/docs/server2/document_renderer.py +++ /dev/null
@@ -1,112 +0,0 @@ -# Copyright 2013 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 logging -import os -from document_parser import ParseDocument -from platform_util import ExtractPlatformFromURL -from third_party.json_schema_compiler.model import UnixName - - -class DocumentRenderer(object): - '''Performs document-level rendering such as the title, references, - and table of contents: pulling that data out of the document, then - replacing the $(title), $(ref:...) and $(table_of_contents) tokens with them. - - This can be thought of as a parallel to TemplateRenderer; while - TemplateRenderer is responsible for interpreting templates and rendering files - within the template engine, DocumentRenderer is responsible for interpreting - higher-level document concepts like the title and TOC, then performing string - replacement for them. The syntax for this replacement is $(...) where ... is - the concept. Currently title and table_of_contents are supported. - ''' - - def __init__(self, table_of_contents_renderer, platform_bundle): - self._table_of_contents_renderer = table_of_contents_renderer - self._platform_bundle = platform_bundle - - def _RenderLinks(self, document, path): - ''' Replaces all $(ref:...) references in |document| with html links. - - References have two forms: - - $(ref:api.node) - Replaces the reference with a link to node on the - API page. The title is set to the name of the node. - - $(ref:api.node Title) - Same as the previous form, but title is set - to "Title". - ''' - START_REF = '$(ref:' - END_REF = ')' - MAX_REF_LENGTH = 256 - - new_document = [] - - # Keeps track of position within |document| - cursor_index = 0 - start_ref_index = document.find(START_REF) - - while start_ref_index != -1: - end_ref_index = document.find(END_REF, start_ref_index) - - if (end_ref_index == -1 or - end_ref_index - start_ref_index > MAX_REF_LENGTH): - end_ref_index = document.find(' ', start_ref_index) - logging.error('%s:%s has no terminating ) at line %s' % ( - path, - document[start_ref_index:end_ref_index], - document.count('\n', 0, end_ref_index))) - - new_document.append(document[cursor_index:end_ref_index + 1]) - else: - ref = document[start_ref_index:end_ref_index] - ref_parts = ref[len(START_REF):].split(None, 1) - - # Guess the api name from the html name, replacing '_' with '.' (e.g. - # if the page is app_window.html, guess the api name is app.window) - api_name = os.path.splitext(os.path.basename(path))[0].replace('_', '.') - title = ref_parts[0] if len(ref_parts) == 1 else ref_parts[1] - - platform = ExtractPlatformFromURL(path) - if platform is None: - logging.error('Cannot resolve reference without a platform.') - continue - ref_dict = self._platform_bundle.GetReferenceResolver( - platform).SafeGetLink(ref_parts[0], - namespace=api_name, - title=title, - path=path) - - new_document.append(document[cursor_index:start_ref_index]) - new_document.append('<a href=%s/%s>%s</a>' % ( - self._platform_bundle._base_path + platform, - ref_dict['href'], - ref_dict['text'])) - - cursor_index = end_ref_index + 1 - start_ref_index = document.find(START_REF, cursor_index) - - new_document.append(document[cursor_index:]) - - return ''.join(new_document) - - def Render(self, document, path, render_title=False): - ''' |document|: document to be rendered. - |path|: request path to the document. - |render_title|: boolean representing whether or not to render a title. - ''' - # Render links first so that parsing and later replacements aren't - # affected by $(ref...) substitutions - document = self._RenderLinks(document, path) - - parsed_document = ParseDocument(document, expect_title=render_title) - toc_text, toc_warnings = self._table_of_contents_renderer.Render( - parsed_document.sections) - - # Only 1 title and 1 table of contents substitution allowed; in the common - # case, save necessarily running over the entire file. - if parsed_document.title: - document = document.replace('$(title)', parsed_document.title, 1) - return (document.replace('$(table_of_contents)', toc_text, 1), - parsed_document.warnings + toc_warnings)
diff --git a/chrome/common/extensions/docs/server2/document_renderer_test.py b/chrome/common/extensions/docs/server2/document_renderer_test.py deleted file mode 100755 index 5394ea3..0000000 --- a/chrome/common/extensions/docs/server2/document_renderer_test.py +++ /dev/null
@@ -1,155 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from document_renderer import DocumentRenderer -from server_instance import ServerInstance -from test_file_system import TestFileSystem -from test_data.canned_data import CANNED_TEST_FILE_SYSTEM_DATA - - -class DocumentRendererUnittest(unittest.TestCase): - def setUp(self): - self._renderer = ServerInstance.ForTest( - TestFileSystem(CANNED_TEST_FILE_SYSTEM_DATA)).document_renderer - self._path = 'apps/some/path/to/document.html' - - def _Render(self, document, render_title=False): - return self._renderer.Render(document, - self._path, - render_title=render_title) - - def testNothingToSubstitute(self): - document = 'hello world' - - text, warnings = self._Render(document) - self.assertEqual(document, text) - self.assertEqual([], warnings) - - text, warnings = self._Render(document, render_title=True) - self.assertEqual(document, text) - self.assertEqual(['Expected a title'], warnings) - - def testTitles(self): - document = '<h1>title</h1> then $(title) then another $(title)' - - text, warnings = self._Render(document) - self.assertEqual(document, text) - self.assertEqual(['Found unexpected title "title"'], warnings) - - text, warnings = self._Render(document, render_title=True) - self.assertEqual('<h1>title</h1> then title then another $(title)', text) - self.assertEqual([], warnings) - - def testTocs(self): - document = ('here is a toc $(table_of_contents) ' - 'and another $(table_of_contents)') - expected_document = ('here is a toc <table-of-contents> and another ' - '$(table_of_contents)') - - text, warnings = self._Render(document) - self.assertEqual(expected_document, text) - self.assertEqual([], warnings) - - text, warnings = self._Render(document, render_title=True) - self.assertEqual(expected_document, text) - self.assertEqual(['Expected a title'], warnings) - - def testRefs(self): - # The references in this and subsequent tests won't actually be resolved - document = 'A ref $(ref:baz.baz_e1) here, $(ref:foo.foo_t3 ref title) there' - expected_document = ''.join([ - 'A ref <a href=/apps/#type-baz_e1>baz.baz_e1</a> here, ', - '<a href=/apps/#type-foo_t3>ref title</a> there' - ]) - - text, warnings = self._Render(document) - self.assertEqual(expected_document, text) - self.assertEqual([], warnings) - - text, warnings = self._Render(document, render_title=True) - self.assertEqual(expected_document, text) - self.assertEqual(['Expected a title'], warnings) - - def testTitleAndToc(self): - document = '<h1>title</h1> $(title) and $(table_of_contents)' - - text, warnings = self._Render(document) - self.assertEqual('<h1>title</h1> $(title) and <table-of-contents>', text) - self.assertEqual(['Found unexpected title "title"'], warnings) - - text, warnings = self._Render(document, render_title=True) - self.assertEqual('<h1>title</h1> title and <table-of-contents>', text) - self.assertEqual([], warnings) - - def testRefInTitle(self): - document = '<h1>$(ref:baz.baz_e1 title)</h1> A $(title) was here' - href = '/apps/#type-baz_e1' - expected_document_no_title = ''.join([ - '<h1><a href=%s>title</a></h1> A $(title) was here' % href - ]) - - expected_document = ''.join([ - '<h1><a href=%s>title</a></h1> A title was here' % href - ]) - - text, warnings = self._Render(document) - self.assertEqual(expected_document_no_title, text) - self.assertEqual([('Found unexpected title "title"')], warnings) - - text, warnings = self._Render(document, render_title=True) - self.assertEqual(expected_document, text) - self.assertEqual([], warnings) - - def testRefSplitAcrossLines(self): - document = 'Hello, $(ref:baz.baz_e1 world). A $(ref:foo.foo_t3\n link)' - expected_document = ''.join([ - 'Hello, <a href=/apps/#type-baz_e1>world</a>. ', - 'A <a href=/apps/#type-foo_t3>link</a>' - ]) - - - text, warnings = self._Render(document) - self.assertEqual(expected_document, text) - self.assertEqual([], warnings) - - text, warnings = self._Render(document, render_title=True) - self.assertEqual(expected_document, text) - self.assertEqual(['Expected a title'], warnings) - - def testInvalidRef(self): - # DocumentRenderer attempts to detect unclosed $(ref:...) tags by limiting - # how far it looks ahead. Lorem Ipsum should be long enough to trigger that. - _LOREM_IPSUM = ( - 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do ' - 'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ' - 'ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut ' - 'aliquip ex ea commodo consequat. Duis aute irure dolor in ' - 'reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla ' - 'pariatur. Excepteur sint occaecat cupidatat non proident, sunt in ' - 'culpa qui officia deserunt mollit anim id est laborum.') - document = ''.join([ - 'An invalid $(ref:foo.foo_t3 a title ', - _LOREM_IPSUM, - '$(ref:baz.baz_e1) here' - ]) - expected_document = ''.join([ - 'An invalid $(ref:foo.foo_t3 a title ', - _LOREM_IPSUM, - '<a href=/apps/#type-baz_e1>baz.baz_e1</a> here' - ]) - - text, warnings = self._Render(document) - self.assertEqual(expected_document, text) - self.assertEqual([], warnings) - - text, warnings = self._Render(document, render_title=True) - self.assertEqual(expected_document, text) - self.assertEqual(['Expected a title'], warnings) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/empty_dir_file_system.py b/chrome/common/extensions/docs/server2/empty_dir_file_system.py deleted file mode 100644 index a5087476..0000000 --- a/chrome/common/extensions/docs/server2/empty_dir_file_system.py +++ /dev/null
@@ -1,32 +0,0 @@ -# Copyright 2013 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 file_system import FileNotFoundError, FileSystem, StatInfo -from future import Future -from path_util import IsDirectory - - -class EmptyDirFileSystem(FileSystem): - '''A FileSystem with empty directories. Useful to inject places to disable - features such as samples. - ''' - def Read(self, paths, skip_not_found=False): - result = {} - for path in paths: - if not IsDirectory(path): - if skip_not_found: continue - raise FileNotFoundError('EmptyDirFileSystem cannot read %s' % path) - result[path] = [] - return Future(value=result) - - def Refresh(self): - return Future(value=()) - - def Stat(self, path): - if not IsDirectory(path): - raise FileNotFoundError('EmptyDirFileSystem cannot stat %s' % path) - return StatInfo(0, child_versions=[]) - - def GetIdentity(self): - return self.__class__.__name__
diff --git a/chrome/common/extensions/docs/server2/environment.py b/chrome/common/extensions/docs/server2/environment.py deleted file mode 100644 index c86ed464..0000000 --- a/chrome/common/extensions/docs/server2/environment.py +++ /dev/null
@@ -1,66 +0,0 @@ -# Copyright 2013 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 re -import os -import sys - -from app_yaml_helper import AppYamlHelper -from third_party.json_schema_compiler.memoize import memoize - - -@memoize -def GetAppVersion(): - return GetAppVersionNonMemoized() - - -# This one is for running from tests, which memoization messes up. -def GetAppVersionNonMemoized(): - if 'CURRENT_VERSION_ID' in os.environ: - # The version ID looks like 2-0-25.36712548 or 2-0-25.23/223; we only - # want the 2-0-25. - return re.compile('[./]').split(os.environ['CURRENT_VERSION_ID'])[0] - # Not running on appengine, get it from the app.yaml file ourselves. - app_yaml_path = os.path.join(os.path.split(__file__)[0], 'app.yaml') - with open(app_yaml_path, 'r') as app_yaml: - return AppYamlHelper.ExtractVersion(app_yaml.read()) - - -def _IsServerSoftware(name): - return os.environ.get('SERVER_SOFTWARE', '').find(name) == 0 - - -def IsComputeEngine(): - return _IsServerSoftware('Compute Engine') - - -def IsDevServer(): - return _IsServerSoftware('Development') - - -def IsReleaseServer(): - return _IsServerSoftware('Google App Engine') - - -def IsPreviewServer(): - return sys.argv and os.path.basename(sys.argv[0]) == 'preview.py' - - -def IsAppEngine(): - return IsDevServer() or IsReleaseServer() - -def IsTest(): - if not sys.argv: - return False - - script_path_head, script_basename = os.path.split(sys.argv[0]) - if script_basename.endswith('_test.py'): - return True - - # Tests under extension_docserver_python_unittests target are run by typ. - return (script_basename == 'runner.py' and - os.path.basename(script_path_head) == 'typ') - -class UnknownEnvironmentError(Exception): - pass
diff --git a/chrome/common/extensions/docs/server2/environment_test.py b/chrome/common/extensions/docs/server2/environment_test.py deleted file mode 100755 index 04488ebb..0000000 --- a/chrome/common/extensions/docs/server2/environment_test.py +++ /dev/null
@@ -1,45 +0,0 @@ -#!/usr/bin/env python -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import unittest - -from environment import GetAppVersionNonMemoized - - -class EnvironmentTest(unittest.TestCase): - def testGetAppVersion(self): - # GetAppVersion uses 2 heuristics: the CURRENT_VERSION_ID environment - # variable that AppEngine sets, or the version extracted from app.yaml - # if no such variable exists (e.g. preview.py). The latter, we assume, - # is already tested because AppYamlHelper.ExtractVersion is already - # tested. So, for this test, we fake a CURRENT_VERSION_ID. - def test_single(expected, current_version_id): - key = 'CURRENT_VERSION_ID' - old_value = os.environ.get(key) - os.environ[key] = current_version_id - try: - self.assertEqual(expected, GetAppVersionNonMemoized()) - finally: - if old_value is None: - del os.environ[key] - else: - os.environ[key] = old_value - def test_all(expected): - test_single(expected, expected) - test_single(expected, expected + '.48w7dl48wl') - test_single(expected, expected + '/48w7dl48wl') - test_single(expected, expected + '.48w7dl48wl.w847lw83') - test_single(expected, expected + '.48w7dl48wl/w847lw83') - test_single(expected, expected + '/48w7dl48wl.w847lw83') - test_single(expected, expected + '/48w7dl48wl/w847lw83') - test_all('2') - test_all('2-0') - test_all('2-0-25') - test_all('2-0-25-b') - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/environment_wrappers.py b/chrome/common/extensions/docs/server2/environment_wrappers.py deleted file mode 100644 index 13e60209..0000000 --- a/chrome/common/extensions/docs/server2/environment_wrappers.py +++ /dev/null
@@ -1,70 +0,0 @@ -# Copyright 2013 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 json -import logging -import os - -from environment import IsAppEngine, IsComputeEngine, IsTest - - -_METADATA_SERVER = 'http://metadata/computeMetadata/v1/instance/service-accounts' -_SERVICE_ACCOUNT = 'default' - -# The environment variable to use as a fallback token source. -_ACCESS_TOKEN_ENV = 'DOCSERVER_ACCESS_TOKEN' - - -def CreateUrlFetcher(base_path=None): - if IsAppEngine(): - from url_fetcher_appengine import UrlFetcherAppengine - fetcher = UrlFetcherAppengine() - elif not IsTest(): - from url_fetcher_urllib2 import UrlFetcherUrllib2 - fetcher = UrlFetcherUrllib2() - else: - from url_fetcher_fake import UrlFetcherFake - fetcher = UrlFetcherFake() - fetcher.SetBasePath(base_path) - return fetcher - - -def CreatePersistentObjectStore(namespace): - if IsAppEngine(): - from persistent_object_store_appengine import PersistentObjectStoreAppengine - object_store = PersistentObjectStoreAppengine(namespace) - else: - from persistent_object_store_fake import PersistentObjectStoreFake - object_store = PersistentObjectStoreFake(namespace) - return object_store - - -def GetAccessToken(): - '''Acquires an access token either from the metadata service (if running on - a real CE VM) or the DOCSERVER_ACCESS_TOKEN environment variable. - - This may return None if no token is available. That should never happen while - running on a VM. - ''' - # Attempt to grab an access token from the VM instance's metadata. - if IsComputeEngine(): - fetcher = CreateUrlFetcher() - token_uri = '%s/%s/token' % (_METADATA_SERVER, _SERVICE_ACCOUNT) - token_response = None - try: - token_response = fetcher.Fetch(token_uri, - headers={'Metadata-Flavor': 'Google'}) - if token_response.status_code == 200: - return json.loads(token_response.content)['access_token'] - except Exception as e: - logging.warn('Failed to fetch access token from VM metadata.') - pass - - logging.warn('Using access token from local environment.') - access_token = os.getenv(_ACCESS_TOKEN_ENV) - if access_token is None: - logging.error('No access token available. ' - 'Please set %s if you want things to work.' % - _ACCESS_TOKEN_ENV) - return access_token
diff --git a/chrome/common/extensions/docs/server2/extensions_paths.py b/chrome/common/extensions/docs/server2/extensions_paths.py deleted file mode 100644 index 40b353d..0000000 --- a/chrome/common/extensions/docs/server2/extensions_paths.py +++ /dev/null
@@ -1,58 +0,0 @@ -# Copyright 2013 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 posixpath import join - - -# Extensions-related paths within the Chromium repository. - -EXTENSIONS = 'extensions/common/' -CHROME_EXTENSIONS = 'chrome/common/extensions/' -CHROME_APPS = 'chrome/common/apps/platform_apps/' - -BROWSER_EXTENSIONS = 'extensions/browser/' -BROWSER_CHROME_EXTENSIONS = 'chrome/browser/extensions/' -BROWSER_CHROME_APPS = 'chrome/browser/apps/platform_apps/' - -EXTENSIONS_API = join(EXTENSIONS, 'api/') -CHROME_API = join(CHROME_EXTENSIONS, 'api/') -CHROME_APPS_API = join(CHROME_APPS, 'api/') - -BROWSER_EXTENSIONS_API = join(BROWSER_EXTENSIONS, 'api/') -BROWSER_CHROME_API = join(BROWSER_CHROME_EXTENSIONS, 'api/') -BROWSER_CHROME_APPS_API = join(BROWSER_CHROME_APPS, 'api/') - -# Note: This determines search order when APIs are resolved in the filesystem. -API_PATHS = ( - CHROME_API, - EXTENSIONS_API, - CHROME_APPS_API, -) - -BROWSER_API_PATHS = ( - BROWSER_CHROME_API, - BROWSER_EXTENSIONS_API, - BROWSER_CHROME_APPS_API, -) - -DOCS = join(CHROME_EXTENSIONS, 'docs/') - -EXAMPLES = join(DOCS, 'examples/') -SERVER2 = join(DOCS, 'server2/') -STATIC_DOCS = join(DOCS, 'static/') -TEMPLATES = join(DOCS, 'templates/') - -APP_YAML = join(SERVER2, 'app.yaml') - -ARTICLES_TEMPLATES = join(TEMPLATES, 'articles/') -INTROS_TEMPLATES = join(TEMPLATES, 'intros/') -JSON_TEMPLATES = join(TEMPLATES, 'json/') -PRIVATE_TEMPLATES = join(TEMPLATES, 'private/') -PUBLIC_TEMPLATES = join(TEMPLATES, 'public/') - -CONTENT_PROVIDERS = join(JSON_TEMPLATES, 'content_providers.json') - -LOCAL_DEBUG_DIR = join(SERVER2, 'local_debug/') -LOCAL_GCS_DIR = join(LOCAL_DEBUG_DIR, 'gcs/') -LOCAL_GCS_DEBUG_CONF = join(LOCAL_DEBUG_DIR, 'gcs_debug.conf')
diff --git a/chrome/common/extensions/docs/server2/fail_on_access_file_system.py b/chrome/common/extensions/docs/server2/fail_on_access_file_system.py deleted file mode 100644 index 4cf3e1be..0000000 --- a/chrome/common/extensions/docs/server2/fail_on_access_file_system.py +++ /dev/null
@@ -1,11 +0,0 @@ -# Copyright 2013 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 file_system import FileSystem - -class FailOnAccessFileSystem(FileSystem): - # All this needs to do is implement GetIdentity. All other methods will - # automatically fail with NotImplementedErrors. - def GetIdentity(self): - return '42'
diff --git a/chrome/common/extensions/docs/server2/fake_fetchers.py b/chrome/common/extensions/docs/server2/fake_fetchers.py deleted file mode 100644 index 4b6dc07..0000000 --- a/chrome/common/extensions/docs/server2/fake_fetchers.py +++ /dev/null
@@ -1,138 +0,0 @@ -# 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. - -# These are fake fetchers that are used for testing and the preview server. -# They return canned responses for URLs. url_fetcher_fake.py uses the fake -# fetchers if other URL fetching APIs are unavailable. - -import base64 -import json -import os -import re - -import url_fetcher_fake -from extensions_paths import SERVER2 -from path_util import IsDirectory -from test_util import ReadFile, ChromiumPath -import url_constants - - -# TODO(kalman): Investigate why logging in this class implies that the server -# isn't properly caching some fetched files; often it fetches the same file -# 10+ times. This may be a test anomaly. - - -def _ReadTestData(*path, **read_args): - return ReadFile(SERVER2, 'test_data', *path, **read_args) - - -class _FakeFetcher(object): - def _ListDir(self, path): - return os.listdir(path) - - def _IsDir(self, path): - return os.path.isdir(path) - - def _Stat(self, path): - return int(os.stat(path).st_mtime) - - -class _FakeOmahaProxy(_FakeFetcher): - def fetch(self, url): - return _ReadTestData('branch_utility', 'first.json') - - -class _FakeOmahaHistory(_FakeFetcher): - def fetch(self, url): - return _ReadTestData('branch_utility', 'second.json') - - -_SVN_URL_TO_PATH_PATTERN = re.compile( - r'^.*chrome/.*(trunk|branches/.*)/src/?([^?]*).*?') -def _ExtractPathFromSvnUrl(url): - return _SVN_URL_TO_PATH_PATTERN.match(url).group(2) - - -class _FakeSubversionServer(_FakeFetcher): - def fetch(self, url): - path = _ExtractPathFromSvnUrl(url) - if IsDirectory(path): - html = ['<html>Revision 000000'] - try: - for f in self._ListDir(ChromiumPath(path)): - if f.startswith('.'): - continue - if self._IsDir(ChromiumPath(path, f)): - html.append('<a>' + f + '/</a>') - else: - html.append('<a>' + f + '</a>') - html.append('</html>') - return '\n'.join(html) - except OSError as e: - return None - try: - return ReadFile(path) - except IOError: - return None - - -class _FakeViewvcServer(_FakeFetcher): - def fetch(self, url): - path = ChromiumPath(_ExtractPathFromSvnUrl(url)) - if self._IsDir(path): - html = ['<table><tbody><tr>...</tr>'] - # The version of the directory. - dir_stat = self._Stat(path) - html.append('<tr>') - html.append('<td>Directory revision:</td>') - html.append('<td><a>%s</a><a></a></td>' % dir_stat) - html.append('</tr>') - # The version of each file. - for f in self._ListDir(path): - if f.startswith('.'): - continue - html.append('<tr>') - html.append(' <td><a>%s%s</a></td>' % ( - f, '/' if self._IsDir(os.path.join(path, f)) else '')) - html.append(' <td><a><strong>%s</strong></a></td>' % - self._Stat(os.path.join(path, f))) - html.append('<td></td><td></td><td></td>') - html.append('</tr>') - html.append('</tbody></table>') - return '\n'.join(html) - try: - return ReadFile(path) - except IOError: - return None - -class _FakeRietveldAPI(_FakeFetcher): - def __init__(self): - self._base_pattern = re.compile(r'.*/(api/.*)') - - def fetch(self, url): - return _ReadTestData( - 'rietveld_patcher', self._base_pattern.match(url).group(1), 'json') - - -class _FakeRietveldTarball(_FakeFetcher): - def __init__(self): - self._base_pattern = re.compile(r'.*/(tarball/\d+/\d+)') - - def fetch(self, url): - return _ReadTestData( - 'rietveld_patcher', self._base_pattern.match(url).group(1) + '.tar.bz2', - mode='rb') - - -def ConfigureFakeFetchers(): - '''Configure the fake fetcher paths relative to the docs directory. - ''' - url_fetcher_fake.ConfigureFakeUrlFetch({ - url_constants.OMAHA_HISTORY: _FakeOmahaHistory(), - url_constants.OMAHA_PROXY_URL: _FakeOmahaProxy(), - '%s/.*' % url_constants.SVN_URL: _FakeSubversionServer(), - '%s/.*' % url_constants.VIEWVC_URL: _FakeViewvcServer(), - '%s/api/.*' % url_constants.CODEREVIEW_SERVER: _FakeRietveldAPI(), - '%s/tarball/.*' % url_constants.CODEREVIEW_SERVER: _FakeRietveldTarball(), - })
diff --git a/chrome/common/extensions/docs/server2/fake_host_file_system_provider.py b/chrome/common/extensions/docs/server2/fake_host_file_system_provider.py deleted file mode 100644 index c8691c1..0000000 --- a/chrome/common/extensions/docs/server2/fake_host_file_system_provider.py +++ /dev/null
@@ -1,19 +0,0 @@ -# Copyright 2013 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 mock_file_system import MockFileSystem -from test_file_system import TestFileSystem -from third_party.json_schema_compiler.memoize import memoize - -class FakeHostFileSystemProvider(object): - - def __init__(self, file_system_data): - self._file_system_data = file_system_data - - def GetMaster(self): - return self.GetBranch('master') - - @memoize - def GetBranch(self, branch): - return MockFileSystem(TestFileSystem(self._file_system_data[str(branch)]))
diff --git a/chrome/common/extensions/docs/server2/fake_url_fetcher.py b/chrome/common/extensions/docs/server2/fake_url_fetcher.py deleted file mode 100644 index 21b6cf6..0000000 --- a/chrome/common/extensions/docs/server2/fake_url_fetcher.py +++ /dev/null
@@ -1,157 +0,0 @@ -# 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. - -import os -import posixpath - -from future import Future -from path_util import AssertIsDirectory, IsDirectory - - -class _Response(object): - def __init__(self, content=''): - self.content = content - self.headers = {'Content-Type': 'none'} - self.status_code = 200 - - -class FakeUrlFetcher(object): - def __init__(self, base_path): - self._base_path = base_path - # Mock capabilities. Perhaps this class should be MockUrlFetcher. - self._sync_count = 0 - self._async_count = 0 - self._async_resolve_count = 0 - - def _ReadFile(self, filename): - # Fake DownloadError, the error that appengine usually raises. - class DownloadError(Exception): pass - try: - with open(os.path.join(self._base_path, filename), 'r') as f: - return f.read() - except IOError as e: - raise DownloadError(e) - - def _ListDir(self, directory): - # In some tests, we need to test listing a directory from the HTML returned - # from SVN. This reads an HTML file that has the directories HTML. - if not os.path.isdir(os.path.join(self._base_path, directory)): - return self._ReadFile(directory[:-1]) - files = os.listdir(os.path.join(self._base_path, directory)) - html = '<html><title>Revision: 00000</title>\n' - for filename in files: - if filename.startswith('.'): - continue - if os.path.isdir(os.path.join(self._base_path, directory, filename)): - html += '<a>' + filename + '/</a>\n' - else: - html += '<a>' + filename + '</a>\n' - html += '</html>' - return html - - def FetchAsync(self, url): - self._async_count += 1 - url = url.rsplit('?', 1)[0] - def resolve(): - self._async_resolve_count += 1 - return self._DoFetch(url) - return Future(callback=resolve) - - def Fetch(self, url): - self._sync_count += 1 - return self._DoFetch(url) - - def _DoFetch(self, url): - url = url.rsplit('?', 1)[0] - result = _Response() - if IsDirectory(url): - result.content = self._ListDir(url) - else: - result.content = self._ReadFile(url) - return result - - def CheckAndReset(self, sync_count=0, async_count=0, async_resolve_count=0): - '''Returns a tuple (success, error). Use in tests like: - self.assertTrue(*fetcher.CheckAndReset(...)) - ''' - errors = [] - for desc, expected, actual in ( - ('sync_count', sync_count, self._sync_count), - ('async_count', async_count, self._async_count), - ('async_resolve_count', async_resolve_count, - self._async_resolve_count)): - if actual != expected: - errors.append('%s: expected %s got %s' % (desc, expected, actual)) - try: - return (len(errors) == 0, ', '.join(errors)) - finally: - self.Reset() - - def Reset(self): - self._sync_count = 0 - self._async_count = 0 - self._async_resolve_count = 0 - - -class FakeURLFSFetcher(object): - '''Use a file_system to resolve fake fetches. Mimics the interface of Google - Appengine's urlfetch. - ''' - - def __init__(self, file_system, base_path): - AssertIsDirectory(base_path) - self._base_path = base_path - self._file_system = file_system - - def FetchAsync(self, url, **kwargs): - return Future(value=self.Fetch(url)) - - def Fetch(self, url, **kwargs): - return _Response(self._file_system.ReadSingle( - posixpath.join(self._base_path, url)).Get()) - - def UpdateFS(self, file_system, base_path=None): - '''Replace the underlying FileSystem used to reslove URLs. - ''' - self._file_system = file_system - self._base_path = base_path or self._base_path - - -class MockURLFetcher(object): - def __init__(self, fetcher): - self._fetcher = fetcher - self.Reset() - - def Fetch(self, url, **kwargs): - self._fetch_count += 1 - return self._fetcher.Fetch(url, **kwargs) - - def FetchAsync(self, url, **kwargs): - self._fetch_async_count += 1 - def next(result): - self._fetch_resolve_count += 1 - return result - return self._fetcher.FetchAsync(url, **kwargs).Then(next) - - def CheckAndReset(self, - fetch_count=0, - fetch_async_count=0, - fetch_resolve_count=0): - errors = [] - for desc, expected, actual in ( - ('fetch_count', fetch_count, self._fetch_count), - ('fetch_async_count', fetch_async_count, self._fetch_async_count), - ('fetch_resolve_count', fetch_resolve_count, - self._fetch_resolve_count)): - if actual != expected: - errors.append('%s: expected %s got %s' % (desc, expected, actual)) - try: - return (len(errors) == 0, ', '.join(errors)) - finally: - self.Reset() - - def Reset(self): - self._fetch_count = 0 - self._fetch_async_count = 0 - self._fetch_resolve_count = 0
diff --git a/chrome/common/extensions/docs/server2/features_bundle.py b/chrome/common/extensions/docs/server2/features_bundle.py deleted file mode 100644 index 87e01d8..0000000 --- a/chrome/common/extensions/docs/server2/features_bundle.py +++ /dev/null
@@ -1,411 +0,0 @@ -# Copyright 2013 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 logging - -from branch_utility import BranchUtility -from compiled_file_system import SingleFile, Unicode -from copy import copy -from docs_server_utils import StringIdentity -from extensions_paths import API_PATHS, JSON_TEMPLATES -from file_system import FileNotFoundError -from future import All, Future -from path_util import Join -from platform_util import GetExtensionTypes, PlatformToExtensionType -from third_party.json_schema_compiler.json_parse import Parse - - -_API_FEATURES = '_api_features.json' -_MANIFEST_FEATURES = '_manifest_features.json' -_PERMISSION_FEATURES = '_permission_features.json' - - -def HasParent(feature_name, feature, all_feature_names): - # A feature has a parent if it has a . in its name, its parent exists, - # and it does not explicitly specify that it has no parent. - return ('.' in feature_name and - feature_name.rsplit('.', 1)[0] in all_feature_names and - not feature.get('noparent')) - - -def GetParentName(feature_name, feature, all_feature_names): - '''Returns the name of the parent feature, or None if it does not have a - parent. - ''' - if not HasParent(feature_name, feature, all_feature_names): - return None - return feature_name.rsplit('.', 1)[0] - - -def _CreateFeaturesFromJSONFutures(json_futures): - '''Returns a dict of features. The value of each feature is a list with - all of its possible values. - ''' - def ignore_feature(name, value): - '''Returns true if this feature should be ignored. Features are ignored if - they are only available to whitelisted apps or component extensions/apps, as - in these cases the APIs are not available to public developers. - - Private APIs are also unavailable to public developers, but logic elsewhere - makes sure they are not listed. So they shouldn't be ignored via this - mechanism. - ''' - if name.endswith('Private'): - return False - return value.get('location') == 'component' or 'whitelist' in value - - features = {} - - for json_future in json_futures: - try: - features_json = Parse(json_future.Get()) - except FileNotFoundError: - # Not all file system configurations have the extra files. - continue - for name, rawvalue in features_json.iteritems(): - if name not in features: - features[name] = [] - for value in (rawvalue if isinstance(rawvalue, list) else (rawvalue,)): - if not ignore_feature(name, value): - features[name].append(value) - - return features - - -def _CopyParentFeatureValues(child, parent): - '''Takes data from feature dict |parent| and copies/merges it - into feature dict |child|. Two passes are run over the features, - and on the first pass features are not resolved across caches, - so a None value for |parent| may be passed in. - ''' - if parent is None: - return child - merged = copy(parent) - merged.pop('noparent', None) - merged.pop('name', None) - merged.update(child) - return merged - - -def _ResolveFeature(feature_name, - feature_values, - extra_feature_values, - platform, - features_type, - features_map): - '''Filters and combines the possible values for a feature into one dict. - - It uses |features_map| to resolve dependencies for each value and inherit - unspecified platform and channel data. |feature_values| is then filtered - by platform and all values with the most stable platform are merged into one - dict. All values in |extra_feature_values| get merged into this dict. - - Returns |resolve_successful| and |feature|. |resolve_successful| is False - if the feature's dependencies have not been merged yet themselves, meaning - that this feature can not be reliably resolved yet. |feature| is the - resulting feature dict, or None if the feature does not exist on the - platform specified. - ''' - feature = None - most_stable_channel = None - for value in feature_values: - # If 'extension_types' or 'channel' is unspecified, these values should - # be inherited from dependencies. If they are specified, these values - # should override anything specified by dependencies. - inherit_valid_platform = 'extension_types' not in value - if inherit_valid_platform: - valid_platform = None - else: - valid_platform = (value['extension_types'] == 'all' or - platform in value['extension_types']) - inherit_channel = 'channel' not in value - channel = value.get('channel') - - dependencies = value.get('dependencies', []) - parent = GetParentName( - feature_name, value, features_map[features_type]['all_names']) - if parent is not None: - # The parent data needs to be resolved so the child can inherit it. - if parent in features_map[features_type].get('unresolved', ()): - return False, None - value = _CopyParentFeatureValues( - value, features_map[features_type]['resolved'].get(parent)) - # Add the parent as a dependency to ensure proper platform filtering. - dependencies.append(features_type + ':' + parent) - - for dependency in dependencies: - dep_type, dep_name = dependency.split(':') - - # Ignore dependencies on behavior features for the purpose of resolving - # feature characteristics, since behavior features are generally used for - # configuring certain specific allowlisted extension behaviors. - if dep_type == 'behavior': - continue - - if (dep_type not in features_map or - dep_name in features_map[dep_type].get('unresolved', ())): - # The dependency itself has not been merged yet or the features map - # does not have the needed data. Fail to resolve. - return False, None - - dep = features_map[dep_type]['resolved'].get(dep_name) - if inherit_valid_platform and (valid_platform is None or valid_platform): - # If dep is None, the dependency does not exist because it has been - # filtered out by platform. This feature value does not explicitly - # specify platform data, so filter this feature value out. - # Only run this check if valid_platform is True or None so that it - # can't be reset once it is False. - valid_platform = dep is not None - if inherit_channel and dep and 'channel' in dep: - if channel is None or BranchUtility.NewestChannel( - (dep['channel'], channel)) != channel: - # Inherit the least stable channel from the dependencies. - channel = dep['channel'] - - # Default to stable on all platforms. - if valid_platform is None: - valid_platform = True - if valid_platform and channel is None: - channel = 'stable' - - if valid_platform: - # The feature value is valid. Merge it into the feature dict. - if feature is None or BranchUtility.NewestChannel( - (most_stable_channel, channel)) != channel: - # If this is the first feature value to be merged, copy the dict. - # If this feature value has a more stable channel than the most stable - # channel so far, replace the old dict so that it only merges values - # from the most stable channel. - feature = copy(value) - most_stable_channel = channel - elif channel == most_stable_channel: - feature.update(value) - - if feature is None: - # Nothing was left after filtering the values, but all dependency resolves - # were successful. This feature does not exist on |platform|. - return True, None - - # Merge in any extra values. - for value in extra_feature_values: - feature.update(value) - - # Cleanup, fill in missing fields. - if 'name' not in feature: - feature['name'] = feature_name - feature['channel'] = most_stable_channel - return True, feature - - -class _FeaturesCache(object): - def __init__(self, - file_system, - compiled_fs_factory, - json_paths, - extra_paths, - platform, - features_type): - self._cache = compiled_fs_factory.Create( - file_system, self._CreateCache, type(self), category=platform) - self._text_cache = compiled_fs_factory.ForUnicode(file_system) - self._json_paths = json_paths - self._extra_paths = extra_paths - self._platform = platform - self._features_type = features_type - - @Unicode - def _CreateCache(self, _, features_json): - json_path_futures = [self._text_cache.GetFromFile(path) - for path in self._json_paths[1:]] - extra_path_futures = [self._text_cache.GetFromFile(path) - for path in self._extra_paths] - - features_values = _CreateFeaturesFromJSONFutures( - [Future(value=features_json)] + json_path_futures) - - extra_features_values = _CreateFeaturesFromJSONFutures(extra_path_futures) - - features = { - 'resolved': {}, - 'unresolved': copy(features_values), - 'extra': extra_features_values, - 'all_names': set(features_values.keys()) - } - - # Merges as many feature values as possible without resolving dependencies - # from other FeaturesCaches. Pass in a features_map with just this - # FeatureCache's features_type. Makes repeated passes until no new - # resolves are successful. - new_resolves = True - while new_resolves: - new_resolves = False - for feature_name, feature_values in features_values.iteritems(): - if feature_name not in features['unresolved']: - continue - resolve_successful, feature = _ResolveFeature( - feature_name, - feature_values, - extra_features_values.get(feature_name, ()), - self._platform, - self._features_type, - {self._features_type: features}) - if resolve_successful: - del features['unresolved'][feature_name] - new_resolves = True - if feature is not None: - features['resolved'][feature_name] = feature - - return features - - def GetFeatures(self): - if not self._json_paths: - return Future(value={}) - return self._cache.GetFromFile(self._json_paths[0]) - - -class FeaturesBundle(object): - '''Provides access to properties of API, Manifest, and Permission features. - ''' - def __init__(self, - file_system, - compiled_fs_factory, - object_store_creator, - platform): - def create_features_cache(features_type, feature_file, *extra_paths): - return _FeaturesCache( - file_system, - compiled_fs_factory, - [Join(path, feature_file) for path in API_PATHS], - extra_paths, - self._platform, - features_type) - - if platform not in GetExtensionTypes(): - self._platform = PlatformToExtensionType(platform) - else: - self._platform = platform - - self._caches = { - 'api': create_features_cache('api', _API_FEATURES), - 'manifest': create_features_cache( - 'manifest', - _MANIFEST_FEATURES, - Join(JSON_TEMPLATES, 'manifest.json')), - 'permission': create_features_cache( - 'permission', - _PERMISSION_FEATURES, - Join(JSON_TEMPLATES, 'permissions.json')) - } - # Namespace the object store by the file system ID because this class is - # used by the availability finder cross-channel. - self._object_store = object_store_creator.Create( - _FeaturesCache, - category=StringIdentity(file_system.GetIdentity(), self._platform)) - - def GetPermissionFeatures(self): - return self.GetFeatures('permission', ('permission',)) - - def GetManifestFeatures(self): - return self.GetFeatures('manifest', ('manifest',)) - - def GetAPIFeatures(self): - return self.GetFeatures('api', ('api', 'manifest', 'permission')) - - def GetFeatures(self, features_type, dependencies): - '''Resolves all dependencies in the categories specified by |dependencies|. - Returns the features in the |features_type| category. - ''' - def next_(features): - if features is not None: - return Future(value=features) - - dependency_futures = [] - cache_types = [] - for cache_type in dependencies: - cache_types.append(cache_type) - dependency_futures.append(self._object_store.Get(cache_type)) - - def load_features(dependency_features_list): - futures = [] - for dependency_features, cache_type in zip(dependency_features_list, - cache_types): - if dependency_features is not None: - # Get cached dependencies if possible. If it has been cached, all - # of its features have been resolved, so the other fields are - # unnecessary. - futures.append(Future(value={'resolved': dependency_features})) - else: - futures.append(self._caches[cache_type].GetFeatures()) - - def resolve(features): - features_map = {} - for cache_type, feature in zip(cache_types, features): - # Copy down to features_map level because the 'resolved' and - # 'unresolved' dicts will be modified. - features_map[cache_type] = dict((c, copy(d)) - for c, d in feature.iteritems()) - - def has_unresolved(): - '''Determines if there are any unresolved features left over in any - of the categories in |dependencies|. - ''' - return any(cache.get('unresolved') - for cache in features_map.itervalues()) - - def get_unresolved(): - '''Returns a dictionary of unresolved features mapping the type of - features to the list of unresolved feature names - ''' - unresolved = {} - for cache_type, cache in features_map.iteritems(): - if 'unresolved' not in cache: - continue - unresolved[cache_type] = cache['unresolved'].keys() - return unresolved - - # Iterate until we can't resolve any more features. If dependencies - # are multiple levels deep, it might take multiple passes to inherit - # data to the topmost feature. - any_resolved = True - while has_unresolved() and any_resolved: - any_resolved = False - for cache_type, cache in features_map.iteritems(): - if 'unresolved' not in cache: - continue - to_remove = [] - for name, values in cache['unresolved'].iteritems(): - resolve_successful, feature = _ResolveFeature( - name, - values, - cache['extra'].get(name, ()), - self._platform, - cache_type, - features_map) - if not resolve_successful: - continue # Try again on the next iteration of the while loop - - if resolve_successful: - any_resolved = True - - # When successfully resolved, remove it from the unresolved - # dict. Add it to the resolved dict if it didn't get deleted. - to_remove.append(name) - if feature is not None: - cache['resolved'][name] = feature - - for key in to_remove: - del cache['unresolved'][key] - - # TODO(karandeepb): Add a test to ensure that all features are - # correctly resolved. - if has_unresolved(): - logging.error('Some features were left unresolved ' + - str(get_unresolved())) - - for cache_type, cache in features_map.iteritems(): - self._object_store.Set(cache_type, cache['resolved']) - return features_map[features_type]['resolved'] - return All(futures).Then(resolve) - return All(dependency_futures).Then(load_features) - return self._object_store.Get(features_type).Then(next_)
diff --git a/chrome/common/extensions/docs/server2/features_bundle_test.py b/chrome/common/extensions/docs/server2/features_bundle_test.py deleted file mode 100755 index 4cb0eb02..0000000 --- a/chrome/common/extensions/docs/server2/features_bundle_test.py +++ /dev/null
@@ -1,566 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 json -import unittest - -from extensions_paths import CHROME_EXTENSIONS -from server_instance import ServerInstance -from test_file_system import TestFileSystem - - -_TEST_FILESYSTEM = { - 'api': { - '_api_features.json': json.dumps({ - 'audioCapture': { - 'channel': 'stable', - 'extension_types': ['platform_app'] - }, - 'background': [ - { - 'channel': 'stable', - 'extension_types': ['extension'] - }, - { - 'channel': 'stable', - 'extension_types': ['platform_app'], - 'whitelist': ['im not here'] - } - ], - 'inheritsFromDifferentDependencyName': { - 'dependencies': ['manifest:inheritsPlatformAndChannelFromDependency'] - }, - 'inheritsPlatformAndChannelFromDependency': { - 'dependencies': ['manifest:inheritsPlatformAndChannelFromDependency'] - }, - 'omnibox': { - 'dependencies': ['manifest:omnibox'], - 'contexts': ['blessed_extension'] - }, - 'syncFileSystem': { - 'dependencies': ['permission:syncFileSystem'], - 'contexts': ['blessed_extension'] - }, - 'tabs': { - 'channel': 'stable', - 'extension_types': ['extension', 'legacy_packaged_app'], - 'contexts': ['blessed_extension'] - }, - 'test': { - 'channel': 'stable', - 'extension_types': 'all', - 'contexts': [ - 'blessed_extension', 'unblessed_extension', 'content_script'] - }, - 'overridesPlatformAndChannelFromDependency': { - 'channel': 'beta', - 'dependencies': [ - 'permission:overridesPlatformAndChannelFromDependency' - ], - 'extension_types': ['platform_app'] - }, - 'windows': { - 'dependencies': ['api:tabs'], - 'contexts': ['blessed_extension'] - }, - 'testDeep1': { - 'dependencies': ['api:testDeep2'] - }, - 'testDeep2': { - 'dependencies': ['api:testDeep3'] - }, - 'testDeep3': { - 'dependencies': ['manifest:testDeep4'] - }, - 'testDeep1.child': {}, - 'multipleAmbiguous': [{ - 'value': 1, - 'extension_types': ['platform_app'] - }, { - 'value': 2, - 'dependencies': ['manifest:multipleAmbiguous'] - }], - 'mergingDependencies1': { - 'dependencies': [ - 'permission:mergingDependencies1', - 'permission:mergingDependencies2' - ] - }, - 'mergingDependencies2': { - 'dependencies': [ - 'permission:mergingDependencies1', - 'permission:mergingDependencies3' - ] - }, - 'mergingDependencies3': { - 'dependencies': [ - 'permission:mergingDependencies2', - 'permission:mergingDependencies3' - ] - }, - 'implicitNoParent.child': { - 'extension_types': ['extension'], - 'channel': 'stable' - }, - 'parent': { - 'extension_types': ['extension'], - 'channel': 'beta' - }, - 'parent.explicitNoParent': { - 'extension_types': ['extension'], - 'noparent': True - }, - 'parent.inheritAndOverride': { - 'channel': 'dev' - }, - 'overridePlatform': { - 'dependencies': ['permission:tabs'], - 'extension_types': 'platform_app' - }, - 'mergeMostStableChannel': [{ - 'channel': 'dev', - 'extension_types': ['extension'], - 'value1': 1 - }, { - 'channel': 'stable', - 'extension_types': ['extension'], - 'value2': 2 - }, { - 'channel': 'beta', - 'extension_types': ['extension'], - 'value3': 3 - }, { - 'channel': 'stable', - 'extension_types': ['extension'], - 'value4': 4 - }, { - 'extension_types': ['extension'], - 'value5': 5 - }] - }), - '_manifest_features.json': json.dumps({ - 'app.content_security_policy': { - 'channel': 'stable', - 'extension_types': ['platform_app'], - 'min_manifest_version': 2, - 'whitelist': ['this isnt happening'] - }, - 'background': { - 'channel': 'stable', - 'extension_types': ['extension', 'legacy_packaged_app', 'hosted_app'] - }, - 'inheritsPlatformAndChannelFromDependency': { - 'channel': 'dev', - 'extension_types': ['extension'] - }, - 'manifest_version': { - 'channel': 'stable', - 'extension_types': 'all' - }, - 'omnibox': { - 'channel': 'stable', - 'extension_types': ['extension'], - 'platforms': ['win'] - }, - 'page_action': { - 'channel': 'stable', - 'extension_types': ['extension'] - }, - 'sockets': { - 'channel': 'dev', - 'extension_types': ['platform_app'] - }, - 'testDeep4': { - 'extension_types': ['extension'] - }, - 'multipleAmbiguous': { - 'extension_types': ['extension'] - } - }), - '_permission_features.json': json.dumps({ - 'bluetooth': { - 'channel': 'dev', - 'extension_types': ['platform_app'] - }, - 'overridesPlatformAndChannelFromDependency': { - 'channel': 'stable', - 'extension_types': ['extension'] - }, - 'power': { - 'channel': 'stable', - 'extension_types': [ - 'extension', 'legacy_packaged_app', 'platform_app' - ] - }, - 'syncFileSystem': { - 'channel': 'stable', - 'extension_types': ['platform_app'] - }, - 'tabs': { - 'channel': 'stable', - 'extension_types': ['extension'] - }, - 'mergingDependencies1': { - 'channel': 'stable', - 'extension_types': 'all' - }, - 'mergingDependencies2': { - 'channel': 'beta', - 'extension_types': ['platform_app'] - }, - 'mergingDependencies3': { - 'extension_types': ['extension'] - }, - 'defaults': {} - }) - }, - 'docs': { - 'templates': { - 'json': { - 'manifest.json': json.dumps({ - 'background': { - 'documentation': 'background_pages.html' - }, - 'manifest_version': { - 'documentation': 'manifest/manifest_version.html', - 'example': 2, - 'level': 'required' - }, - 'page_action': { - 'documentation': 'pageAction.html', - 'example': {}, - 'level': 'only_one' - } - }), - 'permissions.json': json.dumps({ - 'fakeUnsupportedFeature': {}, - 'syncFileSystem': { - 'partial': 'permissions/sync_file_system.html' - }, - 'tabs': { - 'partial': 'permissions/tabs.html' - } - }) - } - } - } -} - - -class FeaturesBundleTest(unittest.TestCase): - def setUp(self): - self._server = ServerInstance.ForTest( - TestFileSystem(_TEST_FILESYSTEM, relative_to=CHROME_EXTENSIONS)) - - def testManifestFeatures(self): - expected_features = { - 'background': { - 'name': 'background', - 'channel': 'stable', - 'documentation': 'background_pages.html', - 'extension_types': ['extension', 'legacy_packaged_app', 'hosted_app'] - }, - 'inheritsPlatformAndChannelFromDependency': { - 'name': 'inheritsPlatformAndChannelFromDependency', - 'channel': 'dev', - 'extension_types': ['extension'] - }, - 'manifest_version': { - 'name': 'manifest_version', - 'channel': 'stable', - 'documentation': 'manifest/manifest_version.html', - 'extension_types': 'all', - 'level': 'required', - 'example': 2, - }, - 'omnibox': { - 'name': 'omnibox', - 'channel': 'stable', - 'extension_types': ['extension'], - 'platforms': ['win'], - }, - 'page_action': { - 'name': 'page_action', - 'channel': 'stable', - 'documentation': 'pageAction.html', - 'extension_types': ['extension'], - 'level': 'only_one', - 'example': {}, - }, - 'testDeep4': { - 'name': 'testDeep4', - 'channel': 'stable', - 'extension_types': ['extension'] - }, - 'multipleAmbiguous': { - 'name': 'multipleAmbiguous', - 'channel': 'stable', - 'extension_types': ['extension'] - } - } - self.assertEqual( - expected_features, - self._server.platform_bundle.GetFeaturesBundle( - 'extensions').GetManifestFeatures().Get()) - expected_features = { - 'manifest_version': { - 'name': 'manifest_version', - 'channel': 'stable', - 'documentation': 'manifest/manifest_version.html', - 'extension_types': 'all', - 'level': 'required', - 'example': 2, - }, - 'sockets': { - 'name': 'sockets', - 'channel': 'dev', - 'extension_types': ['platform_app'] - } - } - self.assertEqual( - expected_features, - self._server.platform_bundle.GetFeaturesBundle( - 'apps').GetManifestFeatures().Get()) - - def testPermissionFeatures(self): - expected_features = { - 'power': { - 'name': 'power', - 'channel': 'stable', - 'extension_types': ['extension', 'legacy_packaged_app', 'platform_app'] - }, - 'overridesPlatformAndChannelFromDependency': { - 'name': 'overridesPlatformAndChannelFromDependency', - 'channel': 'stable', - 'extension_types': ['extension'] - }, - 'tabs': { - 'name': 'tabs', - 'channel': 'stable', - 'extension_types': ['extension'], - 'partial': 'permissions/tabs.html' - }, - 'mergingDependencies1': { - 'name': 'mergingDependencies1', - 'channel': 'stable', - 'extension_types': 'all' - }, - 'mergingDependencies3': { - 'name': 'mergingDependencies3', - 'channel': 'stable', - 'extension_types': ['extension'] - }, - 'defaults': { - 'name': 'defaults', - 'channel': 'stable' - } - } - self.assertEqual( - expected_features, - self._server.platform_bundle.GetFeaturesBundle( - 'extensions').GetPermissionFeatures().Get()) - expected_features = { - 'bluetooth': { - 'name': 'bluetooth', - 'channel': 'dev', - 'extension_types': ['platform_app'] - }, - 'power': { - 'name': 'power', - 'channel': 'stable', - 'extension_types': ['extension', 'legacy_packaged_app', 'platform_app'] - }, - 'syncFileSystem': { - 'name': 'syncFileSystem', - 'channel': 'stable', - 'extension_types': ['platform_app'], - 'partial': 'permissions/sync_file_system.html' - }, - 'mergingDependencies1': { - 'name': 'mergingDependencies1', - 'channel': 'stable', - 'extension_types': 'all' - }, - 'mergingDependencies2': { - 'name': 'mergingDependencies2', - 'channel': 'beta', - 'extension_types': ['platform_app'] - }, - 'defaults': { - 'name': 'defaults', - 'channel': 'stable' - } - } - self.assertEqual( - expected_features, - self._server.platform_bundle.GetFeaturesBundle( - 'apps').GetPermissionFeatures().Get()) - - def testAPIFeatures(self): - expected_features = { - 'background': { - 'name': 'background', - 'channel': 'stable', - 'extension_types': ['extension'] - }, - 'omnibox': { - 'name': 'omnibox', - 'contexts': ['blessed_extension'], - 'dependencies': ['manifest:omnibox'], - 'channel': 'stable' - }, - 'tabs': { - 'name': 'tabs', - 'channel': 'stable', - 'contexts': ['blessed_extension'], - 'extension_types': ['extension', 'legacy_packaged_app'], - }, - 'test': { - 'name': 'test', - 'channel': 'stable', - 'contexts': [ - 'blessed_extension', 'unblessed_extension', 'content_script'], - 'extension_types': 'all', - }, - 'windows': { - 'name': 'windows', - 'contexts': ['blessed_extension'], - 'dependencies': ['api:tabs'], - 'channel': 'stable' - }, - 'testDeep1': { - 'name': 'testDeep1', - 'dependencies': ['api:testDeep2'], - 'channel': 'stable' - }, - 'testDeep2': { - 'name': 'testDeep2', - 'dependencies': ['api:testDeep3'], - 'channel': 'stable' - }, - 'testDeep3': { - 'name': 'testDeep3', - 'dependencies': ['manifest:testDeep4'], - 'channel': 'stable' - }, - 'testDeep1.child': { - 'name': 'testDeep1.child', - 'channel': 'stable', - 'dependencies': ['api:testDeep2'] - }, - 'multipleAmbiguous': { - 'name': 'multipleAmbiguous', - 'value': 2, - 'dependencies': ['manifest:multipleAmbiguous'], - 'channel': 'stable' - }, - 'mergingDependencies2': { - 'name': 'mergingDependencies2', - 'dependencies': [ - 'permission:mergingDependencies1', - 'permission:mergingDependencies3' - ], - 'channel': 'stable' - }, - 'inheritsFromDifferentDependencyName': { - 'channel': 'dev', - 'name': 'inheritsFromDifferentDependencyName', - 'dependencies': ['manifest:inheritsPlatformAndChannelFromDependency'], - }, - 'inheritsPlatformAndChannelFromDependency': { - 'channel': 'dev', - 'name': 'inheritsPlatformAndChannelFromDependency', - 'dependencies': ['manifest:inheritsPlatformAndChannelFromDependency'], - }, - 'implicitNoParent.child': { - 'name': 'implicitNoParent.child', - 'channel': 'stable', - 'extension_types': ['extension'], - }, - 'parent': { - 'name': 'parent', - 'channel': 'beta', - 'extension_types': ['extension'], - }, - 'parent.explicitNoParent': { - 'name': 'parent.explicitNoParent', - 'channel': 'stable', - 'extension_types': ['extension'], - 'noparent': True - }, - 'parent.inheritAndOverride': { - 'name': 'parent.inheritAndOverride', - 'channel': 'dev', - 'extension_types': ['extension'] - }, - 'mergeMostStableChannel': { - 'name': 'mergeMostStableChannel', - 'channel': 'stable', - 'extension_types': ['extension'], - 'value2': 2, - 'value4': 4, - 'value5': 5 - } - } - self.assertEqual( - expected_features, - self._server.platform_bundle.GetFeaturesBundle( - 'extensions').GetAPIFeatures().Get()) - expected_features = { - 'audioCapture': { - 'name': 'audioCapture', - 'channel': 'stable', - 'extension_types': ['platform_app'] - }, - 'syncFileSystem': { - 'name': 'syncFileSystem', - 'contexts': ['blessed_extension'], - 'dependencies': ['permission:syncFileSystem'], - 'channel': 'stable' - }, - 'test': { - 'name': 'test', - 'channel': 'stable', - 'contexts': [ - 'blessed_extension', 'unblessed_extension', 'content_script'], - 'extension_types': 'all', - }, - 'multipleAmbiguous': { - 'name': 'multipleAmbiguous', - 'channel': 'stable', - 'extension_types': ['platform_app'], - 'value': 1, - }, - 'mergingDependencies1': { - 'name': 'mergingDependencies1', - 'channel': 'beta', - 'dependencies': [ - 'permission:mergingDependencies1', - 'permission:mergingDependencies2' - ], - }, - 'overridesPlatformAndChannelFromDependency': { - 'name': 'overridesPlatformAndChannelFromDependency', - 'channel': 'beta', - 'dependencies': [ - 'permission:overridesPlatformAndChannelFromDependency' - ], - 'extension_types': ['platform_app'] - }, - 'overridePlatform': { - 'name': 'overridePlatform', - 'channel': 'stable', - 'dependencies': ['permission:tabs'], - 'extension_types': 'platform_app' - } - } - self.assertEqual( - expected_features, - self._server.platform_bundle.GetFeaturesBundle( - 'apps').GetAPIFeatures().Get()) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/file_system.py b/chrome/common/extensions/docs/server2/file_system.py deleted file mode 100644 index 1cbeb75..0000000 --- a/chrome/common/extensions/docs/server2/file_system.py +++ /dev/null
@@ -1,239 +0,0 @@ -# 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. - -import posixpath -import traceback - -from future import Future -from path_util import ( - AssertIsDirectory, AssertIsValid, IsDirectory, IsValid, SplitParent, - ToDirectory) - - -def IsFileSystemThrottledError(error): - return type(error).__name__ == 'FileSystemThrottledError' - - -class _BaseFileSystemException(Exception): - def __init__(self, message): - Exception.__init__(self, message) - - @classmethod - def RaiseInFuture(cls, message): - stack = traceback.format_stack() - def boom(): raise cls('%s. Creation stack:\n%s' % (message, ''.join(stack))) - return Future(callback=boom) - - -class FileNotFoundError(_BaseFileSystemException): - '''Raised when a file isn't found for read or stat. - ''' - def __init__(self, filename): - _BaseFileSystemException.__init__(self, filename) - - -class FileSystemThrottledError(_BaseFileSystemException): - '''Raised when access to a file system resource is temporarily unavailable - due to service throttling. - ''' - def __init__(self, filename): - _BaseFileSystemException.__init__(self, filename) - - -class FileSystemError(_BaseFileSystemException): - '''Raised on when there are errors reading or statting files, such as a - network timeout. - ''' - def __init__(self, filename): - _BaseFileSystemException.__init__(self, filename) - - -class StatInfo(object): - '''The result of calling Stat on a FileSystem. - ''' - def __init__(self, version, child_versions=None): - if child_versions: - assert all(IsValid(path) for path in child_versions.iterkeys()), \ - child_versions - self.version = version - self.child_versions = child_versions - - def __eq__(self, other): - return (isinstance(other, StatInfo) and - self.version == other.version and - self.child_versions == other.child_versions) - - def __ne__(self, other): - return not (self == other) - - def __str__(self): - return '{version: %s, child_versions: %s}' % (self.version, - self.child_versions) - - def __repr__(self): - return str(self) - - -class FileSystem(object): - '''A FileSystem interface that can read files and directories. - ''' - def Read(self, paths, skip_not_found=False): - '''Reads each file in paths and returns a dictionary mapping the path to the - contents. If a path in paths ends with a '/', it is assumed to be a - directory, and a list of files in the directory is mapped to the path. - - The contents will be a str. - - If any path cannot be found: - - If |skip_not_found| is True, the resulting object will not contain any - mapping for that path. - - Otherwise, and by default, a FileNotFoundError is raised. This is - guaranteed to only happen once the Future has been resolved (Get() - called). - - For any other failure, raises a FileSystemError. - ''' - raise NotImplementedError(self.__class__) - - def ReadSingle(self, path, skip_not_found=False): - '''Reads a single file from the FileSystem. Returns a Future with the same - rules as Read(). If |path| is not found raise a FileNotFoundError on Get(), - or if |skip_not_found| is True then return None. - ''' - AssertIsValid(path) - read_single = self.Read([path], skip_not_found=skip_not_found) - return Future(callback=lambda: read_single.Get().get(path, None)) - - def Exists(self, path): - '''Returns a Future to the existence of |path|; True if |path| exists, - False if not. This method will not throw a FileNotFoundError unlike - the Read* methods, however it may still throw a FileSystemError. - - There are several ways to implement this method via the interface but this - method exists to do so in a canonical and most efficient way for caching. - ''' - AssertIsValid(path) - if path == '': - # There is always a root directory. - return Future(value=True) - - parent, base = SplitParent(path) - def handle(error): - if isinstance(error, FileNotFoundError): - return False - raise error - return self.ReadSingle(ToDirectory(parent)).Then(lambda l: base in l, - handle) - - def Refresh(self): - '''Asynchronously refreshes the content of the FileSystem, returning a - future to its completion. - ''' - raise NotImplementedError(self.__class__) - - # TODO(cduvall): Allow Stat to take a list of paths like Read. - def Stat(self, path): - '''DEPRECATED: Please try to use StatAsync instead. - - Returns a |StatInfo| object containing the version of |path|. If |path| - is a directory, |StatInfo| will have the versions of all the children of - the directory in |StatInfo.child_versions|. - - If the path cannot be found, raises a FileNotFoundError. - For any other failure, raises a FileSystemError. - ''' - # Delegate to this implementation's StatAsync if it has been implemented. - if type(self).StatAsync != FileSystem.StatAsync: - return self.StatAsync(path).Get() - raise NotImplementedError(self.__class__) - - def StatAsync(self, path): - '''An async version of Stat. Returns a Future to a StatInfo rather than a - raw StatInfo. - - This is a bandaid for a lack of an async Stat function. Stat() should be - async by default but for now just let implementations override this if they - like. - ''' - return Future(callback=lambda: self.Stat(path)) - - def GetIdentity(self): - '''The identity of the file system, exposed for caching classes to - namespace their caches. This will usually depend on the configuration of - that file system - e.g. a LocalFileSystem with a base path of /var is - different to that of a SubversionFileSystem with a base path of /bar, is - different to a LocalFileSystem with a base path of /usr. - ''' - raise NotImplementedError(self.__class__) - - def GetVersion(self): - '''The version of the file system, exposed for more granular caching. - This may be any serializable data, though generally it should be a revision - number or hash string. The default implementation returns None, indicating - that the FileSystem is not versioned. - ''' - return None - - def Walk(self, root, depth=-1, file_lister=None): - '''Recursively walk the directories in a file system, starting with root. - - Behaviour is very similar to os.walk from the standard os module, yielding - (base, dirs, files) recursively, where |base| is the base path of |files|, - |dirs| relative to |root|, and |files| and |dirs| the list of files/dirs in - |base| respectively. If |depth| is specified and greater than 0, Walk will - only recurse |depth| times. - - |file_lister|, if specified, should be a callback of signature - - def my_file_lister(root):, - - which returns a tuple (dirs, files), where |dirs| is a list of directory - names under |root|, and |files| is a list of file names under |root|. Note - that the listing of files and directories should be for a *single* level - only, i.e. it should not recursively list anything. - - Note that directories will always end with a '/', files never will. - - If |root| cannot be found, raises a FileNotFoundError. - For any other failure, raises a FileSystemError. - ''' - AssertIsDirectory(root) - basepath = root - - def walk(root, depth): - if depth == 0: - return - AssertIsDirectory(root) - - if file_lister: - dirs, files = file_lister(root) - else: - dirs, files = [], [] - for f in self.ReadSingle(root).Get(): - if IsDirectory(f): - dirs.append(f) - else: - files.append(f) - - yield root[len(basepath):].rstrip('/'), dirs, files - - for d in dirs: - for walkinfo in walk(root + d, depth - 1): - yield walkinfo - - for walkinfo in walk(root, depth): - yield walkinfo - - def __eq__(self, other): - return (isinstance(other, FileSystem) and - self.GetIdentity() == other.GetIdentity()) - - def __ne__(self, other): - return not (self == other) - - def __repr__(self): - return '<%s>' % type(self).__name__ - - def __str__(self): - return repr(self)
diff --git a/chrome/common/extensions/docs/server2/file_system_test.py b/chrome/common/extensions/docs/server2/file_system_test.py deleted file mode 100755 index d747024..0000000 --- a/chrome/common/extensions/docs/server2/file_system_test.py +++ /dev/null
@@ -1,129 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from test_file_system import TestFileSystem - -file_system = TestFileSystem({ - 'file.txt': '', - 'templates': { - 'README': '', - 'public': { - 'apps': { - '404.html': '', - 'a11y.html': '' - }, - 'extensions': { - '404.html': '', - 'cookies.html': '' - }, - 'redirects.json': 'redirect' - }, - 'json': { - 'manifest.json': 'manifest' - } - } -}) - -class FileSystemTest(unittest.TestCase): - def testWalk(self): - expected_files = [ - '^/file.txt', - 'templates/README', - 'templates/public/apps/404.html', - 'templates/public/apps/a11y.html', - 'templates/public/extensions/404.html', - 'templates/public/extensions/cookies.html', - 'templates/public/redirects.json', - 'templates/json/manifest.json' - ] - - expected_dirs = [ - '^/templates/', - 'templates/public/', - 'templates/public/apps/', - 'templates/public/extensions/', - 'templates/json/' - ] - - all_files = [] - all_dirs = [] - for root, dirs, files in file_system.Walk(''): - if not root: root = '^' - all_files += [root + '/' + name for name in files] - all_dirs += [root + '/' + name for name in dirs] - - self.assertEqual(sorted(expected_files), sorted(all_files)) - self.assertEqual(sorted(expected_dirs), sorted(all_dirs)) - - def testWalkDepth(self): - all_dirs = [] - all_files = [] - for root, dirs, files in file_system.Walk('', depth=0): - all_dirs.extend(dirs) - all_files.extend(files) - self.assertEqual([], all_dirs) - self.assertEqual([], all_files) - - for root, dirs, files in file_system.Walk('', depth=1): - all_dirs.extend(dirs) - all_files.extend(files) - self.assertEqual(['templates/'], all_dirs) - self.assertEqual(['file.txt'], all_files) - - all_dirs = [] - all_files = [] - for root, dirs, files in file_system.Walk('', depth=2): - all_dirs.extend(dirs) - all_files.extend(files) - self.assertEqual(sorted(['templates/', 'public/', 'json/']), - sorted(all_dirs)) - self.assertEqual(sorted(['file.txt', 'README']), sorted(all_files)) - - - def testSubWalk(self): - expected_files = set([ - '/redirects.json', - 'apps/404.html', - 'apps/a11y.html', - 'extensions/404.html', - 'extensions/cookies.html' - ]) - - all_files = set() - for root, dirs, files in file_system.Walk('templates/public/'): - all_files.update(root + '/' + name for name in files) - - self.assertEqual(expected_files, all_files) - - def testExists(self): - def exists(path): - return file_system.Exists(path).Get() - - # Root directory. - self.assertTrue(exists('')) - - # Directories (are not files). - self.assertFalse(exists('templates')) - self.assertTrue(exists('templates/')) - self.assertFalse(exists('templates/public')) - self.assertTrue(exists('templates/public/')) - self.assertFalse(exists('templates/public/apps')) - self.assertTrue(exists('templates/public/apps/')) - - # Files (are not directories). - self.assertTrue(exists('file.txt')) - self.assertFalse(exists('file.txt/')) - self.assertTrue(exists('templates/README')) - self.assertFalse(exists('templates/README/')) - self.assertTrue(exists('templates/public/redirects.json')) - self.assertFalse(exists('templates/public/redirects.json/')) - self.assertTrue(exists('templates/public/apps/a11y.html')) - self.assertFalse(exists('templates/public/apps/a11y.html/')) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/file_system_util.py b/chrome/common/extensions/docs/server2/file_system_util.py deleted file mode 100644 index 0882564..0000000 --- a/chrome/common/extensions/docs/server2/file_system_util.py +++ /dev/null
@@ -1,14 +0,0 @@ -# Copyright 2013 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 posixpath - -def CreateURLsFromPaths(file_system, directory, urlprefix): - '''Yields a tuple (url, prefix) for every file in |directory|, where the URL - is given relative to |urlprefix|. - ''' - for root, _, files in file_system.Walk(directory): - for f in files: - url = posixpath.join(urlprefix, root, f) - yield url, posixpath.join(directory, root, f)
diff --git a/chrome/common/extensions/docs/server2/future.py b/chrome/common/extensions/docs/server2/future.py deleted file mode 100644 index 289761c4..0000000 --- a/chrome/common/extensions/docs/server2/future.py +++ /dev/null
@@ -1,133 +0,0 @@ -# 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. - -import logging -import sys -import traceback - -_no_value = object() - - -def _DefaultErrorHandler(error): - raise error - - -def All(futures, except_pass=None, except_pass_log=False): - '''Creates a Future which returns a list of results from each Future in - |futures|. - - If any Future raises an error other than those in |except_pass| the returned - Future will raise as well. - - If any Future raises an error in |except_pass| then None will be inserted as - its result. If |except_pass_log| is True then the exception will be logged. - ''' - def resolve(): - resolved = [] - for f in futures: - try: - resolved.append(f.Get()) - # "except None" will simply not catch any errors. - except except_pass: - if except_pass_log: - logging.error(traceback.format_exc()) - resolved.append(None) - pass - return resolved - return Future(callback=resolve) - - -def Race(futures, except_pass=None, default=_no_value): - '''Returns a Future which resolves to the first Future in |futures| that - either succeeds or throws an error apart from those in |except_pass|. - - If all Futures throw errors in |except_pass| then |default| is returned, - if specified. If |default| is not specified then one of the passed errors - will be re-thrown, for a nice stack trace. - ''' - def resolve(): - first_future = None - for future in futures: - if first_future is None: - first_future = future - try: - return future.Get() - # "except None" will simply not catch any errors. - except except_pass: - pass - if default is not _no_value: - return default - # Everything failed and there is no default value, propagate the first - # error even though it was caught by |except_pass|. - return first_future.Get() - return Future(callback=resolve) - - -class Future(object): - '''Stores a value, error, or callback to be used later. - ''' - def __init__(self, value=_no_value, callback=None, exc_info=None): - self._value = value - self._callback = callback - self._exc_info = exc_info - if (self._value is _no_value and - self._callback is None and - self._exc_info is None): - raise ValueError('Must have either a value, error, or callback.') - - def Then(self, callback, error_handler=_DefaultErrorHandler): - '''Creates and returns a future that runs |callback| on the value of this - future, or runs optional |error_handler| if resolving this future results in - an exception. - - If |callback| returns a non-Future value then the returned Future will - resolve to that value. - - If |callback| returns a Future then it gets chained to the current Future. - This means that the returned Future will resolve to *that* Future's value. - This behaviour is transitive. - - For example, - - def fortytwo(): - return Future(value=42) - - def inc(x): - return x + 1 - - def inc_future(x): - return Future(value=x + 1) - - fortytwo().Then(inc).Get() ==> 43 - fortytwo().Then(inc_future).Get() ==> 43 - fortytwo().Then(inc_future).Then(inc_future).Get() ==> 44 - ''' - def then(): - val = None - try: - val = self.Get() - except Exception as e: - val = error_handler(e) - else: - val = callback(val) - return val.Get() if isinstance(val, Future) else val - return Future(callback=then) - - def Get(self): - '''Gets the stored value, error, or callback contents. - ''' - if self._value is not _no_value: - return self._value - if self._exc_info is not None: - self._Raise() - try: - self._value = self._callback() - return self._value - except: - self._exc_info = sys.exc_info() - self._Raise() - - def _Raise(self): - exc_info = self._exc_info - raise exc_info[0], exc_info[1], exc_info[2]
diff --git a/chrome/common/extensions/docs/server2/future_test.py b/chrome/common/extensions/docs/server2/future_test.py deleted file mode 100755 index 33c82b27..0000000 --- a/chrome/common/extensions/docs/server2/future_test.py +++ /dev/null
@@ -1,285 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 traceback -import unittest - - -from future import All, Future, Race -from mock_function import MockFunction - - -class FutureTest(unittest.TestCase): - def testNoValueOrDelegate(self): - self.assertRaises(ValueError, Future) - - def testValue(self): - future = Future(value=42) - self.assertEqual(42, future.Get()) - self.assertEqual(42, future.Get()) - - def testDelegateValue(self): - called = [False,] - def callback(): - self.assertFalse(called[0]) - called[0] = True - return 42 - future = Future(callback=callback) - self.assertEqual(42, future.Get()) - self.assertEqual(42, future.Get()) - - def testErrorThrowingDelegate(self): - class FunkyException(Exception): - pass - - # Set up a chain of functions to test the stack trace. - def qux(): - raise FunkyException() - def baz(): - return qux() - def bar(): - return baz() - def foo(): - return bar() - chain = [foo, bar, baz, qux] - - called = [False,] - def callback(): - self.assertFalse(called[0]) - called[0] = True - return foo() - - fail = self.fail - assertTrue = self.assertTrue - def assert_raises_full_stack(future, err): - try: - future.Get() - fail('Did not raise %s' % err) - except Exception as e: - assertTrue(isinstance(e, err)) - stack = traceback.format_exc() - assertTrue(all(stack.find(fn.__name__) != -1 for fn in chain)) - - future = Future(callback=callback) - assert_raises_full_stack(future, FunkyException) - assert_raises_full_stack(future, FunkyException) - - def testAll(self): - def callback_with_value(value): - return MockFunction(lambda: value) - - # Test a single value. - callback = callback_with_value(42) - future = All((Future(callback=callback),)) - self.assertTrue(*callback.CheckAndReset(0)) - self.assertEqual([42], future.Get()) - self.assertTrue(*callback.CheckAndReset(1)) - - # Test multiple callbacks. - callbacks = (callback_with_value(1), - callback_with_value(2), - callback_with_value(3)) - future = All(Future(callback=callback) for callback in callbacks) - for callback in callbacks: - self.assertTrue(*callback.CheckAndReset(0)) - self.assertEqual([1, 2, 3], future.Get()) - for callback in callbacks: - self.assertTrue(*callback.CheckAndReset(1)) - - # Test throwing an error. - def throws_error(): - raise ValueError() - callbacks = (callback_with_value(1), - callback_with_value(2), - MockFunction(throws_error)) - - future = All(Future(callback=callback) for callback in callbacks) - for callback in callbacks: - self.assertTrue(*callback.CheckAndReset(0)) - self.assertRaises(ValueError, future.Get) - for callback in callbacks: - # Can't check that the callbacks were actually run because in theory the - # Futures can be resolved in any order. - callback.CheckAndReset(0) - - # Test throwing an error with except_pass. - future = All((Future(callback=callback) for callback in callbacks), - except_pass=ValueError) - for callback in callbacks: - self.assertTrue(*callback.CheckAndReset(0)) - self.assertEqual([1, 2, None], future.Get()) - - def testRaceSuccess(self): - callback = MockFunction(lambda: 42) - - # Test a single value. - race = Race((Future(callback=callback),)) - self.assertTrue(*callback.CheckAndReset(0)) - self.assertEqual(42, race.Get()) - self.assertTrue(*callback.CheckAndReset(1)) - - # Test multiple success values. Note that we could test different values - # and check that the first returned, but this is just an implementation - # detail of Race. When we have parallel Futures this might not always hold. - race = Race((Future(callback=callback), - Future(callback=callback), - Future(callback=callback))) - self.assertTrue(*callback.CheckAndReset(0)) - self.assertEqual(42, race.Get()) - # Can't assert the actual count here for the same reason as above. - callback.CheckAndReset(99) - - # Test values with except_pass. - def throws_error(): - raise ValueError() - race = Race((Future(callback=callback), - Future(callback=throws_error)), - except_pass=(ValueError,)) - self.assertTrue(*callback.CheckAndReset(0)) - self.assertEqual(42, race.Get()) - self.assertTrue(*callback.CheckAndReset(1)) - - def testRaceErrors(self): - def throws_error(): - raise ValueError() - - # Test a single error. - race = Race((Future(callback=throws_error),)) - self.assertRaises(ValueError, race.Get) - - # Test multiple errors. Can't use different error types for the same reason - # as described in testRaceSuccess. - race = Race((Future(callback=throws_error), - Future(callback=throws_error), - Future(callback=throws_error))) - self.assertRaises(ValueError, race.Get) - - # Test values with except_pass. - def throws_except_error(): - raise NotImplementedError() - race = Race((Future(callback=throws_error), - Future(callback=throws_except_error)), - except_pass=(NotImplementedError,)) - self.assertRaises(ValueError, race.Get) - - race = Race((Future(callback=throws_error), - Future(callback=throws_error)), - except_pass=(ValueError,)) - self.assertRaises(ValueError, race.Get) - - # Test except_pass with default values. - race = Race((Future(callback=throws_error), - Future(callback=throws_except_error)), - except_pass=(NotImplementedError,), - default=42) - self.assertRaises(ValueError, race.Get) - - race = Race((Future(callback=throws_error), - Future(callback=throws_error)), - except_pass=(ValueError,), - default=42) - self.assertEqual(42, race.Get()) - - def testThen(self): - def assertIs42(val): - self.assertEqual(val, 42) - return val - - then = Future(value=42).Then(assertIs42) - # Shouldn't raise an error. - self.assertEqual(42, then.Get()) - - # Test raising an error. - then = Future(value=41).Then(assertIs42) - self.assertRaises(AssertionError, then.Get) - - # Test setting up an error handler. - def handle(error): - if isinstance(error, ValueError): - return 'Caught' - raise error - - def raiseValueError(): - raise ValueError - - def raiseException(): - raise Exception - - then = Future(callback=raiseValueError).Then(assertIs42, handle) - self.assertEqual('Caught', then.Get()) - then = Future(callback=raiseException).Then(assertIs42, handle) - self.assertRaises(Exception, then.Get) - - # Test chains of thens. - addOne = lambda val: val + 1 - then = Future(value=40).Then(addOne).Then(addOne).Then(assertIs42) - # Shouldn't raise an error. - self.assertEqual(42, then.Get()) - - # Test error in chain. - then = Future(value=40).Then(addOne).Then(assertIs42).Then(addOne) - self.assertRaises(AssertionError, then.Get) - - # Test handle error in chain. - def raiseValueErrorWithVal(val): - raise ValueError - - then = Future(value=40).Then(addOne).Then(raiseValueErrorWithVal).Then( - addOne, handle).Then(lambda val: val + ' me') - self.assertEquals(then.Get(), 'Caught me') - - # Test multiple handlers. - def myHandle(error): - if isinstance(error, AssertionError): - return 10 - raise error - - then = Future(value=40).Then(assertIs42).Then(addOne, handle).Then(addOne, - myHandle) - self.assertEquals(then.Get(), 10) - - def testThenResolvesReturnedFutures(self): - def returnsFortyTwo(): - return Future(value=42) - def inc(x): - return x + 1 - def incFuture(x): - return Future(value=x + 1) - - self.assertEqual(43, returnsFortyTwo().Then(inc).Get()) - self.assertEqual(43, returnsFortyTwo().Then(incFuture).Get()) - self.assertEqual(44, returnsFortyTwo().Then(inc).Then(inc).Get()) - self.assertEqual(44, returnsFortyTwo().Then(inc).Then(incFuture).Get()) - self.assertEqual(44, returnsFortyTwo().Then(incFuture).Then(inc).Get()) - self.assertEqual( - 44, returnsFortyTwo().Then(incFuture).Then(incFuture).Get()) - - # The same behaviour should apply to error handlers. - def raisesSomething(): - def boom(): raise ValueError - return Future(callback=boom) - def shouldNotHappen(_): - raise AssertionError() - def oops(error): - return 'oops' - def oopsFuture(error): - return Future(value='oops') - - self.assertEqual( - 'oops', raisesSomething().Then(shouldNotHappen, oops).Get()) - self.assertEqual( - 'oops', raisesSomething().Then(shouldNotHappen, oopsFuture).Get()) - self.assertEqual( - 'oops', - raisesSomething().Then(shouldNotHappen, raisesSomething) - .Then(shouldNotHappen, oops).Get()) - self.assertEqual( - 'oops', - raisesSomething().Then(shouldNotHappen, raisesSomething) - .Then(shouldNotHappen, oopsFuture).Get()) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/gcs_file_system.py b/chrome/common/extensions/docs/server2/gcs_file_system.py deleted file mode 100644 index 62c21be..0000000 --- a/chrome/common/extensions/docs/server2/gcs_file_system.py +++ /dev/null
@@ -1,120 +0,0 @@ -# Copyright 2014 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 json -import logging -import posixpath -import traceback -import urllib - -from docs_server_utils import StringIdentity -from environment_wrappers import CreateUrlFetcher -from file_system import FileSystem, FileNotFoundError, StatInfo -from future import Future -from path_util import ( - AssertIsDirectory, AssertIsFile, AssertIsValid, IsDirectory, Join) - - -# See gcs_file_system_provider.py for documentation on using Google Cloud -# Storage as a filesystem. -# -# Note that the path requirements for GCS are different for the docserver; -# GCS requires that paths start with a /, we require that they don't. - - -# Name of the file containing the Git hash of the latest commit sync'ed -# to Cloud Storage. This file is generated by the Github->GCS sync script -_LAST_COMMIT_HASH_FILENAME = '.__lastcommit.txt' - - -# Base URL for GCS requests. -_STORAGE_API_BASE = 'https://www.googleapis.com/storage/v1' - - -class CloudStorageFileSystem(FileSystem): - '''FileSystem implementation which fetches resources from Google Cloud - Storage. - ''' - def __init__(self, bucket, debug_bucket_prefix=None): - self._bucket = bucket - self._access_token = None - self._last_commit_hash = None - AssertIsValid(self._bucket) - - def Read(self, paths, skip_not_found=False): - def resolve(): - result = {} - for path in paths: - if IsDirectory(path): - result[path] = self._ListDir(path) - else: - result[path] = self._ReadFile(path) - return result - - return Future(callback=resolve) - - def Refresh(self): - return Future(value=()) - - def Stat(self, path): - AssertIsValid(path) - return self._CreateStatInfo(path) - - def GetIdentity(self): - return '@'.join((self.__class__.__name__, StringIdentity(self._bucket))) - - def _CreateStatInfo(self, path): - if not self._last_commit_hash: - self._last_commit_hash = self._ReadFile(_LAST_COMMIT_HASH_FILENAME) - if IsDirectory(path): - child_versions = dict((filename, self._last_commit_hash) - for filename in self._ListDir(path)) - else: - child_versions = None - return StatInfo(self._last_commit_hash, child_versions) - - def _ReadFile(self, path): - AssertIsFile(path) - return self._FetchObjectData(path) - - def _ListDir(self, path, recursive=False): - AssertIsDirectory(path) - # The listbucket method uses a prefix approach to simulate hierarchy. - # Calling it with the "delimiter" argument set to '/' gets only files - # directly inside the directory, not all recursive content. - - # Subdirectories are returned in the 'prefixes' property, but they are - # full paths from the root. This plucks off the name of the leaf with a - # trailing slash. - def path_from_prefix(prefix): - return posixpath.split(posixpath.split(prefix)[0])[1] + '/' - - query = { 'prefix': path } - if not recursive: - query['delimiter'] = '/' - root_object = json.loads(self._FetchObject('', query=query)) - files = [posixpath.basename(o['name']) - for o in root_object.get('items', [])] - dirs = [path_from_prefix(prefix) - for prefix in root_object.get('prefixes', [])] - return files + dirs - - def _FetchObject(self, path, query={}): - # Escape the path, including slashes. - url_path = urllib.quote(path.lstrip('/'), safe='') - fetcher = CreateUrlFetcher() - object_url = '%s/b/%s/o/%s' % (_STORAGE_API_BASE, self._bucket, url_path) - response = fetcher.Fetch(object_url, query=query) - if response.status_code != 200: - raise FileNotFoundError( - 'Path %s not found in GCS bucket %s' % (path, self._bucket)) - return response.content - - def _FetchObjectData(self, path, query={}): - q = query.copy() - q.update({ 'alt': 'media' }) - return self._FetchObject(path, query=q) - - def __repr__(self): - return 'CloudStorageFileSystem(%s)' % self._bucket
diff --git a/chrome/common/extensions/docs/server2/gcs_file_system_provider.py b/chrome/common/extensions/docs/server2/gcs_file_system_provider.py deleted file mode 100644 index f355e64c..0000000 --- a/chrome/common/extensions/docs/server2/gcs_file_system_provider.py +++ /dev/null
@@ -1,65 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import environment -import logging - -from caching_file_system import CachingFileSystem -from empty_dir_file_system import EmptyDirFileSystem -from environment import IsTest -from extensions_paths import LOCAL_GCS_DIR, LOCAL_GCS_DEBUG_CONF -from gcs_file_system import CloudStorageFileSystem -from local_file_system import LocalFileSystem -from path_util import ToDirectory - - -class CloudStorageFileSystemProvider(object): - '''Provides CloudStorageFileSystem bound to a GCS bucket. - ''' - def __init__(self, object_store_creator): - self._object_store_creator = object_store_creator - - def Create(self, bucket): - '''Creates a CloudStorageFileSystemProvider. - - |bucket| is the name of GCS bucket, eg devtools-docs. It is expected - that this bucket has Read permission for this app in its ACLs. - - Optional configuration can be set in a local_debug/gcs_debug.conf file: - use_local_fs=True|False - remote_bucket_prefix=<prefix> - - If running in Preview mode or in Development mode with use_local_fs set to - True, buckets and files are looked for inside the local_debug folder instead - of in the real GCS server. - ''' - if IsTest(): - return EmptyDirFileSystem() - - debug_bucket_prefix = None - use_local_fs = False - if os.path.exists(LOCAL_GCS_DEBUG_CONF): - with open(LOCAL_GCS_DEBUG_CONF, "r") as token_file: - properties = dict(line.strip().split('=', 1) for line in token_file) - use_local_fs = properties.get('use_local_fs', 'False')=='True' - debug_bucket_prefix = properties.get('remote_bucket_prefix', None) - logging.debug('gcs: prefixing all bucket names with %s' % - debug_bucket_prefix) - - if use_local_fs: - return LocalFileSystem(ToDirectory(os.path.join(LOCAL_GCS_DIR, bucket))) - - if debug_bucket_prefix: - bucket = debug_bucket_prefix + bucket - - return CachingFileSystem(CloudStorageFileSystem(bucket), - self._object_store_creator) - - @staticmethod - def ForEmpty(): - class EmptyImpl(object): - def Create(self, bucket): - return EmptyDirFileSystem() - return EmptyImpl()
diff --git a/chrome/common/extensions/docs/server2/handler.py b/chrome/common/extensions/docs/server2/handler.py deleted file mode 100644 index 736e352..0000000 --- a/chrome/common/extensions/docs/server2/handler.py +++ /dev/null
@@ -1,46 +0,0 @@ -# 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. - -import time - -from admin_servlets import (QueryCommitServlet, FlushMemcacheServlet, - UpdateCacheServlet) -from instance_servlet import InstanceServlet -from patch_servlet import PatchServlet -from servlet import Servlet, Request, Response -from test_servlet import TestServlet - - -_DEFAULT_SERVLET = InstanceServlet.GetConstructor() - - -_SERVLETS = { - 'patch': PatchServlet, - 'query_commit': QueryCommitServlet, - 'flush_memcache': FlushMemcacheServlet, - 'update_cache': UpdateCacheServlet, - 'test': TestServlet, -} - - -class Handler(Servlet): - def Get(self): - path = self._request.path - - if path.startswith('_'): - servlet_path = path[1:] - if not '/' in servlet_path: - servlet_path += '/' - servlet_name, servlet_path = servlet_path.split('/', 1) - servlet = _SERVLETS.get(servlet_name) - if servlet is None: - return Response.NotFound('"%s" servlet not found' % servlet_path) - else: - servlet_path = path - servlet = _DEFAULT_SERVLET - - return servlet(Request(servlet_path, - self._request.host, - self._request.headers, - self._request.arguments)).Get()
diff --git a/chrome/common/extensions/docs/server2/handler_test.py b/chrome/common/extensions/docs/server2/handler_test.py deleted file mode 100755 index 34dd2b1..0000000 --- a/chrome/common/extensions/docs/server2/handler_test.py +++ /dev/null
@@ -1,18 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from handler import Handler -from servlet import Request - -class HandlerTest(unittest.TestCase): - - def testInvalid(self): - handler = Handler(Request.ForTest('_notreal')) - self.assertEqual(404, handler.Get().status) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/host_file_system_iterator.py b/chrome/common/extensions/docs/server2/host_file_system_iterator.py deleted file mode 100644 index 867adec..0000000 --- a/chrome/common/extensions/docs/server2/host_file_system_iterator.py +++ /dev/null
@@ -1,37 +0,0 @@ -# Copyright 2013 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. - - -class HostFileSystemIterator(object): - '''Provides methods for iterating through host file systems, in both - ascending (oldest to newest version) and descending order. - ''' - - def __init__(self, file_system_provider, branch_utility): - self._file_system_provider = file_system_provider - self._branch_utility = branch_utility - - def _ForEach(self, channel_info, callback, get_next): - '''Iterates through a sequence of file systems defined by |get_next| until - |callback| returns False, or until the end of the sequence of file systems - is reached. Returns the BranchUtility.ChannelInfo of the last file system - for which |callback| returned True. - ''' - last_true = None - while channel_info is not None: - if channel_info.branch == 'master': - file_system = self._file_system_provider.GetMaster() - else: - file_system = self._file_system_provider.GetBranch(channel_info.branch) - if not callback(file_system, channel_info): - return last_true - last_true = channel_info - channel_info = get_next(channel_info) - return last_true - - def Ascending(self, channel_info, callback): - return self._ForEach(channel_info, callback, self._branch_utility.Newer) - - def Descending(self, channel_info, callback): - return self._ForEach(channel_info, callback, self._branch_utility.Older)
diff --git a/chrome/common/extensions/docs/server2/host_file_system_iterator_test.py b/chrome/common/extensions/docs/server2/host_file_system_iterator_test.py deleted file mode 100755 index 5ef4ab2..0000000 --- a/chrome/common/extensions/docs/server2/host_file_system_iterator_test.py +++ /dev/null
@@ -1,186 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 copy import deepcopy -import unittest - -from host_file_system_provider import HostFileSystemProvider -from host_file_system_iterator import HostFileSystemIterator -from object_store_creator import ObjectStoreCreator -from test_branch_utility import TestBranchUtility -from test_data.canned_data import CANNED_API_FILE_SYSTEM_DATA -from test_file_system import TestFileSystem - - -def _GetIterationTracker(version): - '''Adds the ChannelInfo object from each iteration to a list, and signals the - loop to stop when |version| is reached. - ''' - iterations = [] - def callback(file_system, channel_info): - if channel_info.version == version: - return False - iterations.append(channel_info) - return True - return (iterations, callback) - - -class HostFileSystemIteratorTest(unittest.TestCase): - - def setUp(self): - def host_file_system_constructor(branch, **optargs): - return TestFileSystem(deepcopy(CANNED_API_FILE_SYSTEM_DATA[branch])) - host_file_system_provider = HostFileSystemProvider( - ObjectStoreCreator.ForTest(), - constructor_for_test=host_file_system_constructor) - self._branch_utility = TestBranchUtility.CreateWithCannedData() - self._iterator = HostFileSystemIterator( - host_file_system_provider, - self._branch_utility) - - def _GetStableChannelInfo(self,version): - return self._branch_utility.GetStableChannelInfo(version) - - def _GetChannelInfo(self, channel_name): - return self._branch_utility.GetChannelInfo(channel_name) - - def testAscending(self): - # Start at |stable| version 5, and move up towards |master|. - # Total: 28 file systems. - iterations, callback = _GetIterationTracker(0) - self.assertEqual( - self._iterator.Ascending(self._GetStableChannelInfo(5), callback), - self._GetChannelInfo('master')) - self.assertEqual(len(iterations), 28) - - # Start at |stable| version 5, and move up towards |master|. The callback - # fails at |beta|, so the last successful callback was the latest version - # of |stable|. Total: 25 file systems. - iterations, callback = _GetIterationTracker( - self._GetChannelInfo('beta').version) - self.assertEqual( - self._iterator.Ascending(self._GetStableChannelInfo(5), callback), - self._GetChannelInfo('stable')) - self.assertEqual(len(iterations), 25) - - # Start at |stable| version 5, and the callback fails immediately. Since - # no file systems are successfully processed, expect a return of None. - iterations, callback = _GetIterationTracker(5) - self.assertEqual( - self._iterator.Ascending(self._GetStableChannelInfo(5), callback), - None) - self.assertEqual([], iterations) - - # Start at |stable| version 5, and the callback fails at version 6. - # The return should represent |stable| version 5. - iterations, callback = _GetIterationTracker(6) - self.assertEqual( - self._iterator.Ascending(self._GetStableChannelInfo(5), callback), - self._GetStableChannelInfo(5)) - self.assertEqual([self._GetStableChannelInfo(5)], iterations) - - # Start at the latest version of |stable|, and the callback fails at - # |master|. Total: 3 file systems. - iterations, callback = _GetIterationTracker('master') - self.assertEqual( - self._iterator.Ascending(self._GetChannelInfo('stable'), callback), - self._GetChannelInfo('dev')) - self.assertEqual([self._GetChannelInfo('stable'), - self._GetChannelInfo('beta'), - self._GetChannelInfo('dev')], iterations) - - # Start at |stable| version 10, and the callback fails at |master|. - iterations, callback = _GetIterationTracker('master') - self.assertEqual( - self._iterator.Ascending(self._GetStableChannelInfo(10), callback), - self._GetChannelInfo('dev')) - self.assertEqual([self._GetStableChannelInfo(10), - self._GetStableChannelInfo(11), - self._GetStableChannelInfo(12), - self._GetStableChannelInfo(13), - self._GetStableChannelInfo(14), - self._GetStableChannelInfo(15), - self._GetStableChannelInfo(16), - self._GetStableChannelInfo(17), - self._GetStableChannelInfo(18), - self._GetStableChannelInfo(19), - self._GetStableChannelInfo(20), - self._GetStableChannelInfo(21), - self._GetStableChannelInfo(22), - self._GetStableChannelInfo(23), - self._GetStableChannelInfo(24), - self._GetStableChannelInfo(25), - self._GetStableChannelInfo(26), - self._GetStableChannelInfo(27), - self._GetStableChannelInfo(28), - self._GetChannelInfo('stable'), - self._GetChannelInfo('beta'), - self._GetChannelInfo('dev')], iterations) - - def testDescending(self): - # Start at |master|, and the callback fails immediately. No file systems - # are successfully processed, so Descending() will return None. - iterations, callback = _GetIterationTracker('master') - self.assertEqual( - self._iterator.Descending(self._GetChannelInfo('master'), callback), - None) - self.assertEqual([], iterations) - - # Start at |master|, and the callback fails at |dev|. Last good iteration - # should be |master|. - iterations, callback = _GetIterationTracker( - self._GetChannelInfo('dev').version) - self.assertEqual( - self._iterator.Descending(self._GetChannelInfo('master'), callback), - self._GetChannelInfo('master')) - self.assertEqual([self._GetChannelInfo('master')], iterations) - - # Start at |master|, and then move from |dev| down to |stable| at version 5. - # Total: 28 file systems. - iterations, callback = _GetIterationTracker(0) - self.assertEqual( - self._iterator.Descending(self._GetChannelInfo('master'), callback), - self._GetStableChannelInfo(5)) - self.assertEqual(len(iterations), 28) - - # Start at the latest version of |stable|, and move down to |stable| at - # version 5. Total: 25 file systems. - iterations, callback = _GetIterationTracker(0) - self.assertEqual( - self._iterator.Descending(self._GetChannelInfo('stable'), callback), - self._GetStableChannelInfo(5)) - self.assertEqual(len(iterations), 25) - - # Start at |dev| and iterate down through |stable| versions. The callback - # fails at version 10. Total: 18 file systems. - iterations, callback = _GetIterationTracker(10) - self.assertEqual( - self._iterator.Descending(self._GetChannelInfo('dev'), callback), - self._GetStableChannelInfo(11)) - self.assertEqual([self._GetChannelInfo('dev'), - self._GetChannelInfo('beta'), - self._GetChannelInfo('stable'), - self._GetStableChannelInfo(28), - self._GetStableChannelInfo(27), - self._GetStableChannelInfo(26), - self._GetStableChannelInfo(25), - self._GetStableChannelInfo(24), - self._GetStableChannelInfo(23), - self._GetStableChannelInfo(22), - self._GetStableChannelInfo(21), - self._GetStableChannelInfo(20), - self._GetStableChannelInfo(19), - self._GetStableChannelInfo(18), - self._GetStableChannelInfo(17), - self._GetStableChannelInfo(16), - self._GetStableChannelInfo(15), - self._GetStableChannelInfo(14), - self._GetStableChannelInfo(13), - self._GetStableChannelInfo(12), - self._GetStableChannelInfo(11)], iterations) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/host_file_system_provider.py b/chrome/common/extensions/docs/server2/host_file_system_provider.py deleted file mode 100644 index 32fbacb..0000000 --- a/chrome/common/extensions/docs/server2/host_file_system_provider.py +++ /dev/null
@@ -1,116 +0,0 @@ -# Copyright 2013 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 caching_file_system import CachingFileSystem -from local_file_system import LocalFileSystem -from local_git_file_system import LocalGitFileSystem -from offline_file_system import OfflineFileSystem -from third_party.json_schema_compiler.memoize import memoize - - -class HostFileSystemProvider(object): - '''Provides host file systems ("host" meaning the file system that hosts the - server's source code and templates) tracking master, or any branch. - - File system instances are memoized to maintain the in-memory caches across - multiple callers. - ''' - def __init__(self, - object_store_creator, - pinned_commit=None, - default_master_instance=None, - offline=False, - constructor_for_test=None, - cache_only=False): - ''' - |object_store_creator| - Provides caches for file systems that need one. - |pinned_commit| - If not None, the commit at which a 'master' file system will be created. - If None, 'master' file systems will use HEAD. - |default_master_instance| - If not None, 'master' file systems provided by this class without a - specific commit will return |default_master_instance| instead. - |offline| - If True all provided file systems will be wrapped in an OfflineFileSystem. - |constructor_for_test| - Provides a custom constructor rather than creating LocalGitFileSystems. - |cache_only| - If True, all provided file systems will be cache-only, meaning that cache - misses will result in errors rather than cache updates. - ''' - self._object_store_creator = object_store_creator - self._pinned_commit = pinned_commit - self._default_master_instance = default_master_instance - self._offline = offline - self._constructor_for_test = constructor_for_test - self._cache_only = cache_only - - @memoize - def GetMaster(self, commit=None): - '''Gets a file system tracking 'master'. Use this method rather than - GetBranch('master') because the behaviour is subtly different; 'master' can - be pinned to a specific commit (|pinned_commit| in constructor) and can have - have its default instance overridden (|default_master_instance| in the - constructor). - - |commit| if non-None determines a specific commit to pin the host file - system at, though it will be ignored if it's newer than |pinned_commit|. - If None then |commit| will track |pinned_commit| if is has been - set, or just HEAD (which might change during server runtime!). - ''' - if commit is None: - if self._default_master_instance is not None: - return self._default_master_instance - return self._Create('master', commit=self._pinned_commit) - return self._Create('master', commit=commit) - - @memoize - def GetBranch(self, branch): - '''Gets a file system tracking |branch|, for example '1150' - anything other - than 'master', which must be constructed via the GetMaster() method. - - Note: Unlike GetMaster this function doesn't take a |commit| argument - since we assume that branches hardly ever change, while master frequently - changes. - ''' - assert isinstance(branch, basestring), 'Branch %s must be a string' % branch - assert branch != 'master', ( - 'Cannot specify branch=\'master\', use GetMaster()') - return self._Create(branch) - - def _Create(self, branch, commit=None): - '''Creates local git file systems (or if in a test, potentially whatever - |self._constructor_for_test specifies). Wraps the resulting file system in - an Offline file system if the offline flag is set, and finally wraps it in - a Caching file system. - ''' - if self._constructor_for_test is not None: - file_system = self._constructor_for_test(branch=branch, commit=commit) - else: - file_system = LocalGitFileSystem.Create(branch=branch, commit=commit) - if self._offline: - file_system = OfflineFileSystem(file_system) - return CachingFileSystem(file_system, self._object_store_creator, - fail_on_miss=self._cache_only) - - @staticmethod - def ForLocal(object_store_creator, **optargs): - '''Used in creating a server instance on localhost. - ''' - return HostFileSystemProvider( - object_store_creator, - constructor_for_test=lambda **_: LocalFileSystem.Create(), - **optargs) - - @staticmethod - def ForTest(file_system, object_store_creator, **optargs): - '''Used in creating a test server instance. The HostFileSystemProvider - returned here will always return |file_system| when its Create() method is - called. - ''' - return HostFileSystemProvider( - object_store_creator, - constructor_for_test=lambda **_: file_system, - **optargs)
diff --git a/chrome/common/extensions/docs/server2/host_file_system_provider_test.py b/chrome/common/extensions/docs/server2/host_file_system_provider_test.py deleted file mode 100755 index e1cebb62..0000000 --- a/chrome/common/extensions/docs/server2/host_file_system_provider_test.py +++ /dev/null
@@ -1,48 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 copy import deepcopy -import unittest - -from extensions_paths import CHROME_API -from file_system import FileNotFoundError -from host_file_system_provider import HostFileSystemProvider -from object_store_creator import ObjectStoreCreator -from test_data.canned_data import CANNED_API_FILE_SYSTEM_DATA -from test_file_system import TestFileSystem - -class HostFileSystemProviderTest(unittest.TestCase): - def setUp(self): - self._idle_path = CHROME_API + 'idle.json' - self._canned_data = deepcopy(CANNED_API_FILE_SYSTEM_DATA) - - def _constructor_for_test(self, branch, **optargs): - return TestFileSystem(self._canned_data[branch]) - - def testWithCaching(self): - creator = HostFileSystemProvider( - ObjectStoreCreator.ForTest(), - constructor_for_test=self._constructor_for_test) - - fs = creator.GetBranch('1500') - first_read = fs.ReadSingle(self._idle_path).Get() - self._canned_data['1500']['chrome']['common']['extensions'].get('api' - )['idle.json'] = 'blah blah blah' - second_read = fs.ReadSingle(self._idle_path).Get() - - self.assertEqual(first_read, second_read) - - def testWithOffline(self): - creator = HostFileSystemProvider( - ObjectStoreCreator.ForTest(), - offline=True, - constructor_for_test=self._constructor_for_test) - - fs = creator.GetBranch('1500') - # Offline file system should raise a FileNotFoundError if read is attempted. - self.assertRaises(FileNotFoundError, fs.ReadSingle(self._idle_path).Get) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/instance_servlet.py b/chrome/common/extensions/docs/server2/instance_servlet.py deleted file mode 100644 index 99b7914b..0000000 --- a/chrome/common/extensions/docs/server2/instance_servlet.py +++ /dev/null
@@ -1,76 +0,0 @@ -# Copyright 2013 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 branch_utility import BranchUtility -from commit_tracker import CommitTracker -from compiled_file_system import CompiledFileSystem -from environment import IsDevServer, IsReleaseServer -from host_file_system_provider import HostFileSystemProvider -from third_party.json_schema_compiler.memoize import memoize -from render_servlet import RenderServlet -from object_store_creator import ObjectStoreCreator -from server_instance import ServerInstance -from gcs_file_system_provider import CloudStorageFileSystemProvider - - -class InstanceServletRenderServletDelegate(RenderServlet.Delegate): - '''AppEngine instances should never need to call out to Gitiles. That should - only ever be done by the cronjobs, which then write the result into - DataStore, which is as far as instances look. To enable this, crons can pass - a custom (presumably online) ServerInstance into Get(). - - Why? Gitiles is slow and a bit flaky. Refresh jobs failing is annoying but - temporary. Instances failing affects users, and is really bad. - - Anyway - to enforce this, we actually don't give instances access to - Gitiles. If anything is missing from datastore, it'll be a 404. If the - cronjobs don't manage to catch everything - uhoh. On the other hand, we'll - figure it out pretty soon, and it also means that legitimate 404s are caught - before a round trip to Gitiles. - ''' - def __init__(self, delegate): - self._delegate = delegate - - @memoize - def CreateServerInstance(self): - object_store_creator = ObjectStoreCreator(start_empty=False) - branch_utility = self._delegate.CreateBranchUtility(object_store_creator) - commit_tracker = CommitTracker(object_store_creator) - # In production have offline=True so that we can catch cron errors. In - # development it's annoying to have to run the cron job, so offline=False. - # Note that offline=True if running on any appengine server due to - # http://crbug.com/345361. - host_file_system_provider = self._delegate.CreateHostFileSystemProvider( - object_store_creator, - offline=not (IsDevServer() or IsReleaseServer()), - pinned_commit=commit_tracker.Get('master').Get(), - cache_only=True) - return ServerInstance(object_store_creator, - CompiledFileSystem.Factory(object_store_creator), - branch_utility, - host_file_system_provider, - CloudStorageFileSystemProvider(object_store_creator)) - -class InstanceServlet(object): - '''Servlet for running on normal AppEngine instances. - Create this via GetConstructor() so that cache state can be shared amongst - them via the memoizing Delegate. - ''' - class Delegate(object): - '''Allow runtime dependencies to be overriden for testing. - ''' - def CreateBranchUtility(self, object_store_creator): - return BranchUtility.Create(object_store_creator) - - def CreateHostFileSystemProvider(self, object_store_creator, **optargs): - return HostFileSystemProvider(object_store_creator, **optargs) - - @staticmethod - def GetConstructor(delegate_for_test=None): - render_servlet_delegate = InstanceServletRenderServletDelegate( - delegate_for_test or InstanceServlet.Delegate()) - return lambda request: RenderServlet(request, render_servlet_delegate) - - # NOTE: if this were a real Servlet it would implement a Get() method, but - # GetConstructor returns an appropriate lambda function (Request -> Servlet).
diff --git a/chrome/common/extensions/docs/server2/instance_servlet_test.py b/chrome/common/extensions/docs/server2/instance_servlet_test.py deleted file mode 100755 index 9eff024a..0000000 --- a/chrome/common/extensions/docs/server2/instance_servlet_test.py +++ /dev/null
@@ -1,50 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import unittest - -from instance_servlet import InstanceServlet -from servlet import Request -from fail_on_access_file_system import FailOnAccessFileSystem -from test_branch_utility import TestBranchUtility -from test_util import DisableLogging - -# NOTE(kalman): The ObjectStore created by the InstanceServlet is backed onto -# our fake AppEngine memcache/datastore, so the tests aren't isolated. -class _TestDelegate(InstanceServlet.Delegate): - def __init__(self, file_system_type): - self._file_system_type = file_system_type - - def CreateBranchUtility(self, object_store_creator): - return TestBranchUtility.CreateWithCannedData() - -class InstanceServletTest(unittest.TestCase): - '''Tests that if the file systems underlying the docserver's data fail, - the instance servlet still returns 404s or 301s with a best-effort. - It should never return a 500 (i.e. crash). - ''' - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - @DisableLogging('warning') - def testHostFileSystemNotAccessed(self): - delegate = _TestDelegate(FailOnAccessFileSystem) - constructor = InstanceServlet.GetConstructor(delegate_for_test=delegate) - def test_path(path, status=404): - response = constructor(Request.ForTest(path)).Get() - self.assertEqual(status, response.status) - test_path('extensions/storage.html') - test_path('apps/storage.html') - test_path('extensions/examples/foo.zip') - test_path('extensions/examples/foo.html') - test_path('static/foo.css') - test_path('beta/extensions/storage.html', status=301) - test_path('beta/apps/storage.html', status=301) - test_path('beta/extensions/examples/foo.zip', status=301) - test_path('beta/extensions/examples/foo.html', status=301) - test_path('beta/static/foo.css', status=301) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/integration_test.py b/chrome/common/extensions/docs/server2/integration_test.py deleted file mode 100755 index a36ffac..0000000 --- a/chrome/common/extensions/docs/server2/integration_test.py +++ /dev/null
@@ -1,302 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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_server - -# Run build_server so that files needed by tests are copied to the local -# third_party directory. -if not build_server.HasLocalThirdPartyDirectory(): - build_server.main() - -assert build_server.HasLocalThirdPartyDirectory(), ( - 'Third party dependencies were not copied') - -import json -import optparse -import os -import posixpath -import sys -import time -import unittest -import update_cache - -from branch_utility import BranchUtility -from chroot_file_system import ChrootFileSystem -from extensions_paths import ( - CONTENT_PROVIDERS, CHROME_EXTENSIONS, PUBLIC_TEMPLATES) -from fake_fetchers import ConfigureFakeFetchers -from special_paths import SITE_VERIFICATION_FILE -from handler import Handler -from link_error_detector import LinkErrorDetector, StringifyBrokenLinks -from local_file_system import LocalFileSystem -from local_renderer import LocalRenderer -from path_util import AssertIsValid -from servlet import Request -from third_party.json_schema_compiler import json_parse -from test_util import ( - ChromiumPath, DisableLogging, EnableLogging, ReadFile, Server2Path) - - -# Arguments set up if __main__ specifies them. -_EXPLICIT_TEST_FILES = None -_REBASE = False -_VERBOSE = False - - -def _ToPosixPath(os_path): - return os_path.replace(os.sep, '/') - - -def _FilterHidden(paths): - '''Returns a list of the non-hidden paths from |paths|. - ''' - # Hidden files start with a '.' but paths like './foo' and '../foo' are not - # hidden. - return [path for path in paths if (not path.startswith('.')) or - path.startswith('./') or - path.startswith('../')] - - -def _GetPublicFiles(): - '''Gets all public file paths mapped to their contents. - ''' - def walk(path, prefix=''): - path = ChromiumPath(path) - public_files = {} - for root, dirs, files in os.walk(path, topdown=True): - relative_root = root[len(path):].lstrip(os.path.sep) - dirs[:] = _FilterHidden(dirs) - for filename in _FilterHidden(files): - with open(os.path.join(root, filename), 'r') as f: - request_path = posixpath.join(prefix, relative_root, filename) - public_files[request_path] = f.read() - return public_files - - # Public file locations are defined in content_providers.json, sort of. Epic - # hack to pull them out; list all the files from the directories that - # Chromium content providers ask for. - public_files = {} - content_providers = json_parse.Parse(ReadFile(CONTENT_PROVIDERS)) - for content_provider in content_providers.itervalues(): - if 'chromium' in content_provider: - public_files.update(walk(content_provider['chromium']['dir'], - prefix=content_provider['serveFrom'])) - return public_files - - -class IntegrationTest(unittest.TestCase): - def setUp(self): - ConfigureFakeFetchers() - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - @EnableLogging('info') - def testUpdateAndPublicFiles(self): - '''Runs update then requests every public file. Update needs to be run first - because the public file requests are offline. - ''' - if _EXPLICIT_TEST_FILES is not None: - return - - print('Running update...') - start_time = time.time() - try: - update_cache.UpdateCache() - finally: - print('Took %s seconds' % (time.time() - start_time)) - - # TODO(kalman): Re-enable this, but it takes about an hour at the moment, - # presumably because every page now has a lot of links on it from the - # topnav. - - #print("Checking for broken links...") - #start_time = time.time() - #link_error_detector = LinkErrorDetector( - # # TODO(kalman): Use of ChrootFileSystem here indicates a hack. Fix. - # ChrootFileSystem(LocalFileSystem.Create(), CHROME_EXTENSIONS), - # lambda path: Handler(Request.ForTest(path)).Get(), - # 'templates/public', - # ('extensions/index.html', 'apps/about_apps.html')) - - #broken_links = link_error_detector.GetBrokenLinks() - #if broken_links: - # print('Found %d broken links.' % ( - # len(broken_links))) - # if _VERBOSE: - # print(StringifyBrokenLinks(broken_links)) - - #broken_links_set = set(broken_links) - - #known_broken_links_path = os.path.join( - # Server2Path('known_broken_links.json')) - #try: - # with open(known_broken_links_path, 'r') as f: - # # The JSON file converts tuples and sets into lists, and for this - # # set union/difference logic they need to be converted back. - # known_broken_links = set(tuple(item) for item in json.load(f)) - #except IOError: - # known_broken_links = set() - - #newly_broken_links = broken_links_set - known_broken_links - #fixed_links = known_broken_links - broken_links_set - - #print('Took %s seconds.' % (time.time() - start_time)) - - #print('Searching for orphaned pages...') - #start_time = time.time() - #orphaned_pages = link_error_detector.GetOrphanedPages() - #if orphaned_pages: - # # TODO(jshumway): Test should fail when orphaned pages are detected. - # print('Found %d orphaned pages:' % len(orphaned_pages)) - # for page in orphaned_pages: - # print(page) - #print('Took %s seconds.' % (time.time() - start_time)) - - public_files = _GetPublicFiles() - - print('Rendering %s public files...' % len(public_files.keys())) - start_time = time.time() - try: - for path, content in public_files.iteritems(): - AssertIsValid(path) - if path.endswith('redirects.json'): - continue - - # The non-example html and md files are served without their file - # extensions. - path_without_ext, ext = posixpath.splitext(path) - if (ext in ('.html', '.md') and - '/examples/' not in path and - path != SITE_VERIFICATION_FILE): - path = path_without_ext - - def check_result(response): - is_ok = response.status == 200; - is_redirect = response.status == 302; - # TODO(dbertoni@chromium.org): Explore following redirects and/or - # keeping an explicit list of files that expect 200 vs. 302. - self.assertTrue(is_ok or is_redirect, - 'Got %s when rendering %s' % (response.status, path)) - - self.assertTrue(is_redirect or len(response.content), - 'Rendered content length was 0 when rendering %s' % path) - - # This is reaaaaally rough since usually these will be tiny templates - # that render large files. - self.assertTrue(is_redirect or - len(response.content) >= len(content) or - # Zip files may be served differently than stored - # locally. - path.endswith('.zip'), - 'Rendered content length was %s vs template content length %s ' - 'when rendering %s' % (len(response.content), len(content), path)) - - # TODO(kalman): Hack to avoid failing redirects like extensions/index - # to extensions. Better fix would be to parse or whitelist the - # redirects.json files as part of this test. - if not path.endswith('/index'): - check_result(Handler(Request.ForTest(path)).Get()) - - if path.startswith(('apps/', 'extensions/')): - # Make sure that adding the .html will temporarily redirect to - # the path without the .html for APIs and articles. - if '/examples/' not in path: - redirect_response = Handler(Request.ForTest(path + '.html')).Get() - self.assertEqual( - ('/' + path, False), redirect_response.GetRedirect(), - '%s.html did not (temporarily) redirect to %s (status %s)' % - (path, path, redirect_response.status)) - - # Make sure including a channel will permanently redirect to the same - # path without a channel. - for channel in BranchUtility.GetAllChannelNames(): - redirect_response = Handler( - Request.ForTest(posixpath.join(channel, path))).Get() - self.assertEqual( - ('/' + path, True), - redirect_response.GetRedirect(), - '%s/%s did not (permanently) redirect to %s (status %s)' % - (channel, path, path, redirect_response.status)) - - # Samples are internationalized, test some locales. - if path.endswith('/samples'): - for lang in ('en-US', 'es', 'ar'): - check_result(Handler(Request.ForTest( - path, - headers={'Accept-Language': '%s;q=0.8' % lang})).Get()) - finally: - print('Took %s seconds' % (time.time() - start_time)) - - #if _REBASE: - # print('Rebasing broken links with %s newly broken and %s fixed links.' % - # (len(newly_broken_links), len(fixed_links))) - # with open(known_broken_links_path, 'w') as f: - # json.dump(broken_links, f, - # indent=2, separators=(',', ': '), sort_keys=True) - #else: - # if fixed_links or newly_broken_links: - # print('**********************************************\n' - # 'CHANGE DETECTED IN BROKEN LINKS WITHOUT REBASE\n' - # '**********************************************') - # print('Found %s broken links, and some have changed. ' - # 'If this is acceptable or expected then run %s with the --rebase ' - # 'option.' % (len(broken_links), os.path.split(__file__)[-1])) - # elif broken_links: - # print('%s existing broken links' % len(broken_links)) - # if fixed_links: - # print('%s broken links have been fixed:' % len(fixed_links)) - # print(StringifyBrokenLinks(fixed_links)) - # if newly_broken_links: - # print('There are %s new broken links:' % len(newly_broken_links)) - # print(StringifyBrokenLinks(newly_broken_links)) - # self.fail('See logging for details.') - - # TODO(kalman): Move this test elsewhere, it's not an integration test. - # Perhaps like "presubmit_tests" or something. - def testExplicitFiles(self): - '''Tests just the files in _EXPLICIT_TEST_FILES. - ''' - if _EXPLICIT_TEST_FILES is None: - return - for filename in _EXPLICIT_TEST_FILES: - print('Rendering %s...' % filename) - start_time = time.time() - try: - response = LocalRenderer.Render(_ToPosixPath(filename)) - self.assertTrue(response.status == 200 or response.status == 302, - 'Got %s when rendering %s' % (response.status, - _ToPosixPath(filename))) - self.assertTrue(response.content != '' or response.status == 302) - finally: - print('Took %s seconds' % (time.time() - start_time)) - - # TODO(jshumway): Check page for broken links (currently prohibited by the - # time it takes to render the pages). - - @DisableLogging('warning') - def testFileNotFound(self): - response = LocalRenderer.Render('/extensions/notfound') - self.assertEqual(404, response.status) - - def testSiteVerificationFile(self): - response = LocalRenderer.Render('/' + SITE_VERIFICATION_FILE) - self.assertEqual(200, response.status) - -if __name__ == '__main__': - parser = optparse.OptionParser() - parser.add_option('-a', '--all', action='store_true', default=False, - help='Render all pages, not just the one specified') - parser.add_option('-r', '--rebase', action='store_true', default=False, - help='Rewrites the known_broken_links.json file with ' - 'the current set of broken links') - parser.add_option('-v', '--verbose', action='store_true', default=False, - help='Show verbose output like currently broken links') - (opts, args) = parser.parse_args() - if not opts.all: - _EXPLICIT_TEST_FILES = args - _REBASE = opts.rebase - _VERBOSE = opts.verbose - # Kill sys.argv because we have our own flags. - sys.argv = [sys.argv[0]] - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/jsc_view.py b/chrome/common/extensions/docs/server2/jsc_view.py deleted file mode 100644 index 960ae8c..0000000 --- a/chrome/common/extensions/docs/server2/jsc_view.py +++ /dev/null
@@ -1,654 +0,0 @@ -# Copyright 2014 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 copy import copy -import logging -import posixpath - -from api_models import GetNodeCategories -from api_schema_graph import APINodeCursor -from docs_server_utils import MarkFirstAndLast -from extensions_paths import JSON_TEMPLATES, PRIVATE_TEMPLATES -from operator import itemgetter -from platform_util import PlatformToExtensionType -import third_party.json_schema_compiler.model as model - - -def CreateSamplesView(samples_list, request): - def get_sample_id(sample_name): - return sample_name.lower().replace(' ', '-') - - def get_accepted_languages(request): - if request is None: - return [] - accept_language = request.headers.get('Accept-Language', None) - if accept_language is None: - return [] - return [lang_with_q.split(';')[0].strip() - for lang_with_q in accept_language.split(',')] - - return_list = [] - for dict_ in samples_list: - name = dict_['name'] - description = dict_['description'] - if description is None: - description = '' - if name.startswith('__MSG_') or description.startswith('__MSG_'): - try: - # Copy the sample dict so we don't change the dict in the cache. - sample_data = dict_.copy() - name_key = name[len('__MSG_'):-len('__')] - description_key = description[len('__MSG_'):-len('__')] - locale = sample_data['default_locale'] - for lang in get_accepted_languages(request): - if lang in sample_data['locales']: - locale = lang - break - locale_data = sample_data['locales'][locale] - sample_data['name'] = locale_data[name_key]['message'] - sample_data['description'] = locale_data[description_key]['message'] - sample_data['id'] = get_sample_id(sample_data['name']) - except Exception: - logging.error(traceback.format_exc()) - # Revert the sample to the original dict. - sample_data = dict_ - return_list.append(sample_data) - else: - dict_['id'] = get_sample_id(name) - return_list.append(dict_) - return return_list - - -def GetEventByNameFromEvents(events): - '''Parses the dictionary |events| to find the definitions of members of the - type Event. Returns a dictionary mapping the name of a member to that - member's definition. - ''' - assert 'types' in events, \ - 'The dictionary |events| must contain the key "types".' - event_list = [t for t in events['types'] if t.get('name') == 'Event'] - assert len(event_list) == 1, 'Exactly one type must be called "Event".' - return _GetByNameDict(event_list[0]) - - -def _GetByNameDict(namespace): - '''Returns a dictionary mapping names to named items from |namespace|. - - This lets us render specific API entities rather than the whole thing at once, - for example {{apis.manifestTypes.byName.ExternallyConnectable}}. - - Includes items from namespace['types'], namespace['functions'], - namespace['events'], and namespace['properties']. - ''' - by_name = {} - for item_type in GetNodeCategories(): - if item_type in namespace: - old_size = len(by_name) - by_name.update( - (item['name'], item) for item in namespace[item_type]) - assert len(by_name) == old_size + len(namespace[item_type]), ( - 'Duplicate name in %r' % namespace) - return by_name - - -def _CreateId(node, prefix): - if node.parent is not None and not isinstance(node.parent, model.Namespace): - return '-'.join([prefix, node.parent.simple_name, node.simple_name]) - return '-'.join([prefix, node.simple_name]) - - -def _FormatValue(value): - '''Inserts commas every three digits for integer values. It is magic. - ''' - s = str(value) - return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) - - -class _JSCViewBuilder(object): - '''Uses a Model from the JSON Schema Compiler and generates a dict that - a Motemplate template can use for a data source. - ''' - - def __init__(self, - content_script_apis, - jsc_model, - availability_finder, - json_cache, - template_cache, - features_bundle, - event_byname_future, - platform, - samples): - self._content_script_apis = content_script_apis - self._availability = availability_finder.GetAPIAvailability(jsc_model.name) - self._current_node = APINodeCursor(availability_finder, jsc_model.name) - self._api_availabilities = json_cache.GetFromFile( - posixpath.join(JSON_TEMPLATES, 'api_availabilities.json')) - self._intro_tables = json_cache.GetFromFile( - posixpath.join(JSON_TEMPLATES, 'intro_tables.json')) - self._api_features = features_bundle.GetAPIFeatures() - self._template_cache = template_cache - self._event_byname_future = event_byname_future - self._jsc_model = jsc_model - self._platform = platform - self._samples = samples - - def _GetLink(self, link): - ref = link if '.' in link else (self._jsc_model.name + '.' + link) - return { 'ref': ref, 'text': link, 'name': link } - - def ToDict(self, request): - '''Returns a dictionary representation of |self._jsc_model|, which - is a Namespace object from JSON Schema Compiler. - ''' - assert self._jsc_model is not None - chrome_dot_name = 'chrome.%s' % self._jsc_model.name - as_dict = { - 'channelWarning': self._GetChannelWarning(), - 'documentationOptions': self._jsc_model.documentation_options, - 'domEvents': self._GenerateDomEvents(self._jsc_model.events), - 'events': self._GenerateEvents(self._jsc_model.events), - 'functions': self._GenerateFunctions(self._jsc_model.functions), - 'introList': self._GetIntroTableList(), - 'name': self._jsc_model.name, - 'namespace': self._jsc_model.documentation_options.get('namespace', - chrome_dot_name), - 'properties': self._GenerateProperties(self._jsc_model.properties), - 'samples': CreateSamplesView(self._samples, request), - 'title': self._jsc_model.documentation_options.get('title', - chrome_dot_name), - 'types': self._GenerateTypes(self._jsc_model.types.values()), - } - if self._jsc_model.deprecated: - as_dict['deprecated'] = self._jsc_model.deprecated - - as_dict['byName'] = _GetByNameDict(as_dict) - - return as_dict - - def _IsExperimental(self): - return self._jsc_model.name.startswith('experimental') - - def _GetChannelWarning(self): - if not self._IsExperimental(): - return { - self._availability.channel_info.channel: True - } - return None - - def _GenerateCallback(self, returns_async): - '''Returns a dictionary representation of a callback suitable - for consumption by templates. - ''' - if not returns_async: - return None - callback_dict = { - 'name': returns_async.simple_name, - 'simple_type': {'simple_type': 'function'}, - 'optional': returns_async.optional, - 'parameters': [] - } - with self._current_node.Descend('parameters', returns_async.simple_name, - 'parameters'): - for i, param in enumerate(returns_async.params): - # HACK(https://crbug.com/996488): Callbacks to callbacks of events - # break, and have historically just been omitted completely due to not - # checking the 'callback' property here. With the move to ReturnsAsync, - # the callbacks are now included in the parameters, but this breaks - # assumptions elsewhere (at the very least, in api_schema_graph.py, - # which assumes the path will not be this long when looking up the - # event). For now, hack in ignoring the callback, as we've always done. - is_callback_to_callback = ( - i == len(returns_async.params) - 1 and - param.type_.property_type == model.PropertyType.FUNCTION) - if (is_callback_to_callback): - continue - callback_dict['parameters'].append(self._GenerateProperty(param)) - if (len(callback_dict['parameters']) > 0): - callback_dict['parameters'][-1]['last'] = True - return callback_dict - - def _GenerateCallbackProperty(self, callback, callback_dict): - '''Returns a dictionary representation of a callback property - suitable for consumption by templates. - ''' - property_dict = { - 'name': callback.simple_name, - 'description': callback.description, - 'optional': callback.optional, - 'isCallback': True, - 'asFunction': callback_dict, - 'id': _CreateId(callback, 'property'), - 'simple_type': 'function', - } - if (callback.parent is not None and - not isinstance(callback.parent, model.Namespace)): - property_dict['parentName'] = callback.parent.simple_name - return property_dict - - def _GenerateTypes(self, types): - '''Returns a list of dictionaries representing this Model's types. - ''' - with self._current_node.Descend('types'): - return [self._GenerateType(t) for t in types] - - def _GenerateType(self, type_): - '''Returns a dictionary representation of a type from JSON Schema Compiler. - ''' - with self._current_node.Descend(type_.simple_name): - type_dict = { - 'name': type_.simple_name, - 'description': type_.description, - 'properties': self._GenerateProperties(type_.properties), - 'functions': self._GenerateFunctions(type_.functions), - 'events': self._GenerateEvents(type_.events), - 'id': _CreateId(type_, 'type'), - 'availability': self._GetAvailabilityTemplate( - is_enum=type_.property_type == model.PropertyType.ENUM) - } - self._RenderTypeInformation(type_, type_dict) - return type_dict - - def _GenerateFunctions(self, functions): - '''Returns a list of dictionaries representing this Model's functions. - ''' - with self._current_node.Descend('functions'): - return [self._GenerateFunction(f) for f in functions.values()] - - def _GenerateFunction(self, function): - '''Returns a dictionary representation of a function from - JSON Schema Compiler. - ''' - # When ignoring types, properties must be ignored as well. - with self._current_node.Descend(function.simple_name, - ignore=('types', 'properties')): - function_dict = { - 'name': function.simple_name, - 'description': function.description, - # TODO(https://crbug.com/1143020): Rename this when we're ready to add - # promise support into the docs. For now, keep these as callbacks (which - # are also checked at other places in the docserver code). - 'callback': self._GenerateCallback(function.returns_async), - 'parameters': [], - 'returns': None, - 'id': _CreateId(function, 'method'), - 'availability': self._GetAvailabilityTemplate() - } - self._AddCommonProperties(function_dict, function) - if function.returns: - function_dict['returns'] = self._GenerateType(function.returns) - - with self._current_node.Descend(function.simple_name, 'parameters'): - for param in function.params: - function_dict['parameters'].append(self._GenerateProperty(param)) - if function.returns_async is not None: - # Show the callback as an extra parameter. - function_dict['parameters'].append( - self._GenerateCallbackProperty(function.returns_async, - function_dict['callback'])) - - if len(function_dict['parameters']) > 0: - function_dict['parameters'][-1]['last'] = True - return function_dict - - def _GenerateEvents(self, events): - '''Returns a list of dictionaries representing this Model's events. - ''' - with self._current_node.Descend('events'): - return [self._GenerateEvent(e) for e in events.values() - if not e.supports_dom] - - def _GenerateDomEvents(self, events): - '''Returns a list of dictionaries representing this Model's DOM events. - ''' - with self._current_node.Descend('events'): - return [self._GenerateEvent(e) for e in events.values() - if e.supports_dom] - - def _GenerateEvent(self, event): - '''Returns a dictionary representation of an event from - JSON Schema Compiler. Note that although events are modeled as functions - in JSON Schema Compiler, we model them differently for the templates. - ''' - with self._current_node.Descend(event.simple_name, ignore=('properties',)): - event_dict = { - 'name': event.simple_name, - 'description': event.description, - 'filters': [self._GenerateProperty(f) for f in event.filters], - 'conditions': [self._GetLink(condition) - for condition in event.conditions], - 'actions': [self._GetLink(action) for action in event.actions], - 'supportsRules': event.supports_rules, - 'supportsListeners': event.supports_listeners, - 'properties': [], - 'id': _CreateId(event, 'event'), - 'byName': {}, - 'availability': self._GetAvailabilityTemplate() - } - self._AddCommonProperties(event_dict, event) - # Add the Event members to each event in this object. - if self._event_byname_future: - event_dict['byName'].update(self._event_byname_future.Get()) - # We need to create the method description for addListener based on the - # information stored in |event|. - if event.supports_listeners: - callback_object = model.Function(parent=event, - name='callback', - json={}, - namespace=event.parent, - origin='') - callback_object.params = event.params - if event.returns_async: - callback_object.returns_async = event.returns_async - - with self._current_node.Descend(event.simple_name): - callback = self._GenerateFunction(callback_object) - callback_parameter = self._GenerateCallbackProperty(callback_object, - callback) - callback_parameter['last'] = True - event_dict['byName']['addListener'] = { - 'name': 'addListener', - 'callback': callback, - 'parameters': [callback_parameter] - } - if event.supports_dom: - # Treat params as properties of the custom Event object associated with - # this DOM Event. - with self._current_node.Descend(event.simple_name, - ignore=('properties',)): - event_dict['properties'] += [self._GenerateProperty(param) - for param in event.params] - return event_dict - - def _GenerateProperties(self, properties): - '''Returns a list of dictionaries representing this Model's properites. - ''' - with self._current_node.Descend('properties'): - return [self._GenerateProperty(v) for v in properties.values()] - - def _GenerateProperty(self, property_): - '''Returns a dictionary representation of a property from - JSON Schema Compiler. - ''' - if not hasattr(property_, 'type_'): - for d in dir(property_): - if not d.startswith('_'): - print ('%s -> %s' % (d, getattr(property_, d))) - type_ = property_.type_ - - # Make sure we generate property info for arrays, too. - # TODO(kalman): what about choices? - if type_.property_type == model.PropertyType.ARRAY: - properties = type_.item_type.properties - else: - properties = type_.properties - - with self._current_node.Descend(property_.simple_name): - property_dict = { - 'name': property_.simple_name, - 'optional': property_.optional, - 'description': property_.description, - 'properties': self._GenerateProperties(type_.properties), - 'functions': self._GenerateFunctions(type_.functions), - 'parameters': [], - 'returns': None, - 'id': _CreateId(property_, 'property'), - 'availability': self._GetAvailabilityTemplate() - } - self._AddCommonProperties(property_dict, property_) - - if type_.property_type == model.PropertyType.FUNCTION: - function = type_.function - with self._current_node.Descend('parameters'): - for param in function.params: - property_dict['parameters'].append(self._GenerateProperty(param)) - if function.returns: - with self._current_node.Descend(ignore=('types', 'properties')): - property_dict['returns'] = self._GenerateType(function.returns) - - value = property_.value - if value is not None: - if isinstance(value, int): - property_dict['value'] = _FormatValue(value) - else: - property_dict['value'] = value - else: - self._RenderTypeInformation(type_, property_dict) - - return property_dict - - def _AddCommonProperties(self, target, src): - if src.deprecated is not None: - target['deprecated'] = src.deprecated - if (src.parent is not None and - not isinstance(src.parent, model.Namespace)): - target['parentName'] = src.parent.simple_name - - def _RenderTypeInformation(self, type_, dst_dict): - with self._current_node.Descend(ignore=('types', 'properties')): - dst_dict['is_object'] = type_.property_type == model.PropertyType.OBJECT - if type_.property_type == model.PropertyType.CHOICES: - dst_dict['choices'] = self._GenerateTypes(type_.choices) - # We keep track of which == last for knowing when to add "or" between - # choices in templates. - if len(dst_dict['choices']) > 0: - dst_dict['choices'][-1]['last'] = True - elif type_.property_type == model.PropertyType.REF: - dst_dict['link'] = self._GetLink(type_.ref_type) - elif type_.property_type == model.PropertyType.ARRAY: - dst_dict['array'] = self._GenerateType(type_.item_type) - elif type_.property_type == model.PropertyType.ENUM: - dst_dict['enum_values'] = [ - {'name': value.name, 'description': value.description} - for value in type_.enum_values] - if len(dst_dict['enum_values']) > 0: - dst_dict['enum_values'][-1]['last'] = True - dst_dict['enum_values'][0]['first'] = True - elif type_.instance_of is not None: - dst_dict['simple_type'] = type_.instance_of - else: - dst_dict['simple_type'] = type_.property_type.name - - def _CreateAvailabilityTemplate(self, status, scheduled, version): - '''Returns an object suitable for use in templates to display availability - information. - ''' - return { - 'partial': self._template_cache.GetFromFile( - '%sintro_tables/%s_message.html' % (PRIVATE_TEMPLATES, status)).Get(), - 'scheduled': scheduled, - 'version': version - } - - def _GetAvailabilityTemplate(self, is_enum=False): - '''Gets availability for the current node and returns an appropriate - template object. - ''' - # We don't show an availability warning for enums. - # TODO(devlin): We should also render enums differently, indicating that - # symbolic constants are available from version 44 onwards. - if is_enum: - return None - - # Displaying deprecated status takes precedence over when the API - # became stable. - availability_info = self._current_node.GetDeprecated() - if availability_info is not None: - status = 'deprecated' - else: - availability_info = self._current_node.GetAvailability() - if availability_info is None: - return None - status = availability_info.channel_info.channel - return self._CreateAvailabilityTemplate( - status, - availability_info.scheduled, - availability_info.channel_info.version) - - def _GetIntroTableList(self): - '''Create a generic data structure that can be traversed by the templates - to create an API intro table. - ''' - intro_rows = [ - self._GetIntroDescriptionRow(), - self._GetIntroAvailabilityRow() - ] + self._GetIntroDependencyRows() + self._GetIntroContentScriptRow() - - # Add rows using data from intro_tables.json, overriding any existing rows - # if they share the same 'title' attribute. - row_titles = [row['title'] for row in intro_rows] - for misc_row in self._GetMiscIntroRows(): - if misc_row['title'] in row_titles: - intro_rows[row_titles.index(misc_row['title'])] = misc_row - else: - intro_rows.append(misc_row) - - return intro_rows - - def _GetIntroContentScriptRow(self): - '''Generates the 'Content Script' row data for an API intro table. - ''' - content_script_support = self._content_script_apis.get(self._jsc_model.name) - if content_script_support is None: - return [] - if content_script_support.restrictedTo: - content_script_support.restrictedTo.sort(key=itemgetter('node')) - MarkFirstAndLast(content_script_support.restrictedTo) - return [{ - 'title': 'Content Scripts', - 'content': [{ - 'partial': self._template_cache.GetFromFile( - posixpath.join(PRIVATE_TEMPLATES, - 'intro_tables', - 'content_scripts.html')).Get(), - 'contentScriptSupport': content_script_support.__dict__ - }] - }] - - def _GetIntroDescriptionRow(self): - ''' Generates the 'Description' row data for an API intro table. - ''' - return { - 'title': 'Description', - 'content': [ - { 'text': self._jsc_model.description } - ] - } - - def _GetIntroAvailabilityRow(self): - ''' Generates the 'Availability' row data for an API intro table. - ''' - if self._IsExperimental(): - status = 'experimental' - scheduled = None - version = None - else: - status = self._availability.channel_info.channel - scheduled = self._availability.scheduled - version = self._availability.channel_info.version - return { - 'title': 'Availability', - 'content': [ - self._CreateAvailabilityTemplate(status, scheduled, version) - ] - } - - def _GetIntroDependencyRows(self): - # Devtools aren't in _api_features. If we're dealing with devtools, bail. - if 'devtools' in self._jsc_model.name: - return [] - - api_feature = self._api_features.Get().get(self._jsc_model.name) - if not api_feature: - logging.error('"%s" not found in _api_features.json' % - self._jsc_model.name) - return [] - - permissions_content = [] - manifest_content = [] - - def categorize_dependency(dependency): - def make_code_node(text): - return { 'class': 'code', 'text': text } - - context, name = dependency.split(':', 1) - if context == 'permission': - permissions_content.append(make_code_node('"%s"' % name)) - elif context == 'manifest': - manifest_content.append(make_code_node('"%s": {...}' % name)) - elif context == 'api': - transitive_dependencies = ( - self._api_features.Get().get(name, {}).get('dependencies', [])) - for transitive_dependency in transitive_dependencies: - categorize_dependency(transitive_dependency) - else: - logging.error('Unrecognized dependency for %s: %s' % - (self._jsc_model.name, context)) - - for dependency in api_feature.get('dependencies', ()): - categorize_dependency(dependency) - - dependency_rows = [] - if permissions_content: - dependency_rows.append({ - 'title': 'Permissions', - 'content': permissions_content - }) - if manifest_content: - dependency_rows.append({ - 'title': 'Manifest', - 'content': manifest_content - }) - return dependency_rows - - def _GetMiscIntroRows(self): - ''' Generates miscellaneous intro table row data, such as 'Permissions', - 'Samples', and 'Learn More', using intro_tables.json. - ''' - misc_rows = [] - # Look up the API name in intro_tables.json, which is structured - # similarly to the data structure being created. If the name is found, loop - # through the attributes and add them to this structure. - table_info = self._intro_tables.Get().get(self._jsc_model.name) - if table_info is None: - return misc_rows - - for category in table_info.iterkeys(): - content = [] - for node in table_info[category]: - ext_type = PlatformToExtensionType(self._platform) - # Don't display nodes restricted to a different platform. - if ext_type not in node.get('extension_types', (ext_type,)): - continue - # If there is a 'partial' argument and it hasn't already been - # converted to a Motemplate object, transform it to a template. - if 'partial' in node: - # Note: it's enough to copy() not deepcopy() because only a single - # top-level key is being modified. - node = copy(node) - node['partial'] = self._template_cache.GetFromFile( - posixpath.join(PRIVATE_TEMPLATES, node['partial'])).Get() - content.append(node) - misc_rows.append({ 'title': category, 'content': content }) - return misc_rows - -def CreateJSCView(content_script_apis, - jsc_model, - availability_finder, - json_cache, - template_cache, - features_bundle, - event_byname_future, - platform, - samples, - request): - return _JSCViewBuilder(content_script_apis, - jsc_model, - availability_finder, - json_cache, - template_cache, - features_bundle, - event_byname_future, - platform, - samples).ToDict(request)
diff --git a/chrome/common/extensions/docs/server2/jsc_view_test.py b/chrome/common/extensions/docs/server2/jsc_view_test.py deleted file mode 100755 index 6b7855f6..0000000 --- a/chrome/common/extensions/docs/server2/jsc_view_test.py +++ /dev/null
@@ -1,425 +0,0 @@ -#!/usr/bin/env python -# Copyright 2014 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 json -import os -import unittest - -from jsc_view import GetEventByNameFromEvents -from api_schema_graph import APISchemaGraph -from availability_finder import AvailabilityFinder, AvailabilityInfo -from branch_utility import BranchUtility, ChannelInfo -from compiled_file_system import CompiledFileSystem -from extensions_paths import CHROME_EXTENSIONS -from fake_host_file_system_provider import FakeHostFileSystemProvider -from fake_url_fetcher import FakeUrlFetcher -from features_bundle import FeaturesBundle -from future import Future -from host_file_system_iterator import HostFileSystemIterator -from jsc_view import CreateJSCView, _JSCViewBuilder, _FormatValue -from object_store_creator import ObjectStoreCreator -from schema_processor import SchemaProcessorFactoryForTest -from servlet import Request -from server_instance import ServerInstance -from test_data.api_data_source.canned_master_fs import CANNED_MASTER_FS_DATA -from test_data.canned_data import CANNED_API_FILE_SYSTEM_DATA -from test_data.object_level_availability.tabs import TABS_SCHEMA_BRANCHES -from test_file_system import TestFileSystem -from test_util import Server2Path - - -class _FakeTemplateCache(object): - - def GetFromFile(self, key): - return Future(value='motemplate %s' % key) - - -class _FakeFeaturesBundle(object): - def GetAPIFeatures(self): - return Future(value={ - 'bluetooth': {'value': True}, - 'contextMenus': {'value': True}, - 'jsonStableAPI': {'value': True}, - 'idle': {'value': True}, - 'input.ime': {'value': True}, - 'tabs': {'value': True} - }) - - -class _FakeAvailabilityFinder(object): - def __init__(self, fake_availability): - self._fake_availability = fake_availability - - def GetAPIAvailability(self, api_name): - return self._fake_availability - - def GetAPINodeAvailability(self, api_name): - schema_graph = APISchemaGraph() - api_graph = APISchemaGraph(json.loads( - CANNED_MASTER_FS_DATA['api'][api_name + '.json'])) - # Give the graph fake ChannelInfo; it's not used in tests. - channel_info = ChannelInfo('stable', '28', 28) - schema_graph.Update(api_graph, lambda _: channel_info) - return schema_graph - - -class JSCViewTest(unittest.TestCase): - def setUp(self): - self._base_path = Server2Path('test_data', 'test_json') - - server_instance = ServerInstance.ForTest( - TestFileSystem(CANNED_MASTER_FS_DATA, relative_to=CHROME_EXTENSIONS)) - file_system = server_instance.host_file_system_provider.GetMaster() - self._json_cache = server_instance.compiled_fs_factory.ForJson(file_system) - self._features_bundle = FeaturesBundle(file_system, - server_instance.compiled_fs_factory, - server_instance.object_store_creator, - 'extensions') - self._api_models = server_instance.platform_bundle.GetAPIModels( - 'extensions') - self._fake_availability = AvailabilityInfo(ChannelInfo('stable', '396', 5)) - - def _ReadLocalFile(self, filename): - with open(os.path.join(self._base_path, filename), 'r') as f: - return f.read() - - def _LoadJSON(self, filename): - return json.loads(self._ReadLocalFile(filename)) - - def _FakeLoadAddRulesSchema(self): - events = self._LoadJSON('add_rules_def_test.json') - return Future(value=GetEventByNameFromEvents(events)) - - def testFormatValue(self): - self.assertEquals('1,234,567', _FormatValue(1234567)) - self.assertEquals('67', _FormatValue(67)) - self.assertEquals('234,567', _FormatValue(234567)) - - def testGetEventByNameFromEvents(self): - events = {} - # Missing 'types' completely. - self.assertRaises(AssertionError, GetEventByNameFromEvents, events) - - events['types'] = [] - # No type 'Event' defined. - self.assertRaises(AssertionError, GetEventByNameFromEvents, events) - - events['types'].append({ 'name': 'Event', - 'functions': []}) - add_rules = { "name": "addRules" } - events['types'][0]['functions'].append(add_rules) - self.assertEqual(add_rules, - GetEventByNameFromEvents(events)['addRules']) - - events['types'][0]['functions'].append(add_rules) - # Duplicates are an error. - self.assertRaises(AssertionError, GetEventByNameFromEvents, events) - - def testCreateId(self): - fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability) - dict_ = CreateJSCView( - self._api_models.GetContentScriptAPIs().Get(), - self._api_models.GetModel('tester').Get(), - fake_avail_finder, - self._json_cache, - _FakeTemplateCache(), - self._features_bundle, - None, - 'extensions', - [], - Request.ForTest('')) - self.assertEquals('type-TypeA', dict_['types'][0]['id']) - self.assertEquals('property-TypeA-b', - dict_['types'][0]['properties'][0]['id']) - self.assertEquals('method-get', dict_['functions'][0]['id']) - self.assertEquals('event-EventA', dict_['events'][0]['id']) - - # TODO(kalman): re-enable this when we have a rebase option. - def DISABLED_testToDict(self): - fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability) - expected_json = self._LoadJSON('expected_tester.json') - dict_ = CreateJSCView( - self._api_models.GetContentScriptAPIs().Get(), - self._api_models.GetModel('tester').Get(), - fake_avail_finder, - self._json_cache, - _FakeTemplateCache(), - self._features_bundle, - None, - 'extensions', - [], - Request.ForTest('')) - self.assertEquals(expected_json, dict_) - - def testAddRules(self): - fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability) - dict_ = CreateJSCView( - self._api_models.GetContentScriptAPIs().Get(), - self._api_models.GetModel('add_rules_tester').Get(), - fake_avail_finder, - self._json_cache, - _FakeTemplateCache(), - self._features_bundle, - self._FakeLoadAddRulesSchema(), - 'extensions', - [], - Request.ForTest('')) - - # Check that the first event has the addRulesFunction defined. - self.assertEquals('add_rules_tester', dict_['name']) - self.assertEquals('rules', dict_['events'][0]['name']) - self.assertEquals('notable_name_to_check_for', - dict_['events'][0]['byName']['addRules'][ - 'parameters'][0]['name']) - - # Check that the second event has addListener defined. - self.assertEquals('noRules', dict_['events'][1]['name']) - self.assertEquals('add_rules_tester', dict_['name']) - self.assertEquals('noRules', dict_['events'][1]['name']) - self.assertEquals('callback', - dict_['events'][0]['byName']['addListener'][ - 'parameters'][0]['name']) - - def testGetIntroList(self): - fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability) - model = _JSCViewBuilder( - self._api_models.GetContentScriptAPIs().Get(), - self._api_models.GetModel('tester').Get(), - fake_avail_finder, - self._json_cache, - _FakeTemplateCache(), - self._features_bundle, - None, - 'extensions', - []) - expected_list = [ - { 'title': 'Description', - 'content': [ - { 'text': 'a test api' } - ] - }, - { 'title': 'Availability', - 'content': [ - { 'partial': 'motemplate chrome/common/extensions/docs/' + - 'templates/private/intro_tables/stable_message.html', - 'version': 5, - 'scheduled': None - } - ] - }, - { 'title': 'Permissions', - 'content': [ - { 'class': 'override', - 'text': '"tester"' - }, - { 'text': 'is an API for testing things.' } - ] - }, - { 'title': 'Manifest', - 'content': [ - { 'class': 'code', - 'text': '"tester": {...}' - } - ] - }, - { 'title': 'Content Scripts', - 'content': [ - { - 'partial': 'motemplate chrome/common/extensions/docs' + - '/templates/private/intro_tables/content_scripts.html', - 'contentScriptSupport': { - 'name': 'tester', - 'restrictedTo': None - } - } - ] - }, - { 'title': 'Learn More', - 'content': [ - { 'link': 'https://tester.test.com/welcome.html', - 'text': 'Welcome!' - } - ] - } - ] - self.assertEquals(model._GetIntroTableList(), expected_list) - - # Tests the same data with a scheduled availability. - fake_avail_finder = _FakeAvailabilityFinder( - AvailabilityInfo(ChannelInfo('beta', '1453', 27), scheduled=28)) - model = _JSCViewBuilder( - self._api_models.GetContentScriptAPIs().Get(), - self._api_models.GetModel('tester').Get(), - fake_avail_finder, - self._json_cache, - _FakeTemplateCache(), - self._features_bundle, - None, - 'extensions', - []) - expected_list[1] = { - 'title': 'Availability', - 'content': [ - { 'partial': 'motemplate chrome/common/extensions/docs/' + - 'templates/private/intro_tables/beta_message.html', - 'version': 27, - 'scheduled': 28 - } - ] - } - self.assertEquals(model._GetIntroTableList(), expected_list) - - -class JSCViewWithoutNodeAvailabilityTest(unittest.TestCase): - def setUp(self): - server_instance = ServerInstance.ForTest( - file_system_provider=FakeHostFileSystemProvider( - CANNED_API_FILE_SYSTEM_DATA)) - self._api_models = server_instance.platform_bundle.GetAPIModels( - 'extensions') - self._json_cache = server_instance.compiled_fs_factory.ForJson( - server_instance.host_file_system_provider.GetMaster()) - self._avail_finder = server_instance.platform_bundle.GetAvailabilityFinder( - 'extensions') - - - def testGetAPIAvailability(self): - api_availabilities = { - 'bluetooth': 31, - 'contextMenus': 'master', - 'jsonStableAPI': 20, - 'idle': 5, - 'input.ime': 18, - 'tabs': 18 - } - for api_name, availability in api_availabilities.iteritems(): - model_dict = CreateJSCView( - self._api_models.GetContentScriptAPIs().Get(), - self._api_models.GetModel(api_name).Get(), - self._avail_finder, - self._json_cache, - _FakeTemplateCache(), - _FakeFeaturesBundle(), - None, - 'extensions', - [], - Request.ForTest('')) - self.assertEquals(availability, - model_dict['introList'][1]['content'][0]['version']) - - -class JSCViewWithNodeAvailabilityTest(unittest.TestCase): - def setUp(self): - tabs_unmodified_versions = (16, 20, 23, 24) - self._branch_utility = BranchUtility( - os.path.join('branch_utility', 'first.json'), - os.path.join('branch_utility', 'second.json'), - FakeUrlFetcher(Server2Path('test_data')), - ObjectStoreCreator.ForTest()) - self._node_fs_creator = FakeHostFileSystemProvider(TABS_SCHEMA_BRANCHES) - self._node_fs_iterator = HostFileSystemIterator(self._node_fs_creator, - self._branch_utility) - test_object_store = ObjectStoreCreator.ForTest() - self._avail_finder = AvailabilityFinder( - self._branch_utility, - CompiledFileSystem.Factory(test_object_store), - self._node_fs_iterator, - self._node_fs_creator.GetMaster(), - test_object_store, - 'extensions', - SchemaProcessorFactoryForTest()) - - server_instance = ServerInstance.ForTest( - file_system_provider=FakeHostFileSystemProvider( - TABS_SCHEMA_BRANCHES)) - self._api_models = server_instance.platform_bundle.GetAPIModels( - 'extensions') - self._json_cache = server_instance.compiled_fs_factory.ForJson( - server_instance.host_file_system_provider.GetMaster()) - - # Imitate the actual SVN file system by incrementing the stats for paths - # where an API schema has changed. - last_stat = type('last_stat', (object,), {'val': 0}) - - def stat_paths(file_system, channel_info): - if channel_info.version not in tabs_unmodified_versions: - last_stat.val += 1 - # HACK: |file_system| is a MockFileSystem backed by a TestFileSystem. - # Increment the TestFileSystem stat count. - file_system._file_system.IncrementStat(by=last_stat.val) - # Continue looping. The iterator will stop after 'master' automatically. - return True - - # Use the HostFileSystemIterator created above to change global stat values - # for the TestFileSystems that it creates. - self._node_fs_iterator.Ascending( - # The earliest version represented with the tabs' test data is 13. - self._branch_utility.GetStableChannelInfo(13), - stat_paths) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetAPINodeAvailability(self): - def assertEquals(node, actual): - node_availabilities = { - 'tabs.Tab': None, - 'tabs.fakeTabsProperty1': None, - 'tabs.get': None, - 'tabs.onUpdated': None, - 'tabs.InjectDetails': 25, - 'tabs.fakeTabsProperty2': 15, - 'tabs.getCurrent': 19, - 'tabs.onActivated': 30 - } - self.assertEquals(node_availabilities[node], actual) - - model_dict = CreateJSCView( - self._api_models.GetContentScriptAPIs().Get(), - self._api_models.GetModel('tabs').Get(), - self._avail_finder, - self._json_cache, - _FakeTemplateCache(), - _FakeFeaturesBundle(), - None, - 'extensions', - [], - Request.ForTest('')) - - # Test nodes that have the same availability as their parent. - - # Test type. - assertEquals('tabs.Tab', model_dict['types'][0]['availability']) - # Test property. - assertEquals('tabs.fakeTabsProperty1', - model_dict['properties'][1]['availability']) - # Test function. - assertEquals('tabs.get', model_dict['functions'][1]['availability']) - # Test event. - assertEquals('tabs.onUpdated', model_dict['events'][1]['availability']) - - # Test nodes with varying availabilities. - - # Test type. - assertEquals('tabs.InjectDetails', - model_dict['types'][1]['availability']['version']) - # Test property. - assertEquals('tabs.fakeTabsProperty2', - model_dict['properties'][3]['availability']['version']) - # Test function. - assertEquals('tabs.getCurrent', - model_dict['functions'][0]['availability']['version']) - # Test event. - assertEquals('tabs.onActivated', - model_dict['events'][0]['availability']['version']) - - # Test a node that became deprecated. - self.assertEquals({ - 'scheduled': None, - 'version': 26, - 'partial': 'motemplate chrome/common/extensions/docs/templates/' + - 'private/intro_tables/deprecated_message.html' - }, model_dict['types'][2]['availability']) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/known_broken_links.json b/chrome/common/extensions/docs/server2/known_broken_links.json deleted file mode 100644 index 4b1d59f..0000000 --- a/chrome/common/extensions/docs/server2/known_broken_links.json +++ /dev/null
@@ -1,2019 +0,0 @@ -[ - [ - 302, - "extensions/app_identity.html", - "extensions/publish_app.html", - "redirects to /apps/publish_app.html" - ], - [ - 404, - "apps/manifest/storage.html", - "apps/manifest/chrome:/policy", - "target page not found" - ], - [ - 200, - "apps/api_index.html", - "#manifest", - "target anchor not found" - ], - [ - 404, - "apps/tut_oauth.html", - "apps/examples/extensions/oauth_contacts/chrome_ex_oauth.html", - "target page not found" - ], - [ - 404, - "apps/tut_oauth.html", - "apps/examples/extensions/oauth_contacts/chrome_ex_oauth.js", - "target page not found" - ], - [ - 404, - "apps/tut_oauth.html", - "apps/examples/extensions/oauth_contacts/chrome_ex_oauthsimple.js", - "target page not found" - ], - [ - 404, - "apps/tut_oauth.html", - "apps/examples/extensions/oauth_contacts/onload.js", - "target page not found" - ], - [ - 200, - "extensions/debugger.html", - "extensions/samples.html#debugger", - "target anchor not found" - ], - [ - 200, - "extensions/privacy.html", - "extensions/samples.html#privacy", - "target anchor not found" - ], - [ - 200, - "apps/events.html", - "#filtered", - "target anchor not found" - ], - [ - 200, - "extensions/contextMenus.html", - "extensions/samples.html#contextMenus", - "target anchor not found" - ], - [ - 200, - "extensions/webRequest.html", - "extensions/samples.html#webrequest", - "target anchor not found" - ], - [ - 200, - "extensions/browsingData.html", - "extensions/samples.html#browsingData", - "target anchor not found" - ], - [ - 200, - "extensions/override.html", - "extensions/samples.html#chrome_url_overrides", - "target anchor not found" - ], - [ - 302, - "apps/types.html", - "apps/proxy.html#overview-examples", - "redirects to /extensions/proxy.html" - ], - [ - 302, - "apps/types.html", - "apps/proxy.html#property-settings", - "redirects to /extensions/proxy.html" - ], - [ - 302, - "apps/experimental_webInspector.html", - "apps/experimental_devtools.html", - "redirects to /extensions/experimental_devtools.html" - ], - [ - 302, - "apps/experimental_devtools_network.html", - "apps/devtools_network.html", - "redirects to /extensions/devtools_network.html" - ], - [ - 404, - "extensions/manifest/storage.html", - "extensions/manifest/chrome:/policy", - "target page not found" - ], - [ - 302, - "apps/tut_debugging.html", - "apps/getstarted.html", - "redirects to /extensions/getstarted.html" - ], - [ - 302, - "apps/tut_debugging.html", - "apps/getstarted.html#unpacked", - "redirects to /extensions/getstarted.html" - ], - [ - 302, - "apps/tut_debugging.html", - "apps/getstarted.html#next-steps", - "redirects to /extensions/getstarted.html" - ], - [ - 302, - "apps/storage.html", - "apps/manifest/incognito.html", - "redirects to /extensions/manifest/incognito.html" - ], - [ - 302, - "apps/messaging.html", - "apps/tabs.html#method-sendMessage", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/messaging.html", - "apps/tabs.html#method-connect", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/messaging.html", - "apps/tabs.html#method-connect", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "extensions/notifications.html", - "extensions/app_external.html", - "redirects to /apps/app_external.html" - ], - [ - 302, - "extensions/notifications.html", - "extensions/app_lifecycle.html#create_event_page", - "redirects to /apps/app_lifecycle.html" - ], - [ - 302, - "apps/app_codelab8_webresources.html", - "apps/webview_tag.html", - "redirects to /apps/tags/webview.html" - ], - [ - 302, - "apps/app_codelab8_webresources.html", - "apps/webview_tag.html", - "redirects to /apps/tags/webview.html" - ], - [ - 200, - "apps/contextMenus.html", - "apps/samples.html#contextMenus", - "target anchor not found" - ], - [ - 302, - "apps/contextMenus.html", - "apps/tabs.html#type-Tab", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/contextMenus.html", - "apps/tabs.html#type-Tab", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/contextMenus.html", - "apps/tabs.html#type-Tab", - "redirects to /extensions/tabs.html" - ], - [ - 404, - "extensions/manifest/externally_connectable.html", - "extensions/manifest/runtime.html#method-connect", - "target page not found" - ], - [ - 404, - "extensions/manifest/externally_connectable.html", - "extensions/manifest/runtime.html#method-sendMessage", - "target page not found" - ], - [ - 404, - "extensions/manifest/externally_connectable.html", - "extensions/manifest/runtime.html#property-MessageSender-tlsChannelId", - "target page not found" - ], - [ - 404, - "extensions/manifest/externally_connectable.html", - "extensions/manifest/runtime.html#property-MessageSender-tlsChannelId", - "target page not found" - ], - [ - 404, - "extensions/declare_permissions.html", - "extensions/dns.html", - "target page not found" - ], - [ - 404, - "extensions/declare_permissions.html", - "extensions/idltest.html", - "target page not found" - ], - [ - 302, - "extensions/declare_permissions.html", - "extensions/system_display.html", - "redirects to /apps/system_display.html" - ], - [ - 200, - "extensions/experimental.html", - "extensions/samples.html#experimental", - "target anchor not found" - ], - [ - 302, - "extensions/samples.html", - "extensions/app_runtime.html", - "redirects to /apps/app_runtime.html" - ], - [ - 302, - "extensions/samples.html", - "extensions/app_runtime.html#event-onLaunched", - "redirects to /apps/app_runtime.html" - ], - [ - 302, - "extensions/samples.html", - "extensions/app_window.html#method-create", - "redirects to /apps/app_window.html" - ], - [ - 302, - "extensions/samples.html", - "extensions/app_runtime.html#event-onLaunched", - "redirects to /apps/app_runtime.html" - ], - [ - 302, - "extensions/samples.html", - "extensions/app_runtime.html#event-onRestarted", - "redirects to /apps/app_runtime.html" - ], - [ - 302, - "extensions/samples.html", - "extensions/app_window.html#method-create", - "redirects to /apps/app_window.html" - ], - [ - 200, - "extensions/contentSettings.html", - "extensions/samples.html#contentSettings", - "target anchor not found" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_inspectedWindow.html", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_network.html", - "redirects to /extensions/devtools_network.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_panels.html", - "redirects to /extensions/devtools_panels.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_panels.html", - "redirects to /extensions/devtools_panels.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_inspectedWindow.html", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_network.html", - "redirects to /extensions/devtools_network.html" - ], - [ - 302, - "apps/devtools.html", - "apps/extension.html", - "redirects to /extensions/extension.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_panels.html", - "redirects to /extensions/devtools_panels.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_inspectedWindow.html", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_panels.html#method-ExtensionSidebarPane-setPage", - "redirects to /extensions/devtools_panels.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_panels.html#method-ExtensionSidebarPane-setObject", - "redirects to /extensions/devtools_panels.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_panels.html#method-ExtensionSidebarPane-setExpression", - "redirects to /extensions/devtools_panels.html" - ], - [ - 302, - "apps/devtools.html", - "apps/tabs.html#method-executeScript", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_inspectedWindow.html#property-tabId", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/devtools.html", - "apps/tabs.html#method-executeScript", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_inspectedWindow.html#method-eval", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/devtools.html", - "apps/tabs.html#method-executeScript", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_inspectedWindow.html#method-eval", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/devtools.html", - "apps/devtools_inspectedWindow.html#method-eval", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/devtools.html", - "apps/tabs.html#method-sendMessage", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/event_pages.html", - "apps/declarativeWebRequest.html", - "redirects to /extensions/declarativeWebRequest.html" - ], - [ - 302, - "apps/event_pages.html", - "apps/extension.html#method-getBackgroundPage", - "redirects to /extensions/extension.html" - ], - [ - 200, - "apps/event_pages.html", - "apps/events.html#filtered", - "target anchor not found" - ], - [ - 302, - "apps/event_pages.html", - "apps/tabs.html#event-onUpdated", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/event_pages.html", - "apps/webNavigation.html#event-onCompleted", - "redirects to /extensions/webNavigation.html" - ], - [ - 200, - "extensions/declarativeWebRequest.html", - "#type-Rule", - "target anchor not found" - ], - [ - 200, - "extensions/topSites.html", - "extensions/samples.html#topsites", - "target anchor not found" - ], - [ - 302, - "apps/content_scripts.html", - "apps/extension.html", - "redirects to /extensions/extension.html" - ], - [ - 302, - "apps/content_scripts.html", - "apps/tabs.html#method-executeScript", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/content_scripts.html", - "apps/tabs.html#method-insertCSS", - "redirects to /extensions/tabs.html" - ], - [ - 200, - "apps/content_scripts.html", - "apps/samples.html#script", - "target anchor not found" - ], - [ - 200, - "apps/content_scripts.html", - "apps/samples.html#message-timer", - "target anchor not found" - ], - [ - 200, - "apps/content_scripts.html", - "apps/samples.html#page-redder", - "target anchor not found" - ], - [ - 200, - "apps/content_scripts.html", - "apps/samples.html#email-this-page-(by-google)", - "target anchor not found" - ], - [ - 302, - "apps/experimental_devtools_inspectedWindow.html", - "apps/devtools_inspectedWindow.html", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/background_pages.html", - "apps/manifest/incognito.html", - "redirects to /extensions/manifest/incognito.html" - ], - [ - 302, - "apps/background_pages.html", - "apps/overview.html#arch", - "redirects to /extensions/overview.html" - ], - [ - 200, - "apps/background_pages.html", - "apps/declare_permissions.html#background", - "target anchor not found" - ], - [ - 302, - "apps/background_pages.html", - "apps/extension.html#method-getViews", - "redirects to /extensions/extension.html" - ], - [ - 302, - "apps/background_pages.html", - "apps/extension.html#method-getBackgroundPage", - "redirects to /extensions/extension.html" - ], - [ - 302, - "apps/background_pages.html", - "apps/tabs.html#method-create", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/packaging.html", - "apps/overview.html", - "redirects to /extensions/overview.html" - ], - [ - 302, - "apps/declare_permissions.html", - "apps/cookies.html", - "redirects to /extensions/cookies.html" - ], - [ - 404, - "apps/declare_permissions.html", - "target page not found" - ], - [ - 302, - "apps/declare_permissions.html", - "apps/desktopCapture.html", - "redirects to /extensions/desktopCapture.html" - ], - [ - 404, - "apps/declare_permissions.html", - "apps/diagnostics.html", - "target page not found" - ], - [ - 404, - "apps/declare_permissions.html", - "apps/dns.html", - "target page not found" - ], - [ - 302, - "apps/declare_permissions.html", - "apps/fileBrowserHandler.html", - "redirects to /extensions/fileBrowserHandler.html" - ], - [ - 404, - "apps/declare_permissions.html", - "apps/fileSystemProvider.html", - "target page not found" - ], - [ - 302, - "apps/declare_permissions.html", - "apps/signedInDevices.html", - "redirects to /extensions/signedInDevices.html" - ], - [ - 404, - "apps/declare_permissions.html", - "apps/system_network.html", - "target page not found" - ], - [ - 404, - "apps/declare_permissions.html", - "apps/webview.html", - "target page not found" - ], - [ - 302, - "apps/app_deprecated.html", - "apps/webview_tag.html", - "redirects to /apps/tags/webview.html" - ], - [ - 200, - "extensions/content_scripts.html", - "extensions/samples.html#script", - "target anchor not found" - ], - [ - 302, - "apps/samples.html", - "apps/extension.html#property-lastError", - "redirects to /extensions/extension.html" - ], - [ - 302, - "apps/samples.html", - "apps/extension.html#property-lastError-message", - "redirects to /extensions/extension.html" - ], - [ - 302, - "apps/samples.html", - "apps/extension.html#property-lastError", - "redirects to /extensions/extension.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/activityLogPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/app.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/bookmarkManagerPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/bookmarks.html", - "redirects to /extensions/bookmarks.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/override.html", - "redirects to /extensions/override.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/brailleDisplayPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/browserAction.html", - "redirects to /extensions/browserAction.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/browsingData.html", - "redirects to /extensions/browsingData.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/cast_channel.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/cast_streaming_rtpStream.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/cast_streaming_session.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/cast_streaming_udpTransport.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/chromeosInfoPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/cloudPrintPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/commandLinePrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/commands.html", - "redirects to /extensions/commands.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/contentSettings.html", - "redirects to /extensions/contentSettings.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/cookies.html", - "redirects to /extensions/cookies.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/debugger.html", - "redirects to /extensions/debugger.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/declarativeContent.html", - "redirects to /extensions/declarativeContent.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/declarativeWebRequest.html", - "redirects to /extensions/declarativeWebRequest.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/webRequest.html", - "redirects to /extensions/webRequest.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/desktopCapture.html", - "redirects to /extensions/desktopCapture.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/developerPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/devtools_inspectedWindow.html", - "redirects to /extensions/devtools_inspectedWindow.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/devtools_network.html", - "redirects to /extensions/devtools_network.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/devtools_panels.html", - "redirects to /extensions/devtools_panels.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/diagnostics.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/dial.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/dns.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/downloads.html", - "redirects to /extensions/downloads.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/echoPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/enterprise_platformKeysPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/experimental_accessibility.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/experimental_devtools_console.html", - "redirects to /extensions/experimental_devtools_console.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/experimental_discovery.html", - "redirects to /extensions/experimental_discovery.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/experimental_history.html", - "redirects to /extensions/experimental_history.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/extension.html", - "redirects to /extensions/extension.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/feedbackPrivate.html", - "redirects to /extensions/feedbackPrivate.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/fileBrowserHandler.html", - "redirects to /extensions/fileBrowserHandler.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/fileBrowserHandlerInternal.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/fileManagerPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/fileSystemProvider.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/firstRunPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/fontSettings.html", - "redirects to /extensions/fontSettings.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/history.html", - "redirects to /extensions/history.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/override.html", - "redirects to /extensions/override.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/identityPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/idltest.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/input_ime.html", - "redirects to /extensions/input_ime.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/inputMethodPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/logPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/management.html", - "redirects to /extensions/management.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/override.html", - "redirects to /extensions/override.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/manifestTypes.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/mdns.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/mediaGalleriesPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/mediaPlayerPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/metricsPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/networkingPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/omnibox.html", - "redirects to /extensions/omnibox.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/pageAction.html", - "redirects to /extensions/pageAction.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/pageActions.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/pageCapture.html", - "redirects to /extensions/pageCapture.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/preferencesPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/privacy.html", - "redirects to /extensions/privacy.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/processes.html", - "redirects to /extensions/processes.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/proxy.html", - "redirects to /extensions/proxy.html" - ], - [ - 404, - "apps/private_apis.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/sessions.html", - "redirects to /extensions/sessions.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/signedInDevices.html", - "redirects to /extensions/signedInDevices.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/sockets_tcp.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/sockets_tcpServer.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/sockets_udp.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/streamsPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/system_network.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/systemIndicator.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/systemPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/tabCapture.html", - "redirects to /extensions/tabCapture.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/tabs.html", - "redirects to /extensions/tabs.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/terminalPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/test.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/topSites.html", - "redirects to /extensions/topSites.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/ttsEngine.html", - "redirects to /extensions/ttsEngine.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/virtualKeyboardPrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/wallpaperPrivate.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/webNavigation.html", - "redirects to /extensions/webNavigation.html" - ], - [ - 302, - "apps/private_apis.html", - "apps/webRequest.html", - "redirects to /extensions/webRequest.html" - ], - [ - 404, - "apps/private_apis.html", - "apps/webRequestInternal.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/webstorePrivate.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/webview.html", - "target page not found" - ], - [ - 404, - "apps/private_apis.html", - "apps/webviewTag.html", - "target page not found" - ], - [ - 302, - "apps/private_apis.html", - "apps/windows.html", - "redirects to /extensions/windows.html" - ], - [ - 200, - "apps/private_apis.html", - "#icon", - "target anchor not found" - ], - [ - 200, - "apps/private_apis.html", - "#tooltip", - "target anchor not found" - ], - [ - 200, - "apps/private_apis.html", - "#badge", - "target anchor not found" - ], - [ - 200, - "apps/private_apis.html", - "#popups", - "target anchor not found" - ], - [ - 200, - "apps/private_apis.html", - "#usage", - "target anchor not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-ContentWindow", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-WebRequestEventInteface", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-ClearDataOptions", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-ClearDataTypeSet", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-ClearDataOptions", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-ClearDataTypeSet", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-InjectDetails", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-InjectDetails", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-InjectDetails", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-InjectDetails", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#method-setUserAgentOverride", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-DialogController", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-NewWindow", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-MediaPermissionRequest", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-GeolocationPermissionRequest", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-PointerLockPermissionRequest", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-DownloadPermissionRequest", - "target page not found" - ], - [ - 404, - "apps/tags/webview.html", - "apps/tags/webviewTag.html#type-LoadPluginPermissionRequest", - "target page not found" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/bookmarks.html", - "redirects to /extensions/bookmarks.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/history.html", - "redirects to /extensions/history.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/topSites.html", - "redirects to /extensions/topSites.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/tabs.html", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/windows.html", - "redirects to /extensions/windows.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/webNavigation.html", - "redirects to /extensions/webNavigation.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/contentSettings.html", - "redirects to /extensions/contentSettings.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/debugger.html", - "redirects to /extensions/debugger.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/proxy.html", - "redirects to /extensions/proxy.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/activeTab.html", - "redirects to /extensions/activeTab.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/management.html", - "redirects to /extensions/management.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/privacy.html", - "redirects to /extensions/privacy.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/signedInDevices.html", - "redirects to /extensions/signedInDevices.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/ttsEngine.html", - "redirects to /extensions/ttsEngine.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/tabs.html#type-Tab", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/permission_warnings.html", - "apps/management.html#method-getPermissionWarningsByManifest", - "redirects to /extensions/management.html" - ], - [ - 404, - "extensions/whats_new.html", - "extensions/manifest/geolocation.html", - "target page not found" - ], - [ - 200, - "extensions/devtools_inspectedWindow.html", - "extensions/samples.html#devtools", - "target anchor not found" - ], - [ - 302, - "apps/runtime.html", - "apps/tabs.html#type-Tab", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/runtime.html", - "apps/tabs.html#type-Tab", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/runtime.html", - "apps/tabs.html#method-connect", - "redirects to /extensions/tabs.html" - ], - [ - 302, - "apps/runtime.html", - "apps/tabs.html#method-sendMessage", - "redirects to /extensions/tabs.html" - ], - [ - 200, - "extensions/devtools_network.html", - "extensions/samples.html#devtools.network", - "target anchor not found" - ], - [ - 302, - "apps/desktop_notifications.html", - "apps/extension.html#method-getBackgroundPage", - "redirects to /extensions/extension.html" - ], - [ - 302, - "apps/desktop_notifications.html", - "apps/extension.html#method-getViews", - "redirects to /extensions/extension.html" - ], - [ - 404, - "apps/manifest/externally_connectable.html", - "apps/manifest/runtime.html#method-connect", - "target page not found" - ], - [ - 404, - "apps/manifest/externally_connectable.html", - "apps/manifest/runtime.html#method-sendMessage", - "target page not found" - ], - [ - 404, - "apps/manifest/externally_connectable.html", - "apps/manifest/runtime.html#property-MessageSender-tlsChannelId", - "target page not found" - ], - [ - 404, - "apps/manifest/externally_connectable.html", - "apps/manifest/runtime.html#property-MessageSender-tlsChannelId", - "target page not found" - ], - [ - 200, - "extensions/omnibox.html", - "extensions/samples.html#omnibox", - "target anchor not found" - ], - [ - 302, - "apps/experimental_devtools_panels.html", - "apps/devtools_panels.html", - "redirects to /extensions/devtools_panels.html" - ], - [ - 200, - "extensions/api_index.html", - "#icon", - "target anchor not found" - ], - [ - 200, - "extensions/api_index.html", - "#tooltip", - "target anchor not found" - ], - [ - 200, - "extensions/api_index.html", - "#badge", - "target anchor not found" - ], - [ - 200, - "extensions/api_index.html", - "#popups", - "target anchor not found" - ], - [ - 200, - "extensions/api_index.html", - "#manifest", - "target anchor not found" - ], - [ - 302, - "apps/faq.html", - "apps/browserAction.html", - "redirects to /extensions/browserAction.html" - ], - [ - 302, - "apps/faq.html", - "apps/pageAction.html", - "redirects to /extensions/pageAction.html" - ], - [ - 302, - "apps/faq.html", - "apps/management.html", - "redirects to /extensions/management.html" - ], - [ - 302, - "extensions/runtime.html", - "extensions/app_lifecycle.html", - "redirects to /apps/app_lifecycle.html" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/activityLogPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/app.html", - "target page not found" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/app_runtime.html", - "redirects to /apps/app_runtime.html" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/app_window.html", - "redirects to /apps/app_window.html" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/audio.html", - "redirects to /apps/audio.html" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/bluetooth.html", - "redirects to /apps/bluetooth.html" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/bookmarkManagerPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/brailleDisplayPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/cast_channel.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/cast_streaming_rtpStream.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/cast_streaming_session.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/cast_streaming_udpTransport.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/chromeosInfoPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/cloudPrintPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/commandLinePrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/developerPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/diagnostics.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/dial.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/dns.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/echoPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/enterprise_platformKeysPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/experimental_accessibility.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/fileBrowserHandlerInternal.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/fileManagerPrivate.html", - "target page not found" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/fileSystem.html", - "redirects to /apps/fileSystem.html" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/fileSystemProvider.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/firstRunPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/identityPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/idltest.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/inputMethodPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/logPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/manifestTypes.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/mdns.html", - "target page not found" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/mediaGalleries.html", - "redirects to /apps/mediaGalleries.html" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/mediaGalleriesPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/mediaPlayerPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/metricsPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/networkingPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/pageActions.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/preferencesPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "target page not found" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/serial.html", - "redirects to /apps/serial.html" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/socket.html", - "redirects to /apps/socket.html" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/sockets_tcp.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/sockets_tcpServer.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/sockets_udp.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/streamsPrivate.html", - "target page not found" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/syncFileSystem.html", - "redirects to /apps/syncFileSystem.html" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/app_storage.html", - "redirects to /apps/app_storage.html" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/system_display.html", - "redirects to /apps/system_display.html" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/system_network.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/systemIndicator.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/systemPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/terminalPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/test.html", - "target page not found" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/usb.html", - "redirects to /apps/usb.html" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/virtualKeyboardPrivate.html", - "target page not found" - ], - [ - 302, - "extensions/private_apis.html", - "extensions/wallpaper.html", - "redirects to /apps/wallpaper.html" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/wallpaperPrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/webRequestInternal.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/webstorePrivate.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/webview.html", - "target page not found" - ], - [ - 404, - "extensions/private_apis.html", - "extensions/webviewTag.html", - "target page not found" - ], - [ - 200, - "extensions/private_apis.html", - "#usage", - "target anchor not found" - ], - [ - 200, - "extensions/tabs.html", - "#type-ImageDetails", - "target anchor not found" - ], - [ - 200, - "extensions/tabs.html", - "#type-ImageDetails", - "target anchor not found" - ], - [ - 200, - "extensions/declarativeContent.html", - "#type-Rule", - "target anchor not found" - ], - [ - 200, - "extensions/whats_new.html", - "#badge", - "target anchor not found" - ], - [ - 200, - "extensions/whats_new.html", - "#icon", - "target anchor not found" - ], - [ - 200, - "extensions/whats_new.html", - "#manifest", - "target anchor not found" - ], - [ - 200, - "apps/whats_new.html", - "#manifest", - "target anchor not found" - ], - [ - 200, - "extensions/whats_new.html", - "#popups", - "target anchor not found" - ], - [ - 200, - "extensions/whats_new.html", - "#tooltip", - "target anchor not found" - ] -]
diff --git a/chrome/common/extensions/docs/server2/link_converter.py b/chrome/common/extensions/docs/server2/link_converter.py deleted file mode 100755 index 7b22803a..0000000 --- a/chrome/common/extensions/docs/server2/link_converter.py +++ /dev/null
@@ -1,87 +0,0 @@ -#!/usr/bin/env python -# 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. - -# This script converts old-style <a> links to API docs to the new $ref links. -# See reference_resolver.py for more info on the format of $ref links. - -import optparse -import os -import re - -from docs_server_utils import SanitizeAPIName - -def _ReadFile(filename): - with open(filename) as f: - return f.read() - -def _WriteFile(filename, contents): - with open(filename, 'w') as f: - f.write(contents) - -def _Replace(matches, filename): - title = matches.group(3) - if matches.group(2).count('#') != 1: - return '<a%shref=%s>%s</a>' % (matches.group(1), - matches.group(2), - title) - clean = (matches.group(2).replace('\\', '') - .replace("'", '') - .replace('"', '') - .replace('/', '')) - page, link = clean.split('#') - if not page: - page = '%s.html' % SanitizeAPIName(filename.rsplit(os.sep, 1)[-1]) - if (not link.startswith('property-') and - not link.startswith('type-') and - not link.startswith('method-') and - not link.startswith('event-')): - return '<a%shref=%s>%s</a>' % (matches.group(1), - matches.group(2), - title) - - link = re.sub('^(property|type|method|event)-', '', link).replace('-', '.') - page = page.replace('.html', '.').replace('_', '.') - if matches.group(1) == ' ': - padding = '' - else: - padding = matches.group(1) - if link in title: - return '%s$(ref:%s%s)' % (padding, page, link) - else: - return '%s$(ref:%s%s %s)' % (padding, page, link, title) - -def _ConvertFile(filename, use_stdout): - regex = re.compile(r'<a(.*?)href=(.*?)>(.*?)</a>', flags=re.DOTALL) - contents = _ReadFile(filename) - contents = re.sub(regex, - lambda m: _Replace(m, filename), - contents) - contents = contents.replace('$(ref:extension.lastError)', - '$(ref:runtime.lastError)') - if use_stdout: - print contents - else: - _WriteFile(filename, contents) - -if __name__ == '__main__': - parser = optparse.OptionParser( - description='Converts <a> links to $ref links.', - usage='usage: %prog [option] <directory>') - parser.add_option('-f', '--file', default='', - help='Convert links in single file.') - parser.add_option('-o', '--out', action='store_true', default=False, - help='Write to stdout.') - regex = re.compile(r'<a(.*?)href=(.*?)>(.*?)</a>', flags=re.DOTALL) - - opts, argv = parser.parse_args() - if opts.file: - _ConvertFile(opts.file, opts.out) - else: - if len(argv) != 1: - parser.print_usage() - exit(0) - for root, dirs, files in os.walk(argv[0]): - for name in files: - _ConvertFile(os.path.join(root, name), opts.out)
diff --git a/chrome/common/extensions/docs/server2/link_error_detector.py b/chrome/common/extensions/docs/server2/link_error_detector.py deleted file mode 100644 index ee9bc7c..0000000 --- a/chrome/common/extensions/docs/server2/link_error_detector.py +++ /dev/null
@@ -1,306 +0,0 @@ -# Copyright 2013 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 collections import defaultdict, deque, namedtuple -from HTMLParser import HTMLParser, HTMLParseError -from itertools import groupby -from operator import itemgetter -import posixpath -from urlparse import urlsplit - -from file_system_util import CreateURLsFromPaths -from path_util import AssertIsDirectory - - -Page = namedtuple('Page', 'status, links, anchors, anchor_refs') - - -def _SplitAnchor(url): - components = urlsplit(url) - return components.path, components.fragment - - -def _Process(path, renderer): - '''Render the page at |path| using a |renderer| and process the contents of - that page. Returns a |Page| namedtuple with fields for the http status code - of the page render, the href of all the links that occurred on the page, all - of the anchors on the page (ids and names), and all links that contain an - anchor component. - - If a non-html page is properly rendered, a |Page| with status code 200 and - all other fields empty is returned. - ''' - parser = _ContentParser() - response = renderer(path) - - if response.status != 200: - return Page(response.status, (), (), ()) - if not path.endswith('.html'): - return Page(200, (), (), ()) - - try: - parser.feed(str(response.content)) - except HTMLParseError: - return Page(200, (), (), ()) - - links, anchors = parser.links, parser.anchors - if '/' in path: - base, _ = path.rsplit('/', 1) - else: - base = '' - edges = [] - anchor_refs = [] - - # Convert relative links to absolute links and categorize links as edges - # or anchor_refs. - for link in links: - # Files like experimental_history.html are refered to with the URL - # experimental.history.html. - head, last = link.rsplit('/', 1) if '/' in link else ('', link) - last, anchor = _SplitAnchor(last) - - if last.endswith('.html') and last.count('.') > 1: - last = last.replace('.', '_', last.count('.') - 1) - link = posixpath.join(head, last) - if anchor: - link = '%s#%s' % (link, anchor) - - if link.startswith('#'): - anchor_refs.append(link) - else: - if link.startswith('/'): - link = link[1:] - else: - link = posixpath.normpath('%s/%s' % (base, link)) - - if '#' in link: - anchor_refs.append(link) - else: - edges.append(link) - - return Page(200, edges, anchors, anchor_refs) - - -class _ContentParser(HTMLParser): - '''Parse an html file pulling out all links and anchor_refs, where an - anchor_ref is a link that contains an anchor. - ''' - - def __init__(self): - HTMLParser.__init__(self) - self.links = [] - self.anchors = set() - - def handle_starttag(self, tag, raw_attrs): - attrs = dict(raw_attrs) - - if tag == 'a': - # Handle special cases for href's that: start with a space, contain - # just a '.' (period), contain python templating code, are an absolute - # url, are a zip file, or execute javascript on the page. - href = attrs.get('href', '').strip() - if href and not href == '.' and not '{{' in href: - if not urlsplit(href).scheme in ('http', 'https'): - if not href.endswith('.zip') and not 'javascript:' in href: - self.links.append(href) - - if attrs.get('id'): - self.anchors.add(attrs['id']) - if attrs.get('name'): - self.anchors.add(attrs['name']) - - -class LinkErrorDetector(object): - '''Finds link errors on the doc server. This includes broken links, those with - a target page that 404s or contain an anchor that doesn't exist, or pages that - have no links to them. - ''' - - def __init__(self, file_system, renderer, public_path, root_pages): - '''Creates a new broken link detector. |renderer| is a callable that takes - a path and returns a full html page. |public_path| is the path to public - template files. All URLs in |root_pages| are used as the starting nodes for - the orphaned page search. - ''' - AssertIsDirectory(public_path) - self._file_system = file_system - self._renderer = renderer - self._public_path = public_path - self._pages = defaultdict(lambda: Page(404, (), (), ())) - self._root_pages = frozenset(root_pages) - self._always_detached = frozenset(( - 'apps/404.html', - 'extensions/404.html', - 'apps/private_apis.html', - 'extensions/private_apis.html')) - self._redirection_whitelist = frozenset(('extensions/', 'apps/')) - - self._RenderAllPages() - - def _RenderAllPages(self): - '''Traverses the public templates directory rendering each URL and - processing the resultant html to pull out all links and anchors. - ''' - top_level_directories = ( - ('docs/templates/public/', ''), - ('docs/static/', 'static/'), - ('docs/examples/', 'extensions/examples/'), - ) - - for dirpath, urlprefix in top_level_directories: - files = CreateURLsFromPaths(self._file_system, dirpath, urlprefix) - for url, path in files: - self._pages[url] = _Process(url, self._renderer) - - if self._pages[url].status != 200: - print(url, ', a url derived from the path', dirpath + - ', resulted in a', self._pages[url].status) - - def _FollowRedirections(self, starting_url, limit=4): - '''Follow redirection until a non-redirectable page is reached. Start at - |starting_url| which must return a 301 or 302 status code. - - Return a tuple of: the status of rendering |staring_url|, the final url, - and a list of the pages reached including |starting_url|. If no redirection - occurred, returns (None, None, None). - ''' - pages_reached = [starting_url] - redirect_link = None - target_page = self._renderer(starting_url) - original_status = status = target_page.status - count = 0 - - while status in (301, 302): - if count > limit: - return None, None, None - redirect_link = target_page.headers.get('Location') - target_page = self._renderer(redirect_link) - status = target_page.status - pages_reached.append(redirect_link) - count += 1 - - if redirect_link is None: - return None, None, None - - return original_status, redirect_link, pages_reached - - def _CategorizeBrokenLinks(self, url, page, pages): - '''Find all broken links on a page and create appropriate notes describing - why tehy are broken (broken anchor, target redirects, etc). |page| is the - current page being checked and is the result of rendering |url|. |pages| - is a callable that takes a path and returns a Page. - ''' - broken_links = [] - - for link in page.links + page.anchor_refs: - components = urlsplit(link) - fragment = components.fragment - - if components.path == '': - if fragment == 'top' or fragment == '': - continue - if not fragment in page.anchors: - broken_links.append((200, url, link, 'target anchor not found')) - else: - # Render the target page - target_page = pages(components.path) - - if target_page.status != 200: - if components.path in self._redirection_whitelist: - continue - - status, relink, _ = self._FollowRedirections(components.path) - if relink: - broken_links.append(( - status, - url, - link, - 'redirects to %s' % relink)) - else: - broken_links.append(( - target_page.status, url, link, 'target page not found')) - - elif fragment: - if not fragment in target_page.anchors: - broken_links.append(( - target_page.status, url, link, 'target anchor not found')) - - return broken_links - - def GetBrokenLinks(self): - '''Find all broken links. A broken link is a link that leads to a page - that does not exist (404s), redirects to another page (301 or 302), or - has an anchor whose target does not exist. - - Returns a list of tuples of four elements: status, url, target_page, - notes. - ''' - broken_links = [] - - for url in self._pages.keys(): - page = self._pages[url] - if page.status != 200: - continue - broken_links.extend(self._CategorizeBrokenLinks( - url, page, lambda x: self._pages[x])) - - return broken_links - - def GetOrphanedPages(self): - '''Crawls the server find all pages that are connected to the pages at - |seed_url|s. Return the links that are valid on the server but are not in - part of the connected component containing the |root_pages|. These pages - are orphans and cannot be reached simply by clicking through the server. - ''' - pages_to_check = deque(self._root_pages.union(self._always_detached)) - found = set(self._root_pages) | self._always_detached - - while pages_to_check: - item = pages_to_check.popleft() - target_page = self._pages[item] - - if target_page.status != 200: - redirected_page = self._FollowRedirections(item)[1] - if not redirected_page is None: - target_page = self._pages[redirected_page] - - for link in target_page.links: - if link not in found: - found.add(link) - pages_to_check.append(link) - - all_urls = set( - [url for url, page in self._pages.iteritems() if page.status == 200]) - - return [url for url in all_urls - found if url.endswith('.html')] - - -def StringifyBrokenLinks(broken_links): - '''Prints out broken links in a more readable format. - ''' - def fixed_width(string, width): - return "%s%s" % (string, (width - len(string)) * ' ') - - first_col_width = max(len(link[1]) for link in broken_links) - second_col_width = max(len(link[2]) for link in broken_links) - target = itemgetter(2) - output = [] - - def pretty_print(link, col_offset=0): - return "%s -> %s %s" % ( - fixed_width(link[1], first_col_width - col_offset), - fixed_width(link[2], second_col_width), - link[3]) - - for target, links in groupby(sorted(broken_links, key=target), target): - links = list(links) - # Compress messages - if len(links) > 50 and not links[0][2].startswith('#'): - message = "Found %d broken links (" % len(links) - output.append("%s%s)" % (message, pretty_print(links[0], len(message)))) - else: - for link in links: - output.append(pretty_print(link)) - - return '\n'.join(output)
diff --git a/chrome/common/extensions/docs/server2/link_error_detector_test.py b/chrome/common/extensions/docs/server2/link_error_detector_test.py deleted file mode 100755 index b1fc115d..0000000 --- a/chrome/common/extensions/docs/server2/link_error_detector_test.py +++ /dev/null
@@ -1,90 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from file_system import FileNotFoundError -from link_error_detector import LinkErrorDetector -from servlet import Response -from test_file_system import TestFileSystem - -file_system = TestFileSystem({ - 'docs': { - 'templates': { - 'public': { - 'apps': { - '404.html': '404', - 'index.html': ''' - <h1 id="actual-top">Hello</h1> - <a href="#top">world</p> - <a href="#actual-top">!</a> - <a href="broken.json"></a> - <a href="crx.html"></a> - ''', - 'crx.html': ''' - <a href="index.html#actual-top">back</a> - <a href="broken.html"></a> - <a href="devtools.events.html">do to underscore translation</a> - ''', - 'devtools_events.html': ''' - <a href=" http://www.google.com/">leading space in href</a> - <a href=" index.html">home</a> - <a href="index.html#invalid"></a> - <a href="fake.html#invalid"></a> - ''', - 'unreachable.html': ''' - <p>so lonely</p> - <a href="#aoesu"></a> - <a href="invalid.html"></a> - ''', - 'devtools_disconnected.html': '' - } - } - }, - 'static': {}, - 'examples': {}, - } -}) - -class LinkErrorDetectorTest(unittest.TestCase): - def _Render(self, path): - try: - return Response( - content=file_system.ReadSingle('docs/templates/public/' + path).Get(), - status=200) - except FileNotFoundError: - return Response(status=404) - - def testGetBrokenLinks(self): - expected_broken_links = set([ - (404, 'apps/crx.html', 'apps/broken.html', 'target page not found'), - (404, 'apps/index.html', 'apps/broken.json', 'target page not found'), - (404, 'apps/unreachable.html', 'apps/invalid.html', - 'target page not found'), - (404, 'apps/devtools_events.html', 'apps/fake.html#invalid', - 'target page not found'), - (200, 'apps/devtools_events.html', 'apps/index.html#invalid', - 'target anchor not found'), - (200, 'apps/unreachable.html', '#aoesu', 'target anchor not found')]) - - link_error_detector = LinkErrorDetector( - file_system, self._Render, 'templates/public/', ('apps/index.html')) - broken_links = link_error_detector.GetBrokenLinks() - - self.assertEqual(expected_broken_links, set(broken_links)) - - def testGetOrphanedPages(self): - expected_orphaned_pages = set([ - 'apps/unreachable.html', - 'apps/devtools_disconnected.html']) - - link_error_detector = LinkErrorDetector( - file_system, self._Render, 'templates/public/', ('apps/crx.html',)) - orphaned_pages = link_error_detector.GetOrphanedPages() - - self.assertEqual(expected_orphaned_pages, set(orphaned_pages)) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/local_file_system.py b/chrome/common/extensions/docs/server2/local_file_system.py deleted file mode 100644 index 5b14ca1..0000000 --- a/chrome/common/extensions/docs/server2/local_file_system.py +++ /dev/null
@@ -1,113 +0,0 @@ -# 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. - -import os -import sys - -from docs_server_utils import StringIdentity -from file_system import FileSystem, FileNotFoundError, StatInfo -from future import Future -from path_util import AssertIsDirectory, AssertIsValid -from test_util import ChromiumPath - - -def _ConvertToFilepath(path): - return path.replace('/', os.sep) - - -def _ConvertFromFilepath(path): - return path.replace(os.sep, '/') - - -def _ReadFile(filename): - try: - with open(filename, 'rb') as f: - return f.read() - except IOError as e: - raise FileNotFoundError('Read failed for %s: %s' % (filename, e)) - - -def _ListDir(dir_name): - all_files = [] - try: - files = os.listdir(dir_name) - except OSError as e: - raise FileNotFoundError('os.listdir failed for %s: %s' % (dir_name, e)) - for os_path in files: - posix_path = _ConvertFromFilepath(os_path) - if os_path.startswith('.'): - continue - if os.path.isdir(os.path.join(dir_name, os_path)): - all_files.append(posix_path + '/') - else: - all_files.append(posix_path) - return all_files - - -def _CreateStatInfo(path): - try: - path_mtime = os.stat(path).st_mtime - if os.path.isdir(path): - child_versions = dict((_ConvertFromFilepath(filename), - os.stat(os.path.join(path, filename)).st_mtime) - for filename in os.listdir(path)) - # This file system stat mimics subversion, where the stat of directories - # is max(file stats). That means we need to recursively check the whole - # file system tree :\ so approximate that by just checking this dir. - version = max([path_mtime] + child_versions.values()) - else: - child_versions = None - version = path_mtime - return StatInfo(version, child_versions) - except OSError as e: - raise FileNotFoundError('os.stat failed for %s: %s' % (path, e)) - - -class LocalFileSystem(FileSystem): - '''FileSystem implementation which fetches resources from the local - filesystem. - ''' - def __init__(self, base_path): - # Enforce POSIX path, so path validity checks pass for Windows. - base_path = base_path.replace(os.sep, '/') - AssertIsDirectory(base_path) - self._base_path = _ConvertToFilepath(base_path) - - @staticmethod - def Create(*path): - return LocalFileSystem(ChromiumPath(*path)) - - def Read(self, paths, skip_not_found=False): - def resolve(): - result = {} - for path in paths: - AssertIsValid(path) - full_path = os.path.join(self._base_path, - _ConvertToFilepath(path).lstrip(os.sep)) - if path == '' or path.endswith('/'): - result[path] = _ListDir(full_path) - else: - try: - result[path] = _ReadFile(full_path) - except FileNotFoundError: - if skip_not_found: - continue - return Future(exc_info=sys.exc_info()) - return result - return Future(callback=resolve) - - def Refresh(self): - return Future(value=()) - - def Stat(self, path): - AssertIsValid(path) - full_path = os.path.join(self._base_path, - _ConvertToFilepath(path).lstrip(os.sep)) - return _CreateStatInfo(full_path) - - def GetIdentity(self): - return '@'.join((self.__class__.__name__, StringIdentity(self._base_path))) - - def __repr__(self): - return 'LocalFileSystem(%s)' % self._base_path
diff --git a/chrome/common/extensions/docs/server2/local_file_system_test.py b/chrome/common/extensions/docs/server2/local_file_system_test.py deleted file mode 100755 index ff29088..0000000 --- a/chrome/common/extensions/docs/server2/local_file_system_test.py +++ /dev/null
@@ -1,39 +0,0 @@ -#!/usr/bin/env python -# 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. - -import os -import sys -import posixpath -import unittest - -from extensions_paths import SERVER2 -from local_file_system import LocalFileSystem - - -class LocalFileSystemTest(unittest.TestCase): - def setUp(self): - self._file_system = LocalFileSystem.Create( - SERVER2, 'test_data', 'file_system/') - - def testReadFiles(self): - expected = { - 'test1.txt': 'test1\n', - 'test2.txt': 'test2\n', - 'test3.txt': 'test3\n', - } - self.assertEqual( - expected, - self._file_system.Read(['test1.txt', 'test2.txt', 'test3.txt']).Get()) - - def testListDir(self): - expected = ['dir/'] - for i in range(7): - expected.append('file%d.html' % i) - self.assertEqual(expected, - sorted(self._file_system.ReadSingle('list/').Get())) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/local_git_file_system.py b/chrome/common/extensions/docs/server2/local_git_file_system.py deleted file mode 100644 index 77423d0..0000000 --- a/chrome/common/extensions/docs/server2/local_git_file_system.py +++ /dev/null
@@ -1,125 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - - -import local_git_util -import posixpath - -from environment import IsTest, IsAppEngine -from file_system import FileNotFoundError, FileSystem, StatInfo -from future import Future -from local_file_system import LocalFileSystem -from path_util import IsDirectory - - -class LocalGitFileSystem(FileSystem): - '''Class to fetch filesystem data from this script's local git repository. - ''' - @classmethod - def Create(cls, branch='master', commit=None): - if IsTest(): - return LocalFileSystem.Create('') - return LocalGitFileSystem(branch, commit) - - def __init__(self, branch, pinned_commit): - self._branch = branch - self._pinned_commit = pinned_commit - if self._pinned_commit: - commit = self._pinned_commit - else: - if branch != 'master': - commit = 'branch-heads/%s' % branch - else: - commit = 'origin/master' - # Don't bother trying to load git stuff from AppEngine; it won't work. - if not IsAppEngine(): - try: - self._commit = local_git_util.ParseRevision(commit) - except ImportError: - # TODO(devlin|karandeepb): The comment below is old, and we can probably - # remove this try-except block. But let's tackle that when there are no - # fires. - # We ignore ImportErrors here. It means we're running in AppEngine, so - # this doesn't need to work anyway. - pass - - def Read(self, paths, skip_not_found=False): - - def get_entry_name(entry): - if entry['type'] == 'tree': - return entry['name'] + '/' - return entry['name'] - - def read_path(path): - try: - if IsDirectory(path): - return [get_entry_name(e) - for e in local_git_util.ListDir(path, self._commit)] - else: - return local_git_util.ReadFile(path, self._commit) - except FileNotFoundError as e: - if skip_not_found: - return None - raise e - - results = dict((path, read_path(path)) for path in paths) - return Future(value=dict((k, v) for k, v in results.iteritems() - if v is not None)) - - def Refresh(self): - return Future(value=()) - - def GetCommitID(self): - '''Returns a future that resolves to the commit ID for this file system's - revision. - ''' - return Future(value=self._commit) - - def GetPreviousCommitID(self): - '''Returns a future that resolves to the parent commit ID of this file - system's revision. - ''' - return Future(value=local_git_util.GetParentRevision(self._commit)) - - def StatAsync(self, path): - - def get_child_versions(path): - return dict((e['name'], e['id']) - for e in local_git_util.ListDir(path, self._commit)) - - def get_file_version(dir, filename): - try: - return next(e['id'] for e in local_git_util.ListDir(dir, self._commit) - if e['name'] == filename) - except StopIteration: - raise FileNotFoundError('%s not found in revision %s' % - (path, self._commit)) - - dir, filename = posixpath.split(path) - if path == '': - version = local_git_util.GetRootTree(self._commit) - child_versions = get_child_versions('') - elif IsDirectory(path): - parent_dir, stat_dir = posixpath.split(dir) - version = get_file_version(parent_dir, stat_dir) - child_versions = get_child_versions(dir) - else: - version = get_file_version(dir, filename) - child_versions = None - - #print 'Accessing local git for stat on %s (%s)' % (path, version) - return Future(value=StatInfo(version, child_versions)) - - def GetIdentity(self): - if self._branch == 'master': - # A master FS always carries the same identity even if pinned to a commit. - str_id = 'master' - elif self._pinned_commit is not None: - str_id = self._pinned_commit - else: - str_id = 'branch-heads/%s' % self._branch - return '@'.join((self.__class__.__name__, str_id)) - - def GetVersion(self): - return self._pinned_commit
diff --git a/chrome/common/extensions/docs/server2/local_git_util.py b/chrome/common/extensions/docs/server2/local_git_util.py deleted file mode 100644 index 47b351c0..0000000 --- a/chrome/common/extensions/docs/server2/local_git_util.py +++ /dev/null
@@ -1,79 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import re - -from file_system import FileNotFoundError - - -# This provides utilities for extracting information from the local git -# repository to which it belongs. - - -# Regex to match ls-tree output. -_LS_TREE_REGEX = re.compile( - '\d+\s(?P<type>\w+)\s(?P<id>[0-9a-f]{40})\s(?P<name>.*)') - - -def _GetRoot(): - return os.path.join(os.path.dirname(os.path.realpath(__file__)), - os.pardir, os.pardir, os.pardir, os.pardir, os.pardir) - - -def _RelativePath(path): - return os.path.join(_GetRoot(), path) - - -def RunGit(command, args=[]): - # We import subprocess symbols lazily because they aren't available on - # AppEngine, and the frontend may load (but should never execute) this module. - from subprocess import check_output - with open(os.devnull, 'w') as dev_null: - return check_output(['git', command] + args, stderr=dev_null, - cwd=_GetRoot()) - - -def ParseRevision(name): - return RunGit('rev-parse', [name]).rstrip() - - -def GetParentRevision(revision): - return RunGit('show', ['-s', '--format=%P', revision]).rstrip() - - -def GetRootTree(revision): - return RunGit('show', ['-s', '--format=%T', revision]).rstrip() - - -def ListDir(path, revision='HEAD'): - '''Retrieves a directory listing for the specified path and optional revision - (default is HEAD.) Returns a list of objects with the following properties: - - |type|: the type of entry; 'blob' (file) or 'tree' (directory) - |id|: the hash of the directory entry. This is either tree hash or blob hash - |name|: the name of the directory entry. - ''' - from subprocess import CalledProcessError - try: - ref = '%s:%s' % (ParseRevision(revision), path.lstrip('/')) - listing = RunGit('ls-tree', [ref]).rstrip().splitlines() - except CalledProcessError: - raise FileNotFoundError('%s not found in revision %s' % (path, revision)) - - def parse_line(line): - return re.match(_LS_TREE_REGEX, line).groupdict() - - return map(parse_line, listing) - - -def ReadFile(path, revision='HEAD'): - '''Retrieves the contents of a file at the specified path and optional - revision (default is HEAD.) Returns its contents as a string. - ''' - from subprocess import CalledProcessError - try: - return RunGit('show', ['%s:%s' % (ParseRevision(revision), path)]) - except CalledProcessError: - raise FileNotFoundError('%s not found in revision %s' % (path, revision))
diff --git a/chrome/common/extensions/docs/server2/local_renderer.py b/chrome/common/extensions/docs/server2/local_renderer.py deleted file mode 100644 index ef43dcd..0000000 --- a/chrome/common/extensions/docs/server2/local_renderer.py +++ /dev/null
@@ -1,20 +0,0 @@ -# Copyright 2013 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 render_servlet import RenderServlet -from server_instance import ServerInstance -from servlet import Request - -class _LocalRenderServletDelegate(object): - def CreateServerInstance(self): - return ServerInstance.ForLocal() - -class LocalRenderer(object): - '''Renders pages fetched from the local file system. - ''' - @staticmethod - def Render(path, headers=None): - assert not '\\' in path - return RenderServlet(Request.ForTest(path, headers=headers), - _LocalRenderServletDelegate()).Get()
diff --git a/chrome/common/extensions/docs/server2/manifest_data_source.py b/chrome/common/extensions/docs/server2/manifest_data_source.py deleted file mode 100644 index 56da852..0000000 --- a/chrome/common/extensions/docs/server2/manifest_data_source.py +++ /dev/null
@@ -1,142 +0,0 @@ -# Copyright 2013 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 copy import deepcopy -import json - -from data_source import DataSource -from future import Future -from manifest_features import ConvertDottedKeysToNested -from platform_util import GetPlatforms, PluralToSingular - - -def _ListifyAndSortDocs(features, app_name): - '''Convert a |feautres| dictionary, and all 'children' dictionaries, into - lists recursively. Sort lists first by 'level' then by name. - ''' - def sort_key(item): - '''Key function to sort items primarily by level (according to index into - levels) then subsort by name. - ''' - levels = ('required', 'recommended', 'only_one', 'optional') - - return (levels.index(item.get('level', 'optional')), item['name']) - - def coerce_example_to_feature(feature): - '''To display json in examples more clearly, convert the example of - |feature| into the feature format, with a name and children, to be rendered - by the templates. Only applicable to examples that are dictionaries. - ''' - if not isinstance(feature.get('example'), dict): - if 'example' in feature: - feature['example'] = json.dumps(feature['example']) - return - # Add any keys/value pairs in the dict as children - for key, value in feature['example'].iteritems(): - if not 'children' in feature: - feature['children'] = {} - feature['children'][key] = { 'name': key, 'example': value } - del feature['example'] - del feature['has_example'] - - def convert_and_sort(features): - for key, value in features.items(): - if 'example' in value: - value['has_example'] = True - example = json.dumps(value['example']) - if example == '{}': - value['example'] = '{...}' - elif example == '[]': - value['example'] = '[...]' - elif example == '[{}]': - value['example'] = '[{...}]' - else: - coerce_example_to_feature(value) - if 'children' in value: - features[key]['children'] = convert_and_sort(value['children']) - return sorted(features.values(), key=sort_key) - - # Replace {{platform}} in the 'name' manifest property example with - # |app_name|, the convention that the normal template rendering uses. - # TODO(kalman): Make the example a template and pass this through there. - if 'name' in features: - name = features['name'] - name['example'] = name['example'].replace('{{platform}}', app_name) - - features = convert_and_sort(features) - - return features - -def _AddLevelAnnotations(features): - '''Add level annotations to |features|. |features| and children lists must be - sorted by 'level'. Annotations are added to the first item in a group of - features of the same 'level'. - - The last item in a list has 'is_last' set to True. - ''' - annotations = { - 'required': 'Required', - 'recommended': 'Recommended', - 'only_one': 'Pick one (or none)', - 'optional': 'Optional' - } - - def add_annotation(item, annotation): - if not 'annotations' in item: - item['annotations'] = [] - item['annotations'].insert(0, annotation) - - def annotate(parent_level, features): - current_level = parent_level - for item in features: - level = item.get('level', 'optional') - if level != current_level: - add_annotation(item, annotations[level]) - current_level = level - if 'children' in item: - annotate(level, item['children']) - if features: - features[-1]['is_last'] = True - - annotate('required', features) - return features - -class ManifestDataSource(DataSource): - '''Provides access to the properties in manifest features. - ''' - def __init__(self, server_instance, _): - self._platform_bundle = server_instance.platform_bundle - self._object_store = server_instance.object_store_creator.Create( - ManifestDataSource) - - def _CreateManifestDataForPlatform(self, platform): - future_manifest_features = self._platform_bundle.GetFeaturesBundle( - platform).GetManifestFeatures() - def resolve(): - manifest_features = future_manifest_features.Get() - return _AddLevelAnnotations(_ListifyAndSortDocs( - ConvertDottedKeysToNested(deepcopy(manifest_features)), - app_name=PluralToSingular(platform).capitalize())) - return Future(callback=resolve) - - def _CreateManifestData(self): - manifest_data_futures = dict((p, self._CreateManifestDataForPlatform(p)) - for p in GetPlatforms()) - def resolve(): - return dict((platform, future.Get()) - for platform, future in manifest_data_futures.iteritems()) - return Future(callback=resolve) - - def _GetCachedManifestData(self): - data = self._object_store.Get('manifest_data').Get() - if data is None: - data = self._CreateManifestData().Get() - self._object_store.Set('manifest_data', data) - return data - - def get(self, key): - return self._GetCachedManifestData().get(key) - - def Refresh(self): - return self._CreateManifestData()
diff --git a/chrome/common/extensions/docs/server2/manifest_data_source_test.py b/chrome/common/extensions/docs/server2/manifest_data_source_test.py deleted file mode 100755 index 2ed7a97..0000000 --- a/chrome/common/extensions/docs/server2/manifest_data_source_test.py +++ /dev/null
@@ -1,295 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 copy import deepcopy -import json -import unittest - -from future import Future -import manifest_data_source -from object_store_creator import ObjectStoreCreator - - -convert_and_annotate_docs = { - 'name': { - 'example': "My {{platform}}", - 'name': 'name', - 'level': 'required' - }, - 'doc2': { - 'level': 'required', - 'name': 'doc2' - }, - 'doc1': { - 'level': 'required', - 'name': 'doc1', - 'children': { - 'sub1': { - 'annotations': ['not so important'], - 'level': 'optional', - 'name': 'sub1' - }, - 'sub2': { - 'level': 'required', - 'name': 'sub2' - } - } - }, - 'doc3': { - 'level': 'only_one', - 'name': 'doc3' - }, - 'doc4': { - 'level': 'recommended', - 'name': 'doc4' - }, - 'doc5': { - 'level': 'only_one', - 'name': 'doc5' - }, - 'doc6': { - 'level': 'optional', - 'name': 'doc6' - } -} - - -class ManifestDataSourceTest(unittest.TestCase): - def testListifyAndSortDocs(self): - expected_docs = [ - { - 'level': 'required', - 'name': 'doc1', - 'children': [ - { - 'level': 'required', - 'name': 'sub2' - }, - { - 'annotations': ['not so important'], - 'level': 'optional', - 'name': 'sub1' - } - ] - }, - { - 'level': 'required', - 'name': 'doc2' - }, - { - 'level': 'required', - 'example': '"My App"', - 'has_example': True, - 'name': 'name' - }, - { - 'level': 'recommended', - 'name': 'doc4' - }, - { - 'level': 'only_one', - 'name': 'doc3' - }, - { - 'level': 'only_one', - 'name': 'doc5' - }, - { - 'level': 'optional', - 'name': 'doc6' - } - ] - - self.assertEqual(expected_docs, manifest_data_source._ListifyAndSortDocs( - deepcopy(convert_and_annotate_docs), 'App')) - - def testAnnotate(self): - expected_docs = [ - { - 'level': 'required', - 'name': 'doc1', - 'children': [ - { - 'level': 'required', - 'name': 'sub2' - }, - { - 'annotations': ['Optional', 'not so important'], - 'level': 'optional', - 'name': 'sub1', - 'is_last': True - } - ] - }, - { - 'level': 'required', - 'name': 'doc2' - }, - { - 'name': 'name', - 'level': 'required', - 'example': '"My App"', - 'has_example': True - }, - { - 'annotations': ['Recommended'], - 'level': 'recommended', - 'name': 'doc4' - }, - { - 'annotations': ['Pick one (or none)'], - 'level': 'only_one', - 'name': 'doc3' - }, - { - 'level': 'only_one', - 'name': 'doc5' - }, - { - 'annotations': ['Optional'], - 'level': 'optional', - 'name': 'doc6', - 'is_last': True - } - ] - - annotated = manifest_data_source._ListifyAndSortDocs( - deepcopy(convert_and_annotate_docs), 'App') - manifest_data_source._AddLevelAnnotations(annotated) - self.assertEqual(expected_docs, annotated) - - def testExpandedExamples(self): - docs = { - 'doc1': { - 'name': 'doc1', - 'example': { - 'big': { - 'nested': { - 'json_example': ['with', 'more', 'json'] - } - } - } - } - } - - expected_docs = [ - { - 'name': 'doc1', - 'children': [ - { - 'name': 'big', - 'children': [ - { - 'name': 'nested', - 'children': [ - { - 'name': 'json_example', - 'example': json.dumps(['with', 'more', 'json']), - 'has_example': True - } - ] - } - ] - } - ] - } - ] - - self.assertEqual( - expected_docs, manifest_data_source._ListifyAndSortDocs(docs, 'apps')) - - def testNonExpandedExamples(self): - docs = { - 'doc1': { - 'name': 'doc1', - 'example': {} - }, - 'doc2': { - 'name': 'doc2', - 'example': [] - }, - 'doc3': { - 'name': 'doc3', - 'example': [{}] - } - } - - expected_docs = [ - { - 'name': 'doc1', - 'has_example': True, - 'example': '{...}' - }, - { - 'name': 'doc2', - 'has_example': True, - 'example': '[...]' - }, - { - 'name': 'doc3', - 'has_example': True, - 'example': '[{...}]' - } - ] - self.assertEqual( - expected_docs, manifest_data_source._ListifyAndSortDocs(docs, 'apps')) - - def testManifestDataSource(self): - manifest_features = { - 'doc1': { - 'name': 'doc1', - 'platforms': ['apps', 'extensions'], - 'example': {}, - 'level': 'required' - }, - 'doc1.sub1': { - 'name': 'doc1.sub1', - 'platforms': ['apps'], - 'annotations': ['important!'], - 'level': 'recommended' - } - } - - expected_app = [ - { - 'example': '{...}', - 'has_example': True, - 'level': 'required', - 'name': 'doc1', - 'platforms': ['apps', 'extensions'], - 'children': [ - { - 'annotations': [ - 'Recommended', - 'important!' - ], - 'level': 'recommended', - 'name': 'sub1', - 'platforms': ['apps'], - 'is_last': True - } - ], - 'is_last': True - } - ] - - class FakePlatformBundle(object): - def GetFeaturesBundle(self, platform): - return FakeFeaturesBundle() - - class FakeFeaturesBundle(object): - def GetManifestFeatures(self): - return Future(value=manifest_features) - - class FakeServerInstance(object): - def __init__(self): - self.platform_bundle = FakePlatformBundle() - self.object_store_creator = ObjectStoreCreator.ForTest() - - mds = manifest_data_source.ManifestDataSource(FakeServerInstance(), None) - self.assertEqual(expected_app, mds.get('apps')) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/manifest_features.py b/chrome/common/extensions/docs/server2/manifest_features.py deleted file mode 100644 index ef5a7ab9..0000000 --- a/chrome/common/extensions/docs/server2/manifest_features.py +++ /dev/null
@@ -1,44 +0,0 @@ -# Copyright 2013 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. - -''' -Provides a Manifest Feature abstraction, similar to but more strict than the -Feature schema (see feature_utility.py). - -Each Manifest Feature has a 'level' in addition to the keys defined in a -Feature. 'level' can be 'required', 'only_one', 'recommended', or 'optional', -indicating how an app or extension should define a manifest property. If 'level' -is missing, 'optional' is assumed. -''' - -def ConvertDottedKeysToNested(features): - '''Some Manifest Features are subordinate to others, such as app.background to - app. Subordinate Features can be moved inside the parent Feature under the key - 'children'. - - Modifies |features|, a Manifest Features dictionary, by moving subordinate - Features with names of the form 'parent.child' into the 'parent' Feature. - Child features are renamed to the 'child' section of their previous name. - - Applied recursively so that children can be nested arbitrarily. - ''' - def add_child(features, parent, child_name, value): - value['name'] = child_name - if not 'children' in features[parent]: - features[parent]['children'] = {} - features[parent]['children'][child_name] = value - - def insert_children(features): - for name in features.keys(): - if '.' in name: - value = features.pop(name) - parent, child_name = name.split('.', 1) - add_child(features, parent, child_name, value) - - for value in features.values(): - if 'children' in value: - insert_children(value['children']) - - insert_children(features) - return features
diff --git a/chrome/common/extensions/docs/server2/manifest_features_test.py b/chrome/common/extensions/docs/server2/manifest_features_test.py deleted file mode 100755 index c21286c3..0000000 --- a/chrome/common/extensions/docs/server2/manifest_features_test.py +++ /dev/null
@@ -1,55 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from manifest_features import ConvertDottedKeysToNested - -class ManifestFeaturesTest(unittest.TestCase): - def testConvertDottedKeysToNested(self): - docs = { - 'doc1.sub2': { - 'name': 'doc1.sub2' - }, - 'doc1': { - 'name': 'doc1' - }, - 'doc2': { - 'name': 'doc2' - }, - 'doc1.sub1.subsub1': { - 'name': 'doc1.sub1.subsub1' - }, - 'doc1.sub1': { - 'name': 'doc1.sub1' - } - } - - expected_docs = { - 'doc1': { - 'name': 'doc1', - 'children': { - 'sub1': { - 'name': 'sub1', - 'children': { - 'subsub1': { - 'name' :'subsub1' - } - } - }, - 'sub2': { - 'name': 'sub2' - } - } - }, - 'doc2': { - 'name': 'doc2' - } - } - - self.assertEqual(expected_docs, ConvertDottedKeysToNested(docs)) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/memcache_object_store.py b/chrome/common/extensions/docs/server2/memcache_object_store.py deleted file mode 100644 index 85c3bed2..0000000 --- a/chrome/common/extensions/docs/server2/memcache_object_store.py +++ /dev/null
@@ -1,44 +0,0 @@ -# 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. - -import logging -import traceback - -from appengine_wrappers import memcache -from future import Future -from object_store import ObjectStore - - -class MemcacheObjectStore(ObjectStore): - def __init__(self, namespace): - self._namespace = namespace - - def SetMulti(self, mapping): - # Some files are too big to fit in memcache, and will throw a ValueError if - # we try. That's caught below, but to avoid log spew as much as possible - # (and to try to store as many things as possible, since this is Set*Multi* - # after all, and there may be other things to store from |mapping|), delete - # the paths which we know don't work. - # - # TODO(kalman): Store big things (like example zips) in blobstore so that - # this doesn't happen. - log_spewers = ('assets/remote-debugging/remote-debug-banner.ai',) - for spewer in log_spewers: - mapping.pop(spewer, None) - - try: - rpc = memcache.Client().set_multi_async(mapping, - namespace=self._namespace) - return Future(callback=rpc.get_result) - except ValueError as e: - logging.error('Caught error when memcache-ing keys %s: %s' % - (mapping.keys(), traceback.format_exc())) - return Future(value=None) - - def GetMulti(self, keys): - rpc = memcache.Client().get_multi_async(keys, namespace=self._namespace) - return Future(callback=rpc.get_result) - - def DelMulti(self, keys): - memcache.delete_multi(keys, namespace=self._namespace)
diff --git a/chrome/common/extensions/docs/server2/mock_file_system.py b/chrome/common/extensions/docs/server2/mock_file_system.py deleted file mode 100644 index 1484ab1..0000000 --- a/chrome/common/extensions/docs/server2/mock_file_system.py +++ /dev/null
@@ -1,146 +0,0 @@ -# Copyright 2013 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 posixpath - -from file_system import FileSystem, FileNotFoundError -from future import Future -from test_file_system import _List, _StatTracker, TestFileSystem -from path_util import IsDirectory - - -class MockFileSystem(FileSystem): - '''Wraps FileSystems to add a selection of mock behaviour: - - asserting how often Stat/Read calls are being made to it. - - primitive changes/versioning via applying object "diffs", mapping paths to - new content (similar to how TestFileSystem works). - ''' - def __init__(self, file_system): - self._file_system = file_system - # Updates are stored as TestFileSystems because it already implements a - # bunch of logic to intepret paths into dictionaries. - self._updates = [] - self._stat_tracker = _StatTracker() - self._read_count = 0 - self._read_resolve_count = 0 - self._stat_count = 0 - self._version = None - - @staticmethod - def Create(file_system, updates): - mock_file_system = MockFileSystem(file_system) - for update in updates: - mock_file_system.Update(update) - return mock_file_system - - # - # FileSystem implementation. - # - - def Read(self, paths, skip_not_found=False): - '''Reads |paths| from |_file_system|, then applies the most recent update - from |_updates|, if any. - ''' - self._read_count += 1 - def next(result): - self._read_resolve_count += 1 - for path in result.iterkeys(): - update = self._GetMostRecentUpdate(path) - if update is not None: - result[path] = update - return result - return self._file_system.Read(paths, - skip_not_found=skip_not_found).Then(next) - - def Refresh(self): - return self._file_system.Refresh() - - def _GetMostRecentUpdate(self, path): - '''Returns the latest update for the file at |path|, or None if |path| - has never been updated. - ''' - for update in reversed(self._updates): - try: - return update.ReadSingle(path).Get() - except FileNotFoundError: - pass - return None - - def Stat(self, path): - self._stat_count += 1 - - # This only supports numeric stat values since we need to add to it. In - # reality the logic here could just be to randomly mutate the stat values - # every time there's an Update but that's less meaningful for testing. - def stradd(a, b): - return str(int(a) + b) - - stat = self._file_system.Stat(path) - stat.version = stradd(stat.version, self._stat_tracker.GetVersion(path)) - if stat.child_versions: - for child_path, child_version in stat.child_versions.iteritems(): - stat.child_versions[child_path] = stradd( - stat.child_versions[child_path], - self._stat_tracker.GetVersion(posixpath.join(path, child_path))) - - return stat - - def GetCommitID(self): - return Future(value=str(self._stat_tracker.GetVersion(''))) - - def GetPreviousCommitID(self): - return Future(value=str(self._stat_tracker.GetVersion('') - 1)) - - def GetIdentity(self): - return self._file_system.GetIdentity() - - def GetVersion(self): - return self._version - - def __str__(self): - return repr(self) - - def __repr__(self): - return 'MockFileSystem(read_count=%s, stat_count=%s, updates=%s)' % ( - self._read_count, self._stat_count, len(self._updates)) - - # - # Testing methods. - # - - def GetStatCount(self): - return self._stat_count - - def CheckAndReset(self, stat_count=0, read_count=0, read_resolve_count=0): - '''Returns a tuple (success, error). Use in tests like: - self.assertTrue(*object_store.CheckAndReset(...)) - ''' - errors = [] - for desc, expected, actual in ( - ('read_count', read_count, self._read_count), - ('read_resolve_count', read_resolve_count, self._read_resolve_count), - ('stat_count', stat_count, self._stat_count)): - if actual != expected: - errors.append('%s: expected %s got %s' % (desc, expected, actual)) - try: - return (len(errors) == 0, ', '.join(errors)) - finally: - self.Reset() - - def Reset(self): - self._read_count = 0 - self._read_resolve_count = 0 - self._stat_count = 0 - - def Update(self, update): - self._updates.append(TestFileSystem(update)) - for path in _List(update).iterkeys(): - # Any files (not directories) which changed are now at the version - # derived from |_updates|. - if not IsDirectory(path): - self._stat_tracker.SetVersion(path, len(self._updates)) - - def SetVersion(self, version): - '''Override the reported FileSystem version (default None) for testing.''' - self._version = version
diff --git a/chrome/common/extensions/docs/server2/mock_file_system_test.py b/chrome/common/extensions/docs/server2/mock_file_system_test.py deleted file mode 100755 index 813751f8..0000000 --- a/chrome/common/extensions/docs/server2/mock_file_system_test.py +++ /dev/null
@@ -1,145 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 copy import deepcopy -from file_system import FileNotFoundError, StatInfo -from mock_file_system import MockFileSystem -from test_file_system import TestFileSystem -import unittest - -_TEST_DATA = { - '404.html': '404.html contents', - 'apps': { - 'a11y.html': 'a11y.html contents', - 'about_apps.html': 'about_apps.html contents', - 'fakedir': { - 'file.html': 'file.html contents' - } - }, - 'extensions': { - 'activeTab.html': 'activeTab.html contents', - 'alarms.html': 'alarms.html contents' - } -} - -def _Get(fn): - '''Returns a function which calls Future.Get on the result of |fn|. - ''' - return lambda *args: fn(*args).Get() - -class MockFileSystemTest(unittest.TestCase): - def testCheckAndReset(self): - fs = MockFileSystem(TestFileSystem(deepcopy(_TEST_DATA))) - - self.assertTrue(*fs.CheckAndReset()) - self.assertFalse(*fs.CheckAndReset(read_count=1)) - self.assertFalse(*fs.CheckAndReset(stat_count=1)) - - future = fs.ReadSingle('apps/') - self.assertTrue(*fs.CheckAndReset(read_count=1)) - future.Get() - self.assertTrue(*fs.CheckAndReset(read_resolve_count=1)) - self.assertFalse(*fs.CheckAndReset(read_count=1)) - self.assertTrue(*fs.CheckAndReset()) - - future = fs.ReadSingle('apps/') - self.assertFalse(*fs.CheckAndReset(read_count=2)) - future.Get() - self.assertFalse(*fs.CheckAndReset(read_resolve_count=2)) - - fs.ReadSingle('extensions/').Get() - fs.ReadSingle('extensions/').Get() - self.assertTrue(*fs.CheckAndReset(read_count=2, read_resolve_count=2)) - self.assertFalse(*fs.CheckAndReset(read_count=2, read_resolve_count=2)) - self.assertTrue(*fs.CheckAndReset()) - - fs.ReadSingle('404.html').Get() - self.assertTrue(*fs.CheckAndReset(read_count=1, read_resolve_count=1)) - future = fs.Read(['notfound.html', 'apps/']) - self.assertTrue(*fs.CheckAndReset(read_count=1)) - self.assertRaises(FileNotFoundError, future.Get) - self.assertTrue(*fs.CheckAndReset(read_resolve_count=0)) - - fs.Stat('404.html') - fs.Stat('404.html') - fs.Stat('apps/') - self.assertFalse(*fs.CheckAndReset(stat_count=42)) - self.assertFalse(*fs.CheckAndReset(stat_count=42)) - self.assertTrue(*fs.CheckAndReset()) - - fs.ReadSingle('404.html').Get() - fs.Stat('404.html') - fs.Stat('apps/') - self.assertTrue( - *fs.CheckAndReset(read_count=1, read_resolve_count=1, stat_count=2)) - self.assertTrue(*fs.CheckAndReset()) - - def testUpdates(self): - fs = MockFileSystem(TestFileSystem(deepcopy(_TEST_DATA))) - - self.assertEqual(StatInfo('0', child_versions={ - '404.html': '0', - 'apps/': '0', - 'extensions/': '0' - }), fs.Stat('')) - self.assertEqual(StatInfo('0'), fs.Stat('404.html')) - self.assertEqual(StatInfo('0', child_versions={ - 'a11y.html': '0', - 'about_apps.html': '0', - 'fakedir/': '0', - }), fs.Stat('apps/')) - self.assertEqual('404.html contents', fs.ReadSingle('404.html').Get()) - - fs.Update({ - '404.html': 'New version!' - }) - - self.assertEqual(StatInfo('1', child_versions={ - '404.html': '1', - 'apps/': '0', - 'extensions/': '0' - }), fs.Stat('')) - self.assertEqual(StatInfo('1'), fs.Stat('404.html')) - self.assertEqual(StatInfo('0', child_versions={ - 'a11y.html': '0', - 'about_apps.html': '0', - 'fakedir/': '0', - }), fs.Stat('apps/')) - self.assertEqual('New version!', fs.ReadSingle('404.html').Get()) - - fs.Update({ - '404.html': 'Newer version!', - 'apps': { - 'fakedir': { - 'file.html': 'yo' - } - } - }) - - self.assertEqual(StatInfo('2', child_versions={ - '404.html': '2', - 'apps/': '2', - 'extensions/': '0' - }), fs.Stat('')) - self.assertEqual(StatInfo('2'), fs.Stat('404.html')) - self.assertEqual(StatInfo('2', child_versions={ - 'a11y.html': '0', - 'about_apps.html': '0', - 'fakedir/': '2', - }), fs.Stat('apps/')) - self.assertEqual(StatInfo('0'), fs.Stat('apps/a11y.html')) - self.assertEqual(StatInfo('2', child_versions={ - 'file.html': '2' - }), fs.Stat('apps/fakedir/')) - self.assertEqual(StatInfo('2'), fs.Stat('apps/fakedir/file.html')) - self.assertEqual(StatInfo('0', child_versions={ - 'activeTab.html': '0', - 'alarms.html': '0' - }), fs.Stat('extensions/')) - self.assertEqual('Newer version!', fs.ReadSingle('404.html').Get()) - self.assertEqual('yo', fs.ReadSingle('apps/fakedir/file.html').Get()) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/mock_function.py b/chrome/common/extensions/docs/server2/mock_function.py deleted file mode 100644 index 1e0715c..0000000 --- a/chrome/common/extensions/docs/server2/mock_function.py +++ /dev/null
@@ -1,40 +0,0 @@ -# Copyright 2013 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. - -class MockFunction(object): - '''Decorates a function to record the number of times it's called, and - use that to make test assertions. - - Use like: - - @MockFunction - def my_function(): pass - my_function() - my_function() - self.assertTrue(*my_function.CheckAndReset(2)) - - or - - my_constructor = MockFunction(HTMLParser) - my_constructor() - self.assertTrue(*my_constructor.CheckAndReset(1)) - - and so on. - ''' - - def __init__(self, fn): - self._fn = fn - self._call_count = 0 - - def __call__(self, *args, **optargs): - self._call_count += 1 - return self._fn(*args, **optargs) - - def CheckAndReset(self, expected_call_count): - actual_call_count = self._call_count - self._call_count = 0 - if expected_call_count == actual_call_count: - return True, '' - return (False, '%s: expected %s call(s), got %s' % - (self._fn.__name__, expected_call_count, actual_call_count))
diff --git a/chrome/common/extensions/docs/server2/mock_function_test.py b/chrome/common/extensions/docs/server2/mock_function_test.py deleted file mode 100755 index a2864ff..0000000 --- a/chrome/common/extensions/docs/server2/mock_function_test.py +++ /dev/null
@@ -1,41 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from mock_function import MockFunction - - -class MockFunctionUnittest(unittest.TestCase): - def testMockFunction(self): - @MockFunction - def calc(a, b, mult=1): - return (a + b) * mult - - self.assertTrue(*calc.CheckAndReset(0)) - self.assertEqual( - (False, 'calc: expected 1 call(s), got 0'), calc.CheckAndReset(1)) - - self.assertEqual(20, calc(2, 3, mult=4)) - self.assertTrue(*calc.CheckAndReset(1)) - self.assertTrue(*calc.CheckAndReset(0)) - - self.assertEqual(20, calc(2, 3, mult=4)) - self.assertEqual( - (False, 'calc: expected 0 call(s), got 1'), calc.CheckAndReset(0)) - - self.assertEqual(3, calc(1, 2)) - self.assertEqual(0, calc(3, 4, mult=0)) - self.assertTrue(*calc.CheckAndReset(2)) - self.assertTrue(*calc.CheckAndReset(0)) - - self.assertEqual(3, calc(1, 2)) - self.assertEqual(0, calc(3, 4, mult=0)) - self.assertEqual( - (False, 'calc: expected 3 call(s), got 2'), calc.CheckAndReset(3)) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/object_store.py b/chrome/common/extensions/docs/server2/object_store.py deleted file mode 100644 index b56986b..0000000 --- a/chrome/common/extensions/docs/server2/object_store.py +++ /dev/null
@@ -1,43 +0,0 @@ -# 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 future import Future - - -class ObjectStore(object): - '''A class for caching picklable objects. - ''' - def Get(self, key): - '''Gets a |Future| with the value of |key| in the object store, or None - if |key| is not in the object store. - ''' - return self.GetMulti((key,)).Then(lambda keys: keys.get(key)) - - def GetMulti(self, keys): - '''Gets a |Future| with values mapped to |keys| from the object store, with - any keys not in the object store omitted. - ''' - raise NotImplementedError(self.__class__) - - def Set(self, key, value): - '''Sets key -> value in the object store. Returns a |Future| which is - resolved once the key's new value has been stored. - ''' - return self.SetMulti({ key: value }) - - def SetMulti(self, items): - '''Atomically sets the mapping of keys to values in the object store. - Returns a |Future| which is resolved once the new mapping has been stored. - ''' - raise NotImplementedError(self.__class__) - - def Del(self, key): - '''Deletes a key from the object store. - ''' - self.DelMulti([key]) - - def DelMulti(self, keys): - '''Deletes |keys| from the object store. - ''' - raise NotImplementedError(self.__class__)
diff --git a/chrome/common/extensions/docs/server2/object_store_creator.py b/chrome/common/extensions/docs/server2/object_store_creator.py deleted file mode 100644 index 91bc034e..0000000 --- a/chrome/common/extensions/docs/server2/object_store_creator.py +++ /dev/null
@@ -1,81 +0,0 @@ -# Copyright 2013 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 cache_chain_object_store import CacheChainObjectStore -from environment import GetAppVersion -from environment_wrappers import CreatePersistentObjectStore -from memcache_object_store import MemcacheObjectStore -from test_object_store import TestObjectStore - -_unspecified = object() - -class ObjectStoreCreator(object): - '''Creates ObjectStores with a namespacing and behaviour configuration. - - The initial configuration is specified on object store construction. When - creating ObjectStores via Create this configuration can be overridden (or - via the variants of Create which do this automatically). - ''' - def __init__(self, - # TODO(kalman): rename start_dirty? - start_empty=_unspecified, - # Override for testing. A custom ObjectStore type to construct - # on Create(). Useful with TestObjectStore, for example. - store_type=None, - # Override for testing. Whether the ObjectStore type specified - # with |store_type| should be wrapped e.g. with Caching. This is - # useful to override when specific state tests/manipulations are - # being done on the underlying object store. - disable_wrappers=False): - if start_empty is _unspecified: - raise ValueError('start_empty must be specified (typically False)') - self._start_empty = start_empty - self._store_type = store_type - if disable_wrappers and store_type is None: - raise ValueError('disable_wrappers much specify a store_type') - self._disable_wrappers = disable_wrappers - - @staticmethod - def ForTest(start_empty=False, - store_type=TestObjectStore, - disable_wrappers=True): - return ObjectStoreCreator(start_empty=start_empty, - store_type=store_type, - disable_wrappers=disable_wrappers) - - def Create(self, - cls, - category=None, - # Override any of these for a custom configuration. - start_empty=_unspecified, - app_version=_unspecified): - # Resolve namespace components. - if start_empty is not _unspecified: - start_empty = bool(start_empty) - else: - start_empty = self._start_empty - if app_version is _unspecified: - app_version = GetAppVersion() - - # Reserve & and = for namespace separators. - for component in (category, app_version): - if component and ('&' in component or '=' in component): - raise ValueError('%s cannot be used in a namespace') - - namespace = '&'.join( - '%s=%s' % (key, value) - for key, value in (('class', cls.__name__), - ('category', category), - ('app_version', app_version)) - if value is not None) - - if self._disable_wrappers: - return self._store_type(namespace, start_empty=start_empty) - - if self._store_type is not None: - chain = (self._store_type(namespace),) - else: - chain = (MemcacheObjectStore(namespace), - CreatePersistentObjectStore(namespace)) - return CacheChainObjectStore(chain, start_empty=start_empty)
diff --git a/chrome/common/extensions/docs/server2/object_store_creator_test.py b/chrome/common/extensions/docs/server2/object_store_creator_test.py deleted file mode 100755 index 217571bf..0000000 --- a/chrome/common/extensions/docs/server2/object_store_creator_test.py +++ /dev/null
@@ -1,54 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from environment import GetAppVersion -from test_object_store import TestObjectStore -from object_store_creator import ObjectStoreCreator - -class _FooClass(object): - def __init__(self): pass - -class ObjectStoreCreatorTest(unittest.TestCase): - def setUp(self): - self._creator = ObjectStoreCreator(start_empty=False, - store_type=TestObjectStore, - disable_wrappers=True) - - def testVanilla(self): - store = self._creator.Create(_FooClass) - self.assertEqual( - 'class=_FooClass&app_version=%s' % GetAppVersion(), - store.namespace) - self.assertFalse(store.start_empty) - - def testWithCategory(self): - store = self._creator.Create(_FooClass, category='hi') - self.assertEqual( - 'class=_FooClass&category=hi&app_version=%s' % GetAppVersion(), - store.namespace) - self.assertFalse(store.start_empty) - - def testWithoutAppVersion(self): - store = self._creator.Create(_FooClass, app_version=None) - self.assertEqual('class=_FooClass', store.namespace) - self.assertFalse(store.start_empty) - - def testStartConfiguration(self): - store = self._creator.Create(_FooClass, start_empty=True) - self.assertTrue(store.start_empty) - store = self._creator.Create(_FooClass, start_empty=False) - self.assertFalse(store.start_empty) - self.assertRaises(ValueError, ObjectStoreCreator) - - def testIllegalCharacters(self): - self.assertRaises(ValueError, - self._creator.Create, _FooClass, app_version='1&2') - self.assertRaises(ValueError, - self._creator.Create, _FooClass, category='a=&b') - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/offline_file_system.py b/chrome/common/extensions/docs/server2/offline_file_system.py deleted file mode 100644 index ca74cc6..0000000 --- a/chrome/common/extensions/docs/server2/offline_file_system.py +++ /dev/null
@@ -1,29 +0,0 @@ -# Copyright 2013 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 file_system import FileSystem, FileNotFoundError -from future import Future - - -class OfflineFileSystem(FileSystem): - '''An offline FileSystem which masquerades as another file system. It throws - FileNotFound error for all operations, and overrides GetIdentity. - ''' - def __init__(self, fs): - self._fs = fs - - def Read(self, paths, skip_not_found=False): - if skip_not_found: return Future(value={}) - def raise_file_not_found(): - raise FileNotFoundError('File system is offline, cannot read %s' % paths) - return Future(callback=raise_file_not_found) - - def Stat(self, path): - raise FileNotFoundError('File system is offline, cannot read %s' % path) - - def GetIdentity(self): - return self._fs.GetIdentity() - - def GetVersion(self): - return self._fs.GetVersion()
diff --git a/chrome/common/extensions/docs/server2/owners_data_source.py b/chrome/common/extensions/docs/server2/owners_data_source.py deleted file mode 100644 index 21d19bf..0000000 --- a/chrome/common/extensions/docs/server2/owners_data_source.py +++ /dev/null
@@ -1,106 +0,0 @@ -# Copyright 2014 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 operator import itemgetter -import random - -from data_source import DataSource -from docs_server_utils import MarkLast -from extensions_paths import BROWSER_API_PATHS, BROWSER_CHROME_EXTENSIONS -from future import All -from path_util import Join, Split - - -_COMMENT_START_MARKER = '#' -_CORE_OWNERS = 'Core Extensions/Apps Owners' -_OWNERS = 'OWNERS' - - -# Public for testing. -def ParseOwnersFile(content, randomize): - '''Returns a tuple (owners, notes), where - |owners| is a list of dicts formed from the owners in |content|, - |notes| is a string formed from the comments in |content|. - ''' - if content is None: - return [], 'Use one of the ' + _CORE_OWNERS + '.' - owners = [] - notes = [] - for line in content.splitlines(): - if line == '': - continue - if line.startswith(_COMMENT_START_MARKER): - notes.append(line[len(_COMMENT_START_MARKER):].lstrip()) - else: - # TODO(ahernandez): Mark owners no longer on the project. - owners.append({'email': line, 'username': line[:line.find('@')]}) - # Randomize the list so owners toward the front of the list aren't - # diproportionately inundated with reviews. - if randomize: - random.shuffle(owners) - MarkLast(owners) - return owners, '\n'.join(notes) - - -class OwnersDataSource(DataSource): - def __init__(self, server_instance, _, randomize=True): - self._host_fs = server_instance.host_file_system_provider.GetMaster() - self._cache = server_instance.object_store_creator.Create(OwnersDataSource) - self._owners_fs = server_instance.compiled_fs_factory.Create( - self._host_fs, self._CreateAPIEntry, OwnersDataSource) - self._randomize = randomize - - def _CreateAPIEntry(self, path, content): - '''Creates a dict with owners information for an API, specified - by |owners_file|. - ''' - owners, notes = ParseOwnersFile(content, self._randomize) - api_name = Split(path)[-2][:-1] - return { - 'apiName': api_name, - 'owners': owners, - 'notes': notes, - 'id': api_name - } - - def _CollectOwnersData(self): - '''Walks through the file system, collecting owners data from - API directories. - ''' - def collect(api_owners): - if api_owners is not None: - return api_owners - - # Get API owners from every OWNERS file that exists. - api_owners = [] - for root in BROWSER_API_PATHS: - for base, dirs, _ in self._host_fs.Walk(root, depth=1): - for dir_ in dirs: - owners_file = Join(root, base, dir_, _OWNERS) - api_owners.append( - self._owners_fs.GetFromFile(owners_file, skip_not_found=True)) - - # Add an entry for the core extensions/apps owners. - def fix_core_owners(entry): - entry['apiName'] = _CORE_OWNERS - entry['id'] = 'core' - return entry - - owners_file = Join(BROWSER_CHROME_EXTENSIONS, _OWNERS) - api_owners.append(self._owners_fs.GetFromFile(owners_file).Then( - fix_core_owners)) - def sort_and_cache(api_owners): - api_owners.sort(key=itemgetter('apiName')) - self._cache.Set('api_owners', api_owners) - return api_owners - return All(api_owners).Then(sort_and_cache) - return self._cache.Get('api_owners').Then(collect) - - def get(self, key): - return { - 'apis': self._CollectOwnersData() - }.get(key).Get() - - def Refresh(self): - return self._CollectOwnersData()
diff --git a/chrome/common/extensions/docs/server2/owners_data_source_test.py b/chrome/common/extensions/docs/server2/owners_data_source_test.py deleted file mode 100755 index 93bb8d1..0000000 --- a/chrome/common/extensions/docs/server2/owners_data_source_test.py +++ /dev/null
@@ -1,208 +0,0 @@ -#!/usr/bin/env python -# Copyright 2014 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 unittest - -from owners_data_source import ParseOwnersFile, OwnersDataSource -from server_instance import ServerInstance -from servlet import Request -from test_file_system import TestFileSystem - - -_TEST_FS = { - 'chrome': { - 'browser': { - 'apps': { - 'platform_apps': { - 'OWNERS': '\n'.join([ - '# Apps owners.', - 'apps@owner.tld' - ]), - 'api': { - 'an_app_api': { - 'an_app_api.cc': '' - } - } - } - }, - 'extensions': { - 'OWNERS': '\n'.join([ - '# Core owners.', - 'satsuki@revocs.tld' - ]), - 'api': { - 'some_api': { - 'OWNERS': '\n'.join([ - 'matoi@owner.tld' - ]), - 'some_api.cc': '' - }, - 'another_api': { - 'another_api.cc': '', - 'another_api.h': '' - }, - 'moar_apis': { - 'OWNERS': '\n'.join([ - '# For editing moar_apis.', - 'satsuki@revocs.tld' - ]) - } - } - } - } - }, - 'extensions': { - 'browser': { - 'api': { - 'a_different_api': { - 'OWNERS': '\n'.join([ - '# Hallo!', - 'nonon@owner.tld', - 'matoi@owner.tld' - ]) - } - } - } - } -} - - -class OwnersDataSourceTest(unittest.TestCase): - def setUp(self): - server_instance = ServerInstance.ForTest( - file_system=TestFileSystem(_TEST_FS)) - # Don't randomize the owners to avoid testing issues. - self._owners_ds = OwnersDataSource(server_instance, - Request.ForTest('/'), - randomize=False) - - def testParseOwnersFile(self): - owners_content = '\n'.join([ - 'satsuki@revocs.tld', - 'mankanshoku@owner.tld', - '', - 'matoi@owner.tld' - ]) - owners, notes = ParseOwnersFile(owners_content, randomize=False) - # The order of the owners list should reflect the order of the owners file. - self.assertEqual(owners, [ - { - 'email': 'satsuki@revocs.tld', - 'username': 'satsuki' - }, - { - 'email': 'mankanshoku@owner.tld', - 'username': 'mankanshoku' - }, - { - 'email': 'matoi@owner.tld', - 'username': 'matoi', - 'last': True - } - ]) - self.assertEqual(notes, '') - - owners_content_with_comments = '\n'.join([ - '# This is a comment concerning this file', - '# that should not be ignored.', - 'matoi@owner.tld', - 'mankanshoku@owner.tld', - '', - '# Only bug satsuki if matoi or mankanshoku are unavailable.', - 'satsuki@revocs.tld' - ]) - owners, notes = ParseOwnersFile(owners_content_with_comments, - randomize=False) - self.assertEqual(owners, [ - { - 'email': 'matoi@owner.tld', - 'username': 'matoi' - }, - { - 'email': 'mankanshoku@owner.tld', - 'username': 'mankanshoku' - }, - { - 'email': 'satsuki@revocs.tld', - 'username': 'satsuki', - 'last': True - } - ]) - self.assertEqual(notes, '\n'.join([ - 'This is a comment concerning this file', - 'that should not be ignored.', - 'Only bug satsuki if matoi or mankanshoku are unavailable.' - ])) - - - def testCollectOwners(self): - # NOTE: Order matters. The list should be sorted by 'apiName'. - self.assertEqual(self._owners_ds.get('apis'), [{ - 'apiName': 'Core Extensions/Apps Owners', - 'owners': [ - { - 'email': 'satsuki@revocs.tld', - 'username': 'satsuki', - 'last': True - } - ], - 'notes': 'Core owners.', - 'id': 'core' - }, - { - 'apiName': 'a_different_api', - 'owners': [ - { - 'email': 'nonon@owner.tld', - 'username': 'nonon' - }, - { - 'email': 'matoi@owner.tld', - 'username': 'matoi', - 'last': True - } - ], - 'notes': 'Hallo!', - 'id': 'a_different_api' - }, - { - 'apiName': 'an_app_api', - 'owners': [], - 'notes': 'Use one of the Core Extensions/Apps Owners.', - 'id': 'an_app_api', - }, - { - 'apiName': 'another_api', - 'owners': [], - 'notes': 'Use one of the Core Extensions/Apps Owners.', - 'id': 'another_api' - }, - { - 'apiName': 'moar_apis', - 'owners': [ - { - 'email': 'satsuki@revocs.tld', - 'username': 'satsuki', - 'last': True - } - ], - 'notes': 'For editing moar_apis.', - 'id': 'moar_apis' - }, - { - 'apiName': 'some_api', - 'owners': [ - { - 'email': 'matoi@owner.tld', - 'username': 'matoi', - 'last': True - } - ], - 'notes': '', - 'id': 'some_api' - }]) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/patch_servlet.py b/chrome/common/extensions/docs/server2/patch_servlet.py deleted file mode 100644 index 1dfb4d7..0000000 --- a/chrome/common/extensions/docs/server2/patch_servlet.py +++ /dev/null
@@ -1,116 +0,0 @@ -# Copyright 2013 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 fnmatch import fnmatch -import logging - -from caching_rietveld_patcher import CachingRietveldPatcher -from chained_compiled_file_system import ChainedCompiledFileSystem -from environment import IsDevServer -from environment_wrappers import CreateUrlFetcher -from extensions_paths import CONTENT_PROVIDERS -from instance_servlet import InstanceServlet -from render_servlet import RenderServlet -from rietveld_patcher import RietveldPatcher, RietveldPatcherError -from object_store_creator import ObjectStoreCreator -from patched_file_system import PatchedFileSystem -from server_instance import ServerInstance -from servlet import Request, Response, Servlet -import url_constants -from gcs_file_system_provider import CloudStorageFileSystemProvider - - -class _PatchServletDelegate(RenderServlet.Delegate): - def __init__(self, issue, delegate): - self._issue = issue - self._delegate = delegate - - def CreateServerInstance(self): - # start_empty=False because a patch can rely on files that are already in - # the Git repository but not yet pulled into data store by cron jobs (a - # typical example is to add documentation for an existing API). - object_store_creator = ObjectStoreCreator(start_empty=False) - - unpatched_file_system = self._delegate.CreateHostFileSystemProvider( - object_store_creator).GetMaster() - - rietveld_patcher = CachingRietveldPatcher( - RietveldPatcher(self._issue, - CreateUrlFetcher(url_constants.CODEREVIEW_SERVER)), - object_store_creator) - - patched_file_system = PatchedFileSystem(unpatched_file_system, - rietveld_patcher) - - patched_host_file_system_provider = ( - self._delegate.CreateHostFileSystemProvider( - object_store_creator, - # The patched file system needs to be online otherwise it'd be - # impossible to add files in the patches. - offline=False, - # The master file system for this creator should be the patched one. - default_master_instance=patched_file_system)) - - combined_compiled_fs_factory = ChainedCompiledFileSystem.Factory( - [unpatched_file_system], object_store_creator) - - branch_utility = self._delegate.CreateBranchUtility(object_store_creator) - - server_instance = ServerInstance( - object_store_creator, - combined_compiled_fs_factory, - branch_utility, - patched_host_file_system_provider, - CloudStorageFileSystemProvider(object_store_creator), - base_path='/_patch/%s/' % self._issue) - - # HACK: if content_providers.json changes in this patch then the cron needs - # to be re-run to pull in the new configuration. - _, _, modified = rietveld_patcher.GetPatchedFiles() - if CONTENT_PROVIDERS in modified: - server_instance.content_providers.Refresh().Get() - - return server_instance - -class PatchServlet(Servlet): - '''Servlet which renders patched docs. - ''' - def __init__(self, request, delegate=None): - self._request = request - self._delegate = delegate or InstanceServlet.Delegate() - - def Get(self): - if (not IsDevServer() and - not fnmatch(self._request.host, '*.appspot.com')): - # Only allow patches on appspot URLs; it doesn't matter if appspot.com is - # XSS'ed, but it matters for chrome.com. - redirect_host = 'chrome-apps-doc.appspot.com' - logging.info('Redirecting from XSS-able host %s to %s' % ( - self._request.host, redirect_host)) - return Response.Redirect( - 'https://%s/_patch/%s' % (redirect_host, self._request.path)) - - path_with_issue = self._request.path.lstrip('/') - if '/' in path_with_issue: - issue, path_without_issue = path_with_issue.split('/', 1) - else: - return Response.NotFound('Malformed URL. It should look like ' + - 'https://developer.chrome.com/_patch/12345/extensions/...') - - try: - response = RenderServlet( - Request(path_without_issue, - self._request.host, - self._request.headers), - _PatchServletDelegate(issue, self._delegate)).Get() - # Disable cache for patched content. - response.headers.pop('cache-control', None) - except RietveldPatcherError as e: - response = Response.NotFound(e.message, {'Content-Type': 'text/plain'}) - - redirect_url, permanent = response.GetRedirect() - if redirect_url is not None: - response = Response.Redirect('/_patch/%s%s' % (issue, redirect_url), - permanent) - return response
diff --git a/chrome/common/extensions/docs/server2/patch_servlet_test.py b/chrome/common/extensions/docs/server2/patch_servlet_test.py deleted file mode 100755 index 59b3d72..0000000 --- a/chrome/common/extensions/docs/server2/patch_servlet_test.py +++ /dev/null
@@ -1,164 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 HTMLParser import HTMLParser -import os -import unittest - -from fake_fetchers import ConfigureFakeFetchers -from host_file_system_provider import HostFileSystemProvider -from patch_servlet import PatchServlet -from render_servlet import RenderServlet -from server_instance import ServerInstance -from servlet import Request -from test_branch_utility import TestBranchUtility -from test_util import DisableLogging - - - -_ALLOWED_HOST = 'chrome-apps-doc.appspot.com' - - -def _CheckURLsArePatched(content, patch_servlet_path): - errors = [] - class LinkChecker(HTMLParser): - def handle_starttag(self, tag, attrs): - if tag != 'a': - return - tag_description = '<a %s .../>' % ' '.join('%s="%s"' % (key, val) - for key, val in attrs) - attrs = dict(attrs) - if ('href' in attrs and - attrs['href'].startswith('/') and - not attrs['href'].startswith('/%s/' % patch_servlet_path)): - errors.append('%s has an unqualified href' % tag_description) - LinkChecker().feed(content) - return errors - - -class _RenderServletDelegate(RenderServlet.Delegate): - def CreateServerInstance(self): - return ServerInstance.ForLocal() - -class _PatchServletDelegate(RenderServlet.Delegate): - def CreateBranchUtility(self, object_store_creator): - return TestBranchUtility.CreateWithCannedData() - - def CreateHostFileSystemProvider(self, object_store_creator, **optargs): - return HostFileSystemProvider.ForLocal(object_store_creator, **optargs) - -class PatchServletTest(unittest.TestCase): - def setUp(self): - ConfigureFakeFetchers() - - def _RenderWithPatch(self, path, issue): - path_with_issue = '%s/%s' % (issue, path) - return PatchServlet(Request.ForTest(path_with_issue, host=_ALLOWED_HOST), - _PatchServletDelegate()).Get() - - def _RenderWithoutPatch(self, path): - return RenderServlet(Request.ForTest(path, host=_ALLOWED_HOST), - _RenderServletDelegate()).Get() - - def _RenderAndCheck(self, path, issue, expected_equal): - '''Renders |path| with |issue| patched in and asserts that the result is - the same as |expected_equal| modulo any links that get rewritten to - "_patch/issue". - ''' - patched_response = self._RenderWithPatch(path, issue) - unpatched_response = self._RenderWithoutPatch(path) - for header in ('Cache-Control', 'ETag'): - patched_response.headers.pop(header, None) - unpatched_response.headers.pop(header, None) - unpatched_content = unpatched_response.content.ToString() - - # Check that all links in the patched content are qualified with - # the patch URL, then strip them out for checking (in)equality. - patched_content = patched_response.content.ToString() - patch_servlet_path = '_patch/%s' % issue - errors = _CheckURLsArePatched(patched_content, patch_servlet_path) - self.assertFalse(errors, - '%s\nFound errors:\n * %s' % (patched_content, '\n * '.join(errors))) - patched_content = patched_content.replace('/%s' % patch_servlet_path, '') - - self.assertEqual(patched_response.status, unpatched_response.status) - self.assertEqual(patched_response.headers, unpatched_response.headers) - if expected_equal: - self.assertEqual(patched_content, unpatched_content) - else: - self.assertNotEqual(patched_content, unpatched_content) - - def _RenderAndAssertEqual(self, path, issue): - self._RenderAndCheck(path, issue, True) - - def _RenderAndAssertNotEqual(self, path, issue): - self._RenderAndCheck(path, issue, False) - - @DisableLogging('warning') - def _AssertNotFound(self, path, issue): - response = self._RenderWithPatch(path, issue) - self.assertEqual(response.status, 404, - 'Path %s with issue %s should have been removed for %s.' % ( - path, issue, response)) - - def _AssertOk(self, path, issue): - response = self._RenderWithPatch(path, issue) - self.assertEqual(response.status, 200, - 'Failed to render path %s with issue %s.' % (path, issue)) - self.assertTrue(len(response.content.ToString()) > 0, - 'Rendered result for path %s with issue %s should not be empty.' % - (path, issue)) - - def _AssertRedirect(self, path, issue, redirect_path): - response = self._RenderWithPatch(path, issue) - self.assertEqual(302, response.status) - self.assertEqual('/_patch/%s/%s' % (issue, redirect_path), - response.headers['Location']) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testRender(self): - # '_patch' is not included in paths below because it's stripped by Handler. - issue = '14096030' - - # TODO(kalman): Test with chrome_sidenav.json once the sidenav logic has - # stabilised. - - # extensions/runtime.html is removed in the patch, should redirect to the - # apps version. - self._AssertRedirect('extensions/runtime', issue, 'apps/runtime') - - # apps/runtime.html is not removed. - self._RenderAndAssertEqual('apps/runtime', issue) - - # test_foo.html is added in the patch. - self._AssertOk('extensions/test_foo', issue) - - # Invalid issue number results in a 404. - self._AssertNotFound('extensions/index', '11111') - - def testXssRedirect(self): - def is_redirect(from_host, from_path, to_url): - response = PatchServlet(Request.ForTest(from_path, host=from_host), - _PatchServletDelegate()).Get() - redirect_url, _ = response.GetRedirect() - if redirect_url is None: - return (False, '%s/%s did not cause a redirect' % ( - from_host, from_path)) - if redirect_url != to_url: - return (False, '%s/%s redirected to %s not %s' % ( - from_host, from_path, redirect_url, to_url)) - return (True, '%s/%s redirected to %s' % ( - from_host, from_path, redirect_url)) - self.assertTrue(*is_redirect('developer.chrome.com', '12345', - 'https://%s/_patch/12345' % _ALLOWED_HOST)) - self.assertTrue(*is_redirect('developers.google.com', '12345', - 'https://%s/_patch/12345' % _ALLOWED_HOST)) - self.assertFalse(*is_redirect('chrome-apps-doc.appspot.com', '12345', - None)) - self.assertFalse(*is_redirect('some-other-app.appspot.com', '12345', - None)) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/patched_file_system.py b/chrome/common/extensions/docs/server2/patched_file_system.py deleted file mode 100644 index 52ad0bda..0000000 --- a/chrome/common/extensions/docs/server2/patched_file_system.py +++ /dev/null
@@ -1,156 +0,0 @@ -# Copyright 2013 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 copy import deepcopy - -from file_system import FileSystem, StatInfo, FileNotFoundError -from future import Future - - -class PatchedFileSystem(FileSystem): - ''' Class to fetch resources with a patch applied. - ''' - def __init__(self, base_file_system, patcher): - self._base_file_system = base_file_system - self._patcher = patcher - - def Read(self, paths, skip_not_found=False): - patched_files = set() - added, deleted, modified = self._patcher.GetPatchedFiles() - if set(paths) & set(deleted): - def raise_file_not_found(): - raise FileNotFoundError('Files are removed from the patch.') - return Future(callback=raise_file_not_found) - - patched_files |= (set(added) | set(modified)) - dir_paths = set(path for path in paths if path.endswith('/')) - file_paths = set(paths) - dir_paths - patched_paths = file_paths & patched_files - unpatched_paths = file_paths - patched_files - - def patch_directory_listing(path, original_listing): - added, deleted, modified = ( - self._GetDirectoryListingFromPatch(path)) - if original_listing is None: - if len(added) == 0: - raise FileNotFoundError('Directory %s not found in the patch.' % path) - return added - return list((set(original_listing) | set(added)) - set(deleted)) - - def next(files): - dirs_value = self._TryReadDirectory(dir_paths) - files.update(self._patcher.Apply(patched_paths, - self._base_file_system).Get()) - files.update(dict((path, patch_directory_listing(path, dirs_value[path])) - for path in dirs_value)) - return files - return self._base_file_system.Read(unpatched_paths, - skip_not_found=skip_not_found).Then(next) - - def Refresh(self): - return self._base_file_system.Refresh() - - ''' Given the list of patched files, it's not possible to determine whether - a directory to read exists in self._base_file_system. So try reading each one - and handle FileNotFoundError. - ''' - def _TryReadDirectory(self, paths): - value = {} - for path in paths: - assert path.endswith('/') - try: - value[path] = self._base_file_system.ReadSingle(path).Get() - except FileNotFoundError: - value[path] = None - return value - - def _GetDirectoryListingFromPatch(self, path): - assert path.endswith('/') - def _FindChildrenInPath(files, path): - result = [] - for f in files: - if f.startswith(path): - child_path = f[len(path):] - if '/' in child_path: - child_name = child_path[0:child_path.find('/') + 1] - else: - child_name = child_path - result.append(child_name) - return result - - added, deleted, modified = (tuple( - _FindChildrenInPath(files, path) - for files in self._patcher.GetPatchedFiles())) - - # A patch applies to files only. It cannot delete directories. - deleted_files = [child for child in deleted if not child.endswith('/')] - # However, these directories are actually modified because their children - # are patched. - modified += [child for child in deleted if child.endswith('/')] - - return (added, deleted_files, modified) - - def _PatchStat(self, stat_info, version, added, deleted, modified): - assert len(added) + len(deleted) + len(modified) > 0 - assert stat_info.child_versions is not None - - # Deep copy before patching to make sure it doesn't interfere with values - # cached in memory. - stat_info = deepcopy(stat_info) - - stat_info.version = version - for child in added + modified: - stat_info.child_versions[child] = version - for child in deleted: - if stat_info.child_versions.get(child): - del stat_info.child_versions[child] - - return stat_info - - def Stat(self, path): - version = self._patcher.GetVersion() - assert version is not None - version = 'patched_%s' % version - - directory, filename = path.rsplit('/', 1) - added, deleted, modified = self._GetDirectoryListingFromPatch( - directory + '/') - - if len(added) > 0: - # There are new files added. It's possible (if |directory| is new) that - # self._base_file_system.Stat will throw an exception. - try: - stat_info = self._PatchStat( - self._base_file_system.Stat(directory + '/'), - version, - added, - deleted, - modified) - except FileNotFoundError: - stat_info = StatInfo( - version, - dict((child, version) for child in added + modified)) - elif len(deleted) + len(modified) > 0: - # No files were added. - stat_info = self._PatchStat(self._base_file_system.Stat(directory + '/'), - version, - added, - deleted, - modified) - else: - # No changes are made in this directory. - return self._base_file_system.Stat(path) - - if stat_info.child_versions is not None: - if filename: - if filename in stat_info.child_versions: - stat_info = StatInfo(stat_info.child_versions[filename]) - else: - raise FileNotFoundError('%s was not in child versions' % filename) - return stat_info - - def GetIdentity(self): - return '%s(%s,%s)' % (self.__class__.__name__, - self._base_file_system.GetIdentity(), - self._patcher.GetIdentity())
diff --git a/chrome/common/extensions/docs/server2/patched_file_system_test.py b/chrome/common/extensions/docs/server2/patched_file_system_test.py deleted file mode 100755 index 692c89f1..0000000 --- a/chrome/common/extensions/docs/server2/patched_file_system_test.py +++ /dev/null
@@ -1,200 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 copy import deepcopy -import unittest - -from file_system import FileNotFoundError, StatInfo -from patched_file_system import PatchedFileSystem -from test_file_system import TestFileSystem -from test_patcher import TestPatcher - -_TEST_FS_DATA = { - 'dir1': { - 'file1.html': 'This is dir1/file1.html', - 'unmodified': { - '1': '1', - '2': '', - }, - }, - 'dir2': { - 'subdir1': { - 'sub1.txt': 'in subdir(1)', - 'sub2.txt': 'in subdir(2)', - 'sub3.txt': 'in subdir(3)', - }, - }, - 'dir3': { - }, - 'dir4': { - 'one.txt': '', - }, - 'dir5': { - 'subdir': { - '1.txt': '555', - }, - }, - 'test1.txt': 'test1', - 'test2.txt': 'test2', -} - -_TEST_PATCH_VERSION = '1001' -_TEST_PATCH_FILES = ( - # Added - [ - 'test3.txt', - 'dir1/file2.html', - 'dir1/newsubdir/a.js', - 'newdir/1.html', - ], - # Deleted - [ - 'test2.txt', - 'dir2/subdir1/sub1.txt', - 'dir4/one.txt', - 'dir5/subdir/1.txt', - ], - # Modified - [ - 'dir2/subdir1/sub2.txt', - ] -) -_TEST_PATCH_DATA = { - 'test3.txt': 'test3 is added.', - 'dir1/file2.html': 'This is dir1/file2.html', - 'dir1/newsubdir/a.js': 'This is a.js', - 'newdir/1.html': 'This comes from a new dir.', - 'dir2/subdir1/sub2.txt': 'in subdir', -} - -class PatchedFileSystemTest(unittest.TestCase): - def setUp(self): - self._patcher = TestPatcher(_TEST_PATCH_VERSION, - _TEST_PATCH_FILES, - _TEST_PATCH_DATA) - self._host_file_system = TestFileSystem(_TEST_FS_DATA) - self._file_system = PatchedFileSystem(self._host_file_system, - self._patcher) - - def testRead(self): - expected = deepcopy(_TEST_PATCH_DATA) - # Files that are not modified. - expected.update({ - 'dir2/subdir1/sub3.txt': 'in subdir(3)', - 'dir1/file1.html': 'This is dir1/file1.html', - }) - - for key in expected: - self.assertEqual(expected[key], self._file_system.ReadSingle(key).Get()) - - self.assertEqual( - expected, - self._file_system.Read(expected.keys()).Get()) - - self.assertRaises(FileNotFoundError, - self._file_system.ReadSingle('test2.txt').Get) - self.assertRaises(FileNotFoundError, - self._file_system.ReadSingle('dir2/subdir1/sub1.txt').Get) - self.assertRaises(FileNotFoundError, - self._file_system.ReadSingle('not_existing').Get) - self.assertRaises(FileNotFoundError, - self._file_system.ReadSingle('dir1/not_existing').Get) - self.assertRaises( - FileNotFoundError, - self._file_system.ReadSingle('dir1/newsubdir/not_existing').Get) - - def testReadDir(self): - self.assertEqual( - sorted(self._file_system.ReadSingle('dir1/').Get()), - sorted(set(self._host_file_system.ReadSingle('dir1/').Get()) | - set(('file2.html', 'newsubdir/')))) - - self.assertEqual( - sorted(self._file_system.ReadSingle('dir1/newsubdir/').Get()), - sorted(['a.js'])) - - self.assertEqual(sorted(self._file_system.ReadSingle('dir2/').Get()), - sorted(self._host_file_system.ReadSingle('dir2/').Get())) - - self.assertEqual( - sorted(self._file_system.ReadSingle('dir2/subdir1/').Get()), - sorted(set(self._host_file_system.ReadSingle('dir2/subdir1/').Get()) - - set(('sub1.txt',)))) - - self.assertEqual(sorted(self._file_system.ReadSingle('newdir/').Get()), - sorted(['1.html'])) - - self.assertEqual(self._file_system.ReadSingle('dir3/').Get(), []) - - self.assertEqual(self._file_system.ReadSingle('dir4/').Get(), []) - - self.assertRaises(FileNotFoundError, - self._file_system.ReadSingle('not_existing_dir/').Get) - - def testStat(self): - version = 'patched_%s' % self._patcher.GetVersion() - old_version = self._host_file_system.Stat('dir1/file1.html').version - - # Stat an unmodified file. - self.assertEqual(self._file_system.Stat('dir1/file1.html'), - self._host_file_system.Stat('dir1/file1.html')) - - # Stat an unmodified directory. - self.assertEqual(self._file_system.Stat('dir1/unmodified/'), - self._host_file_system.Stat('dir1/unmodified/')) - - # Stat a modified directory. - self.assertEqual(self._file_system.Stat('dir2/'), - StatInfo(version, {'subdir1/': version})) - self.assertEqual(self._file_system.Stat('dir2/subdir1/'), - StatInfo(version, {'sub2.txt': version, - 'sub3.txt': old_version})) - - # Stat a modified directory with new files. - expected = self._host_file_system.Stat('dir1/') - expected.version = version - expected.child_versions.update({'file2.html': version, - 'newsubdir/': version}) - self.assertEqual(self._file_system.Stat('dir1/'), - expected) - - # Stat an added directory. - self.assertEqual(self._file_system.Stat('dir1/newsubdir/'), - StatInfo(version, {'a.js': version})) - self.assertEqual(self._file_system.Stat('dir1/newsubdir/a.js'), - StatInfo(version)) - self.assertEqual(self._file_system.Stat('newdir/'), - StatInfo(version, {'1.html': version})) - self.assertEqual(self._file_system.Stat('newdir/1.html'), - StatInfo(version)) - - # Stat files removed in the patch. - self.assertRaises(FileNotFoundError, self._file_system.Stat, - 'dir2/subdir1/sub1.txt') - self.assertRaises(FileNotFoundError, self._file_system.Stat, - 'dir4/one.txt') - - # Stat empty directories. - self.assertEqual(self._file_system.Stat('dir3/'), - StatInfo(old_version, {})) - self.assertEqual(self._file_system.Stat('dir4/'), - StatInfo(version, {})) - self.assertEqual(self._file_system.Stat('dir5/subdir/'), - StatInfo(version, {})) - - # Stat empty (after patch) directory's parent - self.assertEqual(self._file_system.Stat('dir5/'), - StatInfo(version, {'subdir/': version})) - - # Stat files that don't exist either before or after patching. - self.assertRaises(FileNotFoundError, self._file_system.Stat, - 'not_existing/') - self.assertRaises(FileNotFoundError, self._file_system.Stat, - 'dir1/not_existing/') - self.assertRaises(FileNotFoundError, self._file_system.Stat, - 'dir1/not_existing') - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/patcher.py b/chrome/common/extensions/docs/server2/patcher.py deleted file mode 100644 index 4a526ae..0000000 --- a/chrome/common/extensions/docs/server2/patcher.py +++ /dev/null
@@ -1,28 +0,0 @@ -# Copyright 2013 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. - -class Patcher(object): - def GetPatchedFiles(self, version=None): - '''Returns patched files as(added_files, deleted_files, modified_files) - from the patchset specified by |version|. - ''' - raise NotImplementedError(self.__class__) - - def GetVersion(self): - '''Returns patch version. Returns None when nothing is patched by the - patcher. - ''' - raise NotImplementedError(self.__class__) - - def Apply(self, paths, file_system, version=None): - '''Apply the patch to added/modified files. Returns Future with patched - data. Throws FileNotFoundError if |paths| contains deleted files. - ''' - raise NotImplementedError(self.__class__) - - def GetIdentity(self): - '''Returns a string that identifies this patch. Typically it would be the - codereview server's ID for this patch. - ''' - raise NotImplementedError(self.__class__)
diff --git a/chrome/common/extensions/docs/server2/path_canonicalizer.py b/chrome/common/extensions/docs/server2/path_canonicalizer.py deleted file mode 100644 index e232bf7..0000000 --- a/chrome/common/extensions/docs/server2/path_canonicalizer.py +++ /dev/null
@@ -1,118 +0,0 @@ -# Copyright 2013 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 collections import defaultdict -import posixpath - -from future import Future -from path_util import SplitParent -from special_paths import SITE_VERIFICATION_FILE - -def _Normalize(file_name, splittext=False): - normalized = file_name - if splittext: - normalized = posixpath.splitext(file_name)[0] - normalized = normalized.replace('.', '').replace('-', '').replace('_', '') - return normalized.lower() - -def _CommonNormalizedPrefix(first_file, second_file): - return posixpath.commonprefix((_Normalize(first_file), - _Normalize(second_file))) - - -class PathCanonicalizer(object): - '''Transforms paths into their canonical forms. Since the docserver has had - many incarnations - e.g. there didn't use to be apps/ - there may be old - paths lying around the webs. We try to redirect those to where they are now. - ''' - def __init__(self, - file_system, - object_store_creator, - strip_extensions): - # |strip_extensions| is a list of file extensions (e.g. .html) that should - # be stripped for a path's canonical form. - self._cache = object_store_creator.Create( - PathCanonicalizer, category=file_system.GetIdentity()) - self._file_system = file_system - self._strip_extensions = strip_extensions - - def _LoadCache(self): - def load(cached): - # |canonical_paths| is the pre-calculated set of canonical paths. - # |simplified_paths_map| is a lazily populated mapping of simplified file - # names to a list of full paths that contain them. For example, - # - browseraction: [extensions/browserAction.html] - # - storage: [apps/storage.html, extensions/storage.html] - canonical_paths, simplified_paths_map = ( - cached.get('canonical_paths'), cached.get('simplified_paths_map')) - - if canonical_paths is None: - assert simplified_paths_map is None - canonical_paths = set() - simplified_paths_map = defaultdict(list) - for base, dirs, files in self._file_system.Walk(''): - for path in dirs + files: - path_without_ext, ext = posixpath.splitext(path) - canonical_path = posixpath.join(base, path_without_ext) - if (ext not in self._strip_extensions or - path == SITE_VERIFICATION_FILE): - canonical_path += ext - canonical_paths.add(canonical_path) - simplified_paths_map[_Normalize(path, splittext=True)].append( - canonical_path) - # Store |simplified_paths_map| sorted. Ties in length are broken by - # taking the shortest, lexicographically smallest path. - for path_list in simplified_paths_map.itervalues(): - path_list.sort(key=lambda p: (len(p), p)) - self._cache.SetMulti({ - 'canonical_paths': canonical_paths, - 'simplified_paths_map': simplified_paths_map, - }) - else: - assert simplified_paths_map is not None - - return canonical_paths, simplified_paths_map - return self._cache.GetMulti(('canonical_paths', - 'simplified_paths_map')).Then(load) - - - def Canonicalize(self, path): - '''Returns the canonical path for |path|. - ''' - canonical_paths, simplified_paths_map = self._LoadCache().Get() - - # Path may already be the canonical path. - if path in canonical_paths: - return path - - # Path not found. Our single heuristic: find |base| in the directory - # structure with the longest common prefix of |path|. - _, base = SplitParent(path) - - # Paths with a non-extension dot separator lose information in - # _SimplifyFileName, so we try paths both with and without the dot to - # maximize the possibility of finding the right path. - potential_paths = ( - simplified_paths_map.get(_Normalize(base), []) + - simplified_paths_map.get(_Normalize(base, splittext=True), [])) - - if potential_paths == []: - # There is no file with anything close to that name. - return path - - # The most likely canonical file is the one with the longest common prefix - # with |path|. This is slightly weaker than it could be; |path| is - # compared without symbols, not the simplified form of |path|, - # which may matter. - max_prefix = potential_paths[0] - max_prefix_length = len(_CommonNormalizedPrefix(max_prefix, path)) - for path_for_file in potential_paths[1:]: - prefix_length = len(_CommonNormalizedPrefix(path_for_file, path)) - if prefix_length > max_prefix_length: - max_prefix, max_prefix_length = path_for_file, prefix_length - - return max_prefix - - def Refresh(self): - return self._LoadCache()
diff --git a/chrome/common/extensions/docs/server2/path_canonicalizer_test.py b/chrome/common/extensions/docs/server2/path_canonicalizer_test.py deleted file mode 100755 index 395298f..0000000 --- a/chrome/common/extensions/docs/server2/path_canonicalizer_test.py +++ /dev/null
@@ -1,154 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 posixpath -import unittest - -from extensions_paths import PUBLIC_TEMPLATES, SERVER2 -from local_file_system import LocalFileSystem -from test_file_system import TestFileSystem -from object_store_creator import ObjectStoreCreator -from path_canonicalizer import PathCanonicalizer -from special_paths import SITE_VERIFICATION_FILE - - -class PathCanonicalizerTest(unittest.TestCase): - def setUp(self): - self._path_canonicalizer = PathCanonicalizer( - LocalFileSystem.Create(PUBLIC_TEMPLATES), - ObjectStoreCreator.ForTest(), - ('.html', '.md')) - - def testSpecifyCorrectly(self): - self._AssertIdentity('extensions/browserAction') - self._AssertIdentity('extensions/storage') - self._AssertIdentity('extensions/blah') - self._AssertIdentity('extensions/index') - self._AssertIdentity('extensions/whats_new') - self._AssertIdentity('apps/storage') - self._AssertIdentity('apps/bluetooth') - self._AssertIdentity('apps/blah') - self._AssertIdentity('apps/tags/webview') - - def testSpecifyIncorrectly(self): - self._AssertRedirectWithDefaultExtensions( - 'extensions/browserAction', 'apps/browserAction') - self._AssertRedirectWithDefaultExtensions( - 'extensions/browserAction', 'apps/extensions/browserAction') - self._AssertRedirectWithDefaultExtensions( - 'apps/bluetooth', 'extensions/bluetooth') - self._AssertRedirectWithDefaultExtensions( - 'apps/bluetooth', 'extensions/apps/bluetooth') - self._AssertRedirectWithDefaultExtensions( - 'extensions/index', 'apps/index') - self._AssertRedirectWithDefaultExtensions( - 'extensions/browserAction', 'static/browserAction') - self._AssertRedirectWithDefaultExtensions( - 'apps/tags/webview', 'apps/webview') - self._AssertRedirectWithDefaultExtensions( - 'apps/tags/webview', 'extensions/webview') - self._AssertRedirectWithDefaultExtensions( - 'apps/tags/webview', 'extensions/tags/webview') - - # These are a little trickier because storage.html is in both directories. - # They must canonicalize to the closest match. - self._AssertRedirectWithDefaultExtensions( - 'extensions/storage', 'extensions/apps/storage') - self._AssertRedirectWithDefaultExtensions( - 'apps/storage', 'apps/extensions/storage') - - def testUnspecified(self): - self._AssertRedirectWithDefaultExtensions( - 'extensions/browserAction', 'browserAction') - self._AssertRedirectWithDefaultExtensions( - 'apps/bluetooth', 'bluetooth') - # Default happens to be apps because it's first alphabetically. - self._AssertRedirectWithDefaultExtensions( - 'apps/storage', 'storage') - # Nonexistent APIs should be left alone. - self._AssertIdentity('blah.html') - - def testDirectories(self): - # Directories can be canonicalized too! - self._AssertIdentity('apps/') - self._AssertIdentity('apps/tags/') - self._AssertIdentity('extensions/') - # No trailing slash should be treated as files not directories, at least - # at least according to PathCanonicalizer. - self._AssertRedirect('extensions/apps', 'apps') - self._AssertRedirect('extensions', 'extensions') - # Just as tolerant of spelling mistakes. - self._AssertRedirect('apps/', 'Apps/') - self._AssertRedirect('apps/tags/', 'Apps/TAGS/') - self._AssertRedirect('extensions/', 'Extensions/') - # Find directories in the correct place. - self._AssertRedirect('apps/tags/', 'tags/') - self._AssertRedirect('apps/tags/', 'extensions/tags/') - - def testSpellingErrors(self): - for spelme in ('browseraction', 'browseraction.htm', 'BrowserAction', - 'BrowserAction.html', 'browseraction.html', 'Browseraction', - 'browser-action', 'Browser.action.html', 'browser_action', - 'browser-action.html', 'Browser_Action.html'): - self._AssertRedirect('extensions/browserAction', spelme) - self._AssertRedirect('extensions/browserAction', 'extensions/%s' % spelme) - self._AssertRedirect('extensions/browserAction', 'apps/%s' % spelme) - - def testNonDefaultExtensions(self): - # The only example currently of a file with a non-default extension is - # the redirects.json file. That shouldn't have its extension stripped since - # it's not in the default extensions. - self._AssertIdentity('redirects.json') - self._AssertRedirect('redirects.json', 'redirects') - self._AssertRedirect('redirects.json', 'redirects.html') - self._AssertRedirect('redirects.json', 'redirects.js') - self._AssertRedirect('redirects.json', 'redirects.md') - - def testSiteVerificationFile(self): - # The site verification file should not redirect. - self._AssertIdentity(SITE_VERIFICATION_FILE) - self._AssertRedirect(SITE_VERIFICATION_FILE, - posixpath.splitext(SITE_VERIFICATION_FILE)[0]) - - def testDotSeparated(self): - self._AssertIdentity('extensions/devtools_inspectedWindow') - self._AssertRedirect('extensions/devtools_inspectedWindow', - 'extensions/devtools.inspectedWindow') - - def testUnderscoreSeparated(self): - file_system = TestFileSystem({ - 'pepper_dev': { - 'c': { - 'index.html': '' - } - }, - 'pepper_stable': { - 'c': { - 'index.html': '' - } - } - }) - self._path_canonicalizer = PathCanonicalizer( - file_system, - ObjectStoreCreator.ForTest(), - ('.html', '.md')) - self._AssertIdentity('pepper_stable/c/index') - self._AssertRedirect('pepper_stable/c/index', - 'pepper_stable/c/index.html') - - def _AssertIdentity(self, path): - self._AssertRedirect(path, path) - - def _AssertRedirect(self, to, from_): - self.assertEqual(to, self._path_canonicalizer.Canonicalize(from_)) - - def _AssertRedirectWithDefaultExtensions(self, to, from_): - for ext in ('', '.html', '.md'): - self._AssertRedirect( - to, self._path_canonicalizer.Canonicalize(from_ + ext)) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/path_util.py b/chrome/common/extensions/docs/server2/path_util.py deleted file mode 100644 index 167e844..0000000 --- a/chrome/common/extensions/docs/server2/path_util.py +++ /dev/null
@@ -1,95 +0,0 @@ -# Copyright 2013 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 posixpath - - -# TODO(kalman): Write a Path class and use that everywhere rather than a -# utility class. - - -def IsDirectory(path): - '''Returns whether |path| should be considered a directory. - ''' - # This assertion is sprinkled throughout the code base. - AssertIsValid(path) - return path in ('', '.', '..') or path.endswith('/') or path.endswith('/..') - - -def IsValid(path): - '''Returns whether |path| is a valid path for the purposes of the docserver. - Paths may not start with /, must be posix paths, and for sanity shouldn't - repeat the path separator //. - ''' - return not path.startswith('/') and not '\\' in path and not '//' in path - - -def AssertIsValid(path): - assert IsValid(path), 'Path "%s" is invalid' % path - - -def Join(*paths): - assert all(IsValid(path) for path in paths), paths - return posixpath.join(*paths) - - -def SplitParent(path): - '''Returns the parent directory and base name of |path| in a tuple. - Any trailing slash of |path| is preserved, such that the parent of - '/hello/world/' is '/hello' and the base is 'world/'. - ''' - parent, base = posixpath.split(path.rstrip('/')) - if path.endswith('/'): - base += '/' - return parent, base - - -def Split(path): - '''Returns a list of the directories and filename in a path. 'p1/p2/p3' - will return ['p1/', 'p2/', 'p3']. - ''' - AssertIsValid(path) - names = [name + '/' for name in path.rstrip('/').split('/')] - if names and not path.endswith('/'): - names[-1] = names[-1][:-1] - return names - - -def ToDirectory(path): - '''Returns a string representing |path| as a directory, that is, - IsDirectory(result) is True (and does not fail assertions). If |path| is - already a directory then this is a no-op. - ''' - return path if IsDirectory(path) else (path + '/') - - -def AssertIsDirectory(path): - assert IsDirectory(path), '"%s" is not a directory' % path - - -def AssertIsFile(path): - assert not IsDirectory(path), '"%s" is not a file' % path - -def Segment(path): - '''Yields a tuple (url, file) for directory split pairs. - For example, if we split the path 'foo/bar/baz', it will yield: - ('', 'foo/bar/baz'), ('foo', "bar/baz'), ('foo/bar', 'baz'), - ('foo/bar/baz', '') - ''' - AssertIsValid(path) - - last_path = '' - yield (last_path, path) - - for segment in (segment for segment in path.split('/') if segment != ''): - last_path = posixpath.join(last_path, segment) - rel_path = posixpath.relpath(path, last_path) - - # Don't let relpath say the filename is '.' - if rel_path == '.': - rel_path = '' - else: - last_path = ToDirectory(last_path) - - yield (last_path, rel_path)
diff --git a/chrome/common/extensions/docs/server2/path_util_test.py b/chrome/common/extensions/docs/server2/path_util_test.py deleted file mode 100755 index 12eda79..0000000 --- a/chrome/common/extensions/docs/server2/path_util_test.py +++ /dev/null
@@ -1,50 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from path_util import SplitParent, Split, Segment - - -class PathUtilTest(unittest.TestCase): - - def testSplitParent(self): - self.assertEqual(('', 'hi'), SplitParent('hi')) - self.assertEqual(('', 'hi/'), SplitParent('hi/')) - self.assertEqual(('/', 'hi'), SplitParent('/hi')) - self.assertEqual(('/', 'hi/'), SplitParent('/hi/')) - self.assertEqual(('parent', 'hi'), SplitParent('parent/hi')) - self.assertEqual(('parent', 'hi/'), SplitParent('parent/hi/')) - self.assertEqual(('/parent', 'hi'), SplitParent('/parent/hi')) - self.assertEqual(('/parent', 'hi/'), SplitParent('/parent/hi/')) - self.assertEqual(('p1/p2', 'hi'), SplitParent('p1/p2/hi')) - self.assertEqual(('p1/p2', 'hi/'), SplitParent('p1/p2/hi/')) - self.assertEqual(('/p1/p2', 'hi'), SplitParent('/p1/p2/hi')) - self.assertEqual(('/p1/p2', 'hi/'), SplitParent('/p1/p2/hi/')) - - def testSplit(self): - self.assertEqual(['p1/', 'p2/', 'p3'], Split('p1/p2/p3')) - self.assertEqual(['p1/', 'p2/', 'p3/'], Split('p1/p2/p3/')) - self.assertEqual([''], Split('')) - self.assertEqual(['p1/'], Split('p1/')) - self.assertEqual(['p1'], Split('p1')) - - def testSegment(self): - self.assertEqual([('', '')], list(Segment(''))) - self.assertEqual([('', 'hi'), ('hi', '')], list(Segment('hi'))) - self.assertEqual([('', 'p1/p2/hi'), - ('p1/', 'p2/hi'), - ('p1/p2/', 'hi'), - ('p1/p2/hi', '')], - list(Segment('p1/p2/hi'))) - self.assertEqual([('', 'foo/bar/baz.txt'), - ('foo/', 'bar/baz.txt'), - ('foo/bar/', 'baz.txt'), - ('foo/bar/baz.txt', '')], - list(Segment('foo/bar/baz.txt'))) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/permissions_data_source.py b/chrome/common/extensions/docs/server2/permissions_data_source.py deleted file mode 100644 index 91621c4..0000000 --- a/chrome/common/extensions/docs/server2/permissions_data_source.py +++ /dev/null
@@ -1,97 +0,0 @@ -# Copyright 2013 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 itertools import ifilter -from operator import itemgetter - -from data_source import DataSource -from extensions_paths import PRIVATE_TEMPLATES -from future import Future -from platform_util import GetPlatforms - - -def _ListifyPermissions(permissions): - '''Filter out any permissions that do not have a description or with a name - that ends with Private then sort permissions features by name into a list. - ''' - def filter_permissions(perm): - return 'description' in perm and not perm['name'].endswith('Private') - - return sorted( - ifilter(filter_permissions, permissions.itervalues()), - key=itemgetter('name')) - - -def _AddDependencyDescriptions(permissions, api_features): - '''Use |api_features| to determine the dependencies APIs have on permissions. - Add descriptions to |permissions| based on those dependencies. - ''' - for name, permission in permissions.iteritems(): - # Don't overwrite the description created by expanding a partial template. - if 'partial' in permission: - continue - - has_deps = False - if name in api_features: - for dependency in api_features[name].get('dependencies', ()): - if dependency.startswith('permission:'): - has_deps = True - - if has_deps: - permission['partial'] = 'permissions/generic_description.html' - -class PermissionsDataSource(DataSource): - '''Load and format permissions features to be used by templates. - ''' - def __init__(self, server_instance, request): - self._platform_bundle = server_instance.platform_bundle - self._object_store = server_instance.object_store_creator.Create( - PermissionsDataSource) - self._template_cache = server_instance.compiled_fs_factory.ForTemplates( - server_instance.host_file_system_provider.GetMaster()) - - def _CreatePermissionsDataForPlatform(self, platform): - features_bundle = self._platform_bundle.GetFeaturesBundle(platform) - api_features_future = features_bundle.GetAPIFeatures() - permission_features_future = features_bundle.GetPermissionFeatures() - - def resolve(): - api_features = api_features_future.Get() - permission_features = permission_features_future.Get() - _AddDependencyDescriptions(permission_features, api_features) - - # Turn partial templates into descriptions, ensure anchors are set. - for permission in permission_features.values(): - if not 'anchor' in permission: - permission['anchor'] = permission['name'] - if 'partial' in permission: - permission['description'] = self._template_cache.GetFromFile( - PRIVATE_TEMPLATES + permission['partial']).Get() - del permission['partial'] - - return _ListifyPermissions(permission_features) - return Future(callback=resolve) - - def _CreatePermissionsData(self): - permissions_data_futures = dict( - (platform, self._CreatePermissionsDataForPlatform(platform)) - for platform in GetPlatforms()) - - def resolve(): - return dict(('declare_' + platform, future.Get()) - for platform, future in permissions_data_futures.iteritems()) - return Future(callback=resolve) - - def _GetCachedPermissionsData(self): - data = self._object_store.Get('permissions_data').Get() - if data is None: - data = self._CreatePermissionsData().Get() - self._object_store.Set('permissions_data', data) - return data - - def get(self, key): - return self._GetCachedPermissionsData().get(key) - - def Refresh(self): - return self._CreatePermissionsData()
diff --git a/chrome/common/extensions/docs/server2/permissions_data_source_test.py b/chrome/common/extensions/docs/server2/permissions_data_source_test.py deleted file mode 100755 index f7a9090f..0000000 --- a/chrome/common/extensions/docs/server2/permissions_data_source_test.py +++ /dev/null
@@ -1,175 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 json -from operator import itemgetter -import unittest - -from extensions_paths import CHROME_EXTENSIONS -from permissions_data_source import PermissionsDataSource -from server_instance import ServerInstance -from third_party.motemplate import Motemplate -from test_file_system import TestFileSystem - - -_PERMISSION_FEATURES = { - # This will appear for extensions with a description as defined in the - # permissions.json file. - 'activeTab': { - 'extension_types': ['extension'], - }, - # This will appear for apps and extensions with an auto-generated description - # since the entry appears in _api_features.json. - 'alarms': { - 'extension_types': ['platform_app', 'extension'], - }, - # This won't appear for anything since there's no entry in permissions.json - # and it's not an API. - 'audioCapture': { - 'extension_types': ['platform_app'], - }, - # This won't appear for anything because it's private. - 'commandLinePrivate': { - 'extension_types': ['platform_app', 'extension'] - }, - # This will only appear for apps with an auto-generated description because - # it's an API. - 'cookies': { - 'extension_types': ['platform_app'] - }, - 'host-permissions': {} -} - - -_PERMISSIONS_JSON = { - # This will appear for both apps and extensions with a custom description, - # anchor, etc. - 'host-permissions': { - 'anchor': 'custom-anchor', - 'extension_types': ['platform_app', 'extension'], - 'literal_name': True, - 'name': 'match pattern', - 'partial': 'permissions/host_permissions.html', - }, - # A custom 'partial' here overrides the default partial. - 'activeTab': { - 'partial': 'permissions/active_tab.html' - }, -} - - -_PERMISSIONS_PARTIALS = { - 'active_tab.html': 'active tab', - 'host_permissions.html': 'host permissions', - 'generic_description.html': 'generic description', -} - - -_API_FEATURES = { - 'alarms': { - 'dependencies': ['permission:alarms'] - }, - 'cookies': { - 'dependencies': ['permission:cookies'] - }, -} - - -class PermissionsDataSourceTest(unittest.TestCase): - def testCreatePermissionsDataSource(self): - expected_extensions = [ - { - 'anchor': 'custom-anchor', - 'description': 'host permissions', - 'extension_types': ['platform_app', 'extension'], - 'literal_name': True, - 'name': 'match pattern', - 'channel': 'stable' - }, - { - 'anchor': 'activeTab', - 'description': 'active tab', - 'extension_types': ['extension'], - 'name': 'activeTab', - 'channel': 'stable' - }, - { - 'anchor': 'alarms', - 'description': 'generic description', - 'extension_types': ['platform_app', 'extension'], - 'name': 'alarms', - 'channel': 'stable' - }, - ] - - expected_apps = [ - { - 'anchor': 'custom-anchor', - 'description': 'host permissions', - 'extension_types': ['platform_app', 'extension'], - 'literal_name': True, - 'name': 'match pattern', - 'channel': 'stable' - }, - { - 'anchor': 'alarms', - 'description': 'generic description', - 'extension_types': ['platform_app', 'extension'], - 'name': 'alarms', - 'channel': 'stable' - }, - { - 'anchor': 'cookies', - 'description': 'generic description', - 'extension_types': ['platform_app'], - 'name': 'cookies', - 'channel': 'stable' - }, - ] - - test_file_system = TestFileSystem({ - 'api': { - '_api_features.json': json.dumps(_API_FEATURES), - '_manifest_features.json': '{}', - '_permission_features.json': json.dumps(_PERMISSION_FEATURES), - }, - 'docs': { - 'templates': { - 'json': { - 'manifest.json': '{}', - 'permissions.json': json.dumps(_PERMISSIONS_JSON), - }, - 'private': { - 'permissions': _PERMISSIONS_PARTIALS - }, - } - } - }, relative_to=CHROME_EXTENSIONS) - - permissions_data_source = PermissionsDataSource( - ServerInstance.ForTest(test_file_system), None) - - actual_extensions = permissions_data_source.get('declare_extensions') - actual_apps = permissions_data_source.get('declare_apps') - - # Normalise all test data. - # - Sort keys. Since the tests don't use OrderedDicts we can't make - # assertions about the order, which is unfortunate. Oh well. - # - Render all of the Handlerbar instances so that we can use ==. - # Motemplates don't implement __eq__, but they probably should. - for lst in (actual_apps, actual_extensions, - expected_apps, expected_extensions): - lst.sort(key=itemgetter('name')) - for mapping in lst: - for key, value in mapping.iteritems(): - if isinstance(value, Motemplate): - mapping[key] = value.Render().text - - self.assertEqual(expected_extensions, actual_extensions) - self.assertEqual(expected_apps, actual_apps) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/persistent_object_store_appengine.py b/chrome/common/extensions/docs/server2/persistent_object_store_appengine.py deleted file mode 100644 index a2d0d5c..0000000 --- a/chrome/common/extensions/docs/server2/persistent_object_store_appengine.py +++ /dev/null
@@ -1,49 +0,0 @@ -# Copyright 2013 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 google.appengine.ext.db as db - -from datastore_models import PersistentObjectStoreItem -from environment import IsDevServer -from future import All, Future -from object_store import ObjectStore - - -class PersistentObjectStoreAppengine(ObjectStore): - '''Stores or retrieves persistent data using the AppEngine Datastore API. - ''' - def __init__(self, namespace): - self._namespace = namespace - - def SetMulti(self, mapping): - entities = [PersistentObjectStoreItem.CreateItem( - self._namespace, key, value) - for key, value in mapping.iteritems()] - # Some entites may be None if they were too large to insert. Skip those. - rpcs = [db.put_async(entity for entity in entities if entity)] - # If running the dev server, the futures don't complete until the server is - # *quitting*. This is annoying. Flush now. - if IsDevServer(): - [rpc.wait() for rpc in rpcs] - return All(Future(callback=lambda: rpc.get_result()) for rpc in rpcs) - - def GetMulti(self, keys): - db_futures = dict((k, db.get_async( - PersistentObjectStoreItem.CreateKey(self._namespace, k))) - for k in keys) - def resolve(): - return dict((key, future.get_result().GetValue()) - for key, future in db_futures.iteritems() - if future.get_result() is not None) - return Future(callback=resolve) - - def DelMulti(self, keys): - futures = [] - for key in keys: - futures.append(db.delete_async( - PersistentObjectStoreItem.CreateKey(self._namespace, key))) - # If running the dev server, the futures don't complete until the server is - # *quitting*. This is annoying. Flush now. - if IsDevServer(): - [future.wait() for future in futures]
diff --git a/chrome/common/extensions/docs/server2/persistent_object_store_fake.py b/chrome/common/extensions/docs/server2/persistent_object_store_fake.py deleted file mode 100644 index 6d244ba..0000000 --- a/chrome/common/extensions/docs/server2/persistent_object_store_fake.py +++ /dev/null
@@ -1,48 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import cPickle -import logging - -from future import Future -from object_store import ObjectStore - - -class PersistentObjectStoreFake(ObjectStore): - '''Stores or retrieves data in memory. Not really persistent. - ''' - # Static storage shared across all fake object stores. - DATA = {} - - def __init__(self, namespace): - if namespace not in PersistentObjectStoreFake.DATA: - PersistentObjectStoreFake.DATA[namespace] = {} - self._data = PersistentObjectStoreFake.DATA[namespace] - - def SetMulti(self, mapping): - self._data.update(mapping) - return Future(value=True) - - def GetMulti(self, keys): - result = dict((key, self._data[key]) for key in keys if key in self._data) - return Future(value=result) - - def DelMulti(self, keys): - for key in keys: - del self._data[key] - - @classmethod - def LoadFromFile(cls, filename): - with open(filename, 'r') as f: - cls.DATA = cPickle.load(f) - for k, v in cls.DATA.iteritems(): - cls.DATA[k] = cPickle.loads(v) - logging.info('Loaded %s keys from %s.' % (len(cls.DATA), filename)) - - @classmethod - def SaveToFile(cls, filename): - data = dict((k, cPickle.dumps(v)) for k, v, in cls.DATA.iteritems()) - with open(filename, 'w') as f: - cPickle.dump(data, f) - logging.info('Saved %s keys to %s.' % (len(cls.DATA), filename))
diff --git a/chrome/common/extensions/docs/server2/persistent_object_store_test.py b/chrome/common/extensions/docs/server2/persistent_object_store_test.py deleted file mode 100755 index 73b7f1f..0000000 --- a/chrome/common/extensions/docs/server2/persistent_object_store_test.py +++ /dev/null
@@ -1,40 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 environment_wrappers import CreatePersistentObjectStore -import unittest - -class PersistentObjectStoreTest(unittest.TestCase): - '''Tests for PersistentObjectStore. These are all a bit contrived because - ultimately it comes down to our use of the appengine datastore API, and we - mock it out for tests anyway. Who knows whether it's correct. - ''' - def testPersistence(self): - # First object store. - object_store = CreatePersistentObjectStore('test') - object_store.Set('key', 'value') - self.assertEqual('value', object_store.Get('key').Get()) - # Other object store should have it too. - another_object_store = CreatePersistentObjectStore('test') - self.assertEqual('value', another_object_store.Get('key').Get()) - # Setting in the other store should set in both. - mapping = {'key2': 'value2', 'key3': 'value3'} - another_object_store.SetMulti(mapping) - self.assertEqual(mapping, object_store.GetMulti(mapping.keys()).Get()) - self.assertEqual(mapping, - another_object_store.GetMulti(mapping.keys()).Get()) - # And delete. - object_store.DelMulti(mapping.keys()) - self.assertEqual({}, object_store.GetMulti(mapping.keys()).Get()) - self.assertEqual({}, another_object_store.GetMulti(mapping.keys()).Get()) - - def testNamespaceIsolation(self): - object_store = CreatePersistentObjectStore('test') - another_object_store = CreatePersistentObjectStore('another') - object_store.Set('key', 'value') - self.assertEqual(None, another_object_store.Get('key').Get()) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/platform_bundle.py b/chrome/common/extensions/docs/server2/platform_bundle.py deleted file mode 100644 index 727abab..0000000 --- a/chrome/common/extensions/docs/server2/platform_bundle.py +++ /dev/null
@@ -1,132 +0,0 @@ -# Copyright 2014 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 api_categorizer import APICategorizer -from api_models import APIModels -from availability_finder import AvailabilityFinder -from empty_dir_file_system import EmptyDirFileSystem -from environment import IsDevServer -from features_bundle import FeaturesBundle -from future import All -from platform_util import GetPlatforms, PlatformToExtensionType -from reference_resolver import ReferenceResolver -from samples_model import SamplesModel -from future import Future -from schema_processor import SchemaProcessorFactory - - -class _PlatformData(object): - def __init__(self): - self.features_bundle = None - self.api_models = None - self.reference_resolver = None - self.availability_finder = None - self.api_categorizer = None - self.samples_model = None - - -class PlatformBundle(object): - '''Creates various objects for different platforms - ''' - def __init__(self, - branch_utility, - compiled_fs_factory, - host_fs_at_master, - host_file_system_iterator, - object_store_creator, - base_path): - self._branch_utility = branch_utility - self._compiled_fs_factory = compiled_fs_factory - self._host_fs_at_master = host_fs_at_master - self._host_file_system_iterator = host_file_system_iterator - self._object_store_creator = object_store_creator - self._base_path = base_path - self._platform_data = dict((p, _PlatformData()) for p in GetPlatforms()) - - def GetSamplesModel(self, platform): - if self._platform_data[platform].samples_model is None: - # Note: samples are super slow in the dev server because it doesn't - # support async fetch, so disable them. - if IsDevServer(): - extension_samples_fs = EmptyDirFileSystem() - app_samples_fs = EmptyDirFileSystem() - else: - extension_samples_fs = self._host_fs_at_master - # TODO(kalman): Re-enable the apps samples, see http://crbug.com/344097. - app_samples_fs = EmptyDirFileSystem() - self._platform_data[platform].samples_model = SamplesModel( - extension_samples_fs, - app_samples_fs, - self._compiled_fs_factory, - self.GetReferenceResolver(platform), - self._base_path, - platform) - return self._platform_data[platform].samples_model - - def GetFeaturesBundle(self, platform): - if self._platform_data[platform].features_bundle is None: - self._platform_data[platform].features_bundle = FeaturesBundle( - self._host_fs_at_master, - self._compiled_fs_factory, - self._object_store_creator, - platform) - return self._platform_data[platform].features_bundle - - def GetAPIModels(self, platform): - if self._platform_data[platform].api_models is None: - # TODO(danielj41): Filter APIModels data here rather than passing the - # platform. - self._platform_data[platform].api_models = APIModels( - self.GetFeaturesBundle(platform), - self._compiled_fs_factory, - self._host_fs_at_master, - self._object_store_creator, - platform, - SchemaProcessorFactory( - Future(callback=lambda: self.GetReferenceResolver(platform)), - Future(callback=lambda: self.GetAPIModels(platform)), - Future(callback=lambda: self.GetFeaturesBundle(platform)), - self._compiled_fs_factory, - self._host_fs_at_master)) - return self._platform_data[platform].api_models - - def GetReferenceResolver(self, platform): - if self._platform_data[platform].reference_resolver is None: - self._platform_data[platform].reference_resolver = ReferenceResolver( - self.GetAPIModels(platform), - self._object_store_creator.Create(ReferenceResolver, - category=platform)) - return self._platform_data[platform].reference_resolver - - def GetAvailabilityFinder(self, platform): - if self._platform_data[platform].availability_finder is None: - self._platform_data[platform].availability_finder = AvailabilityFinder( - self._branch_utility, - self._compiled_fs_factory, - self._host_file_system_iterator, - self._host_fs_at_master, - self._object_store_creator, - platform, - SchemaProcessorFactory( - Future(callback=lambda: self.GetReferenceResolver(platform)), - Future(callback=lambda: self.GetAPIModels(platform)), - Future(callback=lambda: self.GetFeaturesBundle(platform)), - self._compiled_fs_factory, - self._host_fs_at_master)) - return self._platform_data[platform].availability_finder - - def GetAPICategorizer(self, platform): - if self._platform_data[platform].api_categorizer is None: - self._platform_data[platform].api_categorizer = APICategorizer( - self._host_fs_at_master, - self._compiled_fs_factory, - platform) - return self._platform_data[platform].api_categorizer - - def Refresh(self): - return All(self.GetAPIModels(platform).Refresh() - for platform in self._platform_data.keys()) - - def GetIdentity(self): - return self._host_fs_at_master.GetIdentity()
diff --git a/chrome/common/extensions/docs/server2/platform_bundle_test.py b/chrome/common/extensions/docs/server2/platform_bundle_test.py deleted file mode 100755 index 6a8f4a6..0000000 --- a/chrome/common/extensions/docs/server2/platform_bundle_test.py +++ /dev/null
@@ -1,153 +0,0 @@ -#!/usr/bin/env python -# Copyright 2014 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 json -import unittest - -from extensions_paths import CHROME_API, CHROME_EXTENSIONS, EXTENSIONS_API -from mock_file_system import MockFileSystem -from server_instance import ServerInstance -from test_file_system import TestFileSystem -from test_util import ReadFile - - -_TEST_DATA = { - 'api': { - 'devtools': { - 'inspected_window.json': ReadFile( - CHROME_API, 'devtools', 'inspected_window.json'), - }, - '_api_features.json': json.dumps({ - 'alarms': {}, - 'app': {'extension_types': ['platform_app']}, - 'app.runtime': {'noparent': True}, - 'app.runtime.foo': {'extension_types': ['extension']}, - 'declarativeWebRequest': {'extension_types': ['extension']}, - 'devtools.inspectedWindow': {'extension_types': ['extension']}, - 'input': {'extension_types': 'all'}, - 'input.ime': {'extension_types': ['extension', 'platform_app']}, - 'storage': {'extension_types': ['extension']}, - }), - '_manifest_features.json': '{}', - '_permission_features.json': '{}', - 'alarms.idl': ReadFile(EXTENSIONS_API, 'alarms.idl'), - 'input_ime.json': ReadFile(CHROME_API, 'input_ime.json'), - 'page_action.json': ReadFile(CHROME_API, 'page_action.json'), - }, - 'docs': { - 'templates': { - 'json': { - 'manifest.json': '{}', - 'permissions.json': '{}', - } - } - }, -} - - -class PlatformBundleTest(unittest.TestCase): - def setUp(self): - mock_file_system = MockFileSystem( - TestFileSystem(_TEST_DATA, relative_to=CHROME_EXTENSIONS)) - server_instance = ServerInstance.ForTest(file_system=mock_file_system) - self._platform_bundle = server_instance.platform_bundle - - def testGetters(self): - self.assertEqual([ - 'alarms', - 'app.runtime', - 'declarativeWebRequest', - 'devtools.inspectedWindow', - 'input', - 'storage' - ], sorted(self._platform_bundle.GetAPIModels('extensions').GetNames())) - - self.assertEqual([ - 'alarms', - 'app', - 'app.runtime', - 'input' - ], sorted(self._platform_bundle.GetAPIModels('apps').GetNames())) - - self.assertEqual({ - 'app.runtime': { - 'name': 'app.runtime', - 'noparent': True, - 'channel': 'stable' - }, - 'declarativeWebRequest': { - 'name': 'declarativeWebRequest', - 'channel': 'stable', - 'extension_types': ['extension'], - }, - 'app.runtime.foo': { - 'name': 'app.runtime.foo', - 'channel': 'stable', - 'extension_types': ['extension'], - }, - 'storage': { - 'name': 'storage', - 'channel': 'stable', - 'extension_types': ['extension'], - }, - 'input.ime': { - 'name': 'input.ime', - 'channel': 'stable', - 'extension_types': ['extension', 'platform_app'], - }, - 'alarms': { - 'name': 'alarms', - 'channel': 'stable' - }, - 'input': { - 'name': 'input', - 'channel': 'stable', - 'extension_types': 'all' - }, - 'devtools.inspectedWindow': { - 'name': 'devtools.inspectedWindow', - 'channel': 'stable', - 'extension_types': ['extension'], - } - }, self._platform_bundle.GetFeaturesBundle( - 'extensions').GetAPIFeatures().Get()) - - self.assertEqual({ - 'app.runtime': { - 'name': 'app.runtime', - 'noparent': True, - 'channel': 'stable' - }, - 'input': { - 'name': 'input', - 'channel': 'stable', - 'extension_types': 'all' - }, - 'input.ime': { - 'name': 'input.ime', - 'channel': 'stable', - 'extension_types': ['extension', 'platform_app'], - }, - 'app': { - 'name': 'app', - 'channel': 'stable', - 'extension_types': ['platform_app'], - }, - 'alarms': { - 'name': 'alarms', - 'channel': 'stable' - } - }, self._platform_bundle.GetFeaturesBundle('apps').GetAPIFeatures().Get()) - - # Check that 'app' is resolved successfully in apps, but is None otherwise. - self.assertNotEqual( - None, - self._platform_bundle.GetReferenceResolver('apps').GetLink('app')) - self.assertEqual( - None, - self._platform_bundle.GetReferenceResolver('extensions').GetLink('app')) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/platform_util.py b/chrome/common/extensions/docs/server2/platform_util.py deleted file mode 100644 index 84e8c74..0000000 --- a/chrome/common/extensions/docs/server2/platform_util.py +++ /dev/null
@@ -1,38 +0,0 @@ -# Copyright 2014 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 path_util import AssertIsValid - - -_EXTENSION_TYPES = {'extensions': 'extension', 'apps': 'platform_app'} - - -def GetPlatforms(): - return ('apps', 'extensions') - - -def GetExtensionTypes(): - return ('platform_app', 'extension') - - -def ExtractPlatformFromURL(url): - '''Returns 'apps' or 'extensions' depending on the URL. - ''' - AssertIsValid(url) - platform = url.split('/', 1)[0] - if platform not in GetPlatforms(): - return None - return platform - - -def PluralToSingular(platform): - '''Converts 'apps' to 'app' and 'extensions' to 'extension'. - ''' - assert platform in GetPlatforms(), platform - return platform[:-1] - - -def PlatformToExtensionType(platform): - assert platform in GetPlatforms(), platform - return _EXTENSION_TYPES[platform]
diff --git a/chrome/common/extensions/docs/server2/platform_util_test.py b/chrome/common/extensions/docs/server2/platform_util_test.py deleted file mode 100755 index 95378dd1..0000000 --- a/chrome/common/extensions/docs/server2/platform_util_test.py +++ /dev/null
@@ -1,40 +0,0 @@ -#!/usr/bin/env python -# Copyright 2014 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 unittest - -from platform_util import (GetPlatforms, - GetExtensionTypes, - ExtractPlatformFromURL, - PluralToSingular, - PlatformToExtensionType) - - -class PlatformBundleUtilityTest(unittest.TestCase): - def testGetPlatforms(self): - self.assertEqual(('apps', 'extensions'), GetPlatforms()) - - def testGetExtensionTypes(self): - self.assertEqual(('platform_app', 'extension'), GetExtensionTypes()) - - def testExtractPlatformFromURL(self): - self.assertEqual('apps', ExtractPlatformFromURL('apps/something')) - self.assertEqual('apps', ExtractPlatformFromURL('apps')) - self.assertEqual('extensions', ExtractPlatformFromURL('extensions/a/b')) - self.assertTrue(ExtractPlatformFromURL('a/b') is None) - self.assertTrue(ExtractPlatformFromURL('app') is None) - - def testPluralToSingular(self): - self.assertEqual('app', PluralToSingular('apps')) - self.assertEqual('extension', PluralToSingular('extensions')) - self.assertRaises(AssertionError, PluralToSingular, 'ab') - - def testPlatformToExtensionType(self): - self.assertEqual('platform_app', PlatformToExtensionType('apps')) - self.assertEqual('extension', PlatformToExtensionType('extensions')) - self.assertRaises(AssertionError, PlatformToExtensionType, 'ab') - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/preview.py b/chrome/common/extensions/docs/server2/preview.py deleted file mode 100755 index e19e13e..0000000 --- a/chrome/common/extensions/docs/server2/preview.py +++ /dev/null
@@ -1,135 +0,0 @@ -#!/usr/bin/env python -# 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. - -# This helps you preview the apps and extensions docs. -# -# ./preview.py --help -# -# There are two modes: server- and render- mode. The default is server, in which -# a webserver is started on a port (default 8000). Navigating to paths on -# http://localhost:8000, for example -# -# http://localhost:8000/extensions/tabs.html -# -# will render the documentation for the extension tabs API. -# -# On the other hand, render mode statically renders docs to stdout. Use this -# to save the output (more convenient than needing to save the page in a -# browser), handy when uploading the docs somewhere (e.g. for a review), -# and for profiling the server. For example, -# -# ./preview.py -r extensions/tabs.html -# -# will output the documentation for the tabs API on stdout and exit immediately. - -# NOTE: RUN THIS FIRST. Or all third_party imports will fail. -import build_server -# Copy all the files necessary to run the server. These are cleaned up when the -# server quits. -build_server.main() - -from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer -import logging -import optparse -import posixpath -import time - -from local_renderer import LocalRenderer - -class _RequestHandler(BaseHTTPRequestHandler): - '''A HTTPRequestHandler that outputs the docs page generated by Handler. - ''' - def do_GET(self): - # Sanitize path to guarantee that it stays within the server. - if not posixpath.abspath(self.path.lstrip('/')).startswith( - posixpath.abspath('')): - return - - # Rewrite paths that would otherwise be served from app.yaml. - self.path = { - '/robots.txt': '../../server2/robots.txt', - '/favicon.ico': '../../server2/chrome-32.ico', - '/apple-touch-icon-precomposed.png': '../../server2/chrome-128.png' - }.get(self.path, self.path) - response = LocalRenderer.Render(self.path, headers=dict(self.headers)) - self.protocol_version = 'HTTP/1.1' - self.send_response(response.status) - for k, v in response.headers.iteritems(): - self.send_header(k, v) - self.end_headers() - self.wfile.write(response.content.ToString()) - -if __name__ == '__main__': - parser = optparse.OptionParser( - description='Runs a server to preview the extension documentation.', - usage='usage: %prog [option]...') - parser.add_option('-a', '--address', default='127.0.0.1', - help='the local interface address to bind the server to') - parser.add_option('-p', '--port', default='8000', - help='port to run the server on') - parser.add_option('-r', '--render', default='', - help='statically render a page and print to stdout rather than starting ' - 'the server, e.g. apps/storage.html. The path may optionally end ' - 'with #n where n is the number of times to render the page before ' - 'printing it, e.g. apps/storage.html#50, to use for profiling.') - parser.add_option('-s', '--stat', - help='Print profile stats at the end of the run using the given ' - 'profiling option (like "tottime"). -t is ignored if this is set.') - parser.add_option('-t', '--time', action='store_true', - help='Print the time taken rendering rather than the result.') - - (opts, argv) = parser.parse_args() - - if opts.render: - if opts.render.find('#') >= 0: - (path, iterations) = opts.render.rsplit('#', 1) - extra_iterations = int(iterations) - 1 - else: - path = opts.render - extra_iterations = 0 - - if opts.stat: - import cProfile, pstats, StringIO - pr = cProfile.Profile() - pr.enable() - elif opts.time: - start_time = time.time() - - response = LocalRenderer.Render(path) - if response.status != 200: - print('Error status: %s' % response.status) - exit(1) - - for _ in range(extra_iterations): - LocalRenderer.Render(path) - - if opts.stat: - pr.disable() - s = StringIO.StringIO() - pstats.Stats(pr, stream=s).sort_stats(opts.stat).print_stats() - print(s.getvalue()) - elif opts.time: - print('Took %s seconds' % (time.time() - start_time)) - else: - print(response.content.ToString()) - exit() - - print('Starting previewserver on port %s' % opts.port) - print('') - print('The extension documentation can be found at:') - print('') - print(' http://localhost:%s/extensions/' % opts.port) - print('') - print('The apps documentation can be found at:') - print('') - print(' http://localhost:%s/apps/' % opts.port) - print('') - - logging.getLogger().setLevel(logging.INFO) - server = HTTPServer((opts.address, int(opts.port)), _RequestHandler) - try: - server.serve_forever() - finally: - server.socket.close()
diff --git a/chrome/common/extensions/docs/server2/redirector.py b/chrome/common/extensions/docs/server2/redirector.py deleted file mode 100644 index cb14603..0000000 --- a/chrome/common/extensions/docs/server2/redirector.py +++ /dev/null
@@ -1,112 +0,0 @@ -# Copyright 2013 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 posixpath -from urlparse import urlsplit - -from file_system import FileNotFoundError -from future import All -from path_util import Segment, Join, SplitParent - -class Redirector(object): - def __init__(self, compiled_fs_factory, file_system): - self._file_system = file_system - self._cache = compiled_fs_factory.ForJson(file_system) - - def Redirect(self, host, path): - ''' Check if a path should be redirected, first according to host - redirection rules, then from rules in redirects.json files. - - Returns the path that should be redirected to, or None if no redirection - should occur. - ''' - return self._RedirectOldHosts(host, path) or self._RedirectFromConfig(path) - - def _RedirectFromConfig(self, url): - ''' Look up redirects.json file in the directory hierarchy of |url|. - Directory-level redirects occur first, followed by the specific file - redirects. Returns the URL to the redirect, if any exist, or None. - ''' - dirname, filename = posixpath.split(url) - redirected_dirname = self._RedirectDirectory(dirname) - - # Set up default return value. - default_redirect = None - if redirected_dirname != dirname: - default_redirect = posixpath.normpath(Join(redirected_dirname, filename)) - - try: - rules = self._cache.GetFromFile( - posixpath.normpath(Join(redirected_dirname, - 'redirects.json'))).Get() - except FileNotFoundError: - return default_redirect - - redirect = rules.get(filename) - if redirect is None: - return default_redirect - if (redirect.startswith('/') or - urlsplit(redirect).scheme in ('http', 'https')): - return redirect - - return posixpath.normpath(Join(redirected_dirname, redirect)) - - def _RedirectDirectory(self, real_url): - ''' Returns the final redirected directory after all directory hops. - If there is a circular redirection, it skips the redirection that would - cause the infinite loop. - If no redirection rule is matched, the base directory is returned. - ''' - seen_redirects = set() - - def lookup_redirect(url): - sub_url = url - - for sub_url, _ in Segment(url): - for base, filename in Segment(sub_url): - try: - redirects = self._cache.GetFromFile(posixpath.normpath( - posixpath.join(base, 'redirects.json'))).Get() - except FileNotFoundError: - continue - - redirect = redirects.get(posixpath.join(filename, '...')) - - if redirect is None: - continue - - redirect = Join(base, redirect.rstrip('...')) - - # Avoid infinite redirection loops by breaking if seen before. - if redirect in seen_redirects: - break - seen_redirects.add(redirect) - return lookup_redirect( - Join(redirect, posixpath.relpath(url, sub_url))) - return url - - return lookup_redirect(real_url) - - def _RedirectOldHosts(self, host, path): - ''' Redirect paths from the old code.google.com to the new - developer.chrome.com, retaining elements like the channel and https, if - used. - ''' - if host != 'code.google.com': - return None - - path = path.split('/') - if path and path[0] == 'chrome': - path.pop(0) - - return 'https://developer.chrome.com/' + posixpath.join(*path) - - def Refresh(self): - ''' Load files during a cron run. - ''' - futures = [] - for root, dirs, files in self._file_system.Walk(''): - if 'redirects.json' in files: - futures.append(self._cache.GetFromFile(Join(root, 'redirects.json'))) - return All(futures)
diff --git a/chrome/common/extensions/docs/server2/redirector_test.py b/chrome/common/extensions/docs/server2/redirector_test.py deleted file mode 100755 index ede89d5..0000000 --- a/chrome/common/extensions/docs/server2/redirector_test.py +++ /dev/null
@@ -1,265 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 json -import unittest - -from compiled_file_system import CompiledFileSystem -from object_store_creator import ObjectStoreCreator -from redirector import Redirector -from test_file_system import TestFileSystem -from third_party.json_schema_compiler.json_parse import Parse - -HOST = 'localhost/' - -file_system = TestFileSystem({ - 'redirects.json': json.dumps({ - 'foo/...': 'apps/...', - '': '/index.html', - 'home': 'index.html', - 'index.html': 'http://something.absolute.com/' - }), - 'apps': { - 'redirects.json': json.dumps({ - '': '../index.html', - 'index.html': 'about_apps.html', - 'foo.html': '/bar.html', - }) - }, - 'extensions': { - 'redirects.json': json.dumps({ - 'manifest': 'manifest.html', - 'tabs': 'tabs.html', - 'dev/...': '...', - 'a/very/long/dir/chain/...': 'short/...', - '_short/...': 'another/long/chain/...', - 'r1/...': 'r2/r1/...', - 'r2/r1/...': 'r3/...', - 'r3/...': 'r4/...', - 'r5/...': 'r6/...', - 'nofile1/...': 'nofile2/...', - 'noredirects1/...': 'noredirects2/...' - }), - 'manifest': { - 'redirects.json': json.dumps({ - '': '../manifest.html', - 'more-info': 'http://lmgtfy.com' - }), - }, - 'stable': { - 'redirects.json': json.dumps({ - 'tabs': 'tabs.html' - }), - 'manifest': { - 'redirects.json': json.dumps({ - 'storage': 'storage.html' - }) - }, - }, - 'dev': { - 'redirects.json': json.dumps({ - 'tabs': 'tabs.html', - 'manifest': 'manifest.html' - }), - 'manifest': { - 'redirects.json': json.dumps({ - 'storage': 'storage.html' - }) - } - }, - 'r4': { - 'redirects.json': json.dumps({ - 'manifest': 'manifest.html' - }) - }, - 'r6': { - 'redirects.json': json.dumps({ - '...': 'directory/...' - }), - 'directory': { - 'redirects.json': json.dumps({ - 'manifest': 'manifest.html' - }), - 'manifest': 'manifest.html' - } - }, - 'short': { - 'redirects.json': json.dumps({ - 'index': 'index.html' - }) - }, - 'another': { - 'long': { - 'chain': { - 'redirects.json': json.dumps({ - 'index': 'index.html' - }) - } - } - }, - 'nofile': { - 'redirects.json': json.dumps({ - }) - } - }, - 'priority': { - 'redirects.json': json.dumps({ - 'directory/...': 'GOOD/...' - }), - 'directory': { - 'redirects.json': json.dumps({ - '...': '../BAD/...' - }), - } - }, - 'relative_directory': { - 'redirects.json': json.dumps({ - '...': '../...' - }) - }, - 'infinite_redirect': { - 'redirects.json': json.dumps({ - '...': 'loop/...' - }), - 'loop': { - 'redirects.json': json.dumps({ - '...': './...' - }) - } - }, - 'parent_redirect': { - 'redirects.json': json.dumps({ - 'a/...': 'b/...' - }) - } -}) - -class RedirectorTest(unittest.TestCase): - def setUp(self): - self._redirector = Redirector( - CompiledFileSystem.Factory(ObjectStoreCreator.ForTest()), - file_system) - - def testExternalRedirection(self): - self.assertEqual( - 'http://something.absolute.com/', - self._redirector.Redirect(HOST, 'index.html')) - self.assertEqual( - 'http://lmgtfy.com', - self._redirector.Redirect(HOST, 'extensions/manifest/more-info')) - - def testAbsoluteRedirection(self): - self.assertEqual( - '/index.html', self._redirector.Redirect(HOST, '')) - self.assertEqual( - '/bar.html', self._redirector.Redirect(HOST, 'apps/foo.html')) - - def testRelativeRedirection(self): - self.assertEqual( - 'apps/about_apps.html', - self._redirector.Redirect(HOST, 'apps/index.html')) - self.assertEqual( - 'extensions/manifest.html', - self._redirector.Redirect(HOST, 'extensions/manifest/')) - self.assertEqual( - 'extensions/manifest.html', - self._redirector.Redirect(HOST, 'extensions/manifest')) - self.assertEqual( - 'index.html', self._redirector.Redirect(HOST, 'apps/')) - self.assertEqual( - 'index.html', self._redirector.Redirect(HOST, 'home')) - - def testNotFound(self): - self.assertEqual( - None, self._redirector.Redirect(HOST, 'not/a/real/path')) - self.assertEqual( - None, self._redirector.Redirect(HOST, 'public/apps/okay.html')) - - def testOldHosts(self): - self.assertEqual( - 'https://developer.chrome.com/', - self._redirector.Redirect('code.google.com', '')) - - def testRefresh(self): - self._redirector.Refresh().Get() - - expected_paths = set([ - 'redirects.json', - 'apps/redirects.json', - 'extensions/redirects.json', - 'extensions/manifest/redirects.json' - ]) - - for path in expected_paths: - self.assertEqual( - Parse(file_system.ReadSingle(path).Get()), - # Access the cache's object store to see what files were hit during - # the cron run. Returns strings parsed as JSON. - # TODO(jshumway): Make a non hack version of this check. - self._redirector._cache._file_object_store.Get( - path).Get().cache_data) - - def testDirectoryRedirection(self): - # Simple redirect. - self.assertEqual( - 'extensions/manifest.html', - self._redirector.Redirect(HOST, 'extensions/dev/manifest')) - - # Multiple hops with one file. - self.assertEqual( - 'extensions/r4/manifest.html', - self._redirector.Redirect(HOST, 'extensions/r1/manifest')) - - # Multiple hops w/ multiple redirection files. - self.assertEqual( - 'extensions/r6/directory/manifest.html', - self._redirector.Redirect(HOST, 'extensions/r5/manifest')) - - # Redirection from root directory redirector. - self.assertEqual( - 'apps/about_apps.html', - self._redirector.Redirect(HOST, 'foo/index.html')) - - # Short to long. - self.assertEqual( - 'extensions/short/index.html', - self._redirector.Redirect(HOST, 'extensions/a/very/long/dir/chain/index')) - - # Long to short. - self.assertEqual( - 'extensions/another/long/chain/index.html', - self._redirector.Redirect(HOST, 'extensions/_short/index')) - - # Directory redirection without a redirects.json in final directory. - self.assertEqual( - 'extensions/noredirects2/file', - self._redirector.Redirect(HOST, 'extensions/noredirects1/file')) - - # Directory redirection with redirects.json without rule for the filename. - self.assertEqual( - 'extensions/nofile2/file', - self._redirector.Redirect(HOST, 'extensions/nofile1/file')) - - # Relative directory path. - self.assertEqual( - 'index.html', - self._redirector.Redirect(HOST, 'relative_directory/home')) - - # Shallower directory redirects have priority. - self.assertEqual( - 'priority/GOOD/index', - self._redirector.Redirect(HOST, 'priority/directory/index')) - - # Don't infinitely redirect. - self.assertEqual('infinite_redirect/loop/index', - self._redirector.Redirect(HOST, 'infinite_redirect/index')) - - # If a parent directory is redirected, redirect children properly. - self.assertEqual('parent_redirect/b/c/index', - self._redirector.Redirect(HOST, 'parent_redirect/a/c/index')) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/reference_resolver.py b/chrome/common/extensions/docs/server2/reference_resolver.py deleted file mode 100644 index 0418dda..0000000 --- a/chrome/common/extensions/docs/server2/reference_resolver.py +++ /dev/null
@@ -1,184 +0,0 @@ -# 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 copy import copy -import logging -import re - -from file_system import FileNotFoundError -from third_party.json_schema_compiler.model import PropertyType - - -def _ClassifySchemaNode(node_name, node): - """Attempt to classify |node_name| in an API, determining whether |node_name| - refers to a type, function, event, or property in |api|. - """ - if '.' in node_name: - node_name, rest = node_name.split('.', 1) - else: - rest = None - for key, group in [('types', 'type'), - ('functions', 'method'), - ('events', 'event'), - ('properties', 'property')]: - for item in getattr(node, key, {}).itervalues(): - if item.simple_name == node_name: - if rest is not None: - ret = _ClassifySchemaNode(rest, item) - if ret is not None: - return ret - else: - return group, node_name - return None - - -def _MakeKey(namespace, ref): - key = '%s/%s' % (namespace, ref) - # AppEngine doesn't like keys > 500, but there will be some other stuff - # that goes into this key, so truncate it earlier. This shoudn't be - # happening anyway unless there's a bug, such as http://crbug.com/314102. - max_size = 256 - if len(key) > max_size: - logging.error('Key was >%s characters: %s' % (max_size, key)) - key = key[:max_size] - return key - - -class ReferenceResolver(object): - """Resolves references to $ref's by searching through the APIs to find the - correct node. See document_renderer.py for more information on $ref syntax. - """ - def __init__(self, api_models, object_store): - self._api_models = api_models - self._object_store = object_store - - def _GetRefLink(self, ref, api_list, namespace): - # Check nodes within each API the ref might refer to. - parts = ref.split('.') - for i in xrange(1, len(parts)): - api_name = '.'.join(parts[:i]) - if api_name not in api_list: - continue - try: - api_model = self._api_models.GetModel(api_name).Get() - except FileNotFoundError: - continue - name = '.'.join(parts[i:]) - # Attempt to find |name| in the API. - node_info = _ClassifySchemaNode(name, api_model) - if node_info is None: - # Check to see if this ref is a property. If it is, we want the ref to - # the underlying type the property is referencing. - for prop in api_model.properties.itervalues(): - # If the name of this property is in the ref text, replace the - # property with its type, and attempt to classify it. - if prop.name in name and prop.type_.property_type == PropertyType.REF: - name_as_prop_type = name.replace(prop.name, prop.type_.ref_type) - node_info = _ClassifySchemaNode(name_as_prop_type, api_model) - if node_info is not None: - name = name_as_prop_type - text = ref.replace(prop.name, prop.type_.ref_type) - break - if node_info is None: - continue - else: - text = ref - category, node_name = node_info - if namespace is not None and text.startswith('%s.' % namespace): - text = text[len('%s.' % namespace):] - api_model = self._api_models.GetModel(api_name).Get() - filename = api_model.documentation_options.get('documented_in', api_name) - return { - 'href': '%s#%s-%s' % (filename, category, name.replace('.', '-')), - 'text': text, - 'name': node_name - } - - # If it's not a reference to an API node it might just be a reference to an - # API. Check this last so that links within APIs take precedence over links - # to other APIs. - if ref in api_list: - return { - 'href': '%s' % ref, - 'text': ref, - 'name': ref - } - - return None - - def GetRefModel(self, ref, api_list): - """Tries to resolve |ref| from the namespaces given in api_list. If ref - is found in one of those namespaces, return a tuple (api_model, node_info), - where api_model is a model.Namespace class and node info is a tuple - (group, name) where group is one of 'type', 'method', 'event', 'property' - describing the type of the reference, and name is the name of the reference - without the namespace. - """ - # Check nodes within each API the ref might refer to. - parts = ref.split('.') - for i in xrange(1, len(parts)): - api_name = '.'.join(parts[:i]) - if api_name not in api_list: - continue - try: - api_model = self._api_models.GetModel(api_name).Get() - except FileNotFoundError: - continue - name = '.'.join(parts[i:]) - # Attempt to find |name| in the API. - node_info = _ClassifySchemaNode(name, api_model) - if node_info is None: - # Check to see if this ref is a property. If it is, we want the ref to - # the underlying type the property is referencing. - for prop in api_model.properties.itervalues(): - # If the name of this property is in the ref text, replace the - # property with its type, and attempt to classify it. - if prop.name in name and prop.type_.property_type == PropertyType.REF: - name_as_prop_type = name.replace(prop.name, prop.type_.ref_type) - node_info = _ClassifySchemaNode(name_as_prop_type, api_model) - if node_info is None: - continue - return api_model, node_info - return None, None - - def GetLink(self, ref, namespace=None, title=None): - """Resolve $ref |ref| in namespace |namespace| if not None, returning None - if it cannot be resolved. - """ - db_key = _MakeKey(namespace, ref) - link = self._object_store.Get(db_key).Get() - if link is None: - api_list = self._api_models.GetNames() - link = self._GetRefLink(ref, api_list, namespace) - if link is None and namespace is not None: - # Try to resolve the ref in the current namespace if there is one. - api_list = self._api_models.GetNames() - link = self._GetRefLink('%s.%s' % (namespace, ref), - api_list, - namespace) - if link is None: - return None - self._object_store.Set(db_key, link) - - if title is not None: - link = copy(link) - link['text'] = title - - return link - - def SafeGetLink(self, ref, namespace=None, title=None, path=None): - """Resolve $ref |ref| in namespace |namespace|, or globally if None. If it - cannot be resolved, pretend like it is a link to a type. - """ - ref_data = self.GetLink(ref, namespace=namespace, title=title) - if ref_data is not None: - return ref_data - logging.warning('Could not resolve $ref %s in namespace %s on %s.' % - (ref, namespace, path)) - type_name = ref.rsplit('.', 1)[-1] - return { - 'href': '#type-%s' % type_name, - 'text': title or ref, - 'name': ref - }
diff --git a/chrome/common/extensions/docs/server2/reference_resolver_test.py b/chrome/common/extensions/docs/server2/reference_resolver_test.py deleted file mode 100755 index 0e60f993..0000000 --- a/chrome/common/extensions/docs/server2/reference_resolver_test.py +++ /dev/null
@@ -1,394 +0,0 @@ -#!/usr/bin/env python -# 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. - -import os -import unittest - -from future import Future -from reference_resolver import ReferenceResolver -from test_object_store import TestObjectStore -from test_util import Server2Path -from third_party.json_schema_compiler.model import Namespace - - -_TEST_DATA = { - 'baz': { - 'namespace': 'baz', - 'description': '', - 'types': [ - { - 'id': 'baz_t1', - 'type': 'any', - }, - { - 'id': 'baz_t2', - 'type': 'any', - }, - { - 'id': 'baz_t3', - 'type': 'any', - } - ], - 'functions': [ - { - 'name': 'baz_f1', - 'type': 'function' - }, - { - 'name': 'baz_f2', - 'type': 'function' - }, - { - 'name': 'baz_f3', - 'type': 'function' - } - ], - 'events': [ - { - 'name': 'baz_e1', - 'type': 'function' - }, - { - 'name': 'baz_e2', - 'type': 'function' - }, - { - 'name': 'baz_e3', - 'type': 'function' - } - ], - 'properties': { - 'baz_p1': {'type': 'any'}, - 'baz_p2': {'type': 'any'}, - 'baz_p3': {'type': 'any'} - } - }, - 'bar.bon': { - 'namespace': 'bar.bon', - 'description': '', - 'types': [ - { - 'id': 'bar_bon_t1', - 'type': 'any', - }, - { - 'id': 'bar_bon_t2', - 'type': 'any', - }, - { - 'id': 'bar_bon_t3', - 'type': 'any', - } - ], - 'functions': [ - { - 'name': 'bar_bon_f1', - 'type': 'function' - }, - { - 'name': 'bar_bon_f2', - 'type': 'function' - }, - { - 'name': 'bar_bon_f3', - 'type': 'function' - } - ], - 'events': [ - { - 'name': 'bar_bon_e1', - 'type': 'function' - }, - { - 'name': 'bar_bon_e2', - 'type': 'function' - }, - { - 'name': 'bar_bon_e3', - 'type': 'function' - } - ], - 'properties': { - 'bar_bon_p1': {'type': 'any'}, - 'bar_bon_p2': {'type': 'any'}, - 'bar_bon_p3': {'type': 'any'} - } - }, - 'bar': { - 'namespace': 'bar', - 'description': '', - 'types': [ - { - 'id': 'bar_t1', - 'type': 'any', - 'properties': { - 'bar_t1_p1': { - 'type': 'any' - } - } - }, - { - 'id': 'bar_t2', - 'type': 'any', - 'properties': { - 'bar_t2_p1': { - 'type': 'any' - } - } - }, - { - 'id': 'bar_t3', - 'type': 'any', - }, - { - 'id': 'bon', - 'type': 'any' - } - ], - 'functions': [ - { - 'name': 'bar_f1', - 'type': 'function' - }, - { - 'name': 'bar_f2', - 'type': 'function' - }, - { - 'name': 'bar_f3', - 'type': 'function' - } - ], - 'events': [ - { - 'name': 'bar_e1', - 'type': 'function' - }, - { - 'name': 'bar_e2', - 'type': 'function' - }, - { - 'name': 'bar_e3', - 'type': 'function' - } - ], - 'properties': { - 'bar_p1': {'type': 'any'}, - 'bar_p2': {'type': 'any'}, - 'bar_p3': {'$ref': 'bar_t1'} - } - }, - 'foo': { - 'namespace': 'foo', - 'description': '', - 'types': [ - { - 'id': 'foo_t1', - 'type': 'any', - }, - { - 'id': 'foo_t2', - 'type': 'any', - }, - { - 'id': 'foo_t3', - 'type': 'any', - 'events': [ - { - 'name': 'foo_t3_e1', - 'type': 'function' - } - ] - } - ], - 'functions': [ - { - 'name': 'foo_f1', - 'type': 'function' - }, - { - 'name': 'foo_f2', - 'type': 'function' - }, - { - 'name': 'foo_f3', - 'type': 'function' - } - ], - 'events': [ - { - 'name': 'foo_e1', - 'type': 'function' - }, - { - 'name': 'foo_e2', - 'type': 'function' - }, - { - 'name': 'foo_e3', - 'type': 'function' - } - ], - 'properties': { - 'foo_p1': {'$ref': 'foo_t3'}, - 'foo_p2': {'type': 'any'}, - 'foo_p3': {'type': 'any'} - } - } -} - - -class _FakePlatformBundle(object): - def __init__(self): - self.platforms = ('apps', 'extensions') - - def GetAPIModels(self, platform): - if platform == 'apps': - return _FakeAPIModels(_TEST_DATA) - # Only includes some of the data in the 'extensions' APIModels. - # ReferenceResolver will have to look at other platforms to resolve 'foo'. - return _FakeAPIModels({ - 'bar': _TEST_DATA['bar'], - 'bar.bon': _TEST_DATA['bar.bon'], - 'baz': _TEST_DATA['baz'] - }) - - -class _FakeAPIModels(object): - def __init__(self, apis): - self._apis = apis - - def GetNames(self): - return self._apis.keys() - - def GetModel(self, name): - return Future(value=Namespace(self._apis[name], 'fake/path.json')) - - -class ReferenceResolverTest(unittest.TestCase): - def setUp(self): - self._base_path = Server2Path('test_data', 'test_json') - - def _ReadLocalFile(self, filename): - with open(os.path.join(self._base_path, filename), 'r') as f: - return f.read() - - def testGetLink(self): - apps_resolver = ReferenceResolver( - _FakePlatformBundle().GetAPIModels('apps'), - TestObjectStore('apps/test')) - extensions_resolver = ReferenceResolver( - _FakePlatformBundle().GetAPIModels('extensions'), - TestObjectStore('extensions/test')) - - self.assertEqual({ - 'href': 'foo', - 'text': 'foo', - 'name': 'foo' - }, apps_resolver.GetLink('foo', namespace='baz')) - self.assertEqual({ - 'href': 'foo#type-foo_t1', - 'text': 'foo.foo_t1', - 'name': 'foo_t1' - }, apps_resolver.GetLink('foo.foo_t1', namespace='baz')) - self.assertEqual({ - 'href': 'baz#event-baz_e1', - 'text': 'baz_e1', - 'name': 'baz_e1' - }, apps_resolver.GetLink('baz.baz_e1', namespace='baz')) - self.assertEqual({ - 'href': 'baz#event-baz_e1', - 'text': 'baz_e1', - 'name': 'baz_e1' - }, apps_resolver.GetLink('baz_e1', namespace='baz')) - self.assertEqual({ - 'href': 'foo#method-foo_f1', - 'text': 'foo.foo_f1', - 'name': 'foo_f1' - }, apps_resolver.GetLink('foo.foo_f1', namespace='baz')) - self.assertEqual({ - 'href': 'foo#property-foo_p3', - 'text': 'foo.foo_p3', - 'name': 'foo_p3' - }, apps_resolver.GetLink('foo.foo_p3', namespace='baz')) - self.assertEqual({ - 'href': 'bar.bon#type-bar_bon_t3', - 'text': 'bar.bon.bar_bon_t3', - 'name': 'bar_bon_t3' - }, apps_resolver.GetLink('bar.bon.bar_bon_t3', namespace='baz')) - self.assertEqual({ - 'href': 'bar.bon#property-bar_bon_p3', - 'text': 'bar_bon_p3', - 'name': 'bar_bon_p3' - }, apps_resolver.GetLink('bar_bon_p3', namespace='bar.bon')) - self.assertEqual({ - 'href': 'bar.bon#property-bar_bon_p3', - 'text': 'bar_bon_p3', - 'name': 'bar_bon_p3' - }, apps_resolver.GetLink('bar.bon.bar_bon_p3', namespace='bar.bon')) - self.assertEqual({ - 'href': 'bar#event-bar_e2', - 'text': 'bar_e2', - 'name': 'bar_e2' - }, apps_resolver.GetLink('bar.bar_e2', namespace='bar')) - self.assertEqual({ - 'href': 'bar#type-bon', - 'text': 'bon', - 'name': 'bon' - }, apps_resolver.GetLink('bar.bon', namespace='bar')) - self.assertEqual({ - 'href': 'foo#event-foo_t3-foo_t3_e1', - 'text': 'foo_t3.foo_t3_e1', - 'name': 'foo_t3_e1' - }, apps_resolver.GetLink('foo_t3.foo_t3_e1', namespace='foo')) - self.assertEqual({ - 'href': 'foo#event-foo_t3-foo_t3_e1', - 'text': 'foo_t3.foo_t3_e1', - 'name': 'foo_t3_e1' - }, apps_resolver.GetLink('foo.foo_t3.foo_t3_e1', namespace='foo')) - self.assertEqual({ - 'href': 'foo#event-foo_t3-foo_t3_e1', - 'text': 'foo_t3.foo_t3_e1', - 'name': 'foo_t3_e1' - }, apps_resolver.GetLink('foo.foo_p1.foo_t3_e1', namespace='foo')) - self.assertEqual({ - 'href': 'bar#property-bar_t1-bar_t1_p1', - 'text': 'bar.bar_t1.bar_t1_p1', - 'name': 'bar_t1_p1' - }, apps_resolver.GetLink('bar.bar_p3.bar_t1_p1', namespace='foo')) - # Test extensions_resolver. - self.assertEqual({ - 'href': 'bar#property-bar_t1-bar_t1_p1', - 'text': 'bar.bar_t1.bar_t1_p1', - 'name': 'bar_t1_p1' - }, extensions_resolver.GetLink('bar.bar_p3.bar_t1_p1', namespace='foo')) - self.assertEqual({ - 'href': 'bar#property-bar_t1-bar_t1_p1', - 'text': 'bar_t1.bar_t1_p1', - 'name': 'bar_t1_p1' - }, apps_resolver.GetLink('bar_p3.bar_t1_p1', namespace='bar')) - self.assertEqual( - None, - apps_resolver.GetLink('bar.bar_p3.bar_t2_p1', namespace='bar')) - self.assertEqual( - None, - apps_resolver.GetLink('bar.bon.bar_e3', namespace='bar')) - self.assertEqual( - None, - apps_resolver.GetLink('bar_p3', namespace='baz.bon')) - self.assertEqual( - None, - apps_resolver.GetLink('falafel.faf', namespace='a')) - self.assertEqual( - None, - apps_resolver.GetLink('bar_p3', namespace='foo')) - # Exists in apps but not extensions. - self.assertEqual( - None, - extensions_resolver.GetLink('foo.foo_p3', namespace='baz')) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/render_refresher.py b/chrome/common/extensions/docs/server2/render_refresher.py deleted file mode 100644 index bbad6eaf..0000000 --- a/chrome/common/extensions/docs/server2/render_refresher.py +++ /dev/null
@@ -1,94 +0,0 @@ -# Copyright 2014 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 logging -import posixpath - -from custom_logger import CustomLogger -from extensions_paths import EXAMPLES -from file_system_util import CreateURLsFromPaths -from future import All, Future -from render_servlet import RenderServlet -from special_paths import SITE_VERIFICATION_FILE -from timer import Timer - - -_SUPPORTED_TARGETS = { - 'examples': (EXAMPLES, 'extensions/examples'), -} - - -_log = CustomLogger('render_refresher') - - -class _SingletonRenderServletDelegate(RenderServlet.Delegate): - def __init__(self, server_instance): - self._server_instance = server_instance - - def CreateServerInstance(self): - return self._server_instance - - -def _RequestEachItem(title, items, request_callback): - '''Runs a task |request_callback| named |title| for each item in |items|. - |request_callback| must take an item and return a servlet response. - Returns true if every item was successfully run, false if any return a - non-200 response or raise an exception. - ''' - _log.info('%s: starting', title) - success_count, failure_count = 0, 0 - timer = Timer() - try: - for i, item in enumerate(items): - def error_message(detail): - return '%s: error rendering %s (%s of %s): %s' % ( - title, item, i + 1, len(items), detail) - try: - response = request_callback(item) - if response.status == 200: - success_count += 1 - else: - _log.error(error_message('response status %s' % response.status)) - failure_count += 1 - except Exception as e: - _log.error(error_message(traceback.format_exc())) - failure_count += 1 - if IsDeadlineExceededError(e): raise - finally: - _log.info('%s: rendered %s of %s with %s failures in %s', - title, success_count, len(items), failure_count, - timer.Stop().FormatElapsed()) - return success_count == len(items) - - -class RenderRefresher(object): - '''Used to refresh any set of renderable resources. Currently only supports - assets related to extensions examples.''' - def __init__(self, server_instance, request): - self._server_instance = server_instance - self._request = request - - def Refresh(self): - def render(path): - request = Request(path, self._request.host, self._request.headers) - delegate = _SingletonRenderServletDelegate(self._server_instance) - return RenderServlet(request, delegate).Get() - - def request_files_in_dir(path, prefix='', strip_ext=None): - '''Requests every file found under |path| in this host file system, with - a request prefix of |prefix|. |strip_ext| is an optional list of file - extensions that should be stripped from paths before requesting. - ''' - def maybe_strip_ext(name): - if name == SITE_VERIFICATION_FILE or not strip_ext: - return name - base, ext = posixpath.splitext(name) - return base if ext in strip_ext else name - files = [maybe_strip_ext(name) - for name, _ in CreateURLsFromPaths(master_fs, path, prefix)] - return _RequestEachItem(path, files, render) - - return All(request_files_in_dir(dir, prefix=prefix) - for dir, prefix in _SUPPORTED_TARGETS.itervalues()) -
diff --git a/chrome/common/extensions/docs/server2/render_servlet.py b/chrome/common/extensions/docs/server2/render_servlet.py deleted file mode 100644 index 26caca2..0000000 --- a/chrome/common/extensions/docs/server2/render_servlet.py +++ /dev/null
@@ -1,151 +0,0 @@ -# Copyright 2013 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 hashlib -import logging -import posixpath -import traceback - -from branch_utility import BranchUtility -from environment import IsPreviewServer -from file_system import FileNotFoundError -from redirector import Redirector -from servlet import Servlet, Response -from special_paths import SITE_VERIFICATION_FILE -from third_party.motemplate import Motemplate - - -def _MakeHeaders(content_type, etag=None): - headers = { - # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1. - 'Cache-Control': 'public, max-age=0, no-cache', - 'Content-Type': content_type, - 'X-Frame-Options': 'sameorigin', - } - if etag is not None: - headers['ETag'] = etag - return headers - - -class RenderServlet(Servlet): - '''Servlet which renders templates. - ''' - - class Delegate(object): - def CreateServerInstance(self): - raise NotImplementedError(self.__class__) - - def __init__(self, request, delegate): - Servlet.__init__(self, request) - self._delegate = delegate - - def Get(self): - ''' Render the page for a request. - ''' - path = self._request.path.lstrip('/') - - # The server used to be partitioned based on Chrome channel, but it isn't - # anymore. Redirect from the old state. - channel_name, path = BranchUtility.SplitChannelNameFromPath(path) - if channel_name is not None: - return Response.Redirect('/' + path, permanent=True) - - server_instance = self._delegate.CreateServerInstance() - - try: - return self._GetSuccessResponse(path, server_instance) - except FileNotFoundError: - # Find the closest 404.html file and serve that, e.g. if the path is - # extensions/manifest/typo.html then first look for - # extensions/manifest/404.html, then extensions/404.html, then 404.html. - # - # Failing that just print 'Not Found' but that should preferrably never - # happen, because it would look really bad. - path_components = path.split('/') - for i in xrange(len(path_components) - 1, -1, -1): - try: - path_404 = posixpath.join(*(path_components[0:i] + ['404'])) - response = self._GetSuccessResponse(path_404, server_instance) - if response.status != 200: - continue - return Response.NotFound(response.content.ToString(), - headers=response.headers) - except FileNotFoundError: continue - logging.warning('No 404.html found in %s' % path) - return Response.NotFound('Not Found', headers=_MakeHeaders('text/plain')) - - def _GetSuccessResponse(self, request_path, server_instance): - '''Returns the Response from trying to render |path| with - |server_instance|. If |path| isn't found then a FileNotFoundError will be - raised, such that the only responses that will be returned from this method - are Ok and Redirect. - ''' - content_provider, serve_from, path = ( - server_instance.content_providers.GetByServeFrom(request_path)) - assert content_provider, 'No ContentProvider found for %s' % path - - redirect = Redirector( - server_instance.compiled_fs_factory, - content_provider.file_system).Redirect(self._request.host, path) - if redirect is not None: - # Absolute redirects stay absolute, relative redirects are relative to - # |serve_from|; all redirects eventually need to be *served* as absolute. - if not redirect.startswith(('/', 'http://', 'https://')): - redirect = '/' + posixpath.join(serve_from, redirect) - return Response.Redirect(redirect, permanent=False) - - canonical_path = content_provider.GetCanonicalPath(path) - if canonical_path != path: - redirect_path = posixpath.join(serve_from, canonical_path) - return Response.Redirect('/' + redirect_path, permanent=False) - - if request_path.endswith('/'): - # Directory request hasn't been redirected by now. Default behaviour is - # to redirect as though it were a file. - return Response.Redirect('/' + request_path.rstrip('/'), - permanent=False) - - content_and_type = content_provider.GetContentAndType(path).Get() - if not content_and_type.content: - logging.error('%s had empty content' % path) - - content = content_and_type.content - if isinstance(content, Motemplate): - template_content, template_warnings = ( - server_instance.template_renderer.Render(content, self._request)) - # HACK: the site verification file (google2ed...) doesn't have a title. - content, doc_warnings = server_instance.document_renderer.Render( - template_content, - path, - render_title=path != SITE_VERIFICATION_FILE) - warnings = template_warnings + doc_warnings - if warnings: - sep = '\n - ' - logging.warning('Rendering %s:%s%s' % (path, sep, sep.join(warnings))) - # Content was dynamic. The new etag is a hash of the content. - etag = None - elif content_and_type.version is not None: - # Content was static. The new etag is the version of the content. Hash it - # to make sure it's valid. - etag = '"%s"' % hashlib.md5(str(content_and_type.version)).hexdigest() - else: - # Sometimes non-dynamic content does not have a version, for example - # .zip files. The new etag is a hash of the content. - etag = None - - content_type = content_and_type.content_type - if isinstance(content, unicode): - content = content.encode('utf-8') - content_type += '; charset=utf-8' - - if etag is None: - # Note: we're using md5 as a convenient and fast-enough way to identify - # content. It's not intended to be cryptographic in any way, and this - # is *not* what etags is for. That's what SSL is for, this is unrelated. - etag = '"%s"' % hashlib.md5(content).hexdigest() - - headers = _MakeHeaders(content_type, etag=etag) - if etag == self._request.headers.get('If-None-Match'): - return Response.NotModified('Not Modified', headers=headers) - return Response.Ok(content, headers=headers)
diff --git a/chrome/common/extensions/docs/server2/render_servlet_test.py b/chrome/common/extensions/docs/server2/render_servlet_test.py deleted file mode 100755 index b4dcd38..0000000 --- a/chrome/common/extensions/docs/server2/render_servlet_test.py +++ /dev/null
@@ -1,158 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from extensions_paths import EXAMPLES, PUBLIC_TEMPLATES, STATIC_DOCS -from local_file_system import LocalFileSystem -from render_servlet import RenderServlet -from server_instance import ServerInstance -from servlet import Request, Response -from test_util import ReadFile - - -class _RenderServletDelegate(RenderServlet.Delegate): - def CreateServerInstance(self): - return ServerInstance.ForTest(LocalFileSystem.Create()) - - -class RenderServletTest(unittest.TestCase): - def _Render(self, path, headers=None, host=None): - return RenderServlet(Request.ForTest(path, headers=headers, host=host), - _RenderServletDelegate()).Get() - - def testExtensionAppRedirect(self): - self.assertEqual( - Response.Redirect('/apps/storage', permanent=False), - self._Render('storage')) - - def testChannelRedirect(self): - for channel in ('stable', 'beta', 'dev', 'master'): - self.assertEqual( - Response.Redirect('/extensions/storage', permanent=True), - self._Render('%s/extensions/storage' % channel)) - - def testOldHostsRedirect(self): - self.assertEqual( - Response.Redirect('https://developer.chrome.com/extensions', - permanent=False), - self._Render('/chrome/extensions', host='code.google.com')) - self.assertEqual( - Response.Redirect('https://developer.chrome.com/extensions', - permanent=False), - self._Render('/chrome/extensions', host='code.google.com')) - self.assertEqual( - Response.Redirect('https://developer.chrome.com/devtools/docs/network', - permanent=False), - self._Render('/chrome/devtools/docs/network', host='code.google.com')) - - def testNotFound(self): - def create_404_response(real_path): - real_404 = self._Render(real_path) - self.assertEqual(200, real_404.status) - real_404.status = 404 - return real_404 - - root_404 = create_404_response('404') - extensions_404 = create_404_response('extensions/404') - apps_404 = create_404_response('apps/404') - - self.assertEqual(root_404, self._Render('not_found')) - self.assertEqual(root_404, self._Render('not_found/not_found')) - - self.assertEqual(extensions_404, self._Render('extensions/not_found')) - self.assertEqual( - extensions_404, self._Render('extensions/manifest/not_found')) - self.assertEqual( - extensions_404, - self._Render('extensions/manifest/not_found/not_found')) - - self.assertEqual(apps_404, self._Render('apps/not_found')) - self.assertEqual(apps_404, self._Render('apps/manifest/not_found')) - self.assertEqual( - apps_404, self._Render('apps/manifest/not_found/not_found')) - - def testSampleFile(self): - sample_file = 'extensions/talking_alarm_clock/background.js' - response = self._Render('extensions/examples/%s' % sample_file) - self.assertEqual(200, response.status) - self.assertTrue(response.headers['Content-Type'] in ( - 'application/javascript; charset=utf-8', - 'application/x-javascript; charset=utf-8')) - self.assertEqual(ReadFile('%s%s' % (EXAMPLES, sample_file)), - response.content.ToString()) - - def testSampleZip(self): - sample_dir = 'extensions/talking_alarm_clock' - response = self._Render('extensions/examples/%s.zip' % sample_dir) - self.assertEqual(200, response.status) - self.assertEqual('application/zip', response.headers['Content-Type']) - - def testStaticFile(self): - static_file = 'css/out/site.css' - response = self._Render('static/%s' % static_file) - self.assertEqual(200, response.status) - self.assertEqual('text/css; charset=utf-8', - response.headers['Content-Type']) - self.assertEqual(ReadFile('%s%s' % (STATIC_DOCS, static_file)), - response.content.ToString()) - - def testHtmlTemplate(self): - html_file = 'extensions/storage' - response = self._Render(html_file) - self.assertEqual(200, response.status) - self.assertEqual('text/html; charset=utf-8', - response.headers.get('Content-Type')) - # Can't really test rendering all that well. - self.assertTrue(len(response.content) > - len(ReadFile('%s%s.html' % (PUBLIC_TEMPLATES, html_file)))) - - def testIndexRender(self): - self.assertEqual(200, self._Render('extensions').status) - self.assertEqual(('/extensions', False), - self._Render('extensions/index').GetRedirect()) - - def testOtherRedirectsJsonRedirect(self): - response = self._Render('apps/webview_tag') - self.assertEqual(('/apps/tags/webview', False), - response.GetRedirect()) - - def testDirectories(self): - # Directories should be redirected to a URL that doesn't end in a '/' - # whether or not that exists. - self.assertEqual(('/dir', False), self._Render('dir/').GetRedirect()) - - def testEtags(self): - def test_path(path, content_type): - # Render without etag. - response = self._Render(path) - self.assertEqual(200, response.status) - etag = response.headers.get('ETag') - self.assertTrue(etag is not None) - - # Render with an If-None-Match which doesn't match. - response = self._Render(path, headers={ - 'If-None-Match': '"fake etag"', - }) - self.assertEqual(200, response.status) - self.assertEqual(content_type, response.headers.get('Content-Type')) - self.assertEqual(etag, response.headers.get('ETag')) - - # Render with the correct matching If-None-Match. - response = self._Render(path, headers={ - 'If-None-Match': etag, - }) - self.assertEqual(304, response.status) - self.assertEqual('Not Modified', response.content.ToString()) - self.assertEqual(content_type, response.headers.get('Content-Type')) - self.assertEqual(etag, response.headers.get('ETag')) - - # Test with a static path and a dynamic path. - test_path('static/css/out/site.css', 'text/css; charset=utf-8') - test_path('extensions/storage', 'text/html; charset=utf-8') - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/rietveld_patcher.py b/chrome/common/extensions/docs/server2/rietveld_patcher.py deleted file mode 100644 index aa668f3..0000000 --- a/chrome/common/extensions/docs/server2/rietveld_patcher.py +++ /dev/null
@@ -1,142 +0,0 @@ -# Copyright 2013 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 json -import tarfile -from StringIO import StringIO - -from file_system import FileNotFoundError -from future import Future -from patcher import Patcher - - -_CHROMIUM_REPO_BASEURLS = [ - 'https://src.chromium.org/svn/trunk/src/', - 'http://src.chromium.org/svn/trunk/src/', - 'svn://svn.chromium.org/chrome/trunk/src', - 'https://chromium.googlesource.com/chromium/src.git@master', - 'http://git.chromium.org/chromium/src.git@master', -] - - -class RietveldPatcherError(Exception): - def __init__(self, message): - self.message = message - - -class RietveldPatcher(Patcher): - ''' Class to fetch resources from a patchset in Rietveld. - ''' - def __init__(self, - issue, - fetcher): - self._issue = issue - self._fetcher = fetcher - self._cache = None - - # In RietveldPatcher, the version is the latest patchset number. - def GetVersion(self): - try: - issue_json = json.loads(self._fetcher.Fetch( - 'api/%s' % self._issue).content) - except Exception as e: - raise RietveldPatcherError( - 'Failed to fetch information for issue %s.' % self._issue) - - if issue_json.get('closed'): - raise RietveldPatcherError('Issue %s has been closed.' % self._issue) - - patchsets = issue_json.get('patchsets') - if not isinstance(patchsets, list) or len(patchsets) == 0: - raise RietveldPatcherError('Cannot parse issue %s.' % self._issue) - - if not issue_json.get('base_url') in _CHROMIUM_REPO_BASEURLS: - raise RietveldPatcherError('Issue %s\'s base url (%s) is unknown.' % - (self._issue, issue_json.get('base_url'))) - - return str(patchsets[-1]) - - def GetPatchedFiles(self, version=None): - if version is None: - patchset = self.GetVersion() - else: - patchset = version - try: - patchset_json = json.loads(self._fetcher.Fetch( - 'api/%s/%s' % (self._issue, patchset)).content) - except Exception as e: - raise RietveldPatcherError( - 'Failed to fetch details for issue %s patchset %s.' % (self._issue, - patchset)) - - files = patchset_json.get('files') - if files is None or not isinstance(files, dict): - raise RietveldPatcherError('Failed to parse issue %s patchset %s.' % - (self._issue, patchset)) - - added = [] - deleted = [] - modified = [] - for f in files: - status = (files[f].get('status') or 'M') - # status can be 'A ' or 'A + ' - if 'A' in status: - added.append(f) - elif 'D' in status: - deleted.append(f) - elif 'M' in status: - modified.append(f) - else: - raise RietveldPatcherError('Unknown file status for file %s: "%s."' % - (key, status)) - - return (added, deleted, modified) - - def Apply(self, paths, file_system, version=None): - if version is None: - version = self.GetVersion() - - def apply_(tarball_result): - if tarball_result.status_code != 200: - raise RietveldPatcherError( - 'Failed to download tarball for issue %s patchset %s. Status: %s' % - (self._issue, version, tarball_result.status_code)) - - try: - tar = tarfile.open(fileobj=StringIO(tarball_result.content)) - except tarfile.TarError as e: - raise RietveldPatcherError( - 'Error loading tarball for issue %s patchset %s.' % (self._issue, - version)) - - value = {} - for path in paths: - tar_path = 'b/%s' % path - - patched_file = None - try: - patched_file = tar.extractfile(tar_path) - data = patched_file.read() - except tarfile.TarError as e: - # Show appropriate error message in the unlikely case that the tarball - # is corrupted. - raise RietveldPatcherError( - 'Error extracting tarball for issue %s patchset %s file %s.' % - (self._issue, version, tar_path)) - except KeyError as e: - raise FileNotFoundError( - 'File %s not found in the tarball for issue %s patchset %s' % - (tar_path, self._issue, version)) - finally: - if patched_file: - patched_file.close() - - value[path] = data - - return value - return self._fetcher.FetchAsync('tarball/%s/%s' % (self._issue, - version)).Then(apply_) - - def GetIdentity(self): - return self._issue
diff --git a/chrome/common/extensions/docs/server2/rietveld_patcher_test.py b/chrome/common/extensions/docs/server2/rietveld_patcher_test.py deleted file mode 100755 index e22bedbf..0000000 --- a/chrome/common/extensions/docs/server2/rietveld_patcher_test.py +++ /dev/null
@@ -1,86 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import posixpath -import sys -import unittest -from environment_wrappers import CreateUrlFetcher -from extensions_paths import ( - ARTICLES_TEMPLATES, CHROME_EXTENSIONS, DOCS, JSON_TEMPLATES, - PUBLIC_TEMPLATES) -from fake_fetchers import ConfigureFakeFetchers -from file_system import FileNotFoundError -from rietveld_patcher import RietveldPatcher -from test_util import Server2Path -import url_constants - - -def _PrefixWith(prefix, lst): - return [posixpath.join(prefix, item) for item in lst] - - -class RietveldPatcherTest(unittest.TestCase): - def setUp(self): - ConfigureFakeFetchers() - self._patcher = RietveldPatcher( - '14096030', - CreateUrlFetcher(url_constants.CODEREVIEW_SERVER)) - - def _ReadLocalFile(self, filename): - with open(Server2Path('test_data', - 'rietveld_patcher', - 'expected', - filename), 'r') as f: - return f.read() - - def _ApplySingle(self, path): - return self._patcher.Apply([path], None).Get()[path] - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetVersion(self): - self.assertEqual(self._patcher.GetVersion(), '22002') - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testGetPatchedFiles(self): - added, deleted, modified = self._patcher.GetPatchedFiles() - self.assertEqual( - sorted(added), - _PrefixWith(DOCS, ['examples/test', - 'templates/articles/test_foo.html', - 'templates/public/extensions/test_foo.html'])) - self.assertEqual(deleted, - ['%sextensions/runtime.html' % PUBLIC_TEMPLATES]) - self.assertEqual( - sorted(modified), - _PrefixWith(CHROME_EXTENSIONS, - ['api/test.json', - 'docs/templates/json/extensions_sidenav.json', - 'manifest.h'])) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testApply(self): - article_path = '%stest_foo.html' % ARTICLES_TEMPLATES - - # Apply to an added file. - self.assertEqual( - self._ReadLocalFile('test_foo.html'), - self._ApplySingle('%sextensions/test_foo.html' % PUBLIC_TEMPLATES)) - - # Apply to a modified file. - self.assertEqual( - self._ReadLocalFile('extensions_sidenav.json'), - self._ApplySingle('%sextensions_sidenav.json' % JSON_TEMPLATES)) - - # Applying to a deleted file doesn't throw exceptions. It just returns - # empty content. - # self.assertRaises(FileNotFoundError, self._ApplySingle, - # 'docs/templates/public/extensions/runtime.html') - - # Apply to an unknown file. - self.assertRaises(FileNotFoundError, self._ApplySingle, 'not_existing') - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/robots.txt b/chrome/common/extensions/docs/server2/robots.txt deleted file mode 100644 index d2f7182..0000000 --- a/chrome/common/extensions/docs/server2/robots.txt +++ /dev/null
@@ -1,3 +0,0 @@ -User-Agent: * -Disallow: /_cron/ -Disallow: /_patch/
diff --git a/chrome/common/extensions/docs/server2/run_all_unittests.py b/chrome/common/extensions/docs/server2/run_all_unittests.py deleted file mode 100755 index 2770ef5..0000000 --- a/chrome/common/extensions/docs/server2/run_all_unittests.py +++ /dev/null
@@ -1,90 +0,0 @@ -#!/usr/bin/env python -# 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. -'''Unit test suite that runs all Python based docserver tests.''' - -import os.path -import sys - -_SERVER_DIR = os.path.dirname(__file__) -_SRC_DIR = os.path.join(_SERVER_DIR, *((os.pardir, ) * 5)) -_TYP_DIR = os.path.join(_SRC_DIR, 'third_party', 'catapult', 'third_party', - 'typ') - -if not _TYP_DIR in sys.path: - sys.path.append(_TYP_DIR) - -import typ - -def resolve(*paths): - return [os.path.join(_SERVER_DIR, *(p.split('/'))) for p in paths] - - -# Run build_server so that files needed by tests are copied to the local -# third_party directory. -import build_server -build_server.main() - -sys.exit( - typ.main(tests=resolve( - 'api_categorizer_test.py', - 'api_data_source_test.py', - 'api_list_data_source_test.py', - 'api_models_test.py', - 'api_schema_graph_test.py', - 'app_yaml_helper_test.py', - 'availability_finder_test.py', - 'branch_utility_test.py', - 'cache_chain_object_store_test.py', - 'caching_file_system_test.py', - 'caching_rietveld_patcher_test.py', - 'chained_compiled_file_system_test.py', - 'chroot_file_system_test.py', - 'compiled_file_system_test.py', - 'content_provider_test.py', - 'content_providers_test.py', - 'directory_zipper_test.py', - 'docs_server_utils_test.py', - 'document_parser_test.py', - 'document_renderer_test.py', - 'environment_test.py', - 'features_bundle_test.py', - 'file_system_test.py', - 'future_test.py', - 'handler_test.py', - 'host_file_system_iterator_test.py', - 'host_file_system_provider_test.py', - 'instance_servlet_test.py', - 'integration_test.py', - 'jsc_view_test.py', - 'link_error_detector_test.py', - 'local_file_system_test.py', - 'manifest_data_source_test.py', - 'manifest_features_test.py', - 'mock_file_system_test.py', - 'mock_function_test.py', - 'object_store_creator_test.py', - 'owners_data_source_test.py', - 'patch_servlet_test.py', - 'patched_file_system_test.py', - 'path_canonicalizer_test.py', - 'path_util_test.py', - 'permissions_data_source_test.py', - 'persistent_object_store_test.py', - 'platform_bundle_test.py', - 'platform_util_test.py', - 'redirector_test.py', - 'reference_resolver_test.py', - 'rietveld_patcher_test.py', - 'samples_model_test.py', - 'schema_processor_test.py', - 'sidenav_data_source_test.py', - 'template_data_source_test.py', - 'template_renderer_test.py', - 'test_file_system_test.py', - 'test_object_store_test.py', - 'test_servlet_test.py', - 'whats_new_data_source_test.py', - # 'render_servlet_test.py', (This has a test failure currently). - )))
diff --git a/chrome/common/extensions/docs/server2/samples_data_source.py b/chrome/common/extensions/docs/server2/samples_data_source.py deleted file mode 100644 index a259861..0000000 --- a/chrome/common/extensions/docs/server2/samples_data_source.py +++ /dev/null
@@ -1,32 +0,0 @@ -# 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. - -import logging -import traceback - -from data_source import DataSource -from extensions_paths import EXAMPLES -from future import All, Future -from jsc_view import CreateSamplesView -from platform_util import GetPlatforms - - -class SamplesDataSource(DataSource): - '''Constructs a list of samples and their respective files and api calls. - ''' - def __init__(self, server_instance, request): - self._platform_bundle = server_instance.platform_bundle - self._request = request - - def _GetImpl(self, platform): - cache = self._platform_bundle.GetSamplesModel(platform).GetCache() - create_view = lambda samp_list: CreateSamplesView(samp_list, self._request) - return cache.GetFromFileListing('' if platform == 'apps' - else EXAMPLES).Then(create_view) - - def get(self, platform): - return self._GetImpl(platform).Get() - - def Refresh(self): - return All(self._GetImpl(platform) for platform in GetPlatforms())
diff --git a/chrome/common/extensions/docs/server2/samples_model.py b/chrome/common/extensions/docs/server2/samples_model.py deleted file mode 100644 index 94fd899..0000000 --- a/chrome/common/extensions/docs/server2/samples_model.py +++ /dev/null
@@ -1,181 +0,0 @@ -# Copyright 2014 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 json -import logging -import posixpath -import re - -from compiled_file_system import Cache -from extensions_paths import EXAMPLES -from samples_data_source import SamplesDataSource -import third_party.json_schema_compiler.json_comment_eater as json_comment_eater -import url_constants - - -_DEFAULT_ICON_PATH = 'images/sample-default-icon.png' - - -def _GetAPIItems(js_file): - chrome_pattern = r'chrome[\w.]+' - # Add API calls that appear normally, like "chrome.runtime.connect". - calls = set(re.findall(chrome_pattern, js_file)) - # Add API calls that have been assigned into variables, like - # "var storageArea = chrome.storage.sync; storageArea.get", which should - # be expanded like "chrome.storage.sync.get". - for match in re.finditer(r'var\s+(\w+)\s*=\s*(%s);' % chrome_pattern, - js_file): - var_name, api_prefix = match.groups() - for var_match in re.finditer(r'\b%s\.([\w.]+)\b' % re.escape(var_name), - js_file): - api_suffix, = var_match.groups() - calls.add('%s.%s' % (api_prefix, api_suffix)) - return calls - - -class SamplesModel(object): - def __init__(self, - extension_samples_file_system, - app_samples_file_system, - compiled_fs_factory, - reference_resolver, - base_path, - platform): - self._samples_fs = (extension_samples_file_system if - platform == 'extensions' else app_samples_file_system) - self._samples_cache = compiled_fs_factory.Create( - self._samples_fs, - self._MakeSamplesList, - SamplesDataSource, - category=platform) - self._text_cache = compiled_fs_factory.ForUnicode(self._samples_fs) - self._reference_resolver = reference_resolver - self._base_path = base_path - self._platform = platform - - def GetCache(self): - return self._samples_cache - - def FilterSamples(self, api_name): - '''Fetches and filters the list of samples for this platform, returning - a Future to the only the samples that use the API |api_name|. - ''' - def filter_samples(samples_list): - return [sample for sample in samples_list - if any(call['name'].startswith(api_name + '.') - for call in sample['api_calls'])] - def handle_error(_): - # TODO(rockot): This cache is probably not working as intended, since - # it can still lead to underlying filesystem (e.g. gitiles) access - # while processing live requests. Because this can fail, we at least - # trap and log exceptions to prevent 500s from being thrown. - logging.warning('Unable to get samples listing. Skipping.') - return [] - platform_for_samples = '' if self._platform == 'apps' else EXAMPLES - return (self._samples_cache.GetFromFileListing(platform_for_samples) - .Then(filter_samples, error_handler=handle_error)) - - def _GetDataFromManifest(self, path, file_system): - manifest = self._text_cache.GetFromFile(path + '/manifest.json').Get() - try: - manifest_json = json.loads(json_comment_eater.Nom(manifest)) - except ValueError as e: - logging.error('Error parsing manifest.json for %s: %s' % (path, e)) - return None - l10n_data = { - 'name': manifest_json.get('name', ''), - 'description': manifest_json.get('description', None), - 'icon': manifest_json.get('icons', {}).get('128', None), - 'default_locale': manifest_json.get('default_locale', None), - 'locales': {} - } - if not l10n_data['default_locale']: - return l10n_data - locales_path = path + '/_locales/' - locales_dir = file_system.ReadSingle(locales_path).Get() - if locales_dir: - def load_locale_json(path): - return (path, json.loads(self._text_cache.GetFromFile(path).Get())) - - try: - locales_json = [load_locale_json(locales_path + f + 'messages.json') - for f in locales_dir] - except ValueError as e: - logging.error('Error parsing locales files for %s: %s' % (path, e)) - else: - for path, json_ in locales_json: - l10n_data['locales'][path[len(locales_path):].split('/')[0]] = json_ - return l10n_data - - @Cache - def _MakeSamplesList(self, base_path, files): - samples_list = [] - for filename in sorted(files): - if filename.rsplit('/')[-1] != 'manifest.json': - continue - - # This is a little hacky, but it makes a sample page. - sample_path = filename.rsplit('/', 1)[-2] - sample_files = [path for path in files - if path.startswith(sample_path + '/')] - js_files = [path for path in sample_files if path.endswith('.js')] - js_contents = [self._text_cache.GetFromFile( - posixpath.join(base_path, js_file)).Get() - for js_file in js_files] - api_items = set() - for js in js_contents: - api_items.update(_GetAPIItems(js)) - - api_calls = [] - for item in sorted(api_items): - if len(item.split('.')) < 3: - continue - if item.endswith('.removeListener') or item.endswith('.hasListener'): - continue - if item.endswith('.addListener'): - item = item[:-len('.addListener')] - if item.startswith('chrome.'): - item = item[len('chrome.'):] - ref_data = self._reference_resolver.GetLink(item) - # TODO(kalman): What about references like chrome.storage.sync.get? - # That should link to either chrome.storage.sync or - # chrome.storage.StorageArea.get (or probably both). - # TODO(kalman): Filter out API-only references? This can happen when - # the API namespace is assigned to a variable, but it's very hard to - # to disambiguate. - if ref_data is None: - continue - api_calls.append({ - 'name': ref_data['text'], - 'link': ref_data['href'] - }) - - if self._platform == 'apps': - url = url_constants.GITHUB_BASE + '/' + sample_path - icon_base = url_constants.RAW_GITHUB_BASE + '/' + sample_path - download_url = url - else: - extension_sample_path = posixpath.join('examples', sample_path) - url = extension_sample_path - icon_base = extension_sample_path - download_url = extension_sample_path + '.zip' - - manifest_data = self._GetDataFromManifest( - posixpath.join(base_path, sample_path), - self._samples_fs) - if manifest_data['icon'] is None: - icon_path = posixpath.join( - self._base_path, 'static', _DEFAULT_ICON_PATH) - else: - icon_path = '%s/%s' % (icon_base, manifest_data['icon']) - manifest_data.update({ - 'icon': icon_path, - 'download_url': download_url, - 'url': url, - 'files': [f.replace(sample_path + '/', '') for f in sample_files], - 'api_calls': api_calls - }) - samples_list.append(manifest_data) - - return samples_list
diff --git a/chrome/common/extensions/docs/server2/samples_model_test.py b/chrome/common/extensions/docs/server2/samples_model_test.py deleted file mode 100755 index 2d3a6be0..0000000 --- a/chrome/common/extensions/docs/server2/samples_model_test.py +++ /dev/null
@@ -1,43 +0,0 @@ -#!/usr/bin/env python -# Copyright 2014 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 json -import os -import unittest - -from future import Future -from server_instance import ServerInstance -from test_file_system import TestFileSystem -from test_util import Server2Path - - -def _ReadLocalFile(filename): - base_path = Server2Path('test_data', 'samples_data_source') - with open(os.path.join(base_path, filename), 'r') as f: - return f.read() - - -class _FakeCache(object): - def __init__(self, obj): - self._cache = obj - - def GetFromFileListing(self, _): - return Future(value=self._cache) - - -class SamplesModelSourceTest(unittest.TestCase): - def setUp(self): - server_instance = ServerInstance.ForTest(file_system=TestFileSystem({})) - self._samples_model = server_instance.platform_bundle.GetSamplesModel( - 'apps') - self._samples_model._samples_cache = _FakeCache(json.loads(_ReadLocalFile( - 'samples.json'))) - - def testFilterSamples(self): - self.assertEquals(json.loads(_ReadLocalFile('expected.json')), - self._samples_model.FilterSamples('bobaloo').Get()) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/schema_processor.py b/chrome/common/extensions/docs/server2/schema_processor.py deleted file mode 100644 index f4acfd9..0000000 --- a/chrome/common/extensions/docs/server2/schema_processor.py +++ /dev/null
@@ -1,243 +0,0 @@ -# Copyright 2013 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 collections import defaultdict, Mapping -import traceback - -from third_party.json_schema_compiler import json_parse, idl_schema, idl_parser -from reference_resolver import ReferenceResolver -from compiled_file_system import CompiledFileSystem - -class SchemaProcessorForTest(object): - '''Fake SchemaProcessor class. Returns the original schema, without - processing. - ''' - def Process(self, path, file_data): - if path.endswith('.idl'): - idl = idl_schema.IDLSchema(idl_parser.IDLParser().ParseData(file_data)) - # Wrap the result in a list so that it behaves like JSON API data. - return [idl.process()[0]] - return json_parse.Parse(file_data) - -class SchemaProcessorFactoryForTest(object): - '''Returns a fake SchemaProcessor class to be used for testing. - ''' - def Create(self, retain_inlined_types): - return SchemaProcessorForTest() - - -class SchemaProcessorFactory(object): - '''Factory for creating the schema processing utility. - ''' - def __init__(self, - reference_resolver, - api_models, - features_bundle, - compiled_fs_factory, - file_system): - self._reference_resolver = reference_resolver - self._api_models = api_models - self._features_bundle = features_bundle - self._compiled_fs_factory = compiled_fs_factory - self._file_system = file_system - - def Create(self, retain_inlined_types): - return SchemaProcessor(self._reference_resolver.Get(), - self._api_models.Get(), - self._features_bundle.Get(), - self._compiled_fs_factory, - self._file_system, - retain_inlined_types) - - -class SchemaProcessor(object): - '''Helper for parsing the API schema. - ''' - def __init__(self, - reference_resolver, - api_models, - features_bundle, - compiled_fs_factory, - file_system, - retain_inlined_types): - self._reference_resolver = reference_resolver - self._api_models = api_models - self._features_bundle = features_bundle - self._retain_inlined_types = retain_inlined_types - self._compiled_file_system = compiled_fs_factory.Create( - file_system, self.Process, SchemaProcessor, category='json-cache') - self._api_stack = [] - - def _RemoveNoDocs(self, item): - '''Removes nodes that should not be rendered from an API schema. - ''' - if json_parse.IsDict(item): - if item.get('nodoc', False): - return True - for key, value in item.items(): - if self._RemoveNoDocs(value): - del item[key] - elif type(item) == list: - to_remove = [] - for i in item: - if self._RemoveNoDocs(i): - to_remove.append(i) - for i in to_remove: - item.remove(i) - return False - - - def _DetectInlineableTypes(self, schema): - '''Look for documents that are only referenced once and mark them as inline. - Actual inlining is done by _InlineDocs. - ''' - if not schema.get('types'): - return - - ignore = frozenset(('value', 'choices')) - refcounts = defaultdict(int) - # Use an explicit stack instead of recursion. - stack = [schema] - - while stack: - node = stack.pop() - if isinstance(node, list): - stack.extend(node) - elif isinstance(node, Mapping): - if '$ref' in node: - refcounts[node['$ref']] += 1 - stack.extend(v for k, v in node.iteritems() if k not in ignore) - - for type_ in schema['types']: - if not 'noinline_doc' in type_: - if refcounts[type_['id']] == 1: - type_['inline_doc'] = True - - - def _InlineDocs(self, schema): - '''Replace '$ref's that refer to inline_docs with the json for those docs. - If |retain_inlined_types| is False, then the inlined nodes are removed - from the schema. - ''' - inline_docs = {} - types_without_inline_doc = [] - internal_api = False - - api_features = self._features_bundle.GetAPIFeatures().Get() - # We don't want to inline the events API, as it's handled differently - # Also, the webviewTag API is handled differently, as it only exists - # for the purpose of documentation, it's not a true internal api - namespace = schema.get('namespace', '') - if namespace != 'events' and namespace != 'webviewTag': - internal_api = api_features.get(schema.get('namespace', ''), {}).get( - 'internal', False) - - api_refs = set() - # Gather refs to internal APIs - def gather_api_refs(node): - if isinstance(node, list): - for i in node: - gather_api_refs(i) - elif isinstance(node, Mapping): - ref = node.get('$ref') - if ref: - api_refs.add(ref) - for k, v in node.iteritems(): - gather_api_refs(v) - gather_api_refs(schema) - - if len(api_refs) > 0: - api_list = self._api_models.GetNames() - api_name = schema.get('namespace', '') - self._api_stack.append(api_name) - for api in self._api_stack: - if api in api_list: - api_list.remove(api) - for ref in api_refs: - model, node_info = self._reference_resolver.GetRefModel(ref, api_list) - if model and api_features.get(model.name, {}).get('internal', False): - category, name = node_info - for ref_schema in self._compiled_file_system.GetFromFile( - model.source_file).Get(): - if category == 'type': - for type_json in ref_schema.get('types'): - if type_json['id'] == name: - inline_docs[ref] = type_json - elif category == 'event': - for type_json in ref_schema.get('events'): - if type_json['name'] == name: - inline_docs[ref] = type_json - self._api_stack.remove(api_name) - - types = schema.get('types') - if types: - # Gather the types with inline_doc. - for type_ in types: - if type_.get('inline_doc'): - inline_docs[type_['id']] = type_ - if not self._retain_inlined_types: - for k in ('description', 'id', 'inline_doc'): - type_.pop(k, None) - elif internal_api: - inline_docs[type_['id']] = type_ - # For internal apis that are not inline_doc we want to retain them - # in the schema (i.e. same behaviour as remain_inlined_types) - types_without_inline_doc.append(type_) - else: - types_without_inline_doc.append(type_) - if not self._retain_inlined_types: - schema['types'] = types_without_inline_doc - - def apply_inline(node): - if isinstance(node, list): - for i in node: - apply_inline(i) - elif isinstance(node, Mapping): - ref = node.get('$ref') - if ref and ref in inline_docs: - del node['$ref'] - for k, v in inline_docs[ref].iteritems(): - if k not in node: - node[k] = v - for k, v in node.iteritems(): - apply_inline(v) - - apply_inline(schema) - - - def Process(self, path, file_data): - '''Parses |file_data| using a method determined by checking the - extension of the file at the given |path|. Then, trims 'nodoc' and if - |self.retain_inlined_types| is given and False, removes inlineable types - from the parsed schema data. - ''' - def trim_and_inline(schema, is_idl=False): - '''Modifies an API schema in place by removing nodes that shouldn't be - documented and inlining schema types that are only referenced once. - ''' - if self._RemoveNoDocs(schema): - # A return of True signifies that the entire schema should not be - # documented. Otherwise, only nodes that request 'nodoc' are removed. - return None - if is_idl: - self._DetectInlineableTypes(schema) - self._InlineDocs(schema) - return schema - - if path.endswith('.idl'): - idl = idl_schema.IDLSchema( - idl_parser.IDLParser().ParseData(file_data)) - # Wrap the result in a list so that it behaves like JSON API data. - return [trim_and_inline(idl.process()[0], is_idl=True)] - - try: - schemas = json_parse.Parse(file_data) - except: - raise ValueError('Cannot parse "%s" as JSON:\n%s' % - (path, traceback.format_exc())) - for schema in schemas: - # Schemas could consist of one API schema (data for a specific API file) - # or multiple (data from extension_api.json). - trim_and_inline(schema) - return schemas
diff --git a/chrome/common/extensions/docs/server2/schema_processor_test.py b/chrome/common/extensions/docs/server2/schema_processor_test.py deleted file mode 100755 index baa29925..0000000 --- a/chrome/common/extensions/docs/server2/schema_processor_test.py +++ /dev/null
@@ -1,254 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import unittest -from copy import deepcopy - -from schema_processor import SchemaProcessor -from future import Future -from object_store_creator import ObjectStoreCreator -from host_file_system_provider import HostFileSystemProvider -from compiled_file_system import CompiledFileSystem - -class _FakeReferenceResolver(): - def GetRefModel(self, ref, api_list): - return None, None - -class _FakeAPIModels(): - def GetNames(self): - return [] - -class _FakeFeaturesBundle(): - def GetAPIFeatures(self): - return Future(value={}) - -class SchemaUtilTest(unittest.TestCase): - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testRemoveNoDocs(self): - expected_nodoc = [ - { - 'name': 'B', - 'list': [ - { - 'name': 'B2' - } - ] - }, - { - 'name': 'D', - 'nodoc': False - }, - { - 'name': 'E', - 'items1': [ - { - 'name': 'E1', - 'items': [ - { - 'name': 'E1.3' - } - ] - }, - { - 'name': 'E2' - } - ] - } - ] - - nodoc_data = [ - { - 'name': 'A', - 'nodoc': True - }, - { - 'name': 'B', - 'list': [ - { - 'name': 'B1', - 'nodoc': True - }, - { - 'name': 'B2' - }, - { - 'name': 'B3', - 'nodoc': True - } - ] - }, - { - 'name': 'C', - 'nodoc': True - }, - { - 'name': 'D', - 'nodoc': False - }, - { - 'name': 'E', - 'dict': { - 'name': 'Ed', - 'nodoc': True - }, - 'items1': [ - { - 'name': 'E1', - 'items': [ - { - 'name': 'E1.1', - 'nodoc': True - }, - { - 'name': 'E1.2', - 'nodoc': True - }, - { - 'name': 'E1.3' - } - ] - }, - { - 'name': 'E2' - }, - { - 'name': 'E3', - 'nodoc': True - } - ] - } - ] - - object_store_creator = ObjectStoreCreator(start_empty=False) - host_file_system_provider = HostFileSystemProvider(object_store_creator) - schema_processor = SchemaProcessor(_FakeReferenceResolver(), - _FakeAPIModels(), - _FakeFeaturesBundle(), - CompiledFileSystem.Factory( - object_store_creator), - host_file_system_provider.GetMaster(), - True) - schema_processor._RemoveNoDocs(nodoc_data) - self.assertEquals(expected_nodoc, nodoc_data) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testInlineDocs(self): - schema = { - 'namespace': 'storage', - 'properties': { - 'key2': { - 'description': 'second key', - '$ref': 'Key' - }, - 'key1': { - 'description': 'first key', - '$ref': 'Key' - } - }, - 'types': [ - { - 'inline_doc': True, - 'type': 'string', - 'id': 'Key', # Should be inlined into both properties and be removed - # from types. - 'description': 'This is a key.', # This description should disappear. - 'marker': True # This should appear three times in the output. - }, - { - 'items': { - '$ref': 'Key' - }, - 'type': 'array', - 'id': 'KeyList', - 'description': 'A list of keys' - } - ] - } - - expected_schema = { - 'namespace': 'storage', - 'properties': { - 'key2': { - 'marker': True, - 'type': 'string', - 'description': 'second key' - }, - 'key1': { - 'marker': True, - 'type': 'string', - 'description': 'first key' - } - }, - 'types': [ - { - 'items': { - 'marker': True, - 'type': 'string' - }, - 'type': 'array', - 'id': 'KeyList', - 'description': 'A list of keys' - } - ] - } - - object_store_creator = ObjectStoreCreator(start_empty=False) - host_file_system_provider = HostFileSystemProvider(object_store_creator) - schema_processor = SchemaProcessor(_FakeReferenceResolver(), - _FakeAPIModels(), - _FakeFeaturesBundle(), - CompiledFileSystem.Factory( - object_store_creator), - host_file_system_provider.GetMaster(), - False) - inlined_schema = deepcopy(schema) - schema_processor._InlineDocs(inlined_schema) - self.assertEqual(expected_schema, inlined_schema) - - @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") - def testDetectInline(self): - schema = { - 'types': [ - { - 'id': 'Key', - 'items': { - '$ref': 'Value' - } - }, - { - 'id': 'Value', - 'marker': True - } - ] - } - - expected_schema = { - 'types': [ - { - 'id': 'Key', - 'items': { - 'marker': True, - } - } - ] - } - - object_store_creator = ObjectStoreCreator(start_empty=False) - host_file_system_provider = HostFileSystemProvider(object_store_creator) - schema_processor = SchemaProcessor(_FakeReferenceResolver(), - _FakeAPIModels(), - _FakeFeaturesBundle(), - CompiledFileSystem.Factory( - object_store_creator), - host_file_system_provider.GetMaster(), - False) - schema_processor._DetectInlineableTypes(schema) - schema_processor._InlineDocs(schema) - self.assertEqual(expected_schema, schema) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/server_instance.py b/chrome/common/extensions/docs/server2/server_instance.py deleted file mode 100644 index b5b0624..0000000 --- a/chrome/common/extensions/docs/server2/server_instance.py +++ /dev/null
@@ -1,126 +0,0 @@ -# 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 api_data_source import APIDataSource -from api_list_data_source import APIListDataSource -from branch_utility import BranchUtility -from compiled_file_system import CompiledFileSystem -from content_providers import ContentProviders -from document_renderer import DocumentRenderer -from empty_dir_file_system import EmptyDirFileSystem -from environment import IsDevServer -from gcs_file_system_provider import CloudStorageFileSystemProvider -from host_file_system_iterator import HostFileSystemIterator -from host_file_system_provider import HostFileSystemProvider -from object_store_creator import ObjectStoreCreator -from platform_bundle import PlatformBundle -from samples_data_source import SamplesDataSource -from table_of_contents_renderer import TableOfContentsRenderer -from template_renderer import TemplateRenderer -from test_branch_utility import TestBranchUtility -from test_object_store import TestObjectStore - - -class ServerInstance(object): - - def __init__(self, - object_store_creator, - compiled_fs_factory, - branch_utility, - host_file_system_provider, - gcs_file_system_provider, - base_path='/'): - ''' - |object_store_creator| - The ObjectStoreCreator used to create almost all caches. - |compiled_fs_factory| - Factory used to create CompiledFileSystems, a higher-level cache type - than ObjectStores. This can usually be derived from just - |object_store_creator| but under special circumstances a different - implementation needs to be passed in. - |branch_utility| - Has knowledge of Chrome branches, channels, and versions. - |host_file_system_provider| - Creates FileSystem instances which host the server at alternative - revisions. - |base_path| - The path which all HTML is generated relative to. Usually this is / - but some servlets need to override this. - ''' - self.object_store_creator = object_store_creator - - self.compiled_fs_factory = compiled_fs_factory - - self.host_file_system_provider = host_file_system_provider - host_fs_at_master = host_file_system_provider.GetMaster() - - self.gcs_file_system_provider = gcs_file_system_provider - - assert base_path.startswith('/') and base_path.endswith('/') - self.base_path = base_path - - self.host_file_system_iterator = HostFileSystemIterator( - host_file_system_provider, - branch_utility) - - self.platform_bundle = PlatformBundle( - branch_utility, - self.compiled_fs_factory, - host_fs_at_master, - self.host_file_system_iterator, - self.object_store_creator, - self.base_path) - - self.content_providers = ContentProviders( - object_store_creator, - self.compiled_fs_factory, - host_fs_at_master, - self.gcs_file_system_provider) - - # TODO(kalman): Move all the remaining DataSources into DataSourceRegistry, - # then factor out the DataSource creation into a factory method, so that - # the entire ServerInstance doesn't need to be passed in here. - self.template_renderer = TemplateRenderer(self) - - # TODO(kalman): It may be better for |document_renderer| to construct a - # TemplateDataSource itself rather than depending on template_renderer, but - # for that the above todo should be addressed. - self.document_renderer = DocumentRenderer( - TableOfContentsRenderer(host_fs_at_master, - compiled_fs_factory, - self.template_renderer), - self.platform_bundle) - - @staticmethod - def ForTest(file_system=None, file_system_provider=None, base_path='/'): - object_store_creator = ObjectStoreCreator.ForTest() - if file_system is None and file_system_provider is None: - raise ValueError('Either |file_system| or |file_system_provider| ' - 'must be specified') - if file_system and file_system_provider: - raise ValueError('Only one of |file_system| and |file_system_provider| ' - 'can be specified') - if file_system_provider is None: - file_system_provider = HostFileSystemProvider.ForTest( - file_system, - object_store_creator) - return ServerInstance(object_store_creator, - CompiledFileSystem.Factory(object_store_creator), - TestBranchUtility.CreateWithCannedData(), - file_system_provider, - CloudStorageFileSystemProvider(object_store_creator), - base_path=base_path) - - @staticmethod - def ForLocal(): - object_store_creator = ObjectStoreCreator(start_empty=False, - store_type=TestObjectStore) - host_file_system_provider = HostFileSystemProvider.ForLocal( - object_store_creator) - return ServerInstance( - object_store_creator, - CompiledFileSystem.Factory(object_store_creator), - BranchUtility.Create(object_store_creator), - host_file_system_provider, - CloudStorageFileSystemProvider(object_store_creator))
diff --git a/chrome/common/extensions/docs/server2/servlet.py b/chrome/common/extensions/docs/server2/servlet.py deleted file mode 100644 index c9ac5683..0000000 --- a/chrome/common/extensions/docs/server2/servlet.py +++ /dev/null
@@ -1,191 +0,0 @@ -# Copyright 2013 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. - - -class RequestHeaders(object): - '''A custom dictionary impementation for headers which ignores the case - of requests, since different HTTP libraries seem to mangle them. - ''' - def __init__(self, dict_): - if isinstance(dict_, RequestHeaders): - self._dict = dict_ - else: - self._dict = dict((k.lower(), v) for k, v in dict_.iteritems()) - - def get(self, key, default=None): - return self._dict.get(key.lower(), default) - - def __repr__(self): - return repr(self._dict) - - def __str__(self): - return repr(self._dict) - - -class Request(object): - '''Request data. - ''' - def __init__(self, path, host, headers, arguments={}): - self.path = path.lstrip('/') - assert not '/' in host, 'Host "%s" should not contain a slash' % host - self.host = host - self.headers = RequestHeaders(headers) - self.arguments = arguments - - @staticmethod - def ForTest(path, host=None, headers=None, arguments=None): - return Request(path, - host or 'developer.chrome.com', - headers or {}, - arguments or {}) - - def __repr__(self): - return 'Request(path=%s, host=%s, headers=%s)' % ( - self.path, self.host, self.headers) - - def __str__(self): - return repr(self) - -class _ContentBuilder(object): - '''Builds the response content. - ''' - def __init__(self): - self._buf = [] - - def Append(self, content): - if isinstance(content, unicode): - content = content.encode('utf-8', 'replace') - self._buf.append(content) - - def ToString(self): - self._Collapse() - return self._buf[0] - - def __str__(self): - return self.ToString() - - def __len__(self): - return len(self.ToString()) - - def _Collapse(self): - self._buf = [''.join(self._buf)] - -class Response(object): - '''The response from Get(). - ''' - def __init__(self, content=None, headers=None, status=None): - self.content = _ContentBuilder() - if content is not None: - self.content.Append(content) - self.headers = {} - if headers is not None: - self.headers.update(headers) - self.status = status - - @staticmethod - def Ok(content, headers=None): - '''Returns an OK (200) response. - ''' - return Response(content=content, headers=headers, status=200) - - @staticmethod - def Redirect(url, permanent=False): - '''Returns a redirect (301 or 302) response. - ''' - status = 301 if permanent else 302 - return Response(headers={'Location': url}, status=status) - - @staticmethod - def BadRequest(content, headers=None): - '''Returns a bad request (400) response. - ''' - return Response(content=content, headers=headers, status=400) - - @staticmethod - def Unauthorized(content, method, realm, headers={}): - '''Returns an unauthorized (401) response. - ''' - new_headers = headers.copy() - new_headers.update({ - 'WWW-Authentication': '%s realm="%s"' % (method, realm)}) - return Response(content=content, headers=headers, status=401) - - @staticmethod - def Forbidden(content, headers=None): - '''Returns an forbidden (403) response. - ''' - return Response(content=content, headers=headers, status=403) - - @staticmethod - def NotFound(content, headers=None): - '''Returns a not found (404) response. - ''' - return Response(content=content, headers=headers, status=404) - - @staticmethod - def NotModified(content, headers=None): - return Response(content=content, headers=headers, status=304) - - @staticmethod - def InternalError(content, headers=None): - '''Returns an internal error (500) response. - ''' - return Response(content=content, headers=headers, status=500) - - @staticmethod - def ThrottledError(content, headers=None): - '''Returns an HTTP throttle error (429) response. - ''' - return Response(content=content, headers=headers, status=429) - - def Append(self, content): - '''Appends |content| to the response content. - ''' - self.content.append(content) - - def AddHeader(self, key, value): - '''Adds a header to the response. - ''' - self.headers[key] = value - - def AddHeaders(self, headers): - '''Adds several headers to the response. - ''' - self.headers.update(headers) - - def SetStatus(self, status): - self.status = status - - def GetRedirect(self): - if self.headers.get('Location') is None: - return (None, None) - return (self.headers.get('Location'), self.status == 301) - - def IsNotFound(self): - return self.status == 404 - - def __eq__(self, other): - return (isinstance(other, self.__class__) and - str(other.content) == str(self.content) and - other.headers == self.headers and - other.status == self.status) - - def __ne__(self, other): - return not (self == other) - - def __repr__(self): - return 'Response(content=%s bytes, status=%s, headers=%s)' % ( - len(self.content), self.status, self.headers) - - def __str__(self): - return repr(self) - -class Servlet(object): - def __init__(self, request): - self._request = request - - def Get(self): - '''Returns a Response. - ''' - raise NotImplemented()
diff --git a/chrome/common/extensions/docs/server2/sidenav_data_source.py b/chrome/common/extensions/docs/server2/sidenav_data_source.py deleted file mode 100644 index fd06d40..0000000 --- a/chrome/common/extensions/docs/server2/sidenav_data_source.py +++ /dev/null
@@ -1,107 +0,0 @@ -# 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. - -import copy -import logging -import posixpath - -from compiled_file_system import Cache, SingleFile, Unicode -from data_source import DataSource -from extensions_paths import JSON_TEMPLATES -from future import Future -from third_party.json_schema_compiler.json_parse import Parse - - -def _AddLevels(items, level): - '''Add a 'level' key to each item in |items|. 'level' corresponds to how deep - in |items| an item is. |level| sets the starting depth. - ''' - for item in items: - item['level'] = level - if 'items' in item: - _AddLevels(item['items'], level + 1) - - -def _AddAnnotations(items, path, parent=None): - '''Add 'selected', 'child_selected' and 'related' properties to - |items| so that the sidenav can be expanded to show which menu item has - been selected and the related pages section can be drawn. 'related' - is added to all items with the same parent as the selected item. - If more than one item exactly matches the path, the deepest one is considered - 'selected'. A 'parent' property is added to the selected path. - - Returns True if an item was marked 'selected'. - ''' - for item in items: - if 'items' in item: - if _AddAnnotations(item['items'], path, item): - item['child_selected'] = True - return True - - if item.get('href', '') == path: - item['selected'] = True - if parent: - item['parent'] = { 'title': parent.get('title', None), - 'href': parent.get('href', None) } - - for sibling in items: - sibling['related'] = True - - return True - - return False - - -class SidenavDataSource(DataSource): - '''Provides templates with access to JSON files used to create the side - navigation bar. - ''' - def __init__(self, server_instance, request): - self._cache = server_instance.compiled_fs_factory.Create( - server_instance.host_file_system_provider.GetMaster(), - self._CreateSidenavDict, - SidenavDataSource) - self._server_instance = server_instance - self._request = request - - @Cache - @SingleFile - @Unicode - def _CreateSidenavDict(self, _, content): - items = Parse(content) - # Start at level 2, the top <ul> element is level 1. - _AddLevels(items, level=2) - self._QualifyHrefs(items) - return items - - def _QualifyHrefs(self, items): - '''Force hrefs in |items| to either be absolute (http://...) or qualified - (beginning with /, in which case it will be moved relative to |base_path|). - Relative hrefs emit a warning and should be updated. - ''' - for item in items: - if 'items' in item: - self._QualifyHrefs(item['items']) - - href = item.get('href') - if href is not None and not href.startswith(('http://', 'https://')): - if not href.startswith('/'): - logging.warn('Paths in sidenav must be qualified. %s is not.' % href) - else: - href = href.lstrip('/') - item['href'] = self._server_instance.base_path + href - - def Refresh(self): - return self._cache.GetFromFile( - posixpath.join(JSON_TEMPLATES, 'chrome_sidenav.json')) - - def get(self, key): - # TODO(mangini/kalman): Use |key| to decide which sidenav to use, - # which will require a more complex Refresh method. - sidenav = self._cache.GetFromFile( - posixpath.join(JSON_TEMPLATES, 'chrome_sidenav.json')).Get() - sidenav = copy.deepcopy(sidenav) - _AddAnnotations(sidenav, - self._server_instance.base_path + self._request.path) - return sidenav
diff --git a/chrome/common/extensions/docs/server2/sidenav_data_source_test.py b/chrome/common/extensions/docs/server2/sidenav_data_source_test.py deleted file mode 100755 index bf1eabd..0000000 --- a/chrome/common/extensions/docs/server2/sidenav_data_source_test.py +++ /dev/null
@@ -1,160 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 json -import unittest -import copy - -from extensions_paths import JSON_TEMPLATES -from mock_file_system import MockFileSystem -from server_instance import ServerInstance -from servlet import Request -from sidenav_data_source import SidenavDataSource, _AddLevels, _AddAnnotations -from test_file_system import TestFileSystem -from test_util import CaptureLogging - - -class SamplesDataSourceTest(unittest.TestCase): - def testAddLevels(self): - sidenav_json = [{ - 'title': 'H2', - 'items': [{ - 'title': 'H3', - 'items': [{ 'title': 'X1' }] - }] - }] - - expected = [{ - 'level': 1, - 'title': 'H2', - 'items': [{ - 'level': 2, - 'title': 'H3', - 'items': [{ 'level': 3, 'title': 'X1' }] - }] - }] - - _AddLevels(sidenav_json, 1) - self.assertEqual(expected, sidenav_json) - - def testAddAnnotations(self): - item1 = { 'href': '/H1.html' } - item2_1 = { 'href': '/H2_1.html' } - item2_2 = { 'href': '/H2_2.html' } - item2 = { 'href': '/H2.html', 'items': [item2_1, item2_2] } - - expected = [ item1, item2 ] - - sidenav_json = copy.deepcopy(expected) - - item2['child_selected'] = True - item2_1['selected'] = True - item2_1['related'] = True - item2_1['parent'] = { 'title': item2.get('title', None), - 'href': item2.get('href', None) } - - item2_2['related'] = True - - self.assertTrue(_AddAnnotations(sidenav_json, item2_1['href'])) - self.assertEqual(expected, sidenav_json) - - def testWithDifferentBasePath(self): - file_system = TestFileSystem({ - 'chrome_sidenav.json': json.dumps([ - { 'href': '/H1.html' }, - { 'href': '/H2.html' }, - { 'href': '/base/path/H2.html' }, - { 'href': 'https://qualified/X1.html' }, - { - 'href': 'H3.html', - 'items': [{ - 'href': 'H4.html' - }] - }, - ]) - }, relative_to=JSON_TEMPLATES) - - expected = [ - {'href': '/base/path/H1.html', 'level': 2, 'related': True}, - {'href': '/base/path/H2.html', 'level': 2, 'selected': True, 'related': True}, - {'href': '/base/path/base/path/H2.html', 'level': 2, 'related': True}, - {'href': 'https://qualified/X1.html', 'level': 2, 'related': True}, - {'items': [ - {'href': '/base/path/H4.html', 'level': 3} - ], - 'href': '/base/path/H3.html', 'level': 2, 'related': True} - ] - - server_instance = ServerInstance.ForTest(file_system, - base_path='/base/path/') - sidenav_data_source = SidenavDataSource(server_instance, - Request.ForTest('/H2.html')) - - log_output = CaptureLogging( - lambda: self.assertEqual(expected, sidenav_data_source.get('chrome'))) - self.assertEqual(2, len(log_output)) - - def testSidenavDataSource(self): - file_system = MockFileSystem(TestFileSystem({ - 'chrome_sidenav.json': json.dumps([{ - 'title': 'H1', - 'href': 'H1.html', - 'items': [{ - 'title': 'H2', - 'href': '/H2.html' - }] - }]) - }, relative_to=JSON_TEMPLATES)) - - expected = [{ - 'level': 2, - 'child_selected': True, - 'title': 'H1', - 'href': '/H1.html', - 'items': [{ - 'level': 3, - 'selected': True, - 'related': True, - 'title': 'H2', - 'href': '/H2.html', - 'parent': { 'href': '/H1.html', 'title': 'H1'} - }] - }] - - sidenav_data_source = SidenavDataSource( - ServerInstance.ForTest(file_system), Request.ForTest('/H2.html')) - self.assertTrue(*file_system.CheckAndReset()) - - log_output = CaptureLogging( - lambda: self.assertEqual(expected, sidenav_data_source.get('chrome'))) - - self.assertEqual(1, len(log_output)) - self.assertTrue( - log_output[0].msg.startswith('Paths in sidenav must be qualified.')) - - # Test that only a single file is read when creating the sidenav, so that - # we can be confident in the compiled_file_system.SingleFile annotation. - self.assertTrue(*file_system.CheckAndReset( - read_count=1, stat_count=1, read_resolve_count=1)) - - def testRefresh(self): - file_system = TestFileSystem({ - 'chrome_sidenav.json': '[{ "title": "H1" }]' - }, relative_to=JSON_TEMPLATES) - - # Ensure Refresh doesn't rely on request. - sidenav_data_source = SidenavDataSource( - ServerInstance.ForTest(file_system), request=None) - sidenav_data_source.Refresh().Get() - - # If Refresh fails, chrome_sidenav.json will not be cached, and the - # cache_data access will fail. - # TODO(jshumway): Make a non hack version of this check. - sidenav_data_source._cache._file_object_store.Get( - '%schrome_sidenav.json' % JSON_TEMPLATES).Get().cache_data - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/special_paths.py b/chrome/common/extensions/docs/server2/special_paths.py deleted file mode 100644 index 3c493440..0000000 --- a/chrome/common/extensions/docs/server2/special_paths.py +++ /dev/null
@@ -1,10 +0,0 @@ -# Copyright 2013 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. - -# Paths with special significance in the docserver. -# -# This is a bit of a hack, all path configuration should be moved into -# content_providers.json and the code which uses it updated. - -SITE_VERIFICATION_FILE = 'google2ed1af765c529f57.html'
diff --git a/chrome/common/extensions/docs/server2/start_dev_server.py b/chrome/common/extensions/docs/server2/start_dev_server.py deleted file mode 100755 index 687413d..0000000 --- a/chrome/common/extensions/docs/server2/start_dev_server.py +++ /dev/null
@@ -1,34 +0,0 @@ -#!/usr/bin/env python -# 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. - -import os -import signal -import shutil -import subprocess -import sys - -import build_server - -SERVER_PATH = sys.path[0] -SRC_PATH = os.path.join(SERVER_PATH, os.pardir, os.pardir, os.pardir, os.pardir, - os.pardir) -FILENAMES = ['app.yaml', 'appengine_main.py'] - -def CleanUp(signal, frame): - for filename in FILENAMES: - os.remove(os.path.join(SRC_PATH, filename)) - -if len(sys.argv) < 2: - print 'usage: start_dev_server.py <location of dev_appserver.py> [options]' - exit(0) - -signal.signal(signal.SIGINT, CleanUp) - -build_server.main() -for filename in FILENAMES: - shutil.copy(os.path.join(SERVER_PATH, filename), - os.path.join(SRC_PATH, filename)) -args = [sys.executable] + sys.argv[1:] + [SRC_PATH] -subprocess.call(args)
diff --git a/chrome/common/extensions/docs/server2/strings_data_source.py b/chrome/common/extensions/docs/server2/strings_data_source.py deleted file mode 100644 index 0742f0aa..0000000 --- a/chrome/common/extensions/docs/server2/strings_data_source.py +++ /dev/null
@@ -1,29 +0,0 @@ -# Copyright 2013 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 logging - -from extensions_paths import JSON_TEMPLATES -from data_source import DataSource - - -class StringsDataSource(DataSource): - '''Provides templates with access to a key to string mapping defined in a - JSON configuration file. - ''' - def __init__(self, server_instance, _): - self._cache = server_instance.compiled_fs_factory.ForJson( - server_instance.host_file_system_provider.GetMaster()) - - def _GetStringsData(self): - return self._cache.GetFromFile('%sstrings.json' % JSON_TEMPLATES) - - def Refresh(self): - return self._GetStringsData() - - def get(self, key): - string = self._GetStringsData().Get().get(key) - if string is None: - logging.warning('String "%s" not found' % key) - return string
diff --git a/chrome/common/extensions/docs/server2/table_of_contents_renderer.py b/chrome/common/extensions/docs/server2/table_of_contents_renderer.py deleted file mode 100644 index f80bcfcf..0000000 --- a/chrome/common/extensions/docs/server2/table_of_contents_renderer.py +++ /dev/null
@@ -1,56 +0,0 @@ -# Copyright 2013 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 extensions_paths import PRIVATE_TEMPLATES -from file_system import FileNotFoundError - - -class TableOfContentsRenderer(object): - '''Renders a table of contents pulled from a list of DocumentSections - returned from document_parser.ParseDocument. - - This performs key functionality of DocumentRenderer, pulled into its own - class for testability. - ''' - - def __init__(self, - host_file_system, - compiled_fs_factory, - template_renderer): - self._templates = compiled_fs_factory.ForTemplates(host_file_system) - self._template_renderer = template_renderer - - def Render(self, sections): - '''Renders a list of DocumentSections |sections| and returns a tuple - (text, warnings). - ''' - path = '%stable_of_contents.html' % PRIVATE_TEMPLATES - try: - table_of_contents_template = self._templates.GetFromFile(path).Get() - except FileNotFoundError: - return '', ['%s not found' % path] - - def make_toc_items(entries): - return [{ - 'attributes': [{'key': key, 'value': val} - for key, val in entry.attributes.iteritems() - if key != 'id'], - 'link': entry.attributes.get('id', ''), - 'subheadings': make_toc_items(entry.entries), - 'title': entry.name, - } for entry in entries] - - toc_items = [] - for section in sections: - items_for_section = make_toc_items(section.structure) - if toc_items and items_for_section: - items_for_section[0]['separator'] = True - toc_items.extend(items_for_section) - - return self._template_renderer.Render( - self._templates.GetFromFile( - '%stable_of_contents.html' % PRIVATE_TEMPLATES).Get(), - None, # no request - data_sources=('partials'), - additional_context={'items': toc_items})
diff --git a/chrome/common/extensions/docs/server2/template_data_source.py b/chrome/common/extensions/docs/server2/template_data_source.py deleted file mode 100644 index 0fdad5c..0000000 --- a/chrome/common/extensions/docs/server2/template_data_source.py +++ /dev/null
@@ -1,62 +0,0 @@ -# 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. - -import logging -import posixpath -import traceback - -from data_source import DataSource -from docs_server_utils import FormatKey -from extensions_paths import ( - ARTICLES_TEMPLATES, INTROS_TEMPLATES, PRIVATE_TEMPLATES) -from file_system import FileNotFoundError -from future import All -from path_util import AssertIsDirectory - - -class TemplateDataSource(DataSource): - '''Provides a DataSource interface for compiled templates. - ''' - def __init__(self, server_instance, request=None): - self._dir = type(self)._BASE - AssertIsDirectory(self._dir) - self._request = request - self._template_cache = server_instance.compiled_fs_factory.ForTemplates( - server_instance.host_file_system_provider.GetMaster()) - self._file_system = server_instance.host_file_system_provider.GetMaster() - - def get(self, path): - try: - return self._template_cache.GetFromFile('%s%s' % - (self._dir, FormatKey(path))).Get() - except FileNotFoundError: - logging.warning(traceback.format_exc()) - return None - - def Refresh(self): - futures = [] - for root, _, files in self._file_system.Walk(self._dir): - futures += [self._template_cache.GetFromFile( - posixpath.join(self._dir, root, FormatKey(f))) - for f in files - if posixpath.splitext(f)[1] == '.html'] - return All(futures) - - -class ArticleDataSource(TemplateDataSource): - '''Serves templates for Articles. - ''' - _BASE = ARTICLES_TEMPLATES - - -class IntroDataSource(TemplateDataSource): - '''Serves templates for Intros. - ''' - _BASE = INTROS_TEMPLATES - - -class PartialDataSource(TemplateDataSource): - '''Serves templates for private templates. - ''' - _BASE = PRIVATE_TEMPLATES
diff --git a/chrome/common/extensions/docs/server2/template_data_source_test.py b/chrome/common/extensions/docs/server2/template_data_source_test.py deleted file mode 100755 index fee3c9a1..0000000 --- a/chrome/common/extensions/docs/server2/template_data_source_test.py +++ /dev/null
@@ -1,67 +0,0 @@ -#!/usr/bin/env python -# 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. - -import json -import unittest - -from extensions_paths import SERVER2 -from server_instance import ServerInstance -from template_data_source import TemplateDataSource -from test_util import DisableLogging, ReadFile -from third_party.motemplate import Motemplate - -def _ReadFile(*path): - return ReadFile(SERVER2, 'test_data', 'template_data_source', *path) - -def _CreateTestDataSource(base_dir): - '''TemplateDataSource is not instantiated directly, rather, its methods - are invoked through a subclass of it, which has as its only data the - directory in which TemplateDataSource methods should act on. Thus, we test - TemplateDataSource indirectly through the TestDataSource class - ''' - return TestDataSource(ServerInstance.ForLocal(), - '%stest_data/template_data_source/%s/' % - (SERVER2, base_dir)) - - -class TestDataSource(TemplateDataSource): - '''Provides a subclass we can use to test the TemplateDataSource methods - ''' - def __init__(self, server_instance, base_dir): - type(self)._BASE = base_dir - TemplateDataSource.__init__(self, server_instance) - - -class TemplateDataSourceTest(unittest.TestCase): - - def testSimple(self): - test_data_source = _CreateTestDataSource('simple') - template_a1 = Motemplate(_ReadFile('simple', 'test1.html')) - context = [{}, {'templates': {}}] - self.assertEqual( - template_a1.Render(*context).text, - test_data_source.get('test1').Render(*context).text) - template_a2 = Motemplate(_ReadFile('simple', 'test2.html')) - self.assertEqual( - template_a2.Render(*context).text, - test_data_source.get('test2').Render(*context).text) - - @DisableLogging('warning') - def testNotFound(self): - test_data_source = _CreateTestDataSource('simple') - self.assertEqual(None, test_data_source.get('junk')) - - @DisableLogging('warning') - def testPartials(self): - test_data_source = _CreateTestDataSource('partials') - context = json.loads(_ReadFile('partials', 'input.json')) - self.assertEqual( - _ReadFile('partials', 'test_expected.html'), - test_data_source.get('test_tmpl').Render( - context, test_data_source).text) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/template_renderer.py b/chrome/common/extensions/docs/server2/template_renderer.py deleted file mode 100644 index 8408a90..0000000 --- a/chrome/common/extensions/docs/server2/template_renderer.py +++ /dev/null
@@ -1,43 +0,0 @@ -# Copyright 2013 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 data_source_registry import CreateDataSources -from third_party.motemplate import Motemplate -from url_constants import GITHUB_BASE, EXTENSIONS_SAMPLES - - -class TemplateRenderer(object): - '''Renders templates with the server's available data sources. - ''' - - def __init__(self, server_instance): - self._server_instance = server_instance - - def Render(self, - template, - request, - data_sources=None, - additional_context=None): - '''Renders |template| using |request|. - - Specify |data_sources| to only include the DataSources with the given names - when rendering the template. - - Specify |additional_context| to inject additional template context when - rendering the template. - ''' - assert isinstance(template, Motemplate), type(template) - render_context = CreateDataSources(self._server_instance, request) - if data_sources is not None: - render_context = dict((name, d) for name, d in render_context.iteritems() - if name in data_sources) - render_context.update({ - 'apps_samples_url': GITHUB_BASE, - 'base_path': self._server_instance.base_path, - 'extensions_samples_url': EXTENSIONS_SAMPLES, - 'static': self._server_instance.base_path + 'static', - }) - render_context.update(additional_context or {}) - render_data = template.Render(render_context) - return render_data.text, render_data.errors
diff --git a/chrome/common/extensions/docs/server2/template_renderer_test.py b/chrome/common/extensions/docs/server2/template_renderer_test.py deleted file mode 100755 index 386f3e7a..0000000 --- a/chrome/common/extensions/docs/server2/template_renderer_test.py +++ /dev/null
@@ -1,30 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from server_instance import ServerInstance -from third_party.motemplate import Motemplate - - -class TemplateRendererTest(unittest.TestCase): - '''Basic test for TemplateRenderer. - - When the DataSourceRegistry conversion is finished then we could do some more - meaningful tests by injecting a different set of DataSources. - ''' - - def setUp(self): - self._template_renderer = ServerInstance.ForLocal().template_renderer - - def testSimpleWiring(self): - template = Motemplate('hello {{?true}}{{strings.extension}}{{/}}') - text, warnings = self._template_renderer.Render(template, None) - self.assertEqual('hello extension', text) - self.assertEqual([], warnings) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/test_branch_utility.py b/chrome/common/extensions/docs/server2/test_branch_utility.py deleted file mode 100644 index da91f49..0000000 --- a/chrome/common/extensions/docs/server2/test_branch_utility.py +++ /dev/null
@@ -1,67 +0,0 @@ -# Copyright 2013 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 branch_utility import BranchUtility, ChannelInfo -from test_data.canned_data import (CANNED_BRANCHES, CANNED_CHANNELS) - - -class TestBranchUtility(object): - '''Mimics BranchUtility to return valid-ish data without needing omahaproxy - data. - ''' - - def __init__(self, versions, channels): - ''' Parameters: |version| is a mapping of versions to branches, and - |channels| is a mapping of channels to versions. - ''' - self._versions = versions - self._channels = channels - - @staticmethod - def CreateWithCannedData(): - '''Returns a TestBranchUtility that uses 'canned' test data pulled from - older branches of SVN data. - ''' - return TestBranchUtility(CANNED_BRANCHES, CANNED_CHANNELS) - - def GetAllChannelInfo(self): - return tuple(self.GetChannelInfo(channel) - for channel in BranchUtility.GetAllChannelNames()) - - def GetChannelInfo(self, channel): - version = self._channels[channel] - return ChannelInfo(channel, self.GetBranchForVersion(version), version) - - def GetStableChannelInfo(self, version): - return ChannelInfo('stable', self.GetBranchForVersion(version), version) - - def GetBranchForVersion(self, version): - return self._versions[version] - - def GetChannelForVersion(self, version): - if version <= self._channels['stable']: - return 'stable' - for channel in self._channels.iterkeys(): - if self._channels[channel] == version: - return channel - - def Older(self, channel_info): - versions = self._versions.keys() - index = versions.index(channel_info.version) - if index == len(versions) - 1: - return None - version = versions[index + 1] - return ChannelInfo(self.GetChannelForVersion(version), - self.GetBranchForVersion(version), - version) - - def Newer(self, channel_info): - versions = self._versions.keys() - index = versions.index(channel_info.version) - if not index: - return None - version = versions[index - 1] - return ChannelInfo(self.GetChannelForVersion(version), - self.GetBranchForVersion(version), - version)
diff --git a/chrome/common/extensions/docs/server2/test_data/README b/chrome/common/extensions/docs/server2/test_data/README deleted file mode 100644 index 96b5242..0000000 --- a/chrome/common/extensions/docs/server2/test_data/README +++ /dev/null
@@ -1,16 +0,0 @@ -Test JSON Files: - -branch_utility/first.json - Downloaded from: - http://omahaproxy.appspot.com/json - - Contains data on all current releases of Chrome, as found on the main - omahaproxy page (http://omahaproxy.appspot.com) in JSON format. - - File has been formatted for readability. - - -branch_utility/second.json - Downloaded on 5th June 2014 from: - http://10.omahaproxy-hrd.appspot.com/history.json?channel=dev&os=win&json=1 - - Contains a history of revision names for the dev channel on Windows. - - File has been formatted for readability. To view a readable version of the - data at the above URL, remove '&json=1'.
diff --git a/chrome/common/extensions/docs/server2/test_data/__init__.py b/chrome/common/extensions/docs/server2/test_data/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/__init__.py +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/api_data_source/__init__.py b/chrome/common/extensions/docs/server2/test_data/api_data_source/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/api_data_source/__init__.py +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/api_data_source/canned_master_fs.py b/chrome/common/extensions/docs/server2/test_data/api_data_source/canned_master_fs.py deleted file mode 100644 index cd2e49b..0000000 --- a/chrome/common/extensions/docs/server2/test_data/api_data_source/canned_master_fs.py +++ /dev/null
@@ -1,225 +0,0 @@ -# Copyright 2013 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 json - - -CANNED_MASTER_FS_DATA = { - 'api': { - '_api_features.json': json.dumps({ - 'add_rules_tester': { 'dependencies': ['permission:add_rules_tester'] }, - 'ref_test': { 'dependencies': ['permission:ref_test'] }, - 'tester': { - 'dependencies': ['permission:tester', 'manifest:tester'], - 'contexts': ['content_script'] - }, - 'tester.test1': {'contexts': ['content_script']}, - 'tester.test2': {} - }), - '_manifest_features.json': json.dumps({'tester': {}, 'ref_test': {}}), - '_permission_features.json': json.dumps({ - 'tester': {}, - 'ref_test': {}, - 'add_rules_tester': {} - }), - 'add_rules_tester.json': json.dumps([{ - 'namespace': 'add_rules_tester', - 'description': ('A test api with a couple of events which support or ' - 'do not support rules.'), - 'types': [], - 'functions': [], - 'events': [ - { - 'name': 'rules', - 'options': { - 'supportsRules': True, - 'conditions': [], - 'actions': [] - } - }, - { - 'name': 'noRules', - 'type': 'function', - 'description': 'Listeners can be registered with this event.', - 'parameters': [] - } - ] - }]), - 'events.json': json.dumps([{ - 'namespace': 'events', - 'description': 'These are events.', - 'types': [ - { - 'id': 'Event', - 'type': 'object', - 'description': 'An Event object.', - 'functions': [ - { - 'name': 'addListener', - 'type': 'function', - 'description': 'Adds a listener.' - } - ], - } - ] - }]), - 'tester.json': json.dumps([{ - 'namespace': 'tester', - 'description': 'a test api', - 'types': [ - { - 'id': 'TypeA', - 'type': 'object', - 'description': 'A cool thing.', - 'properties': { - 'a': {'nodoc': True, 'type': 'string', 'minimum': 0}, - 'b': {'type': 'array', 'optional': True, 'items': {'$ref': 'TypeA'}, - 'description': 'List of TypeA.'} - } - } - ], - 'functions': [ - { - 'name': 'get', - 'type': 'function', - 'description': 'Gets stuff.', - 'parameters': [ - { - 'name': 'a', - 'description': 'a param', - 'choices': [ - {'type': 'string'}, - {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1} - ] - }, - { - 'type': 'function', - 'name': 'callback', - 'parameters': [ - {'name': 'results', 'type': 'array', 'items': {'$ref': 'TypeA'}} - ] - } - ] - } - ], - 'events': [ - { - 'name': 'EventA', - 'type': 'function', - 'description': 'A cool event.', - 'parameters': [ - {'type': 'string', 'name': 'id'}, - { - '$ref': 'TypeA', - 'name': 'bookmark' - } - ] - } - ] - }]), - 'ref_test.json': json.dumps([{ - 'namespace': 'ref_test', - 'description': 'An API for testing ref\'s', - 'types': [ - { - 'id': 'type1', - 'type': 'string', - 'description': '$ref:type2' - }, - { - 'id': 'type2', - 'type': 'string', - 'description': 'A $ref:type3, or $ref:type2' - }, - { - 'id': 'type3', - 'type': 'string', - 'description': '$ref:other.type2 != $ref:ref_test.type2' - } - ], - 'events': [ - { - 'name': 'event1', - 'type': 'function', - 'description': 'We like $ref:type1', - 'parameters': [ - { - 'name': 'param1', - 'type': 'string' - } - ] - } - ], - 'properties': { - 'prop1': { - '$ref': 'type3' - } - }, - 'functions': [ - { - 'name': 'func1', - 'type': 'function', - 'parameters': [ - { - 'name': 'param1', - 'type': 'string' - } - ] - } - ] - }]) - }, - 'docs': { - 'templates': { - 'intros': { - 'test.html': '<h1>hi</h1>you<h2>first</h2><h3>inner</h3><h2>second</h2>' - }, - 'json': { - 'api_availabilities.json': json.dumps({ - 'master_api': { - 'channel': 'master' - }, - 'dev_api': { - 'channel': 'dev' - }, - 'beta_api': { - 'channel': 'beta' - }, - 'stable_api': { - 'channel': 'stable', - 'version': 20 - } - }), - 'intro_tables.json': json.dumps({ - 'tester': { - 'Permissions': [ - { - 'class': 'override', - 'text': '"tester"' - }, - { - 'text': 'is an API for testing things.' - } - ], - 'Learn More': [ - { - 'link': 'https://tester.test.com/welcome.html', - 'text': 'Welcome!' - } - ] - } - }), - 'manifest.json': '{}', - 'permissions.json': '{}' - }, - 'private': { - 'intro_tables': { - 'master_message.html': 'available on master', - 'stable_message.html': 'Since {{content.version}}.', - 'content_scripts.html': 'Content Scripts' - } - } - } - } -}
diff --git a/chrome/common/extensions/docs/server2/test_data/branch_utility/first.json b/chrome/common/extensions/docs/server2/test_data/branch_utility/first.json deleted file mode 100644 index 24f360a7..0000000 --- a/chrome/common/extensions/docs/server2/test_data/branch_utility/first.json +++ /dev/null
@@ -1,310 +0,0 @@ -[ - { - "os": "win", - "versions": [ - { - "base_trunk_revision": "r?", - "base_webkit_revision": "r?", - "branch_revision": "NA", - "channel": "canary", - "date": "00/00/00", - "prev_date": "05/13/13", - "prev_version": "32.0.1506.0", - "true_branch": null, - "v8_ver": null, - "version": "0.0.0.0", - "wk_ver": null - }, - { - "base_trunk_revision": 198577, - "base_webkit_revision": 149738, - "branch_revision": 199640, - "channel": "dev", - "date": "05/13/13", - "prev_date": "05/09/13", - "prev_version": "31.0.1612.1", - "true_branch": "1612", - "v8_ver": "3.18.5.2", - "version": "31.0.1612.2", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 190564, - "base_webkit_revision": 146842, - "branch_revision": 198567, - "channel": "beta", - "date": "05/08/13", - "prev_date": "05/01/13", - "prev_version": "30.0.1599.0", - "true_branch": "1599", - "v8_ver": "3.17.6.13", - "version": "30.0.1599.10", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 181864, - "base_webkit_revision": 142426, - "branch_revision": 193017, - "channel": "stable", - "date": "04/09/13", - "prev_date": "03/26/13", - "prev_version": "29.0.1547.18", - "true_branch": "1547", - "v8_ver": "3.16.14.11", - "version": "29.0.1547.22", - "wk_ver": "537.31" - } - ] - }, - { - "os": "ios", - "versions": [ - { - "base_trunk_revision": 190564, - "base_webkit_revision": 146842, - "branch_revision": 191487, - "channel": "beta", - "date": "05/10/13", - "prev_date": "05/07/13", - "prev_version": "30.0.1599.9", - "true_branch": "1599", - "v8_ver": "3.17.6.1", - "version": "30.0.1599.10", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 181864, - "base_webkit_revision": 142426, - "branch_revision": "NA", - "channel": "stable", - "date": "04/29/13", - "prev_date": "04/09/13", - "prev_version": "29.0.1547.50", - "true_branch": null, - "v8_ver": null, - "version": "29.0.1410.53", - "wk_ver": null - } - ] - }, - { - "os": "cros", - "versions": [ - { - "base_trunk_revision": 198577, - "base_webkit_revision": 149738, - "branch_revision": 199640, - "channel": "dev", - "date": "05/14/13", - "prev_date": "05/09/13", - "prev_version": "31.0.1612.4", - "true_branch": "1612", - "v8_ver": "3.18.5.2", - "version": "31.0.1612.11", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 190564, - "base_webkit_revision": 146842, - "branch_revision": 198939, - "channel": "beta", - "date": "05/10/13", - "prev_date": "05/03/13", - "prev_version": "30.0.1599.76", - "true_branch": "1599", - "v8_ver": "3.17.6.13", - "version": "30.0.1599.83", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 181864, - "base_webkit_revision": 142426, - "branch_revision": 191765, - "channel": "stable", - "date": "04/11/13", - "prev_date": "04/04/13", - "prev_version": "28.0.1547.173", - "true_branch": "1547", - "v8_ver": "3.16.14.11", - "version": "29.0.1547.57", - "wk_ver": "537.31" - } - ] - }, - { - "os": "cf", - "versions": [ - { - "base_trunk_revision": 198577, - "base_webkit_revision": 149738, - "branch_revision": 199640, - "channel": "dev", - "date": "05/13/13", - "prev_date": "05/09/13", - "prev_version": "31.0.1500.5", - "true_branch": "1612", - "v8_ver": "3.18.5.2", - "version": "31.0.1500.11", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 190564, - "base_webkit_revision": 146842, - "branch_revision": 198567, - "channel": "beta", - "date": "05/08/13", - "prev_date": "05/01/13", - "prev_version": "30.0.1453.73", - "true_branch": "1599", - "v8_ver": "3.17.6.13", - "version": "30.0.1453.81", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 181864, - "base_webkit_revision": 142426, - "branch_revision": 193017, - "channel": "stable", - "date": "04/09/13", - "prev_date": "03/26/13", - "prev_version": "29.0.1410.43", - "true_branch": "1547", - "v8_ver": "3.16.14.11", - "version": "29.0.1410.64", - "wk_ver": "537.31" - } - ] - }, - { - "os": "mac", - "versions": [ - { - "base_trunk_revision": 199851, - "base_webkit_revision": 150220, - "branch_revision": "NA", - "channel": "canary", - "date": "05/14/13", - "prev_date": "05/13/13", - "prev_version": "32.0.1506.0", - "true_branch": "trunk", - "v8_ver": "3.19.0.2", - "version": "32.0.1507.0", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 198577, - "base_webkit_revision": 149738, - "branch_revision": 199640, - "channel": "dev", - "date": "05/13/13", - "prev_date": "05/09/13", - "prev_version": "31.0.1500.6", - "true_branch": "1500", - "v8_ver": "3.18.5.2", - "version": "31.0.1500.11", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 190564, - "base_webkit_revision": 146842, - "branch_revision": 198567, - "channel": "beta", - "date": "05/08/13", - "prev_date": "05/01/13", - "prev_version": "30.0.1453.73", - "true_branch": "1453", - "v8_ver": "3.17.6.13", - "version": "30.0.1453.81", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 181864, - "base_webkit_revision": 142426, - "branch_revision": 193261, - "channel": "stable", - "date": "04/10/13", - "prev_date": "04/09/13", - "prev_version": "29.0.1410.63", - "true_branch": "1410", - "v8_ver": "3.16.14.11", - "version": "29.0.1410.65", - "wk_ver": "537.31" - } - ] - }, - { - "os": "linux", - "versions": [ - { - "base_trunk_revision": 198577, - "base_webkit_revision": 149738, - "branch_revision": 199640, - "channel": "dev", - "date": "05/14/13", - "prev_date": "05/09/13", - "prev_version": "31.0.1612.1", - "true_branch": "1612", - "v8_ver": "3.18.5.2", - "version": "31.0.1612.2", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 190564, - "base_webkit_revision": 146842, - "branch_revision": 198567, - "channel": "beta", - "date": "05/09/13", - "prev_date": "05/02/13", - "prev_version": "30.0.1599.0", - "true_branch": "1599", - "v8_ver": "3.17.6.13", - "version": "30.0.1599.10", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 181864, - "base_webkit_revision": 142426, - "branch_revision": 192696, - "channel": "stable", - "date": "04/09/13", - "prev_date": "03/26/13", - "prev_version": "29.0.1547.18", - "true_branch": "1547", - "v8_ver": "3.16.14.11", - "version": "29.0.1547.22", - "wk_ver": "537.31" - } - ] - }, - { - "os": "android", - "versions": [ - { - "base_trunk_revision": 190564, - "base_webkit_revision": 146842, - "branch_revision": 199333, - "channel": "beta", - "date": "05/11/13", - "prev_date": "05/02/13", - "prev_version": "30.0.1453.74", - "true_branch": "1453", - "v8_ver": "3.17.6.13", - "version": "30.0.1453.85", - "wk_ver": "537.36" - }, - { - "base_trunk_revision": 181864, - "base_webkit_revision": 142426, - "branch_revision": 191860, - "channel": "stable", - "date": "04/18/13", - "prev_date": "03/12/13", - "prev_version": "28.0.1364.169", - "true_branch": "1410", - "v8_ver": "3.16.14.11", - "version": "29.0.1410.58", - "wk_ver": "537.31" - } - ] - } -]
diff --git a/chrome/common/extensions/docs/server2/test_data/branch_utility/second.json b/chrome/common/extensions/docs/server2/test_data/branch_utility/second.json deleted file mode 100644 index f14fd58..0000000 --- a/chrome/common/extensions/docs/server2/test_data/branch_utility/second.json +++ /dev/null
@@ -1 +0,0 @@ -[{"timestamp": "2014-06-03 14:20:11.466940", "version": "37.0.2024.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-28 17:34:14.640050", "version": "37.0.2017.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-23 00:42:16.974880", "version": "37.0.2008.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-20 18:31:15.985070", "version": "36.0.1985.18", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-15 23:55:15.924940", "version": "36.0.1985.5", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-13 17:00:10.004960", "version": "36.0.1985.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-06 22:39:01.402240", "version": "36.0.1976.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-30 21:51:18.067990", "version": "36.0.1964.4", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-29 17:35:11.397850", "version": "36.0.1964.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-24 22:42:37.461710", "version": "36.0.1951.5", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-15 23:55:39.012960", "version": "36.0.1941.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-10 21:26:42.836030", "version": "36.0.1933.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-08 17:40:09.919590", "version": "35.0.1916.27", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-04 14:24:42.078490", "version": "35.0.1916.17", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-03 16:34:05.903530", "version": "35.0.1916.14", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-31 20:24:18.562490", "version": "35.0.1916.6", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-27 19:12:14.284860", "version": "35.0.1912.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-25 22:12:43.934170", "version": "35.0.1908.4", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-18 19:12:45.029430", "version": "35.0.1897.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-11 15:52:03.062480", "version": "35.0.1883.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-04 17:08:05.147800", "version": "35.0.1870.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-27 20:15:24.982930", "version": "35.0.1862.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-25 18:56:50.835670", "version": "34.0.1847.11", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-20 01:00:09.105560", "version": "34.0.1847.3", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-14 01:02:31.857440", "version": "34.0.1838.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-12 08:09:51.218870", "version": "34.0.1833.5", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-06 16:16:44.348590", "version": "34.0.1825.4", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-05 20:10:09.511680", "version": "34.0.1820.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-28 20:49:26.805000", "version": "34.0.1809.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-21 21:34:21.385560", "version": "34.0.1797.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-16 20:06:23.869950", "version": "34.0.1788.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-14 15:52:46.003690", "version": "33.0.1750.29", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-13 16:52:00.486800", "version": "33.0.1750.27", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-09 16:13:53.961450", "version": "33.0.1750.22", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-08 05:33:56.762720", "version": "33.0.1750.18", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-19 19:49:09.574590", "version": "33.0.1750.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-18 01:33:20.112740", "version": "33.0.1750.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-12 20:48:25.292070", "version": "33.0.1736.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-11 18:37:56.569580", "version": "33.0.1734.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-06 21:42:30.823000", "version": "33.0.1729.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-03 16:28:07.934720", "version": "33.0.1726.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-21 18:52:48.991750", "version": "33.0.1712.4", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-20 02:16:12.385330", "version": "33.0.1712.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-12 16:40:15.159270", "version": "33.0.1707.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-07 14:51:35.231580", "version": "32.0.1700.6", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-05 23:25:13.273680", "version": "32.0.1700.4", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-31 19:34:38.528860", "version": "32.0.1687.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-29 20:22:29.668330", "version": "32.0.1685.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-22 19:47:38.530570", "version": "32.0.1678.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-17 18:06:15.765170", "version": "32.0.1671.4", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-15 20:08:18.091540", "version": "32.0.1671.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-09 14:25:52.405750", "version": "32.0.1664.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-04 00:12:16.636970", "version": "32.0.1659.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-02 00:52:42.386520", "version": "31.0.1650.8", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-26 14:40:17.476110", "version": "31.0.1650.4", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-25 03:12:18.996600", "version": "31.0.1650.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-19 22:59:22.657090", "version": "31.0.1636.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-19 01:37:49.821160", "version": "31.0.1632.7", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-12 22:32:48.501310", "version": "31.0.1626.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-10 22:35:15.246280", "version": "31.0.1626.1", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-06 02:43:36.410970", "version": "31.0.1622.7", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-28 20:56:45.395210", "version": "31.0.1612.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-28 01:32:03.681630", "version": "31.0.1612.1", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-20 13:28:08.161490", "version": "30.0.1599.14", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-15 22:36:45.696890", "version": "30.0.1599.10", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-13 16:11:10.052430", "version": "30.0.1599.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-06 18:52:06.791740", "version": "30.0.1588.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-30 20:08:35.055580", "version": "30.0.1581.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-23 19:29:24.547040", "version": "30.0.1573.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-18 23:01:29.276420", "version": "30.0.1568.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-16 22:24:11.526890", "version": "30.0.1566.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-15 22:00:12.802300", "version": "29.0.1547.22", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-11 21:05:36.722350", "version": "29.0.1547.18", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-08 22:38:42.088720", "version": "29.0.1547.15", "os": "win", "channel": "dev"}, {"timestamp": "2013-06-25 20:46:46.536100", "version": "29.0.1547.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-06-18 22:59:55.045240", "version": "29.0.1541.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-06-12 01:26:30.924470", "version": "29.0.1535.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-06-06 22:41:06.770150", "version": "29.0.1530.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-29 17:58:53.665720", "version": "29.0.1521.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-24 17:57:59.583870", "version": "29.0.1516.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-21 20:39:44.712530", "version": "28.0.1500.20", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-13 19:30:30.489720", "version": "28.0.1500.11", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-09 19:58:41.813520", "version": "28.0.1500.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-07 23:38:18.617460", "version": "28.0.1500.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-02 23:41:18.903620", "version": "28.0.1496.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-30 23:25:13.544170", "version": "28.0.1490.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-22 22:59:15.937080", "version": "28.0.1485.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-16 00:48:20.258500", "version": "28.0.1478.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-09 02:46:07.932850", "version": "28.0.1469.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-05 18:19:28.047880", "version": "28.0.1464.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-02 17:53:25.145500", "version": "27.0.1453.12", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-29 18:16:49.135440", "version": "27.0.1453.9", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-28 18:59:48.314880", "version": "27.0.1453.6", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-27 01:53:23.549490", "version": "27.0.1453.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-21 21:49:11.673003", "version": "27.0.1448.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-19 00:30:49.325001", "version": "27.0.1444.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-13 17:35:03.840143", "version": "27.0.1438.7", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-06 18:32:27.534513", "version": "27.0.1430.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-05 23:32:37.811235", "version": "27.0.1430.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-01 01:11:51.636345", "version": "27.0.1425.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-26 22:03:01.937236", "version": "27.0.1423.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-22 00:09:52.181335", "version": "26.0.1410.12", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-20 00:15:47.421613", "version": "26.0.1410.10", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-14 20:18:49.043086", "version": "26.0.1410.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-13 01:49:23.707966", "version": "26.0.1410.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-05 00:43:13.792515", "version": "26.0.1403.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-30 21:11:13.672237", "version": "26.0.1397.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-17 22:44:44.632486", "version": "26.0.1386.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-16 01:48:57.646407", "version": "26.0.1384.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-10 23:07:12.859265", "version": "25.0.1364.29", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-08 00:05:42.205853", "version": "25.0.1364.26", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-20 22:09:26.410205", "version": "25.0.1364.5", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-19 02:42:39.891241", "version": "25.0.1364.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-14 02:37:09.422238", "version": "25.0.1359.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-10 22:13:57.477126", "version": "25.0.1354.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-07 00:16:59.533106", "version": "25.0.1349.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-11-28 23:28:57.174249", "version": "25.0.1337.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-11-13 00:52:33.199907", "version": "25.0.1323.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-11-06 19:47:19.447099", "version": "24.0.1312.5", "os": "win", "channel": "dev"}, {"timestamp": "2012-11-01 19:24:01.894562", "version": "24.0.1312.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-31 00:02:11.721761", "version": "24.0.1312.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-24 19:15:16.032706", "version": "24.0.1305.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-16 21:19:13.934724", "version": "24.0.1297.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-09 21:43:57.388586", "version": "24.0.1290.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-03 00:26:19.358696", "version": "24.0.1284.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-27 18:02:10.613799", "version": "23.0.1271.10", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-25 21:21:48.349277", "version": "23.0.1271.6", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-20 19:44:35.978350", "version": "23.0.1271.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-18 22:20:03.359033", "version": "23.0.1270.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-11 00:20:53.369165", "version": "23.0.1262.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-04 22:21:13.241591", "version": "23.0.1255.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-31 18:17:38.950756", "version": "23.0.1251.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-28 00:25:54.509043", "version": "23.0.1246.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-23 23:54:55.732357", "version": "23.0.1243.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-21 23:18:47.854439", "version": "22.0.1229.12", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-16 23:21:39.455435", "version": "22.0.1229.8", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-14 23:47:34.092347", "version": "22.0.1229.6", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-09 20:31:55.344300", "version": "22.0.1229.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-08 00:27:15.391271", "version": "22.0.1229.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-30 23:47:10.355043", "version": "22.0.1221.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-25 18:00:05.742833", "version": "22.0.1215.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-25 17:44:05.066159", "version": "22.0.1207.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-23 23:56:27.699693", "version": "22.0.1215.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-10 00:02:30.417237", "version": "22.0.1201.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-29 02:43:02.275037", "version": "21.0.1180.15", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-26 02:18:28.893003", "version": "21.0.1180.11", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-22 00:00:03.686656", "version": "21.0.1180.4", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-19 23:29:49.503880", "version": "21.0.1180.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-11 23:44:12.497616", "version": "21.0.1171.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-05 00:47:31.436958", "version": "21.0.1163.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-30 00:52:58.227015", "version": "21.0.1155.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-22 00:44:35.275578", "version": "21.0.1145.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-17 23:34:11.088684", "version": "20.0.1132.11", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-16 00:34:12.839658", "version": "20.0.1132.8", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-11 20:57:40.039867", "version": "20.0.1132.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-09 01:08:05.596451", "version": "20.0.1130.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-04 01:43:59.271464", "version": "20.0.1123.4", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-02 06:26:54.601413", "version": "20.0.1123.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-25 00:17:05.365861", "version": "20.0.1115.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-19 19:17:27.858190", "version": "20.0.1105.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-18 00:32:32.752429", "version": "20.0.1105.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-10 22:39:50.903181", "version": "20.0.1096.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-06 00:24:37.313690", "version": "19.0.1084.15", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-03 22:45:44.162647", "version": "19.0.1084.9", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-29 23:53:38.806929", "version": "19.0.1084.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-28 20:19:37.578118", "version": "19.0.1081.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-23 22:11:16.748494", "version": "19.0.1077.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-15 15:39:24.417446", "version": "19.0.1068.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-13 23:14:16.841667", "version": "19.0.1068.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-07 02:29:03.087025", "version": "19.0.1061.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-29 00:35:00.361479", "version": "19.0.1055.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-24 00:15:03.802307", "version": "19.0.1049.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-15 01:26:52.693277", "version": "19.0.1041.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-10 22:28:43.002042", "version": "19.0.1036.7", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-08 02:11:36.342233", "version": "18.0.1025.7", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-03 02:05:01.992245", "version": "18.0.1025.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-01 00:50:43.302643", "version": "18.0.1025.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-01-25 01:52:32.852157", "version": "18.0.1017.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-01-18 02:18:21.471775", "version": "18.0.1010.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-01-11 04:43:37.274858", "version": "18.0.1003.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-01-05 00:02:51.015231", "version": "17.0.963.26", "os": "win", "channel": "dev"}, {"timestamp": "2011-12-16 02:56:07.709380", "version": "17.0.963.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-12-13 00:20:16.966016", "version": "17.0.963.6", "os": "win", "channel": "dev"}, {"timestamp": "2011-12-09 00:45:52.579935", "version": "17.0.963.2", "os": "win", "channel": "dev"}, {"timestamp": "2011-12-06 23:45:11.121224", "version": "17.0.963.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-18 00:13:13.547951", "version": "17.0.942.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-15 00:36:36.682142", "version": "17.0.938.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-08 00:01:54.107311", "version": "17.0.932.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-03 23:38:13.871933", "version": "17.0.928.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-01 23:05:53.469821", "version": "16.0.912.21", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-27 23:08:29.273571", "version": "16.0.912.15", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-26 00:33:00.645906", "version": "16.0.912.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-20 23:31:54.410987", "version": "16.0.912.4", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-18 23:21:28.765917", "version": "16.0.912.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-10 23:51:01.411375", "version": "16.0.904.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-04 00:00:02.368667", "version": "16.0.899.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-27 00:01:19.501162", "version": "16.0.891.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-23 00:00:04.600297", "version": "16.0.889.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-21 00:29:45.279457", "version": "15.0.874.21", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-15 23:35:15.396772", "version": "15.0.874.15", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-13 23:00:02.220450", "version": "15.0.874.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-09 01:15:01.462271", "version": "15.0.874.5", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-07 23:28:26.943667", "version": "15.0.874.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-30 00:53:44.167535", "version": "15.0.865.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-24 23:45:01.557603", "version": "15.0.861.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-17 17:50:57.766559", "version": "15.0.854.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-16 23:32:55.862838", "version": "15.0.849.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-10 23:45:12.449065", "version": "14.0.835.35", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-08 23:39:27.586298", "version": "14.0.835.29", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-05 00:20:22.656768", "version": "14.0.835.18", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-01 23:30:39.166312", "version": "14.0.835.15", "os": "win", "channel": "dev"}, {"timestamp": "2011-07-29 00:07:02.915730", "version": "14.0.835.8", "os": "win", "channel": "dev"}, {"timestamp": "2011-07-27 00:29:22.495411", "version": "14.0.835.2", "os": "win", "channel": "dev"}, {"timestamp": "2011-07-19 00:18:39.510135", "version": "14.0.825.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-07-12 00:19:19.815197", "version": "14.0.814.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-28 00:25:51.373550", "version": "14.0.803.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-20 23:31:21.882224", "version": "14.0.797.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-16 23:24:40.782210", "version": "14.0.794.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-16 00:50:32.462022", "version": "13.0.782.24", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-14 01:22:42.462647", "version": "13.0.782.20", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-10 00:54:02.498892", "version": "13.0.782.14", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-08 21:28:42.336949", "version": "13.0.782.13", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-08 00:42:42.523798", "version": "13.0.782.11", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-06 05:45:01.690681", "version": "13.0.782.10", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-02 00:18:23.923209", "version": "13.0.782.1", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-24 00:23:25.417993", "version": "13.0.772.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-17 21:36:01.649909", "version": "13.0.767.1", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-12 21:30:02.816615", "version": "13.0.761.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-07 00:26:42.381502", "version": "12.0.742.30", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-06 00:50:01.184756", "version": "12.0.742.21", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-03 01:32:45.837483", "version": "12.0.742.16", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-29 00:47:01.978221", "version": "12.0.742.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-26 00:48:15.791589", "version": "12.0.742.9", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-22 21:52:40.866321", "version": "12.0.742.5", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-21 01:07:21.274640", "version": "12.0.742.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-13 00:18:03.352933", "version": "12.0.733.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-06 01:25:31.730658", "version": "12.0.725.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-24 23:56:50.353141", "version": "12.0.712.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-21 23:12:14.929546", "version": "11.0.696.16", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-17 23:35:19.195017", "version": "11.0.696.14", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-16 00:37:36.670682", "version": "11.0.696.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-11 02:25:22.766989", "version": "11.0.696.3", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-09 02:42:49.254367", "version": "11.0.696.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-03 22:40:08.703552", "version": "11.0.686.3", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-01 20:35:16.946853", "version": "11.0.686.1", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-01 02:36:12.261887", "version": "11.0.686.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-17 23:15:13.205432", "version": "11.0.672.2", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-16 23:02:09.686153", "version": "10.0.648.82", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-09 01:08:19.428149", "version": "10.0.648.45", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-04 01:31:33.914043", "version": "10.0.648.18", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-01 04:02:58.551081", "version": "10.0.648.11", "os": "win", "channel": "dev"}, {"timestamp": "2011-01-27 01:58:03.833503", "version": "10.0.648.6", "os": "win", "channel": "dev"}, {"timestamp": "2011-01-20 20:34:10.485114", "version": "10.0.642.2", "os": "win", "channel": "dev"}, {"timestamp": "2011-01-11 20:29:22.440018", "version": "10.0.634.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-01-06 06:16:24.266016", "version": "10.0.628.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-20 19:43:27.003393", "version": "10.0.612.3", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-16 23:09:02.613656", "version": "10.0.612.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-14 01:51:30.028630", "version": "9.0.597.19", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-10 17:40:35.218863", "version": "9.0.597.16", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-10 02:13:57.432350", "version": "9.0.597.15", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-07 02:02:57.524983", "version": "9.0.597.10", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-01 22:58:13.664530", "version": "9.0.597.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-11-19 01:08:11.505390", "version": "9.0.587.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-11-10 00:46:46.659929", "version": "9.0.576.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-11-05 01:20:03.009405", "version": "9.0.570.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-11-03 01:02:56.557176", "version": "9.0.570.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-30 01:11:40.679688", "version": "8.0.552.23", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-27 01:07:18.524939", "version": "8.0.552.18", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-21 23:21:07.362399", "version": "8.0.552.11", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-19 03:29:35.380392", "version": "8.0.552.5", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-13 00:03:39.843245", "version": "8.0.552.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-06 22:51:53.761849", "version": "7.0.544.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-30 20:34:16.449689", "version": "7.0.536.2", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-28 22:49:52.102607", "version": "7.0.517.24", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-24 23:15:18.317542", "version": "7.0.517.17", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-17 01:02:24.580776", "version": "7.0.517.8", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-13 21:15:08.408742", "version": "7.0.517.5", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-09 01:03:59.649612", "version": "7.0.517.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-26 00:05:03.192544", "version": "7.0.503.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-17 22:28:45.281781", "version": "6.0.495.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-13 14:23:58.981512", "version": "6.0.490.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-06 22:53:12.693314", "version": "6.0.472.25", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-05 00:22:02.989672", "version": "6.0.472.22", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-30 23:14:34.906503", "version": "6.0.472.14", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-28 23:49:30.339032", "version": "6.0.472.11", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-22 00:09:53.631080", "version": "6.0.472.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-15 22:58:14.785376", "version": "6.0.466.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-09 14:18:49.147870", "version": "6.0.458.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-02 23:12:13.572119", "version": "6.0.453.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-25 01:37:06.165522", "version": "6.0.447.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-18 19:49:04.312351", "version": "6.0.437.3", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-17 23:02:50.189680", "version": "6.0.427.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-17 18:31:39.466049", "version": "6.0.437.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-03 18:37:41.545861", "version": "6.0.422.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-05-20 21:03:10.341977", "version": "6.0.408.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-05-14 03:19:25.209091", "version": "6.0.401.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-05-07 01:36:38.203980", "version": "5.0.396.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-05-04 01:31:54.330134", "version": "5.0.375.29", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-30 22:08:37.591885", "version": "5.0.375.28", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-27 20:56:13.817069", "version": "5.0.375.23", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-23 00:30:19.613747", "version": "5.0.375.17", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-17 01:18:06.570807", "version": "5.0.375.9", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-14 23:39:10.591308", "version": "5.0.375.7", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-13 01:11:37.789960", "version": "5.0.375.3", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-09 01:12:39.670401", "version": "5.0.371.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-02 18:16:57.406165", "version": "5.0.366.2", "os": "win", "channel": "dev"}] \ No newline at end of file
diff --git a/chrome/common/extensions/docs/server2/test_data/canned_data.py b/chrome/common/extensions/docs/server2/test_data/canned_data.py deleted file mode 100644 index 7229a53..0000000 --- a/chrome/common/extensions/docs/server2/test_data/canned_data.py +++ /dev/null
@@ -1,1482 +0,0 @@ -# Copyright 2013 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 json - -from extensions_paths import CHROME_EXTENSIONS -from third_party.json_schema_compiler.json_parse import OrderedDict -from test_file_system import MoveAllTo, MoveTo - - -CANNED_CHANNELS = OrderedDict([ - ('master', 'master'), - ('dev', 31), - ('beta', 30), - ('stable', 29) -]) - - -CANNED_BRANCHES = OrderedDict([ - ('master', 'master'), - (31, '1612'), - (30, '1599'), - (29, '1547'), - (28, '1500'), - (27, '1453'), - (26, '1410'), - (25, '1364'), - (24, '1312'), - (23, '1271'), - (22, '1229'), - (21, '1180'), - (20, '1132'), - (19, '1084'), - (18, '1025'), - (17, '963'), - (16, '912'), - (15, '874'), - (14, '835'), - (13, '782'), - (12, '742'), - (11, '696'), - (10, '648'), - ( 9, '597'), - ( 8, '552'), - ( 7, '544'), - ( 6, '495'), - ( 5, '396'), -]) - - -CANNED_TEST_FILE_SYSTEM_DATA = MoveTo(CHROME_EXTENSIONS, { - 'api': { - '_api_features.json': json.dumps({ - 'ref_test': { 'dependencies': ['permission:ref_test'] }, - 'tester': { 'dependencies': ['permission:tester', 'manifest:tester'] } - }), - '_manifest_features.json': '{}', - '_permission_features.json': '{}' - }, - 'docs': { - 'templates': { - 'articles': { - 'test_article.html': - '<h1>hi</h1>you<h2>first</h2><h3>inner</h3><h2>second</h2>' - }, - 'intros': { - 'test_intro.html': - 'you<h2>first</h2><h3>inner</h3><h2>second</h2>' - }, - 'json': { - 'api_availabilities.json': json.dumps({ - 'master_api': { - 'channel': 'master' - }, - 'dev_api': { - 'channel': 'dev' - }, - 'beta_api': { - 'channel': 'beta' - }, - 'stable_api': { - 'channel': 'stable', - 'version': 20 - } - }), - 'intro_tables.json': json.dumps({ - 'tester': { - 'Permissions': [ - { - 'class': 'override', - 'text': '"tester"' - }, - { - 'text': 'is an API for testing things.' - } - ], - 'Learn More': [ - { - 'link': 'https://tester.test.com/welcome.html', - 'text': 'Welcome!' - } - ] - } - }), - 'manifest.json': '{}', - 'permissions.json': '{}' - }, - 'private': { - 'intro_tables': { - 'master_message.html': 'available on master' - }, - 'table_of_contents.html': '<table-of-contents>', - } - } - } -}) - - -_TEST_WHATS_NEW_JSON = { - "backgroundpages.to-be-non-persistent": { - "type": "additionsToExistingApis", - "description": "backgrounds to be non persistent", - "version": 22 - }, - "chromeSetting.set-regular-only-scope": { - "type": "additionsToExistingApis", - "description": "ChromeSetting.set now has a regular_only scope.", - "version": 21 - }, - "manifest-v1-deprecated": { - "type": "manifestChanges", - "description": "Manifest version 1 was deprecated in Chrome 18", - "version": 20 - } -} - - -CANNED_API_FILE_SYSTEM_DATA = MoveAllTo(CHROME_EXTENSIONS, { - 'master': { - 'api': { - '_api_features.json': json.dumps({ - 'alarm': { - 'channel': 'stable' - }, - 'app.window': { - 'channel': 'stable' - }, - 'browserAction': { - 'channel': 'stable' - }, - 'contextMenus': { - 'channel': 'stable' - }, - 'declarativeNetRequest': { - 'channel' : 'trunk' - }, - 'events': { - 'channel': 'stable' - }, - 'extension': { - 'channel': 'stable' - }, - 'signedInDevices': { - 'channel': 'stable' - }, - 'systemInfo.cpu': { - 'channel': 'stable' - }, - 'systemInfo.stuff': { - 'channel': 'dev' - } - }), - '_manifest_features.json': json.dumps({ - 'history': { - 'channel': 'beta' - }, - 'notifications': { - 'channel': 'beta' - }, - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'storage': { - 'channel': 'beta' - }, - 'sync': { - 'channel': 'master' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'bluetooth': { - 'channel': 'dev' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'cookies': { - 'channel': 'dev' - }, - 'declarativeContent': { - 'channel': 'master' - }, - 'declarativeWebRequest': [ - { 'channel': 'beta', - 'extension_types': ['extension'] - }, - { 'channel': 'stable', - 'extension_types': ['extension'], - 'whitelist': ['aaa'] - }, - ], - 'falseBetaAPI': { - 'channel': 'beta' - }, - 'systemInfo.display': { - 'channel': 'stable' - }, - 'masterAPI': { - 'channel': 'master' - } - }), - 'alarm.json': json.dumps([{ - 'namespace': 'alarm', - 'description': '<code>alarm</code>' - }]), - 'app_window.json': json.dumps([{ - 'namespace': 'app.window', - 'description': '<code>app.window</code>' - }]), - 'browser_action.json': json.dumps([{ - 'namespace': 'browserAction', - 'description': '<code>browserAction</code>' - }]), - 'bluetooth.idl': '\n'.join(('//Copyleft Schmopyright', - '', - '//An IDL description, oh my!', - 'namespace bluetooth {', - ' dictionary Socket {', - ' long id;', - ' };', - '};')), - 'context_menus.json': json.dumps([{ - 'namespace': 'contextMenus', - 'description': '' - }]), - 'json_stable_api.json': json.dumps([{ - 'namespace': 'jsonStableAPI', - 'description': 'An API with a predetermined availability.' - }]), - 'idle.json': json.dumps([{'namespace': 'idle', 'description': ''}]), - 'input_ime.json': json.dumps([{ - 'namespace': 'input.ime', - 'description': 'An API that has the potential to cause some trouble.' - }]), - 'menus.json': json.dumps([{'namespace': 'menus', 'description': ''}]), - 'signed_in_devices.json': json.dumps([{ - 'namespace': 'signedInDevices', - 'description': 'Another API that could cause some trouble.' - }]), - 'system_info_stuff.json': json.dumps([{ - 'namespace': 'systemInfo.stuff', - 'description': 'Yet another API that could wreck havoc...' - }]), - 'tabs.json': json.dumps([{'namespace': 'tabs', 'description': ''}]), - 'windows.json': json.dumps([{'namespace': 'windows', 'description': ''}]) - }, - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': json.dumps({ - 'jsonMasterAPI': { - 'channel': 'master' - }, - 'jsonDevAPI': { - 'channel': 'dev' - }, - 'jsonBetaAPI': { - 'channel': 'beta' - }, - 'jsonStableAPI': { - 'channel': 'stable', - 'version': 20 - } - }), - 'intro_tables.json': json.dumps({ - 'test': [ - { - 'Permissions': 'probably none' - } - ] - }), - 'manifest.json': '{}', - 'permissions.json': '{}', - 'whats_new.json': json.dumps(_TEST_WHATS_NEW_JSON) - }, - 'public': { - 'apps': { - 'alarm.html': 'alarm.html', - 'app_window.html': 'app_window.html', - 'contextMenus.html': 'contextMenus.html', - }, - 'extensions': { - 'alarm.html': 'alarm.html', - 'browserAction.html': 'browserAction.html', - 'contextMenus.html': 'contextMenus.html', - } - } - } - } - }, - '1612': { - 'api': { - '_api_features.json': json.dumps({ - 'alarm': { - 'channel': 'stable' - }, - 'app.window': { - 'channel': 'stable' - }, - 'browserAction': { - 'channel': 'stable' - }, - 'declarativeNetRequest': { - 'channel' : 'trunk' - }, - 'events': { - 'channel': 'master' - }, - 'extension': { - 'channel': 'stable' - }, - 'systemInfo.cpu': { - 'channel': 'stable' - }, - 'systemInfo.stuff': { - 'channel': 'dev' - } - }), - '_manifest_features.json': json.dumps({ - 'contextMenus': { - 'channel': 'master' - }, - 'notifications': { - 'channel': 'beta' - }, - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'storage': { - 'channel': 'dev' - }, - 'sync': { - 'channel': 'master' - }, - 'system_info_display': { - 'channel': 'stable' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'appsFirst': { - 'channel': 'stable', - 'extension_types': ['extension', 'platform_app'] - }, - 'bluetooth': { - 'channel': 'dev' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'cookies': { - 'channel': 'dev' - }, - 'declarativeContent': { - 'channel': 'master' - }, - 'declarativeWebRequest': [ - { 'channel': 'beta' }, - { 'channel': 'stable', 'whitelist': ['aaa'] } - ], - 'downloads': { - 'channel': 'beta' - } - }), - 'alarm.json': json.dumps([{ - 'namespace': 'alarm', - 'description': '<code>alarm</code>' - }]), - 'app_window.json': json.dumps([{ - 'namespace': 'app.window', - 'description': '<code>app.window</code>' - }]), - 'browser_action.json': json.dumps([{ - 'namespace': 'browserAction', - 'description': '<code>browserAction</code>' - }]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - }, - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': json.dumps({ - 'jsonMasterAPI': { - 'channel': 'master' - }, - 'jsonDevAPI': { - 'channel': 'dev' - }, - 'jsonBetaAPI': { - 'channel': 'beta' - }, - 'jsonStableAPI': { - 'channel': 'stable', - 'version': 20 - } - }), - 'intro_tables.json': json.dumps({ - 'test': [ - { - 'Permissions': 'probably none' - } - ] - }), - 'manifest.json': '{}', - 'permissions.json': '{}', - 'whats_new.json': json.dumps(_TEST_WHATS_NEW_JSON) - }, - 'public': { - 'apps': { - 'alarm.html': 'alarm.html', - 'app_window.html': 'app_window.html', - }, - 'extensions': { - 'alarm.html': 'alarm.html', - 'browserAction.html': 'browserAction.html', - } - } - } - } - }, - '1599': { - 'api': { - '_api_features.json': json.dumps({ - 'alarm': { - 'channel': 'stable' - }, - 'app.window': { - 'channel': 'stable' - }, - 'browserAction': { - 'channel': 'stable' - }, - 'declarativeNetRequest': { - 'channel' : 'trunk' - }, - 'events': { - 'channel': 'master' - }, - 'extension': { - 'channel': 'stable' - }, - 'systemInfo.cpu': { - 'channel': 'beta' - }, - 'systemInfo.stuff': { - 'channel': 'dev' - } - }), - '_manifest_features.json': json.dumps({ - 'contextMenus': { - 'channel': 'master' - }, - 'notifications': { - 'channel': 'dev' - }, - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'storage': { - 'channel': 'dev' - }, - 'sync': { - 'channel': 'master' - }, - 'system_info_display': { - 'channel': 'stable' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'appsFirst': { - 'channel': 'stable', - 'extension_types': ['extension', 'platform_app'] - }, - 'bluetooth': { - 'channel': 'dev' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'cookies': { - 'channel': 'dev' - }, - 'declarativeContent': { - 'channel': 'master' - }, - 'declarativeWebRequest': [ - { 'channel': 'beta' }, - { 'channel': 'stable', 'whitelist': ['aaa'] } - ], - 'downloads': { - 'channel': 'beta' - } - }), - 'alarm.json': json.dumps([{ - 'namespace': 'alarm', - 'description': '<code>alarm</code>' - }]), - 'app_window.json': json.dumps([{ - 'namespace': 'app.window', - 'description': '<code>app.window</code>' - }]), - 'browser_action.json': json.dumps([{ - 'namespace': 'browserAction', - 'description': '<code>browserAction</code>' - }]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - }, - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': json.dumps({ - 'jsonMasterAPI': { - 'channel': 'master' - }, - 'jsonDevAPI': { - 'channel': 'dev' - }, - 'jsonBetaAPI': { - 'channel': 'beta' - }, - 'jsonStableAPI': { - 'channel': 'stable', - 'version': 20 - } - }), - 'intro_tables.json': json.dumps({ - 'test': [ - { - 'Permissions': 'probably none' - } - ] - }), - 'manifest.json': '{}', - 'permissions.json': '{}', - 'whats_new.json': json.dumps(_TEST_WHATS_NEW_JSON) - }, - 'public': { - 'apps': { - 'alarm.html': 'alarm.html', - 'app_window.html': 'app_window.html', - }, - 'extensions': { - 'alarm.html': 'alarm.html', - 'browserAction.html': 'browserAction.html', - } - } - } - } - }, - '1547': { - 'api': { - '_api_features.json': json.dumps({ - 'alarm': { - 'channel': 'stable' - }, - 'app.window': { - 'channel': 'stable' - }, - 'browserAction': { - 'channel': 'stable' - }, - 'declarativeNetRequest': { - 'channel' : 'trunk' - }, - 'events': { - 'channel': 'master' - }, - 'extension': { - 'channel': 'stable' - }, - 'systemInfo.stuff': { - 'channel': 'dev' - } - }), - '_manifest_features.json': json.dumps({ - 'contextMenus': { - 'channel': 'master' - }, - 'notifications': { - 'channel': 'dev' - }, - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'storage': { - 'channel': 'dev' - }, - 'sync': { - 'channel': 'master' - }, - 'system_info_display': { - 'channel': 'stable' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'appsFirst': { - 'channel': 'stable', - 'extension_types': ['extension', 'platform_app'] - }, - 'bluetooth': { - 'channel': 'dev' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'cookies': { - 'channel': 'dev' - }, - 'declarativeContent': { - 'channel': 'master' - }, - 'declarativeWebRequest': [ - { 'channel': 'beta' }, - { 'channel': 'stable', 'whitelist': ['aaa'] } - ], - 'downloads': { - 'channel': 'beta' - } - }), - 'alarm.json': json.dumps([{ - 'namespace': 'alarm', - 'description': '<code>alarm</code>' - }]), - 'app_window.json': json.dumps([{ - 'namespace': 'app.window', - 'description': '<code>app.window</code>' - }]), - 'browser_action.json': json.dumps([{ - 'namespace': 'browserAction', - 'description': '<code>browserAction</code>' - }]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - }, - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': json.dumps({ - 'jsonMasterAPI': { - 'channel': 'master' - }, - 'jsonDevAPI': { - 'channel': 'dev' - }, - 'jsonBetaAPI': { - 'channel': 'beta' - }, - 'jsonStableAPI': { - 'channel': 'stable', - 'version': 20 - } - }), - 'intro_tables.json': json.dumps({ - 'test': [ - { - 'Permissions': 'probably none' - } - ] - }), - 'manifest.json': '{}', - 'permissions.json': '{}', - 'whats_new.json': json.dumps(_TEST_WHATS_NEW_JSON) - }, - 'public': { - 'apps': { - 'alarm.html': 'alarm.html', - 'app_window.html': 'app_window.html', - }, - 'extensions': { - 'alarm.html': 'alarm.html', - 'browserAction.html': 'browserAction.html', - } - } - } - } - }, - '1500': { - 'api': { - '_api_features.json': json.dumps({ - 'alarm': { - 'channel': 'stable' - }, - 'app.window': { - 'channel': 'stable' - }, - 'browserAction': { - 'channel': 'stable' - }, - 'declarativeNetRequest': { - 'channel' : 'trunk' - }, - 'events': { - 'channel': 'master' - }, - 'extension': { - 'channel': 'stable' - }, - 'systemInfo.stuff': { - 'channel': 'dev' - } - }), - '_manifest_features.json': json.dumps({ - 'contextMenus': { - 'channel': 'master' - }, - 'notifications': { - 'channel': 'dev' - }, - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'storage': { - 'channel': 'dev' - }, - 'sync': { - 'channel': 'master' - }, - 'system_info_display': { - 'channel': 'stable' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'appsFirst': { - 'channel': 'stable', - 'extension_types': ['extension', 'platform_app'] - }, - 'bluetooth': { - 'channel': 'dev' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'cookies': { - 'channel': 'dev' - }, - 'declarativeContent': { - 'channel': 'master' - }, - 'declarativeWebRequest': [ - { 'channel': 'beta' }, - { 'channel': 'stable', 'whitelist': ['aaa'] } - ], - 'downloads': { - 'channel': 'beta' - } - }), - 'alarm.json': json.dumps([{ - 'namespace': 'alarm', - 'description': '<code>alarm</code>' - }]), - 'app_window.json': json.dumps([{ - 'namespace': 'app.window', - 'description': '<code>app.window</code>' - }]), - 'browser_action.json': json.dumps([{ - 'namespace': 'browserAction', - 'description': '<code>browserAction</code>' - }]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - }, - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': json.dumps({ - 'jsonMasterAPI': { - 'channel': 'master' - }, - 'jsonDevAPI': { - 'channel': 'dev' - }, - 'jsonBetaAPI': { - 'channel': 'beta' - }, - 'jsonStableAPI': { - 'channel': 'stable', - 'version': 20 - } - }), - 'intro_tables.json': json.dumps({ - 'test': [ - { - 'Permissions': 'probably none' - } - ] - }), - 'manifest.json': '{}', - 'permissions.json': '{}', - 'whats_new.json': json.dumps(_TEST_WHATS_NEW_JSON) - }, - 'public': { - 'apps': { - 'alarm.html': 'alarm.html', - 'app_window.html': 'app_window.html', - }, - 'extensions': { - 'alarm.html': 'alarm.html', - 'browserAction.html': 'browserAction.html', - } - } - } - } - }, - '1453': { - 'api': { - '_api_features.json': json.dumps({ - 'alarm': { - 'channel': 'stable' - }, - 'app.window': { - 'channel': 'stable' - }, - 'browserAction': { - 'channel': 'stable' - }, - 'declarativeNetRequest': { - 'channel' : 'trunk' - }, - 'events': { - 'channel': 'dev' - }, - 'extension': { - 'channel': 'stable' - }, - 'systemInfo.stuff': { - 'channel': 'dev' - } - }), - '_manifest_features.json': json.dumps({ - 'notifications': { - 'channel': 'dev' - }, - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'storage': { - 'channel': 'dev' - }, - 'system_info_display': { - 'channel': 'stable' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'appsFirst': { - 'channel': 'stable', - 'extension_types': ['extension', 'platform_app'] - }, - 'bluetooth': { - 'channel': 'dev' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'context_menus': { - 'channel': 'master' - }, - 'declarativeContent': { - 'channel': 'master' - }, - 'declarativeWebRequest': [ - { 'channel': 'beta' }, - { 'channel': 'stable', 'whitelist': ['aaa'] } - ], - 'downloads': { - 'channel': 'dev' - } - }), - 'alarm.json': json.dumps([{ - 'namespace': 'alarm', - 'description': '<code>alarm</code>' - }]), - 'app_window.json': json.dumps([{ - 'namespace': 'app.window', - 'description': '<code>app.window</code>' - }]), - 'browser_action.json': json.dumps([{ - 'namespace': 'browserAction', - 'description': '<code>browserAction</code>' - }]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - }, - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': json.dumps({ - 'jsonMasterAPI': { - 'channel': 'master' - }, - 'jsonDevAPI': { - 'channel': 'dev' - }, - 'jsonBetaAPI': { - 'channel': 'beta' - }, - 'jsonStableAPI': { - 'channel': 'stable', - 'version': 20 - } - }), - 'intro_tables.json': json.dumps({ - 'test': [ - { - 'Permissions': 'probably none' - } - ] - }), - 'manifest.json': '{}', - 'permissions.json': '{}', - 'whats_new.json': json.dumps(_TEST_WHATS_NEW_JSON) - }, - 'public': { - 'apps': { - 'alarm.html': 'alarm.html', - 'app_window.html': 'app_window.html', - }, - 'extensions': { - 'alarm.html': 'alarm.html', - 'browserAction.html': 'browserAction.html', - } - - } - } - } - }, - '1410': { - 'api': { - '_manifest_features.json': json.dumps({ - 'alarm': { - 'channel': 'stable' - }, - 'app.window': { - 'channel': 'stable' - }, - 'browserAction': { - 'channel': 'stable' - }, - 'events': { - 'channel': 'beta' - }, - 'notifications': { - 'channel': 'dev' - }, - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'appsFirst': { - 'channel': 'stable', - 'extension_types': ['extension', 'platform_app'] - }, - 'bluetooth': { - 'channel': 'dev' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'context_menus': { - 'channel': 'master' - }, - 'declarativeContent': { - 'channel': 'master' - }, - 'declarativeWebRequest': [ - { 'channel': 'beta' }, - { 'channel': 'stable', 'whitelist': ['aaa'] } - ], - 'systemInfo.display': { - 'channel': 'stable' - } - }), - 'alarm.json': json.dumps([{ - 'namespace': 'alarm', - 'description': '<code>alarm</code>' - }]), - 'app_window.json': json.dumps([{ - 'namespace': 'app.window', - 'description': '<code>app.window</code>' - }]), - 'browser_action.json': json.dumps([{ - 'namespace': 'browserAction', - 'description': '<code>browserAction</code>' - }]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - } - }, - '1364': { - 'api': { - '_manifest_features.json': json.dumps({ - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'appsFirst': { - 'channel': 'stable', - 'extension_types': ['platform_app'] - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'systemInfo.display': { - 'channel': 'stable' - }, - 'webRequest': { - 'channel': 'stable' - } - }), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - } - }, - '1312': { - 'api': { - '_manifest_features.json': json.dumps({ - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'stable' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'systemInfo.display': { - 'channel': 'stable' - } - }), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - } - }, - '1271': { - 'api': { - '_manifest_features.json': json.dumps({ - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'system_info_display': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'alarms': { - 'channel': 'beta' - }, - 'bookmarks': { - 'channel': 'stable' - }, - 'webRequest': { - 'channel': 'stable' - } - }), - 'alarms.idl': '//copy\n\n//desc\nnamespace alarms {}', - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'windows.json': json.dumps([{'namespace': 'windows'}]) - } - }, - '1229': { - 'api': { - '_manifest_features.json': json.dumps({ - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - }, - 'web_request': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'bookmarks': { - 'channel': 'stable' - }, - 'systemInfo.display': { - 'channel': 'beta' - } - }), - 'alarms.idl': '//copy\n\n//desc\nnamespace alarms {}', - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - } - }, - '1180': { - 'api': { - '_manifest_features.json': json.dumps({ - 'page_action': { - 'channel': 'stable' - }, - 'runtime': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'bookmarks': { - 'channel': 'stable' - }, - 'webRequest': { - 'channel': 'stable' - } - }), - 'bookmarks.json': json.dumps([{'namespace': 'bookmarks'}]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input_ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - } - }, - '1132': { - 'api': { - '_manifest_features.json': json.dumps({ - 'bookmarks': { - 'channel': 'master' - }, - 'page_action': { - 'channel': 'stable' - } - }), - '_permission_features.json': json.dumps({ - 'webRequest': { - 'channel': 'stable' - } - }), - 'bookmarks.json': json.dumps([{'namespace': 'bookmarks'}]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input.ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - } - }, - '1084': { - 'api': { - '_manifest_features.json': json.dumps({ - 'contents': 'nothing of interest here,really' - }), - 'bookmarks.json': json.dumps([{'namespace': 'bookmarks'}]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input.ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'pageAction.json': json.dumps([{'namespace': 'pageAction'}]), - 'webRequest.json': json.dumps([{'namespace': 'webRequest'}]) - } - }, - '1025': { - 'api': { - 'bookmarks.json': json.dumps([{'namespace': 'bookmarks'}]), - 'idle.json': json.dumps([{'namespace': 'idle'}]), - 'input.ime.json': json.dumps([{'namespace': 'input.ime'}]), - 'menus.json': json.dumps([{'namespace': 'menus'}]), - 'tabs.json': json.dumps([{'namespace': 'tabs'}]), - 'pageAction.json': json.dumps([{'namespace': 'pageAction'}]), - 'webRequest.json': json.dumps([{'namespace': 'webRequest'}]) - } - }, - '963': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - }, - { - 'namespace': 'webRequest' - } - ]) - } - }, - '912': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - }, - { - 'namespace': 'experimental.webRequest' - } - ]) - } - }, - '874': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - } - ]) - } - }, - '835': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - } - ]) - } - }, - '782': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - } - ]) - } - }, - '742': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - } - ]) - } - }, - '696': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - } - ]) - } - }, - '648': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - } - ]) - } - }, - '597': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - } - ]) - } - }, - '552': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - }, - { - 'namespace': 'pageAction' - } - ]) - } - }, - '544': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - } - ]) - } - }, - '495': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'menus' - } - ]) - } - }, - '396': { - 'api': { - 'extension_api.json': json.dumps([ - { - 'namespace': 'idle' - }, - { - 'namespace': 'experimental.menus' - } - ]) - } - } -})
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system.zip b/chrome/common/extensions/docs/server2/test_data/file_system.zip deleted file mode 100644 index 40e6424..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system.zip +++ /dev/null Binary files differ
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/empty.txt b/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/empty.txt deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/empty.txt +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file0.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file0.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file0.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file1.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file1.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file1.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file2.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file2.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/dir/file2.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/file0.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/file0.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/file0.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/file1.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/file1.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/file1.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/file2.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/file2.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/file2.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/file3.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/file3.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/file3.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/file4.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/file4.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/file4.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/file5.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/file5.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/file5.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/list/file6.html b/chrome/common/extensions/docs/server2/test_data/file_system/list/file6.html deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/list/file6.html +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/stat b/chrome/common/extensions/docs/server2/test_data/file_system/stat deleted file mode 100644 index 6efea24..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/stat +++ /dev/null
@@ -1,2451 +0,0 @@ - - - - -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<!-- ViewVC :: http://www.viewvc.org/ --> -<head> -<title>[chrome] Index of /trunk/src/chrome/common/extensions/api</title> -<meta name="generator" content="ViewVC 1.0.9" /> -<link rel="stylesheet" href="/viewvc/*docroot*/styles.css" type="text/css" /> - -</head> -<body> -<div class="vc_navheader"> - -<form method="get" action="/viewvc/"> - -<table style="padding:0.1em;"> -<tr> -<td> -<strong> - -<a href="/viewvc/chrome/"> - -[chrome]</a> -/ - -<a href="/viewvc/chrome/trunk/"> - -trunk</a> -/ - -<a href="/viewvc/chrome/trunk/src/"> - -src</a> -/ - -<a href="/viewvc/chrome/trunk/src/chrome/"> - -chrome</a> -/ - -<a href="/viewvc/chrome/trunk/src/chrome/common/"> - -common</a> -/ - -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/"> - -extensions</a> -/ - - - -api - - -</strong> - -</td> -<td style="text-align:right;"> - - -<strong>Repository:</strong> -<select name="root" onchange="submit()"> - - -<option value="*viewroots*">Repository Listing</option> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<optgroup label="Subversion Repositories"><option selected="selected">chrome</option><option>multivm</option><option>native_client</option></optgroup> - -</select> -<input type="submit" value="Go" /> - -</td> -</tr> -</table> - -</form> - -</div> -<div style="float: right; padding: 5px;"><a href="http://www.viewvc.org/"><img src="/viewvc/*docroot*/images/logo.png" alt="ViewVC logotype" width="128" height="48" /></a></div> -<h1>Index of /trunk/src/chrome/common/extensions/api</h1> - - -<table class="auto"> -<tr><td>Files shown:</td><td><strong>86</strong> - - -</td></tr> - -<tr> -<td>Directory revision:</td> -<td><a href="/viewvc/chrome?view=rev&revision=151113">151113</a> (of <a href="/viewvc/chrome?view=rev">151144</a>)</td> -</tr> - -<tr> -<td>Sticky Revision:</td> -<td><form method="get" action="/viewvc/chrome" style="display: inline"> -<div style="display: inline"> -<input type="hidden" name="orig_pathtype" value="DIR" /><input type="hidden" name="orig_view" value="dir" /><input type="hidden" name="orig_path" value="trunk/src/chrome/common/extensions/api" /><input type="hidden" name="view" value="redirect_pathrev" /> - -<input type="text" name="pathrev" value="" size="6"/> - -<input type="submit" value="Set" /> -</div> -</form> - -</td> -</tr> - - -</table> - - -<p><a name="dirlist"></a></p> -<hr /> - -<table cellspacing="1" cellpadding="2"> -<thead> -<tr> -<th class="vc_header_sort" colspan="2"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/?sortdir=down#dirlist">File</a> - -<img class="vc_sortarrow" alt="" -width="13" height="13" -src="/viewvc/*docroot*/images/up.png" /> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/?sortby=rev#dirlist">Rev.</a> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/?sortby=date#dirlist">Age</a> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/?sortby=author#dirlist">Author</a> - -</th> - -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/?sortby=log#dirlist">Last log entry</a> - -</th> - -</tr> -</thead> -<tbody> - -<tr class="vc_row_odd"> -<td colspan="2"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/"> -<img src="/viewvc/*docroot*/images/back_small.png" alt="" width="16" height="16" -/> Parent Directory</a> -</td> -<td> </td> -<td> </td> -<td> </td> - -<td> </td> - -</tr> - - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="devtools" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/devtools/" title="View directory contents"> - -<img src="/viewvc/*docroot*/images/dir.png" alt="" width="16" height="16" /> -devtools/</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/devtools/?view=log" title="View directory revision log"><strong>149291</strong></a></td> - -<td> 10 days</td> -<td> cduvall@chromium.org</td> - - -<td> Extensions Docs Server: fix rendering of the Devtools API. - -This change splits d...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="OWNERS" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/OWNERS?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -OWNERS</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/OWNERS?revision=150079&view=markup" title="View file contents"><strong>150079</strong></a></td> - -<td> 4 days</td> -<td> battre@chromium.org</td> - - -<td> Create OWNERS file for chrome/renderer/resources/extensions - -Creating OWNERS fil...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="_manifest_features.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/_manifest_features.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -_manifest_features.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/_manifest_features.json?revision=150827&view=markup" title="View file contents"><strong>150827</strong></a></td> - -<td> 29 hours</td> -<td> aa@chromium.org</td> - - -<td> Add an 'author' field to the manifest definition. - - -Review URL: <a href="https://chromium">https://chromium</a>...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="_permission_features.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/_permission_features.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -_permission_features.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/_permission_features.json?revision=150186&view=markup" title="View file contents"><strong>150186</strong></a></td> - -<td> 3 days</td> -<td> miket@chromium.org</td> - - -<td> Move serial out of experimental. - -This CL is unremarkable except that I figured ...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="alarms.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/alarms.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -alarms.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/alarms.idl?revision=143049&view=markup" title="View file contents"><strong>143049</strong></a></td> - -<td> 7 weeks</td> -<td> mpcomplete@chromium.org</td> - - -<td> Fix how the IDL parser handles comments, and fix the chrome.alarms docs. - -This i...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="api.gyp" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/api.gyp?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -api.gyp</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/api.gyp?revision=151113&view=markup" title="View file contents"><strong>151113</strong></a></td> - -<td> 2 hours</td> -<td> mitchellwrosen@chromium.org</td> - - -<td> Use JSON schema compiler in chrome.management code - -BUG=121174 - - -Review URL: htt...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="app.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/app.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -app.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/app.json?revision=133722&view=markup" title="View file contents"><strong>133722</strong></a></td> - -<td> 3 months</td> -<td> jstritar@chromium.org</td> - - -<td> Add an API for hosted apps to check their install and running states. - -BUG=10721...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="app_window.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/app_window.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -app_window.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/app_window.idl?revision=147710&view=markup" title="View file contents"><strong>147710</strong></a></td> - -<td> 3 weeks</td> -<td> asargent@chromium.org</td> - - -<td> Move chrome.appWindow to chrome.app.window. - -BUG=134573 -TEST=In platform apps, y...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="bookmarks.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/bookmarks.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -bookmarks.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/bookmarks.json?revision=149307&view=markup" title="View file contents"><strong>149307</strong></a></td> - -<td> 9 days</td> -<td> mitchellwrosen@chromium.org</td> - - -<td> Refactor chrome.bookmarks API to use JSON schema compiler. - -BUG=121174 - - -Review ...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="browser_action.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/browser_action.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -browser_action.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/browser_action.json?revision=148043&view=markup" title="View file contents"><strong>148043</strong></a></td> - -<td> 2 weeks</td> -<td> yoz@chromium.org</td> - - -<td> Add browserAction.enable/disable as alias for pageAction.show/hide. - -Depends on ...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="browsing_data.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/browsing_data.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -browsing_data.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/browsing_data.json?revision=142133&view=markup" title="View file contents"><strong>142133</strong></a></td> - -<td> 8 weeks</td> -<td> mkwst@chromium.org</td> - - -<td> `chrome.browsingData` extension API can now remove data from protected origins. -...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="chromeos_info_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/chromeos_info_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -chromeos_info_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/chromeos_info_private.json?revision=150737&view=markup" title="View file contents"><strong>150737</strong></a></td> - -<td> 41 hours</td> -<td> dpolukhin@chromium.org</td> - - -<td> Add board and isOwner properties to chromeosInfoPrivate - -BUG=chrome-os-partner:9...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="cloud_print_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/cloud_print_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -cloud_print_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/cloud_print_private.json?revision=149303&view=markup" title="View file contents"><strong>149303</strong></a></td> - -<td> 9 days</td> -<td> vitalybuka@chromium.org</td> - - -<td> Renamed chrome_auth to cloud_print. -No functionality changed except naming. -Serv...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="content_settings.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/content_settings.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -content_settings.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/content_settings.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="context_menus.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/context_menus.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -context_menus.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/context_menus.json?revision=140112&view=markup" title="View file contents"><strong>140112</strong></a></td> - -<td> 2 months</td> -<td> yoz@chromium.org</td> - - -<td> Dispatch a new event chrome.contextMenus.onClicked. - -Disallow onclick create par...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="cookies.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/cookies.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -cookies.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/cookies.json?revision=124878&view=markup" title="View file contents"><strong>124878</strong></a></td> - -<td> 5 months</td> -<td> cduvall@chromium.org</td> - - -<td> Allow comments in extension config files. - -Added a script to remove comments fro...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="debugger.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/debugger.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -debugger.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/debugger.json?revision=147894&view=markup" title="View file contents"><strong>147894</strong></a></td> - -<td> 2 weeks</td> -<td> mitchellwrosen@chromium.org</td> - - -<td> Refactor chrome.debugger api to use the JSON schema compiler. - -BUG=121174 - - -Rev...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="declarative_web_request.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/declarative_web_request.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -declarative_web_request.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/declarative_web_request.json?revision=150421&view=markup" title="View file contents"><strong>150421</strong></a></td> - -<td> 3 days</td> -<td> yoz@chromium.org</td> - - -<td> Support also excluding content types in declarative webrequest conditions. - -BUG=...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="devtools.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/devtools.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -devtools.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/devtools.json?revision=124878&view=markup" title="View file contents"><strong>124878</strong></a></td> - -<td> 5 months</td> -<td> cduvall@chromium.org</td> - - -<td> Allow comments in extension config files. - -Added a script to remove comments fro...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="downloads.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/downloads.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -downloads.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/downloads.idl?revision=146201&view=markup" title="View file contents"><strong>146201</strong></a></td> - -<td> 4 weeks</td> -<td> benjhayden@chromium.org</td> - - -<td> Switch the downloads API over to IDL/json_schema_compiler - -Modify ppapi/generato...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="echo_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/echo_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -echo_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/echo_private.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="events.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/events.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -events.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/events.json?revision=143168&view=markup" title="View file contents"><strong>143168</strong></a></td> - -<td> 7 weeks</td> -<td> battre@chromium.org</td> - - -<td> Document signatures for Event.[add|remove|has]Listener() - - -BUG=132950 -TEST=no - - -...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_accessibility.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_accessibility.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_accessibility.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_accessibility.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_app.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_app.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_app.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_app.json?revision=148848&view=markup" title="View file contents"><strong>148848</strong></a></td> - -<td> 13 days</td> -<td> asargent@chromium.org</td> - - -<td> Updates to documentation for experimental.apps - --Put nodoc on experimental.apps....</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_bluetooth.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_bluetooth.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_bluetooth.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_bluetooth.idl?revision=150898&view=markup" title="View file contents"><strong>150898</strong></a></td> - -<td> 25 hours</td> -<td> bryeung@chromium.org</td> - - -<td> Bluetooth API: improve discovery - -This CL: -- eliminates unnecessary dispatches -...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="bookmark_manager.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/bookmark_manager.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -bookmark_manager.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/bookmark_manager.json?revision=140864&view=markup" title="View file contents"><strong>140864</strong></a></td> - -<td> 2 months</td> -<td> ananta@chromium.org</td> - - -<td> Disable the new window context menu option in the bookmarks extension for Window...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_commands.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_commands.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_commands.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_commands.json?revision=149147&view=markup" title="View file contents"><strong>149147</strong></a></td> - -<td> 10 days</td> -<td> finnur@chromium.org</td> - - -<td> Renaming the 'keybinding' permission to 'commands'. - -BUG=135562 -TEST=Covered by ...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_dns.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_dns.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_dns.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_dns.idl?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_identity.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_identity.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_identity.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_identity.idl?revision=147523&view=markup" title="View file contents"><strong>147523</strong></a></td> - -<td> 3 weeks</td> -<td> estade@chromium.org</td> - - -<td> convert identity api to .idl - -BUG=135685 -TEST=manual + existing extension tests -...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_idltest.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_idltest.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_idltest.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_idltest.idl?revision=138707&view=markup" title="View file contents"><strong>138707</strong></a></td> - -<td> 2 months</td> -<td> asargent@chromium.org</td> - - -<td> Add support for 'nocompile' to IDL schema compiler. - -The json schema stuff alrea...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="infobars.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/infobars.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -infobars.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/infobars.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_input_virtual_keyboard.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_input_virtual_keyboard.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_input_virtual_keyboard.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_input_virtual_keyboard.json?revision=138223&view=markup" title="View file contents"><strong>138223</strong></a></td> - -<td> 2 months</td> -<td> yusukes@google.com</td> - - -<td> Remove virtual keyboard support: - -1. common.gypi: use_virtual_keyboard define -2....</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_media_galleries.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_media_galleries.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_media_galleries.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_media_galleries.idl?revision=150164&view=markup" title="View file contents"><strong>150164</strong></a></td> - -<td> 3 days</td> -<td> vandebo@chromium.org</td> - - -<td> Move MediaGalleries.getMediaFileSystems back to experimental for M22 - -BUG=110823...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="processes.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/processes.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -processes.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/processes.json?revision=137690&view=markup" title="View file contents"><strong>137690</strong></a></td> - -<td> 2 months</td> -<td> nasko@chromium.org</td> - - -<td> Improving the process model extension API - -BUG=32302 -TEST=Unit tests. - - -Review U...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="push_messaging.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/push_messaging.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -push_messaging.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/push_messaging.idl?revision=149536&view=markup" title="View file contents"><strong>149536</strong></a></td> - -<td> 8 days</td> -<td> dcheng@chromium.org</td> - - -<td> Add skeleton implementation of ExtensionPushMessagingEventRouter. - -BUG=139663 -TE...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_record.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_record.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_record.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_record.json?revision=145342&view=markup" title="View file contents"><strong>145342</strong></a></td> - -<td> 5 weeks</td> -<td> clintstaley@chromium.org</td> - - -<td> Fixes to repeat-count checking and error checking for failed subbrowser run - -BUG...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_rlz.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_rlz.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_rlz.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_rlz.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_speech_input.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_speech_input.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_speech_input.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_speech_input.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_usb.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_usb.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -experimental_usb.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_usb.idl?revision=144221&view=markup" title="View file contents"><strong>144221</strong></a></td> - -<td> 6 weeks</td> -<td> bryeung@chromium.org</td> - - -<td> Publish documentation for the experimental apis - -TEST=none -BUG=130199,134556 - -Co...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="extension.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/extension.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -extension.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/extension.json?revision=146855&view=markup" title="View file contents"><strong>146855</strong></a></td> - -<td> 3 weeks</td> -<td> mpcomplete@chromium.org</td> - - -<td> Fix extension docs for sendMessage/onMessage. - -BUG=136654,136857 -TEST= - -Review U...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="extension_api.cc" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/extension_api.cc?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -extension_api.cc</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/extension_api.cc?revision=149819&view=markup" title="View file contents"><strong>149819</strong></a></td> - -<td> 7 days</td> -<td> vabr@chromium.org</td> - - -<td> Correct const accessors in base/values.(h|cc), Part II (ListValue) - -For problem ...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="extension_api.h" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/extension_api.h?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -extension_api.h</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/extension_api.h?revision=146163&view=markup" title="View file contents"><strong>146163</strong></a></td> - -<td> 4 weeks</td> -<td> ajwong@chromium.org</td> - - -<td> Remove the rest of #pragma once in one big CL. - -For context see this thread: - h...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="extension_api_unittest.cc" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/extension_api_unittest.cc?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -extension_api_unittest.cc</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/extension_api_unittest.cc?revision=149819&view=markup" title="View file contents"><strong>149819</strong></a></td> - -<td> 7 days</td> -<td> vabr@chromium.org</td> - - -<td> Correct const accessors in base/values.(h|cc), Part II (ListValue) - -For problem ...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="file_browser_handler.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/file_browser_handler.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -file_browser_handler.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/file_browser_handler.json?revision=149101&view=markup" title="View file contents"><strong>149101</strong></a></td> - -<td> 10 days</td> -<td> cduvall@chromium.org</td> - - -<td> Extensions Docs Server: Integration testing - -A test that makes sure all the page...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="file_browser_handler_internal.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/file_browser_handler_internal.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -file_browser_handler_internal.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/file_browser_handler_internal.json?revision=142683&view=markup" title="View file contents"><strong>142683</strong></a></td> - -<td> 7 weeks</td> -<td> tbarzic@chromium.org</td> - - -<td> Reland 142611 - Return FileEntry object from fileBrowserHandler.selectFile funct...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="file_manager_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/file_manager_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -file_manager_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/file_manager_private.json?revision=150806&view=markup" title="View file contents"><strong>150806</strong></a></td> - -<td> 30 hours</td> -<td> yoshiki@chromium.org</td> - - -<td> FileBrowser: Hide DriveApps on Open-with menu when the selected file is not on d...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="file_system.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/file_system.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -file_system.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/file_system.idl?revision=150515&view=markup" title="View file contents"><strong>150515</strong></a></td> - -<td> 2 days</td> -<td> thorogood@chromium.org</td> - - -<td> Updates file type selector for fileSystem API - -Allows developers to explicitly s...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="font_settings.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/font_settings.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -font_settings.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/font_settings.json?revision=147621&view=markup" title="View file contents"><strong>147621</strong></a></td> - -<td> 3 weeks</td> -<td> falken@chromium.org</td> - - -<td> Move Font Settings API out of experimental. - -BUG=114148 -TEST=browser_tests and e...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="history.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/history.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -history.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/history.json?revision=129086&view=markup" title="View file contents"><strong>129086</strong></a></td> - -<td> 4 months</td> -<td> cduvall@chromium.org</td> - - -<td> Add callbacks to history.addUrl and history.deleteUrl - -Added optional callbacks ...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="i18n.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/i18n.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -i18n.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/i18n.json?revision=149045&view=markup" title="View file contents"><strong>149045</strong></a></td> - -<td> 11 days</td> -<td> mitchellwrosen@chromium.org</td> - - -<td> Use JSON schema compiler in i18n API code - -TBR=<a href="mailto:ben@chromium.org">ben@chromium.org</a> - -BUG=121174 - -Rev...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="idle.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/idle.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -idle.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/idle.json?revision=124878&view=markup" title="View file contents"><strong>124878</strong></a></td> - -<td> 5 months</td> -<td> cduvall@chromium.org</td> - - -<td> Allow comments in extension config files. - -Added a script to remove comments fro...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="input_ime.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/input_ime.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -input_ime.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/input_ime.json?revision=149101&view=markup" title="View file contents"><strong>149101</strong></a></td> - -<td> 10 days</td> -<td> cduvall@chromium.org</td> - - -<td> Extensions Docs Server: Integration testing - -A test that makes sure all the page...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="input_method_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/input_method_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -input_method_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/input_method_private.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="managed_mode_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/managed_mode_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -managed_mode_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/managed_mode_private.json?revision=142720&view=markup" title="View file contents"><strong>142720</strong></a></td> - -<td> 7 weeks</td> -<td> bauerb@chromium.org</td> - - -<td> Add ManagedModePolicyProvider and extension API to get and set policies. - - -BUG=1...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="management.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/management.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -management.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/management.json?revision=151113&view=markup" title="View file contents"><strong>151113</strong></a></td> - -<td> 2 hours</td> -<td> mitchellwrosen@chromium.org</td> - - -<td> Use JSON schema compiler in chrome.management code - -BUG=121174 - - -Review URL: htt...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="media_player_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/media_player_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -media_player_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/media_player_private.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="metrics_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/metrics_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -metrics_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/metrics_private.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="omnibox.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/omnibox.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -omnibox.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/omnibox.json?revision=124878&view=markup" title="View file contents"><strong>124878</strong></a></td> - -<td> 5 months</td> -<td> cduvall@chromium.org</td> - - -<td> Allow comments in extension config files. - -Added a script to remove comments fro...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="page_action.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/page_action.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -page_action.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/page_action.json?revision=137065&view=markup" title="View file contents"><strong>137065</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Add optional callback to (browser|page)Action.setIcon - -BrowserActionApiTest.Dyna...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="page_actions.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/page_actions.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -page_actions.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/page_actions.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="page_capture.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/page_capture.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -page_capture.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/page_capture.json?revision=147890&view=markup" title="View file contents"><strong>147890</strong></a></td> - -<td> 2 weeks</td> -<td> hebert.christopherj@chromium.org</td> - - -<td> Extension Docs Server Version 2: Various fixes. - -Callbacks no longer appear when...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="permissions.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/permissions.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -permissions.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/permissions.json?revision=124878&view=markup" title="View file contents"><strong>124878</strong></a></td> - -<td> 5 months</td> -<td> cduvall@chromium.org</td> - - -<td> Allow comments in extension config files. - -Added a script to remove comments fro...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="privacy.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/privacy.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -privacy.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/privacy.json?revision=136588&view=markup" title="View file contents"><strong>136588</strong></a></td> - -<td> 2 months</td> -<td> bryeung@chromium.org</td> - - -<td> Make all extension api types fully qualified. - -BUG=123073 -TEST= (unit_tests --gt...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="proxy.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/proxy.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -proxy.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/proxy.json?revision=136588&view=markup" title="View file contents"><strong>136588</strong></a></td> - -<td> 2 months</td> -<td> bryeung@chromium.org</td> - - -<td> Make all extension api types fully qualified. - -BUG=123073 -TEST= (unit_tests --gt...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="runtime.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/runtime.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -runtime.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/runtime.json?revision=148956&view=markup" title="View file contents"><strong>148956</strong></a></td> - -<td> 11 days</td> -<td> mpcomplete@chromium.org</td> - - -<td> Fix the chrome.runtime.onInstalled docs to note it fires for updates as well. - -B...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="script_badge.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/script_badge.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -script_badge.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/script_badge.json?revision=146930&view=markup" title="View file contents"><strong>146930</strong></a></td> - -<td> 3 weeks</td> -<td> jyasskin@chromium.org</td> - - -<td> Implement scriptBadge.requestToAct. - -Currently it just shows the script badge an...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="serial.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/serial.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -serial.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/serial.idl?revision=150186&view=markup" title="View file contents"><strong>150186</strong></a></td> - -<td> 3 days</td> -<td> miket@chromium.org</td> - - -<td> Move serial out of experimental. - -This CL is unremarkable except that I figured ...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="socket.idl" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/socket.idl?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -socket.idl</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/socket.idl?revision=150190&view=markup" title="View file contents"><strong>150190</strong></a></td> - -<td> 3 days</td> -<td> thorogood@chromium.org</td> - - -<td> Adds socket.getInfo to the socket API - -Allows clients to retrieve the state of a...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="storage.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/storage.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -storage.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/storage.json?revision=149837&view=markup" title="View file contents"><strong>149837</strong></a></td> - -<td> 7 days</td> -<td> joaodasilva@chromium.org</td> - - -<td> Disable the managed storage API behind a flag for M22. - -BUG=108992 - - -Review URL:...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="system_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/system_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -system_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/system_private.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="tabs.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/tabs.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -tabs.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/tabs.json?revision=149631&view=markup" title="View file contents"><strong>149631</strong></a></td> - -<td> 8 days</td> -<td> kalman@chromium.org</td> - - -<td> Make ActiveTabPermissionManager also grant the tabs permission for -that tab; onl...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="terminal_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/terminal_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -terminal_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/terminal_private.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="test.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/test.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -test.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/test.json?revision=145505&view=markup" title="View file contents"><strong>145505</strong></a></td> - -<td> 5 weeks</td> -<td> kalman@chromium.org</td> - - -<td> Expose the extension/app's id on chrome.runtime.id and, and make this -an unprivi...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="top_sites.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/top_sites.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -top_sites.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/top_sites.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="tts.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/tts.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -tts.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/tts.json?revision=134209&view=markup" title="View file contents"><strong>134209</strong></a></td> - -<td> 3 months</td> -<td> dtseng@chromium.org</td> - - -<td> Uses a system-wide notion of isSpeaking in the Mac extension TTS api. - - -BUG=none...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="tts_engine.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/tts_engine.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -tts_engine.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/tts_engine.json?revision=136747&view=markup" title="View file contents"><strong>136747</strong></a></td> - -<td> 2 months</td> -<td> cduvall@chromium.org</td> - - -<td> Files generated by the JSON schema compiler are named incorrectly - -Files are now...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="types.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/types.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -types.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/types.json?revision=146093&view=markup" title="View file contents"><strong>146093</strong></a></td> - -<td> 4 weeks</td> -<td> bauerb@chromium.org</td> - - -<td> Add "regular_only" scope to allowed scopes for ChromeSetting.clear(). - - -BUG=1363...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="wallpaper_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/wallpaper_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -wallpaper_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/wallpaper_private.json?revision=148400&view=markup" title="View file contents"><strong>148400</strong></a></td> - -<td> 2 weeks</td> -<td> bshe@chromium.org</td> - - -<td> Wallpaper manager backend APIs - - -BUG=118684 -TEST=none - - -Review URL: <a href="https://chro">https://chro</a>...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="web_navigation.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/web_navigation.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -web_navigation.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/web_navigation.json?revision=148204&view=markup" title="View file contents"><strong>148204</strong></a></td> - -<td> 2 weeks</td> -<td> jochen@chromium.org</td> - - -<td> Revert "Revert 148074 - Pass the render process id to the FrameNavigationState."...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="web_request.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/web_request.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -web_request.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/web_request.json?revision=138481&view=markup" title="View file contents"><strong>138481</strong></a></td> - -<td> 2 months</td> -<td> vabr@chromium.org</td> - - -<td> Making webRequest.addEventListener internal - -Changes required to hide addEventLi...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="web_request_internal.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/web_request_internal.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -web_request_internal.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/web_request_internal.json?revision=138481&view=markup" title="View file contents"><strong>138481</strong></a></td> - -<td> 2 months</td> -<td> vabr@chromium.org</td> - - -<td> Making webRequest.addEventListener internal - -Changes required to hide addEventLi...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="webstore.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/webstore.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -webstore.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/webstore.json?revision=127930&view=markup" title="View file contents"><strong>127930</strong></a></td> - -<td> 4 months</td> -<td> kalman@chromium.org</td> - - -<td> Convert the webstore API to use the schema_generated_bindings infrastructure. - - -...</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="webstore_private.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/webstore_private.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -webstore_private.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/webstore_private.json?revision=150455&view=markup" title="View file contents"><strong>150455</strong></a></td> - -<td> 2 days</td> -<td> mihaip@chromium.org</td> - - -<td> Remove chrome.webstorePrivate.silentlyInstall. - -BUG=117168 - -Review URL: https://...</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="windows.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/windows.json?view=log" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" /> -windows.json</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/windows.json?revision=140947&view=markup" title="View file contents"><strong>140947</strong></a></td> - -<td> 2 months</td> -<td> jeremya@chromium.org</td> - - -<td> Remove chrome.windows.* support for platform apps. - -Use chrome.appWindow.* inste...</td> - - - -</tr> - -</tbody> -</table> - -</div> - - - -<hr /> -<table> -<tr> -<td><address><a href="mailto:cvs-admin@insert.your.domain.here">No admin address has been configured</a></address></td> -<td style="text-align: right;"><strong><a href="/viewvc/*docroot*/help_dirview.html">ViewVC Help</a></strong></td> -</tr> -<tr> -<td>Powered by <a href="http://viewvc.tigris.org/">ViewVC 1.0.9</a></td> -<td style="text-align: right;"> </td> -</tr> -</table> -</body> -</html>
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json b/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json deleted file mode 100644 index 0c5d79d9..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json +++ /dev/null
@@ -1,86 +0,0 @@ -{ - "extension_api.h": "146163", - "_permission_features.json": "150186", - "file_system.idl": "150515", - "input_ime.json": "149101", - "context_menus.json": "140112", - "app.json": "133722", - "browser_action.json": "148043", - "test.json": "145505", - "chromeos_info_private.json": "150737", - "font_settings.json": "147621", - "management.json": "151113", - "bookmark_manager.json": "140864", - "experimental_commands.json": "149147", - "web_navigation.json": "148204", - "echo_private.json": "136747", - "i18n.json": "149045", - "storage.json": "149837", - "experimental_media_galleries.idl": "150164", - "web_request_internal.json": "138481", - "app_window.idl": "147710", - "web_request.json": "138481", - "windows.json": "140947", - "terminal_private.json": "136747", - "experimental_rlz.json": "136747", - "system_private.json": "136747", - "content_settings.json": "136747", - "file_browser_handler.json": "149101", - "devtools.json": "124878", - "experimental_dns.idl": "136747", - "experimental_speech_input.json": "136747", - "api.gyp": "151113", - "experimental_identity.idl": "147523", - "runtime.json": "148956", - "alarms.idl": "143049", - "declarative_web_request.json": "150421", - "devtools/": "149291", - "experimental_idltest.idl": "138707", - "script_badge.json": "146930", - "extension_api_unittest.cc": "149819", - "events.json": "143168", - "tts.json": "134209", - "metrics_private.json": "136747", - "experimental_usb.idl": "144221", - "webstore.json": "127930", - "managed_mode_private.json": "142720", - "downloads.idl": "146201", - "serial.idl": "150186", - "page_capture.json": "147890", - "_manifest_features.json": "150827", - "browsing_data.json": "142133", - "top_sites.json": "136747", - "page_actions.json": "136747", - "page_action.json": "137065", - "history.json": "129086", - "bookmarks.json": "149307", - "permissions.json": "124878", - "experimental_app.json": "148848", - "media_player_private.json": "136747", - "experimental_input_virtual_keyboard.json": "138223", - "privacy.json": "136588", - "tabs.json": "149631", - "tts_engine.json": "136747", - "experimental_bluetooth.idl": "150898", - "idle.json": "124878", - "input_method_private.json": "136747", - "experimental_accessibility.json": "136747", - "push_messaging.idl": "149536", - "webstore_private.json": "150455", - "extension.json": "146855", - "extension_api.cc": "149819", - "file_manager_private.json": "150806", - "cloud_print_private.json": "149303", - "omnibox.json": "124878", - "processes.json": "137690", - "proxy.json": "136588", - "file_browser_handler_internal.json": "142683", - "types.json": "146093", - "experimental_record.json": "145342", - "debugger.json": "147894", - "socket.idl": "150190", - "OWNERS": "150079", - "cookies.json": "124878", - "infobars.json": "136747", - "wallpaper_private.json": "148400" -}
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/test1.txt b/chrome/common/extensions/docs/server2/test_data/file_system/test1.txt deleted file mode 100644 index a5bce3f..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/test1.txt +++ /dev/null
@@ -1 +0,0 @@ -test1
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/test2.txt b/chrome/common/extensions/docs/server2/test_data/file_system/test2.txt deleted file mode 100644 index 180cf83..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/test2.txt +++ /dev/null
@@ -1 +0,0 @@ -test2
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/test3.txt b/chrome/common/extensions/docs/server2/test_data/file_system/test3.txt deleted file mode 100644 index df6b0d2b..0000000 --- a/chrome/common/extensions/docs/server2/test_data/file_system/test3.txt +++ /dev/null
@@ -1 +0,0 @@ -test3
diff --git a/chrome/common/extensions/docs/server2/test_data/object_level_availability/__init__.py b/chrome/common/extensions/docs/server2/test_data/object_level_availability/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/chrome/common/extensions/docs/server2/test_data/object_level_availability/__init__.py +++ /dev/null
diff --git a/chrome/common/extensions/docs/server2/test_data/object_level_availability/tabs.py b/chrome/common/extensions/docs/server2/test_data/object_level_availability/tabs.py deleted file mode 100644 index 6d9cb2ea..0000000 --- a/chrome/common/extensions/docs/server2/test_data/object_level_availability/tabs.py +++ /dev/null
@@ -1,1501 +0,0 @@ -# Copyright 2013 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 json - -from extensions_paths import CHROME_EXTENSIONS -from test_file_system import MoveAllTo -from test_util import ReadFile - -FAKE_TABS_IDL = '\n'.join([ - '// Copyleft stuff.', - '', - '// Some description here.', - 'namespace fakeTabs {', - ' dictionary WasImplicitlyInlinedType {};', - ' interface Functions {', - ' static void myFunc(WasImplicitlyInlinedType arg);', - ' static void anotherFunc(WasImplicitlyInlinedType arg);', - ' };', - '};']) - -FAKE_TABS_WITH_INLINING_IDL = '\n'.join([ - '// Copyleft stuff.', - '', - '// Some description here.', - 'namespace fakeTabs {', - ' dictionary WasImplicitlyInlinedType {};', - ' interface Functions {', - ' static void myFunc(WasImplicitlyInlinedType arg);', - ' };', - '};']) - -TABS_SCHEMA_BRANCHES = MoveAllTo(CHROME_EXTENSIONS, { - 'master': { - 'docs': { - 'templates': { - 'json': { - 'api_availabilities.json': json.dumps({ - 'tabs.fakeTabsProperty4': { - 'channel': 'stable', - 'version': 27 - } - }), - 'intro_tables.json': '{}' - } - } - }, - 'api': { - '_api_features.json': json.dumps({ - 'tabs.scheduledFunc': { - 'channel': 'stable' - } - }), - '_manifest_features.json': '{}', - '_permission_features.json': '{}', - 'fake_tabs.idl': FAKE_TABS_IDL, - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'type': 'any', - 'properties': { - 'url': { - 'type': 'any' - }, - 'index': { - 'type': 'any' - }, - 'selected': { - 'type': 'any' - }, - 'id': { - 'type': 'any' - }, - 'windowId': { - 'type': 'any' - } - } - }, - { - 'id': 'InlinedType', - 'type': 'any', - 'inline_doc': True - }, - { - 'id': 'InjectDetails', - 'type': 'any', - 'properties': { - 'allFrames': { - 'type': 'any' - }, - 'code': { - 'type': 'any' - }, - 'file': { - 'type':'any' - } - } - }, - { - 'id': 'DeprecatedType', - 'type': 'any', - 'deprecated': 'This is deprecated' - } - ], - 'properties': { - 'fakeTabsProperty1': { - 'type': 'any' - }, - 'fakeTabsProperty2': { - 'type': 'any' - }, - 'fakeTabsProperty3': { - 'type': 'any' - }, - 'fakeTabsProperty4': { - 'type': 'any' - } - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'type': 'function', - 'parameters': [ - { - 'name': 'tab', - 'type': 'any' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'tabId', - 'type': 'any' - }, - { - 'name': 'callback', - 'type': 'function', - 'parameters': [ - { - 'name': 'tab', - 'type': 'any' - } - ] - } - ] - }, - { - 'name': 'restrictedFunc' - }, - { - 'name': 'scheduledFunc', - 'parameters': [] - } - ], - 'events': [ - { - 'name': 'onActivated', - 'type': 'event', - 'parameters': [ - { - 'name': 'activeInfo', - 'type': 'any', - 'properties': { - 'tabId': { - 'type': 'any' - }, - 'windowId': { - 'type': 'any' - } - } - } - ] - }, - { - 'name': 'onUpdated', - 'type': 'event', - 'parameters': [ - { - 'name': 'tabId', - 'type': 'any' - }, - { - 'name': 'tab', - 'type': 'any' - }, - { - 'name': 'changeInfo', - 'type': 'any', - 'properties': { - 'pinned': { - 'type': 'any' - }, - 'status': { - 'type': 'any' - } - } - } - ] - } - ] - }]) - } - }, - '1612': { - 'api': { - '_api_features.json': json.dumps({ - 'tabs.scheduledFunc': { - 'channel': 'stable' - } - }), - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'fake_tabs.idl': FAKE_TABS_IDL, - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - }, - { - 'id': 'InjectDetails', - 'properties': { - 'allFrames': {}, - 'code': {}, - 'file': {} - } - }, - { - 'id': 'DeprecatedType', - 'deprecated': 'This is deprecated' - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'restrictedFunc' - }, - { - 'name': 'scheduledFunc', - 'parameters': [] - } - ], - 'events': [ - { - 'name': 'onActivated', - 'parameters': [ - { - 'name': 'activeInfo', - 'properties': { - 'tabId': {}, - 'windowId': {} - } - } - ] - }, - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'tab' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1599': { - 'api': { - '_api_features.json': "{}", - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'fake_tabs.idl': FAKE_TABS_IDL, - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - }, - { - 'id': 'InjectDetails', - 'properties': { - 'allFrames': {}, - 'code': {}, - 'file': {} - } - }, - { - 'id': 'DeprecatedType', - 'deprecated': 'This is deprecated' - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'restrictedFunc' - } - ], - 'events': [ - { - 'name': 'onActivated', - 'parameters': [ - { - 'name': 'activeInfo', - 'properties': { - 'tabId': {}, - } - } - ] - }, - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1547': { - 'api': { - '_api_features.json': json.dumps({ - 'tabs.restrictedFunc': { - 'channel': 'dev' - } - }), - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'fake_tabs.idl': FAKE_TABS_IDL, - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - }, - { - 'id': 'InjectDetails', - 'properties': { - 'allFrames': {}, - 'code': {}, - 'file': {} - } - }, - { - 'id': 'DeprecatedType', - 'deprecated': 'This is deprecated' - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - }, - ] - }, - { - 'name': 'restrictedFunc' - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1500': { - 'api': { - '_api_features.json': "{}", - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'fake_tabs.idl': FAKE_TABS_IDL, - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - }, - { - 'id': 'InjectDetails', - 'properties': { - 'allFrames': {}, - } - }, - { - 'id': 'DeprecatedType', - 'deprecated': 'This is deprecated' - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - }, - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1453': { - 'api': { - '_api_features.json': "{}", - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'fake_tabs.idl': FAKE_TABS_IDL, - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - }, - { - 'id': 'InjectDetails', - 'properties': { - 'allFrames': {}, - } - }, - { - 'id': 'DeprecatedType', - 'deprecated': 'This is deprecated' - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - }, - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1410': { - 'api': { - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'fake_tabs.idl': FAKE_TABS_IDL, - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - }, - { - 'id': 'InjectDetails', - 'properties': { - 'allFrames': {}, - } - }, - { - 'id': 'DeprecatedType', - 'deprecated': 'This is deprecated' - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1364': { - 'api': { - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'fake_tabs.idl': FAKE_TABS_WITH_INLINING_IDL, - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - }, - { - 'id': 'InjectDetails', - 'properties': { - 'allFrames': {} - } - }, - { - 'id': 'DeprecatedType', - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1312': { - 'api': { - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1271': { - 'api': { - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1229': { - 'api': { - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {}, - 'windowId': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1180': { - 'api': { - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'selected': {}, - 'id': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1132': { - 'api': { - '_manifest_features.json': "{}", - '_permission_features.json': "{}", - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'id': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1084': { - 'api': { - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'id': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'getCurrent', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - }, - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '1025': { - 'api': { - 'tabs.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'index': {}, - 'id': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '963': { - 'api': { - 'extension_api.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'id': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - }, - { - 'name': 'changeInfo', - 'properties': { - 'pinned': {}, - 'status': {} - } - } - ] - } - ] - }]) - } - }, - '912': { - 'api': { - 'extension_api.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'id': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - } - ] - } - ] - }]) - } - }, - '874': { - 'api': { - 'extension_api.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'id': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {}, - 'fakeTabsProperty2': {} - }, - 'functions': [ - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - } - ] - } - ] - }]) - } - }, - '835': { - 'api': { - 'extension_api.json': json.dumps([{ - 'namespace': 'tabs', - 'types': [ - { - 'id': 'Tab', - 'properties': { - 'url': {}, - 'id': {} - } - } - ], - 'properties': { - 'fakeTabsProperty1': {} - }, - 'functions': [ - { - 'name': 'get', - 'parameters': [ - { - 'name': 'callback', - 'parameters': [ - { - 'name': 'tab' - } - ] - } - ] - } - ], - 'events': [ - { - 'name': 'onUpdated', - 'parameters': [ - { - 'name': 'tabId' - } - ] - } - ] - }]) - } - }, - '782': { - 'api': { - 'extension_api.json': "{}" - } - } -})
diff --git a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/api/14096030/22002/json b/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/api/14096030/22002/json deleted file mode 100644 index 96faac1..0000000 --- a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/api/14096030/22002/json +++ /dev/null
@@ -1 +0,0 @@ -{"files":{"chrome/common/extensions/api/test.json":{"status":"M ","num_chunks":1,"no_base_file":false,"property_changes":"","num_added":0,"num_removed":1,"id":21002,"is_binary":false},"chrome/common/extensions/docs/templates/public/extensions/test_foo.html":{"status":"A ","num_chunks":1,"no_base_file":false,"property_changes":"\nAdded: svn:mime-type\n + text/html\nAdded: svn:eol-style\n + LF\n","num_added":1,"num_removed":0,"id":21007,"is_binary":false},"chrome/common/extensions/docs/templates/json/extensions_sidenav.json":{"status":"M ","num_chunks":1,"no_base_file":false,"property_changes":"","num_added":2,"num_removed":218,"id":21005,"is_binary":false},"chrome/common/extensions/docs/templates/public/extensions/runtime.html":{"status":"D ","num_chunks":1,"no_base_file":false,"property_changes":"","num_added":0,"num_removed":1,"id":21006,"is_binary":false},"chrome/common/extensions/manifest.h":{"status":"M ","num_chunks":1,"no_base_file":false,"property_changes":"","num_added":1,"num_removed":1,"id":21008,"is_binary":false},"chrome/common/extensions/docs/examples/test":{"status":"A ","num_chunks":1,"no_base_file":false,"property_changes":"","num_added":1,"num_removed":0,"id":21003,"is_binary":false},"chrome/common/extensions/docs/templates/articles/test_foo.html":{"status":"A ","num_chunks":1,"no_base_file":false,"property_changes":"\nAdded: svn:eol-style\n + LF\nAdded: svn:mime-type\n + text/html\n","num_added":2,"num_removed":0,"id":21004,"is_binary":false}},"owner_email":"fangjue23303@gmail.com","owner":"\u65b9\u89c9(Fang Jue)","message":" ","try_job_results":[],"created":"2013-05-03 08:43:17.399990","url":null,"num_comments":0,"modified":"2013-05-03 08:43:17.400410","patchset":22002,"issue":14096030}
diff --git a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/api/14096030/json b/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/api/14096030/json deleted file mode 100644 index 5a17a82..0000000 --- a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/api/14096030/json +++ /dev/null
@@ -1 +0,0 @@ -{"description":"(TEST FOR 14125010, NOT FOR COMMIT) rietveld_patcher_test data","cc":[],"reviewers":[],"owner_email":"fangjue23303@gmail.com","private":false,"base_url":"https://src.chromium.org/svn/trunk/src/","owner":"\u65b9\u89c9(Fang Jue)","subject":"(TEST FOR 14125010, NOT FOR COMMIT) unittest data","created":"2013-04-28 10:29:31.098160","patchsets":[1,3001,5004,4004,14001,22002],"modified":"2013-05-03 08:43:17.504060","closed":false,"commit":false,"issue":14096030}
diff --git a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/extensions_sidenav.json b/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/extensions_sidenav.json deleted file mode 100644 index e5c4cc2..0000000 --- a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/extensions_sidenav.json +++ /dev/null
@@ -1,6 +0,0 @@ -[ - { - "title": "Test Foo", - "fileName": "test_foo.html" - } -]
diff --git a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/test_foo.html b/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/test_foo.html deleted file mode 100644 index dd9e169..0000000 --- a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/test_foo.html +++ /dev/null
@@ -1 +0,0 @@ -{{+partials.standard_extensions_article article:intros.test_foo/}}
diff --git a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/tarball/14096030/22002.tar.bz2 b/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/tarball/14096030/22002.tar.bz2 deleted file mode 100644 index fad29ec7..0000000 --- a/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/tarball/14096030/22002.tar.bz2 +++ /dev/null Binary files differ
diff --git a/chrome/common/extensions/docs/server2/test_data/samples_data_source/expected.json b/chrome/common/extensions/docs/server2/test_data/samples_data_source/expected.json deleted file mode 100644 index 904e5d8..0000000 --- a/chrome/common/extensions/docs/server2/test_data/samples_data_source/expected.json +++ /dev/null
@@ -1,10 +0,0 @@ -[ - { - "api_calls": [ - { "name": "bobaloo.foop" }, - { "name": "jimmy.bobaloo.loopoo" }, - { "name": "jimmy.jimmy" }, - { "name": "hallo.bobaloo" } - ] - } -]
diff --git a/chrome/common/extensions/docs/server2/test_data/samples_data_source/samples.json b/chrome/common/extensions/docs/server2/test_data/samples_data_source/samples.json deleted file mode 100644 index 4c01527..0000000 --- a/chrome/common/extensions/docs/server2/test_data/samples_data_source/samples.json +++ /dev/null
@@ -1,24 +0,0 @@ -[ - { - "api_calls": [ - { "name": "bobaloo.foop" }, - { "name": "jimmy.bobaloo.loopoo" }, - { "name": "jimmy.jimmy" }, - { "name": "hallo.bobaloo" } - ] - }, - { - "api_calls": [ - { "name": "timmy.bobaloo.affa" }, - { "name": "jimmy.baloo.loopoo" }, - { "name": "jimmy.jimmy" } - ] - }, - { - "api_calls": [ - { "name": "torta.lamb.paco" }, - { "name": "jimmy.baloo.loopoo" }, - { "name": "jimmy.jimmy" } - ] - } -]
diff --git a/chrome/common/extensions/docs/server2/test_data/subversion_file_system/api_icons_214898 b/chrome/common/extensions/docs/server2/test_data/subversion_file_system/api_icons_214898 deleted file mode 100644 index c4697ba5..0000000 --- a/chrome/common/extensions/docs/server2/test_data/subversion_file_system/api_icons_214898 +++ /dev/null
@@ -1,136 +0,0 @@ - - - - -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<!-- ViewVC :: http://www.viewvc.org/ --> -<head> -<title>[chrome] Index of /trunk/src/chrome/common/extensions/api/icons</title> -<meta name="generator" content="ViewVC 1.1.5" /> -<link rel="shortcut icon" href="/viewvc/*docroot*/images/favicon.ico" type="image/x-icon" /> -<link rel="stylesheet" href="/viewvc/*docroot*/styles.css" type="text/css" /> - -</head> -<body> -<div class="vc_navheader"> -<table><tr> -<td><strong><a href="/viewvc"><span class="pathdiv">/</span></a><a href="/viewvc/chrome/?pathrev=214898">[chrome]</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/?pathrev=214898">trunk</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/?pathrev=214898">src</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/?pathrev=214898">chrome</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/common/?pathrev=214898">common</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/common/extensions/?pathrev=214898">extensions</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/?pathrev=214898">api</a><span class="pathdiv">/</span>icons</strong></td> -<td style="text-align: right;"></td> -</tr></table> -</div> -<div style="float: right; padding: 5px;"><a href="http://www.chromium.org" title="ViewVC Home"><img src="/viewvc/*docroot*/images/viewvc-logo.png" alt="Chromium logo" width="345" height="76" /></a></div> -<h1>Index of /trunk/src/chrome/common/extensions/api/icons</h1> - - -<table class="auto"> -<tr><td>Files shown:</td><td><strong>0</strong> - - -</td></tr> - -<tr> -<td>Directory revision:</td> -<td><a href="/viewvc/chrome?view=revision&revision=193838" title="Revision 193838">193838</a> (of <a href="/viewvc/chrome?view=revision" title="Revision 215520">215520</a>)</td> -</tr> - -<tr> -<td>Sticky Revision:</td> -<td><form method="get" action="/viewvc/chrome" style="display: inline"> -<div style="display: inline"> -<input type="hidden" name="orig_pathrev" value="214898"/><input type="hidden" name="orig_pathtype" value="DIR"/><input type="hidden" name="orig_view" value="dir"/><input type="hidden" name="orig_path" value="trunk/src/chrome/common/extensions/api/icons"/><input type="hidden" name="view" value="redirect_pathrev"/> - -<input type="text" name="pathrev" value="214898" size="6"/> - -<input type="submit" value="Set" /> -</div> -</form> - -<form method="get" action="/viewvc/chrome/trunk/src/chrome/common/extensions/api/icons/" style="display: inline"> -<div style="display: inline"> - - -<input type="submit" value="Clear" /> - -</div> -</form> - -</td> -</tr> - - -</table> - - -<p><a name="dirlist"></a></p> -<hr /> - -<table cellspacing="1" cellpadding="2"> -<thead> -<tr> -<th class="vc_header_sort" colspan="2"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/icons/?sortdir=down&pathrev=214898#dirlist">File</a> - -<img class="vc_sortarrow" alt="" -width="13" height="13" -src="/viewvc/*docroot*/images/up.png" /> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/icons/?sortby=rev&pathrev=214898#dirlist">Rev.</a> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/icons/?sortby=date&pathrev=214898#dirlist">Age</a> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/icons/?sortby=author&pathrev=214898#dirlist">Author</a> - -</th> - -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/icons/?sortby=log&pathrev=214898#dirlist">Last log entry</a> - -</th> - -</tr> -</thead> -<tbody> - -<tr class="vc_row_odd"> -<td colspan="2"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/?pathrev=214898"> -<img src="/viewvc/*docroot*/images/back_small.png" alt="" class="vc_icon" -/> Parent Directory</a> -</td> -<td> </td> -<td> </td> -<td> </td> - -<td> </td> - -</tr> - - -</tbody> -</table> - - - - - -<hr /> -<table> -<tr> -<td>Powered by <a href="http://viewvc.tigris.org/">ViewVC 1.1.5</a></td> -<!--td style="text-align: right;"> </td--> -<!--td> </td--> -<td style="text-align: right;"><strong><a href="/viewvc/*docroot*/help_dirview.html">ViewVC Help</a></strong></td> -</tr> -</table> -</body> -</html> - -
diff --git a/chrome/common/extensions/docs/server2/test_data/subversion_file_system/docs_public_extensions_214898 b/chrome/common/extensions/docs/server2/test_data/subversion_file_system/docs_public_extensions_214898 deleted file mode 100644 index bd45085..0000000 --- a/chrome/common/extensions/docs/server2/test_data/subversion_file_system/docs_public_extensions_214898 +++ /dev/null
@@ -1,3664 +0,0 @@ - - - - -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<!-- ViewVC :: http://www.viewvc.org/ --> -<head> -<title>[chrome] Index of /trunk/src/chrome/common/extensions/docs/templates/public/extensions</title> -<meta name="generator" content="ViewVC 1.1.5" /> -<link rel="shortcut icon" href="/viewvc/*docroot*/images/favicon.ico" type="image/x-icon" /> -<link rel="stylesheet" href="/viewvc/*docroot*/styles.css" type="text/css" /> - -</head> -<body> -<div class="vc_navheader"> -<table><tr> -<td><strong><a href="/viewvc"><span class="pathdiv">/</span></a><a href="/viewvc/chrome/?pathrev=214898">[chrome]</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/?pathrev=214898">trunk</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/?pathrev=214898">src</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/?pathrev=214898">chrome</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/common/?pathrev=214898">common</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/common/extensions/?pathrev=214898">extensions</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/?pathrev=214898">docs</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/?pathrev=214898">templates</a><span class="pathdiv">/</span><a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/?pathrev=214898">public</a><span class="pathdiv">/</span>extensions</strong></td> -<td style="text-align: right;"></td> -</tr></table> -</div> -<div style="float: right; padding: 5px;"><a href="http://www.chromium.org" title="ViewVC Home"><img src="/viewvc/*docroot*/images/viewvc-logo.png" alt="Chromium logo" width="345" height="76" /></a></div> -<h1>Index of /trunk/src/chrome/common/extensions/docs/templates/public/extensions</h1> - - -<table class="auto"> -<tr><td>Files shown:</td><td><strong>125</strong> - - -</td></tr> - -<tr> -<td>Directory revision:</td> -<td><a href="/viewvc/chrome?view=revision&revision=214692" title="Revision 214692">214692</a> (of <a href="/viewvc/chrome?view=revision" title="Revision 215508">215508</a>)</td> -</tr> - -<tr> -<td>Sticky Revision:</td> -<td><form method="get" action="/viewvc/chrome" style="display: inline"> -<div style="display: inline"> -<input type="hidden" name="orig_pathrev" value="214898"/><input type="hidden" name="orig_pathtype" value="DIR"/><input type="hidden" name="orig_view" value="dir"/><input type="hidden" name="orig_path" value="trunk/src/chrome/common/extensions/docs/templates/public/extensions"/><input type="hidden" name="view" value="redirect_pathrev"/> - -<input type="text" name="pathrev" value="214898" size="6"/> - -<input type="submit" value="Set" /> -</div> -</form> - -<form method="get" action="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/" style="display: inline"> -<div style="display: inline"> - - -<input type="submit" value="Clear" /> - -</div> -</form> - -</td> -</tr> - - -</table> - - -<p><a name="dirlist"></a></p> -<hr /> - -<table cellspacing="1" cellpadding="2"> -<thead> -<tr> -<th class="vc_header_sort" colspan="2"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/?sortdir=down&pathrev=214898#dirlist">File</a> - -<img class="vc_sortarrow" alt="" -width="13" height="13" -src="/viewvc/*docroot*/images/up.png" /> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/?sortby=rev&pathrev=214898#dirlist">Rev.</a> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/?sortby=date&pathrev=214898#dirlist">Age</a> - -</th> -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/?sortby=author&pathrev=214898#dirlist">Author</a> - -</th> - -<th class="vc_header"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/?sortby=log&pathrev=214898#dirlist">Last log entry</a> - -</th> - -</tr> -</thead> -<tbody> - -<tr class="vc_row_odd"> -<td colspan="2"> -<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/?pathrev=214898"> -<img src="/viewvc/*docroot*/images/back_small.png" alt="" class="vc_icon" -/> Parent Directory</a> -</td> -<td> </td> -<td> </td> -<td> </td> - -<td> </td> - -</tr> - - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="manifest" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/manifest/?pathrev=214898" title="View directory contents"> - -<img src="/viewvc/*docroot*/images/dir.png" alt="" class="vc_icon" /> -manifest/</a> - -</td> - - - -<td> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/manifest/?view=log&pathrev=214898" title="View directory revision log"><strong>212903</strong></a></td> - -<td> 11 days</td> -<td> jaredshumway94@gmail.com</td> - - -<td> Docserver: generate the manifest page. - -The manifest page is now unique for apps…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="404.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/404.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -404.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/404.html?revision=203435&pathrev=214898" title="View file contents"><strong>203435</strong></a> - -</td> - -<td> 2 months</td> -<td> fangjue23303@gmail.com</td> - - -<td> Extension docs: Include sidenav in 404 pages - -Include sidenav in 404 pages of ex…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="a11y.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/a11y.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -a11y.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/a11y.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="activeTab.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/activeTab.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -activeTab.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/activeTab.html?revision=157945&pathrev=214898" title="View file contents"><strong>157945</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Document the activeTab extension permission. - -BUG=141862 - -Review URL: <a href="https://codereview.chromium.org/10874057">https://co</a>…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="alarms.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/alarms.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -alarms.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/alarms.html?revision=212595&pathrev=214898" title="View file contents"><strong>212595</strong></a> - -</td> - -<td> 2 weeks</td> -<td> evan.peterson.EP@gmail.com</td> - - -<td> Linking AvailabilityFinder with APIDataSource and intro-table templates. - -BUG=23…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="api_index.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/api_index.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -api_index.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/api_index.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="api_other.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/api_other.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -api_other.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/api_other.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="app_identity.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/app_identity.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -app_identity.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/app_identity.html?revision=208313&pathrev=214898" title="View file contents"><strong>208313</strong></a> - -</td> - -<td> 5 weeks</td> -<td> courage@chromium.org</td> - - -<td> Add chrome.identity documentation. - -BUG=181641 - -Review URL: <a href="https://chromiumcodereview.appspot.com/17501007">https://chromiumcode</a>…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="apps.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/apps.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -apps.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/apps.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="autoupdate.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/autoupdate.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -autoupdate.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/autoupdate.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="background_pages.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/background_pages.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -background_pages.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/background_pages.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="bookmarks.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/bookmarks.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -bookmarks.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/bookmarks.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="browserAction.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/browserAction.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -browserAction.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/browserAction.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="browsingData.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/browsingData.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -browsingData.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/browsingData.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="cloudMessaging.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/cloudMessaging.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -cloudMessaging.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/cloudMessaging.html?revision=174425&pathrev=214898" title="View file contents"><strong>174425</strong></a> - -</td> - -<td> 7 months</td> -<td> mkearney@google.com</td> - - -<td> Added new articles: API Reference for GCM Service and Google Cloud Messaging for…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="commands.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/commands.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -commands.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/commands.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="contentSecurityPolicy.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/contentSecurityPolicy.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -contentSecurityPolicy.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/contentSecurityPolicy.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="contentSettings.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/contentSettings.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -contentSettings.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/contentSettings.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="content_scripts.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/content_scripts.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -content_scripts.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/content_scripts.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="contextMenus.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/contextMenus.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -contextMenus.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/contextMenus.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="cookies.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/cookies.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -cookies.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/cookies.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="crx.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/crx.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -crx.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/crx.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="debugger.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/debugger.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -debugger.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/debugger.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="declarativeContent.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/declarativeContent.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -declarativeContent.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/declarativeContent.html?revision=181197&pathrev=214898" title="View file contents"><strong>181197</strong></a> - -</td> - -<td> 5 months</td> -<td> jyasskin@chromium.org</td> - - -<td> Document the declarativeContent API. - -BUG=172011 - -Review URL: <a href="https://chromiumcodereview.appspot.com/12042062">https://chromiumco</a>…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="declarativeWebRequest.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/declarativeWebRequest.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -declarativeWebRequest.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/declarativeWebRequest.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="declare_permissions.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/declare_permissions.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -declare_permissions.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/declare_permissions.html?revision=161498&pathrev=214898" title="View file contents"><strong>161498</strong></a> - -</td> - -<td> 9 months</td> -<td> mkearney@chromium.org</td> - - -<td> Improvements to permissions and permission warning docs; - -* This is a redo of <a href="https://codereview.chromium.org/10964056/.">ht</a>…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="desktop_notifications.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/desktop_notifications.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -desktop_notifications.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/desktop_notifications.html?revision=186368&pathrev=214898" title="View file contents"><strong>186368</strong></a> - -</td> - -<td> 4 months</td> -<td> mkearney@chromium.org</td> - - -<td> Additional fixes to new notification docs - -Implemented as many of Mike's comment…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="devguide.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devguide.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -devguide.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devguide.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="devtools.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devtools.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -devtools.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devtools.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="devtools_inspectedWindow.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devtools_inspectedWindow.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -devtools_inspectedWindow.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devtools_inspectedWindow.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="devtools_network.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devtools_network.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -devtools_network.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devtools_network.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="devtools_panels.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devtools_panels.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -devtools_panels.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/devtools_panels.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="downloads.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/downloads.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -downloads.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/downloads.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="event_pages.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/event_pages.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -event_pages.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/event_pages.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="events.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/events.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -events.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/events.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_browsingData.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_browsingData.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_browsingData.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_browsingData.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_contentSettings.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_contentSettings.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_contentSettings.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_contentSettings.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_contextMenus.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_contextMenus.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_contextMenus.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_contextMenus.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_cookies.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_cookies.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_cookies.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_cookies.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_debugger.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_debugger.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_debugger.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_debugger.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_devtools.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_devtools.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_devtools_audits.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_audits.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_devtools_audits.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_audits.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_devtools_console.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_console.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_devtools_console.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_console.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_devtools_inspectedWindow.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_inspectedWindow.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_devtools_inspectedWindow.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_inspectedWindow.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_devtools_network.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_network.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_devtools_network.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_network.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_devtools_panels.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_panels.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_devtools_panels.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_panels.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_devtools_resources.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_resources.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_devtools_resources.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_devtools_resources.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_history.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_history.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_history.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_history.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_identity.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_identity.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_identity.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_identity.html?revision=208313&pathrev=214898" title="View file contents"><strong>208313</strong></a> - -</td> - -<td> 5 weeks</td> -<td> courage@chromium.org</td> - - -<td> Add chrome.identity documentation. - -BUG=181641 - -Review URL: <a href="https://chromiumcodereview.appspot.com/17501007">https://chromiumcode</a>…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_inputUI.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_inputUI.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_inputUI.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_inputUI.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_privacy.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_privacy.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_privacy.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_privacy.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="processes.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/processes.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -processes.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/processes.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_record.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_record.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_record.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_record.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_storage.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_storage.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_storage.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_storage.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_webInspector.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webInspector.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_webInspector.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webInspector.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_webInspector_audits.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webInspector_audits.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_webInspector_audits.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webInspector_audits.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_webInspector_panels.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webInspector_panels.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_webInspector_panels.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webInspector_panels.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="experimental_webInspector_resources.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webInspector_resources.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_webInspector_resources.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webInspector_resources.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="experimental_webRequest.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webRequest.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -experimental_webRequest.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_webRequest.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="extension.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/extension.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -extension.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/extension.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="external_extensions.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/external_extensions.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -external_extensions.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/external_extensions.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="faq.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/faq.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -faq.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/faq.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="feedbackPrivate.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/feedbackPrivate.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -feedbackPrivate.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/feedbackPrivate.html?revision=206931&pathrev=214898" title="View file contents"><strong>206931</strong></a> - -</td> - -<td> 6 weeks</td> -<td> rkc@chromium.org</td> - - -<td> Implement the feedbackPrivate API. -This CL implements the feedbackPrivate API. T…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="fileBrowserHandler.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/fileBrowserHandler.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -fileBrowserHandler.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/fileBrowserHandler.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="fontSettings.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/fontSettings.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -fontSettings.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/fontSettings.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="gcm_server.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/gcm_server.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -gcm_server.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/gcm_server.html?revision=174425&pathrev=214898" title="View file contents"><strong>174425</strong></a> - -</td> - -<td> 7 months</td> -<td> mkearney@google.com</td> - - -<td> Added new articles: API Reference for GCM Service and Google Cloud Messaging for…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="gcm_tos.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/gcm_tos.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -gcm_tos.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/gcm_tos.html?revision=178067&pathrev=214898" title="View file contents"><strong>178067</strong></a> - -</td> - -<td> 6 months</td> -<td> mkearney@google.com</td> - - -<td> Improvements to Google Cloud Messaging for Chrome docs. - -Added new left-side nav…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="getstarted.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/getstarted.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -getstarted.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/getstarted.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="history.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/history.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -history.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/history.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="hosting.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/hosting.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -hosting.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/hosting.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="i18n-messages.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/i18n-messages.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -i18n-messages.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/i18n-messages.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="i18n.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/i18n.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -i18n.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/i18n.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="identity.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/identity.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -identity.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/identity.html?revision=212595&pathrev=214898" title="View file contents"><strong>212595</strong></a> - -</td> - -<td> 2 weeks</td> -<td> evan.peterson.EP@gmail.com</td> - - -<td> Linking AvailabilityFinder with APIDataSource and intro-table templates. - -BUG=23…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="idle.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/idle.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -idle.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/idle.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="index.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/index.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -index.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/index.html?revision=189684&pathrev=214898" title="View file contents"><strong>189684</strong></a> - -</td> - -<td> 4 months</td> -<td> kalman@chromium.org</td> - - -<td> Developer server: Rearrange the header and extension index, then add a -"Send Fee…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="input_ime.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/input_ime.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -input_ime.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/input_ime.html?revision=159644&pathrev=214898" title="View file contents"><strong>159644</strong></a> - -</td> - -<td> 10 months</td> -<td> zork@chromium.org</td> - - -<td> Add an overview and sample for the input.ime extension api - - -R=<a href="mailto:aa%40chromium.org">aa@chromium.org</a> -B…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="management.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/management.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -management.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/management.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="manifest.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/manifest.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -manifest.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/manifest.html?revision=212903&pathrev=214898" title="View file contents"><strong>212903</strong></a> - -</td> - -<td> 11 days</td> -<td> jaredshumway94@gmail.com</td> - - -<td> Docserver: generate the manifest page. - -The manifest page is now unique for apps…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="manifestVersion.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/manifestVersion.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -manifestVersion.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/manifestVersion.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="match_patterns.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/match_patterns.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -match_patterns.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/match_patterns.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="messaging.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/messaging.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -messaging.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/messaging.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="notifications.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/notifications.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -notifications.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/notifications.html?revision=192921&pathrev=214898" title="View file contents"><strong>192921</strong></a> - -</td> - -<td> 3 months</td> -<td> kalman@chromium.org</td> - - -<td> Document the notifications API for extensions. - -Review URL: <a href="https://codereview.chromium.org/13744002">https://codereview.c</a>…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="npapi.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/npapi.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -npapi.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/npapi.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="omnibox.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/omnibox.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -omnibox.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/omnibox.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="options.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/options.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -options.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/options.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="override.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/override.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -override.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/override.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="overview.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/overview.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -overview.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/overview.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="packaging.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/packaging.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -packaging.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/packaging.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="pageAction.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/pageAction.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -pageAction.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/pageAction.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="pageCapture.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/pageCapture.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -pageCapture.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/pageCapture.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="permission_warnings.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/permission_warnings.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -permission_warnings.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/permission_warnings.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="permissions.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/permissions.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -permissions.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/permissions.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="power.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/power.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -power.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/power.html?revision=191365&pathrev=214898" title="View file contents"><strong>191365</strong></a> - -</td> - -<td> 4 months</td> -<td> mkearney@google.com</td> - - -<td> New power API docs - -Review URL: <a href="https://codereview.chromium.org/13004015">https://codereview.chromium.org/13004015</a></td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="privacy.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/privacy.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -privacy.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/privacy.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="proxy.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/proxy.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -proxy.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/proxy.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="pushMessaging.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/pushMessaging.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -pushMessaging.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/pushMessaging.html?revision=213109&pathrev=214898" title="View file contents"><strong>213109</strong></a> - -</td> - -<td> 11 days</td> -<td> fangjue23303@gmail.com</td> - - -<td> Extension docs: Cleanup after there's only one version. - -R=<a href="mailto:kalman%40chromium.org">kalman@chromium.org</a> -B…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="redirects.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/redirects.json?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -redirects.json</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/redirects.json?revision=213857&pathrev=214898" title="View file contents"><strong>213857</strong></a> - -</td> - -<td> 8 days</td> -<td> Hokein.Wu@gmail.com</td> - - -<td> [SystemInfo API] Move Storage API out of experimental namespace and rename to th…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="runtime.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/runtime.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -runtime.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/runtime.html?revision=212595&pathrev=214898" title="View file contents"><strong>212595</strong></a> - -</td> - -<td> 2 weeks</td> -<td> evan.peterson.EP@gmail.com</td> - - -<td> Linking AvailabilityFinder with APIDataSource and intro-table templates. - -BUG=23…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="samples.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/samples.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -samples.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/samples.html?revision=204215&pathrev=214898" title="View file contents"><strong>204215</strong></a> - -</td> - -<td> 8 weeks</td> -<td> jaredshumway94@gmail.com</td> - - -<td> Docserver: inline return and item types. Fix a couple of bugs. - -BUG=187494 - -Revi…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="sandboxingEval.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/sandboxingEval.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -sandboxingEval.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/sandboxingEval.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="scriptBadge.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/scriptBadge.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -scriptBadge.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/scriptBadge.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="sessionRestore.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/sessionRestore.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -sessionRestore.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/sessionRestore.html?revision=179426&pathrev=214898" title="View file contents"><strong>179426</strong></a> - -</td> - -<td> 6 months</td> -<td> ncj674@motorola.com</td> - - -<td> Reland 178902 Implementation of sessionRestore apis. - -BUG=14737 -TEST=ExtensionAp…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="storage.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/storage.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -storage.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/storage.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="system_cpu.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/system_cpu.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -system_cpu.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/system_cpu.html?revision=212204&pathrev=214898" title="View file contents"><strong>212204</strong></a> - -</td> - -<td> 2 weeks</td> -<td> Hokein.Wu@gmail.com</td> - - -<td> [SystemInfo API] Rename systemInfo Cpu API. - -Rename from "systemInfo.cpu.get" to…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="system_memory.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/system_memory.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -system_memory.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/system_memory.html?revision=213127&pathrev=214898" title="View file contents"><strong>213127</strong></a> - -</td> - -<td> 11 days</td> -<td> Hokein.Wu@gmail.com</td> - - -<td> [SystemInfo API] Rename systemInfo Memory API. - -Rename from "systemInfo.memory.g…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="system_storage.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/system_storage.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -system_storage.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/system_storage.html?revision=213857&pathrev=214898" title="View file contents"><strong>213857</strong></a> - -</td> - -<td> 8 days</td> -<td> Hokein.Wu@gmail.com</td> - - -<td> [SystemInfo API] Move Storage API out of experimental namespace and rename to th…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="tabCapture.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tabCapture.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -tabCapture.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tabCapture.html?revision=168679&pathrev=214898" title="View file contents"><strong>168679</strong></a> - -</td> - -<td> 8 months</td> -<td> justinlin@chromium.org</td> - - -<td> Enable TabCapture feature by default (there is an animation in the favicon area …</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="tabs.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tabs.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -tabs.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tabs.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="themes.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/themes.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -themes.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/themes.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="topSites.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/topSites.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -topSites.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/topSites.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="tts.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tts.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -tts.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tts.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="ttsEngine.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/ttsEngine.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -ttsEngine.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/ttsEngine.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="tut_analytics.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tut_analytics.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -tut_analytics.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tut_analytics.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="tut_debugging.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tut_debugging.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -tut_debugging.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tut_debugging.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="tut_migration_to_manifest_v2.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tut_migration_to_manifest_v2.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -tut_migration_to_manifest_v2.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tut_migration_to_manifest_v2.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="tut_oauth.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tut_oauth.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -tut_oauth.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tut_oauth.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="tutorials.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tutorials.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -tutorials.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/tutorials.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="types.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/types.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -types.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/types.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="webNavigation.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/webNavigation.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -webNavigation.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/webNavigation.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="webRequest.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/webRequest.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -webRequest.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/webRequest.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="webstore.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/webstore.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -webstore.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/webstore.html?revision=212595&pathrev=214898" title="View file contents"><strong>212595</strong></a> - -</td> - -<td> 2 weeks</td> -<td> evan.peterson.EP@gmail.com</td> - - -<td> Linking AvailabilityFinder with APIDataSource and intro-table templates. - -BUG=23…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="whats_new.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/whats_new.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -whats_new.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/whats_new.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_even"> -<td colspan="2"> - -<a name="windows.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/windows.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -windows.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/windows.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -<tr class="vc_row_odd"> -<td colspan="2"> - -<a name="xhr.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/xhr.html?view=log&pathrev=214898" title="View file revision log"> - -<img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" /> -xhr.html</a> - -</td> - - - - -<td style="white-space: nowrap;"> <a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/xhr.html?revision=157264&pathrev=214898" title="View file contents"><strong>157264</strong></a> - -</td> - -<td> 10 months</td> -<td> kalman@chromium.org</td> - - -<td> Copy the extension docs content from chrome/common/extensions/docs/server2 into -…</td> - - - -</tr> - -</tbody> -</table> - - - - - -<hr /> -<table> -<tr> -<td>Powered by <a href="http://viewvc.tigris.org/">ViewVC 1.1.5</a></td> -<!--td style="text-align: right;"> </td--> -<!--td> </td--> -<td style="text-align: right;"><strong><a href="/viewvc/*docroot*/help_dirview.html">ViewVC Help</a></strong></td> -</tr> -</table> -</body> -</html> - -
diff --git a/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/input.json b/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/input.json deleted file mode 100644 index e089d8b..0000000 --- a/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/input.json +++ /dev/null
@@ -1,7 +0,0 @@ -{ - "name": { - "first": "Bob", - "last": "Jones" - }, - "part": "elbow" -}
diff --git a/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/name_tmpl.html b/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/name_tmpl.html deleted file mode 100644 index 50f86c0..0000000 --- a/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/name_tmpl.html +++ /dev/null
@@ -1 +0,0 @@ -{{name.first}} {{name.last}}
diff --git a/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/test_expected.html b/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/test_expected.html deleted file mode 100644 index b9b52dd..0000000 --- a/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/test_expected.html +++ /dev/null
@@ -1 +0,0 @@ -Hello Bob Jones how is your elbow?
diff --git a/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/test_tmpl.html b/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/test_tmpl.html deleted file mode 100644 index e52904b..0000000 --- a/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/test_tmpl.html +++ /dev/null
@@ -1 +0,0 @@ -Hello {{+name_tmpl/}} how is your {{part}}?
diff --git a/chrome/common/extensions/docs/server2/test_data/template_data_source/simple/test1.html b/chrome/common/extensions/docs/server2/test_data/template_data_source/simple/test1.html deleted file mode 100644 index 0075e9c..0000000 --- a/chrome/common/extensions/docs/server2/test_data/template_data_source/simple/test1.html +++ /dev/null
@@ -1 +0,0 @@ -Hello {{test}}
diff --git a/chrome/common/extensions/docs/server2/test_data/template_data_source/simple/test2.html b/chrome/common/extensions/docs/server2/test_data/template_data_source/simple/test2.html deleted file mode 100644 index 1a78ab13..0000000 --- a/chrome/common/extensions/docs/server2/test_data/template_data_source/simple/test2.html +++ /dev/null
@@ -1 +0,0 @@ -Hello second {{test}}
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json b/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json deleted file mode 100644 index 01fbab6..0000000 --- a/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json +++ /dev/null
@@ -1,19 +0,0 @@ -{ - "namespace": "events", - "description": "A namespace to contain addRules.", - "types": [ - { - "name": "Event", - "type": "object", - "description": "The object to contain addRules.", - "functions": [ - { - "name": "addRules", - "type": "function", - "description": "Registers rules to handle events.", - "parameters": [ { "name": "notable_name_to_check_for" } ] - } - ] - } - ] -}
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/expected_tester.json b/chrome/common/extensions/docs/server2/test_data/test_json/expected_tester.json deleted file mode 100644 index 4c91dfd8..0000000 --- a/chrome/common/extensions/docs/server2/test_data/test_json/expected_tester.json +++ /dev/null
@@ -1,218 +0,0 @@ -{ - "functions": [ - { - "name": "get", - "parameters": [ - { - "parentName": "get", - "functions": [], - "choices": [ - { - "properties": [], - "name": "string", - "simple_type": "string", - "functions": [], - "events": [], - "id": "type-a-string", - "description": null - }, - { - "properties": [], - "last": true, - "name": "array", - "functions": [], - "events": [], - "array": { - "properties": [], - "name": "arrayType", - "simple_type": "string", - "functions": [], - "events": [], - "id": "type-array-arrayType", - "description": null - }, - "id": "type-a-array", - "description": null - } - ], - "name": "a", - "parameters": [], - "id": "property-get-a", - "returns": null, - "optional": null, - "properties": [], - "description": "a param" - }, - { - "parentName": "get", - "last": true, - "name": "callback", - "simple_type": "function", - "optional": false, - "id": "property-get-callback", - "description": null - } - ], - "callback": { - "parameters": [ - { - "description": null, - "array": { - "properties": [], - "name": "resultsType", - "functions": [], - "events": [], - "link": { - "text": "TypeA", - "href": "tester.html#type-TypeA", - "name": "TypeA" - }, - "id": "type-results-resultsType", - "description": null - }, - "optional": null, - "id": "property-callback-results", - "parentName": "callback", - "functions": [], - "last": true, - "name": "results", - "parameters": [], - "properties": [], - "returns": null - } - ], - "optional": false, - "name": "callback", - "simple_type": { - "simple_type": "function" - } - }, - "returns": null, - "id": "method-get", - "description": "Gets stuff." - } - ], - "properties": [], - "name": "tester", - "description": "a test api", - "introList": [ - { - "content": [ - { - "text": "a test api" - } - ], - "title": "Description" - }, - { - "content": [ - { - "message": true, - "trunk": true, - "version": null - } - ], - "title": "Availability" - }, - { - "content": [ - { - "text": "\"thing1\", \"thing2\"", - "perm": "tester" - }, - { - "text": "is an API for testing things." - } - ], - "title": "Permissions" - }, - { - "content": [ - { - "text": "Welcome!", - "link": "https://tester.test.com/welcome.html" - } - ], - "title": "Learn More" - } - ], - "types": [ - { - "properties": [ - { - "parentName": "TypeA", - "functions": [], - "name": "b", - "parameters": [], - "id": "property-TypeA-b", - "array": { - "properties": [], - "name": "bType", - "functions": [], - "events": [], - "link": { - "text": "TypeA", - "href": "tester.html#type-TypeA", - "name": "TypeA" - }, - "id": "type-b-bType", - "description": null - }, - "returns": null, - "optional": true, - "properties": [], - "description": "List of TypeA." - } - ], - "name": "TypeA", - "simple_type": "object", - "functions": [], - "events": [], - "id": "type-TypeA", - "description": "A cool thing." - } - ], - "events": [ - { - "callback": null, - "name": "EventA", - "parameters": [ - { - "parentName": "EventA", - "functions": [], - "simple_type": "string", - "name": "id", - "parameters": [], - "id": "property-EventA-id", - "returns": null, - "optional": null, - "properties": [], - "description": null - }, - { - "description": null, - "link": { - "text": "TypeA", - "href": "tester.html#type-TypeA", - "name": "TypeA" - }, - "optional": null, - "id": "property-EventA-bookmark", - "parentName": "EventA", - "functions": [], - "last": true, - "name": "bookmark", - "parameters": [], - "properties": [], - "returns": null - } - ], - "supportsRules": false, - "filters": [], - "conditions": [], - "id": "event-EventA", - "actions": [], - "description": "A cool event." - } - ] -}
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/ref_test_data_source.json b/chrome/common/extensions/docs/server2/test_data/test_json/ref_test_data_source.json deleted file mode 100644 index 1121609..0000000 --- a/chrome/common/extensions/docs/server2/test_data/test_json/ref_test_data_source.json +++ /dev/null
@@ -1,23 +0,0 @@ -{ - "ref_test": { - "types": [ - { "name": "type1" }, - { "name": "type2" }, - { "name": "type3" } - ], - "events": [ - { "name": "event1" } - ], - "properties": [ - { "name": "prop1" } - ], - "functions": [ - { "name": "func1" } - ] - }, - "other": { - "types": [ - { "name": "type2" } - ] - } -}
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/test_file_data_source.json b/chrome/common/extensions/docs/server2/test_data/test_json/test_file_data_source.json deleted file mode 100644 index 13bd52a..0000000 --- a/chrome/common/extensions/docs/server2/test_data/test_json/test_file_data_source.json +++ /dev/null
@@ -1,13 +0,0 @@ -{ - "tester": { - "types": [ - { "name": "TypeA" } - ], - "functions": [ - { "name": "get" } - ], - "events": [ - { "name": "EventA" } - ] - } -}
diff --git a/chrome/common/extensions/docs/server2/test_file_system.py b/chrome/common/extensions/docs/server2/test_file_system.py deleted file mode 100644 index 227b4dab..0000000 --- a/chrome/common/extensions/docs/server2/test_file_system.py +++ /dev/null
@@ -1,147 +0,0 @@ -# Copyright 2013 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 file_system import FileSystem, FileNotFoundError, StatInfo -from future import Future -from path_util import AssertIsValid, AssertIsDirectory, IsDirectory - - -def MoveTo(base, obj): - '''Returns an object as |obj| moved to |base|. That is, - MoveTo('foo/bar', {'a': 'b'}) -> {'foo': {'bar': {'a': 'b'}}} - ''' - AssertIsDirectory(base) - result = {} - leaf = result - for k in base.rstrip('/').split('/'): - leaf[k] = {} - leaf = leaf[k] - leaf.update(obj) - return result - - -def MoveAllTo(base, obj): - '''Moves every value in |obj| to |base|. See MoveTo. - ''' - result = {} - for key, value in obj.iteritems(): - result[key] = MoveTo(base, value) - return result - - -def _List(file_system): - '''Returns a list of '/' separated paths derived from |file_system|. - For example, {'index.html': '', 'www': {'file.txt': ''}} would return - ['index.html', 'www/file.txt']. - ''' - assert isinstance(file_system, dict) - result = {} - def update_result(item, path): - AssertIsValid(path) - if isinstance(item, dict): - if path != '': - path += '/' - result[path] = [p if isinstance(content, basestring) else (p + '/') - for p, content in item.iteritems()] - for subpath, subitem in item.iteritems(): - update_result(subitem, path + subpath) - elif isinstance(item, basestring): - result[path] = item - else: - raise ValueError('Unsupported item type: %s' % type(item)) - update_result(file_system, '') - return result - - -class _StatTracker(object): - '''Maintains the versions of paths in a file system. The versions of files - are changed either by |Increment| or |SetVersion|. The versions of - directories are derived from the versions of files within it. - ''' - - def __init__(self): - self._path_stats = {} - self._global_stat = 0 - - def Increment(self, path=None, by=1): - if path is None: - self._global_stat += by - else: - self.SetVersion(path, self._path_stats.get(path, 0) + by) - - def SetVersion(self, path, new_version): - if IsDirectory(path): - raise ValueError('Only files have an incrementable stat, ' - 'but "%s" is a directory' % path) - - # Update version of that file. - self._path_stats[path] = new_version - - # Update all parent directory versions as well. - slash_index = 0 # (deliberately including '' in the dir paths) - while slash_index != -1: - dir_path = path[:slash_index] + '/' - self._path_stats[dir_path] = max(self._path_stats.get(dir_path, 0), - new_version) - if dir_path == '/': - # Legacy support for '/' being the root of the file system rather - # than ''. Eventually when the path normalisation logic is complete - # this will be impossible and this logic will change slightly. - self._path_stats[''] = self._path_stats['/'] - slash_index = path.find('/', slash_index + 1) - - def GetVersion(self, path): - return self._global_stat + self._path_stats.get(path, 0) - - -class TestFileSystem(FileSystem): - '''A FileSystem backed by an object. Create with an object representing file - paths such that {'a': {'b': 'hello'}} will resolve Read('a/b') as 'hello', - Read('a/') as ['b'], and Stat determined by a value incremented via - IncrementStat. - ''' - - def __init__(self, obj, relative_to=None, identity=None): - assert obj is not None - if relative_to is not None: - obj = MoveTo(relative_to, obj) - self._identity = identity or type(self).__name__ - self._path_values = _List(obj) - self._stat_tracker = _StatTracker() - - # - # FileSystem implementation. - # - - def Read(self, paths, skip_not_found=False): - for path in paths: - if path not in self._path_values: - if skip_not_found: continue - return FileNotFoundError.RaiseInFuture( - '%s not in %s' % (path, '\n'.join(self._path_values))) - return Future(value=dict((k, v) for k, v in self._path_values.iteritems() - if k in paths)) - - def Refresh(self): - return Future(value=()) - - def Stat(self, path): - read_result = self.ReadSingle(path).Get() - stat_result = StatInfo(str(self._stat_tracker.GetVersion(path))) - if isinstance(read_result, list): - stat_result.child_versions = dict( - (file_result, - str(self._stat_tracker.GetVersion('%s%s' % (path, file_result)))) - for file_result in read_result) - return stat_result - - # - # Testing methods. - # - - def IncrementStat(self, path=None, by=1): - self._stat_tracker.Increment(path, by=by) - - def GetIdentity(self): - return self._identity
diff --git a/chrome/common/extensions/docs/server2/test_file_system_test.py b/chrome/common/extensions/docs/server2/test_file_system_test.py deleted file mode 100755 index 2a7e91a..0000000 --- a/chrome/common/extensions/docs/server2/test_file_system_test.py +++ /dev/null
@@ -1,188 +0,0 @@ -#!/usr/bin/env python -# 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 copy import deepcopy -from file_system import FileNotFoundError, StatInfo -from test_file_system import TestFileSystem, MoveTo -import unittest - - -_TEST_DATA = { - '404.html': '404.html contents', - 'apps': { - 'a11y.html': 'a11y.html contents', - 'about_apps.html': 'about_apps.html contents', - 'fakedir': { - 'file.html': 'file.html contents' - } - }, - 'extensions': { - 'activeTab.html': 'activeTab.html contents', - 'alarms.html': 'alarms.html contents' - } -} - - -def _Get(fn): - '''Returns a function which calls Future.Get on the result of |fn|. - ''' - return lambda *args: fn(*args).Get() - - -class TestFileSystemTest(unittest.TestCase): - def testEmptyFileSystem(self): - self._TestMetasyntacticPaths(TestFileSystem({})) - - def testNonemptyFileNotFoundErrors(self): - fs = TestFileSystem(deepcopy(_TEST_DATA)) - self._TestMetasyntacticPaths(fs) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['404.html/']) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['apps/foo/']) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['apps/foo.html']) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['apps/foo.html']) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['apps/foo/', - 'apps/foo.html']) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['apps/foo/', - 'apps/a11y.html']) - - def _TestMetasyntacticPaths(self, fs): - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['foo']) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['bar/']) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['bar/baz']) - self.assertRaises(FileNotFoundError, _Get(fs.Read), ['foo', - 'bar/', - 'bar/baz']) - self.assertRaises(FileNotFoundError, fs.Stat, 'foo') - self.assertRaises(FileNotFoundError, fs.Stat, 'bar/') - self.assertRaises(FileNotFoundError, fs.Stat, 'bar/baz') - - def testNonemptySuccess(self): - fs = TestFileSystem(deepcopy(_TEST_DATA)) - self.assertEqual('404.html contents', fs.ReadSingle('404.html').Get()) - self.assertEqual('a11y.html contents', - fs.ReadSingle('apps/a11y.html').Get()) - self.assertEqual(['404.html', 'apps/', 'extensions/'], - sorted(fs.ReadSingle('').Get())) - self.assertEqual(['a11y.html', 'about_apps.html', 'fakedir/'], - sorted(fs.ReadSingle('apps/').Get())) - - def testReadFiles(self): - fs = TestFileSystem(deepcopy(_TEST_DATA)) - self.assertEqual('404.html contents', - fs.ReadSingle('404.html').Get()) - self.assertEqual('a11y.html contents', - fs.ReadSingle('apps/a11y.html').Get()) - self.assertEqual('file.html contents', - fs.ReadSingle('apps/fakedir/file.html').Get()) - - def testReadDirs(self): - fs = TestFileSystem(deepcopy(_TEST_DATA)) - self.assertEqual(['404.html', 'apps/', 'extensions/'], - sorted(fs.ReadSingle('').Get())) - self.assertEqual(['a11y.html', 'about_apps.html', 'fakedir/'], - sorted(fs.ReadSingle('apps/').Get())) - self.assertEqual(['file.html'], fs.ReadSingle('apps/fakedir/').Get()) - - def testStat(self): - fs = TestFileSystem(deepcopy(_TEST_DATA)) - self.assertRaises(FileNotFoundError, fs.Stat, 'foo') - self.assertRaises(FileNotFoundError, fs.Stat, '404.html/') - self.assertEquals(StatInfo('0', child_versions={ - '404.html': '0', - 'apps/': '0', - 'extensions/': '0', - }), fs.Stat('')) - self.assertEquals(StatInfo('0'), fs.Stat('404.html')) - self.assertEquals(StatInfo('0', child_versions={ - 'activeTab.html': '0', - 'alarms.html': '0', - }), fs.Stat('extensions/')) - - fs.IncrementStat() - self.assertEquals(StatInfo('1', child_versions={ - '404.html': '1', - 'apps/': '1', - 'extensions/': '1', - }), fs.Stat('')) - self.assertEquals(StatInfo('1'), fs.Stat('404.html')) - self.assertEquals(StatInfo('1', child_versions={ - 'activeTab.html': '1', - 'alarms.html': '1', - }), fs.Stat('extensions/')) - - fs.IncrementStat(path='404.html') - self.assertEquals(StatInfo('2', child_versions={ - '404.html': '2', - 'apps/': '1', - 'extensions/': '1', - }), fs.Stat('')) - self.assertEquals(StatInfo('2'), fs.Stat('404.html')) - self.assertEquals(StatInfo('1', child_versions={ - 'activeTab.html': '1', - 'alarms.html': '1', - }), fs.Stat('extensions/')) - - fs.IncrementStat() - self.assertEquals(StatInfo('3', child_versions={ - '404.html': '3', - 'apps/': '2', - 'extensions/': '2', - }), fs.Stat('')) - self.assertEquals(StatInfo('3'), fs.Stat('404.html')) - self.assertEquals(StatInfo('2', child_versions={ - 'activeTab.html': '2', - 'alarms.html': '2', - }), fs.Stat('extensions/')) - - # It doesn't make sense to increment the version of directories. Directory - # versions are derived from the version of files within them. - self.assertRaises(ValueError, fs.IncrementStat, path='') - self.assertRaises(ValueError, fs.IncrementStat, path='extensions/') - self.assertEquals(StatInfo('3', child_versions={ - '404.html': '3', - 'apps/': '2', - 'extensions/': '2', - }), fs.Stat('')) - self.assertEquals(StatInfo('3'), fs.Stat('404.html')) - self.assertEquals(StatInfo('2', child_versions={ - 'activeTab.html': '2', - 'alarms.html': '2', - }), fs.Stat('extensions/')) - - fs.IncrementStat(path='extensions/alarms.html') - self.assertEquals(StatInfo('3', child_versions={ - '404.html': '3', - 'apps/': '2', - 'extensions/': '3', - }), fs.Stat('')) - self.assertEquals(StatInfo('3'), fs.Stat('404.html')) - self.assertEquals(StatInfo('3', child_versions={ - 'activeTab.html': '2', - 'alarms.html': '3', - }), fs.Stat('extensions/')) - - fs.IncrementStat(path='extensions/activeTab.html', by=3) - self.assertEquals(StatInfo('5', child_versions={ - '404.html': '3', - 'apps/': '2', - 'extensions/': '5', - }), fs.Stat('')) - self.assertEquals(StatInfo('3'), fs.Stat('404.html')) - self.assertEquals(StatInfo('5', child_versions={ - 'activeTab.html': '5', - 'alarms.html': '3', - }), fs.Stat('extensions/')) - - def testMoveTo(self): - self.assertEqual({'foo': {'a': 'b', 'c': 'd'}}, - MoveTo('foo/', {'a': 'b', 'c': 'd'})) - self.assertEqual({'foo': {'bar': {'a': 'b', 'c': 'd'}}}, - MoveTo('foo/bar/', {'a': 'b', 'c': 'd'})) - self.assertEqual({'foo': {'bar': {'baz': {'a': 'b'}}}}, - MoveTo('foo/bar/baz/', {'a': 'b'})) - - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/test_object_store.py b/chrome/common/extensions/docs/server2/test_object_store.py deleted file mode 100644 index 386828c..0000000 --- a/chrome/common/extensions/docs/server2/test_object_store.py +++ /dev/null
@@ -1,66 +0,0 @@ -# Copyright 2013 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 future import Future -from object_store import ObjectStore - -class TestObjectStore(ObjectStore): - '''An object store which records its namespace and behaves like a dict. - Specify |init| with an initial object for the object store. - Use CheckAndReset to assert how many times Get/Set/Del have been called. Get - is a special case; it is only incremented once the future has had Get called. - ''' - def __init__(self, namespace, start_empty=False, init=None): - self.namespace = namespace - self.start_empty = start_empty - self._store = {} if init is None else init - if start_empty: - assert not self._store - self._get_count = 0 - self._set_count = 0 - self._del_count = 0 - - # - # ObjectStore implementation. - # - - def GetMulti(self, keys): - def callback(): - self._get_count += 1 - return dict((k, self._store.get(k)) for k in keys if k in self._store) - return Future(callback=callback) - - def SetMulti(self, mapping): - self._set_count += 1 - self._store.update(mapping) - return Future(value=None) - - def DelMulti(self, keys): - self._del_count += 1 - for k in keys: - self._store.pop(k, None) - - # - # Testing methods. - # - - def CheckAndReset(self, get_count=0, set_count=0, del_count=0): - '''Returns a tuple (success, error). Use in tests like: - self.assertTrue(*object_store.CheckAndReset(...)) - ''' - errors = [] - for desc, expected, actual in (('get_count', get_count, self._get_count), - ('set_count', set_count, self._set_count), - ('del_count', del_count, self._del_count)): - if actual != expected: - errors.append('%s: expected %s got %s' % (desc, expected, actual)) - try: - return (len(errors) == 0, ', '.join(errors)) - finally: - self.Reset() - - def Reset(self): - self._get_count = 0 - self._set_count = 0 - self._del_count = 0
diff --git a/chrome/common/extensions/docs/server2/test_object_store_test.py b/chrome/common/extensions/docs/server2/test_object_store_test.py deleted file mode 100755 index b060873..0000000 --- a/chrome/common/extensions/docs/server2/test_object_store_test.py +++ /dev/null
@@ -1,43 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 test_object_store import TestObjectStore -import unittest - -class TestObjectStoreTest(unittest.TestCase): - def testEmpty(self): - store = TestObjectStore('namespace') - self.assertEqual(None, store.Get('hi').Get()) - self.assertEqual({}, store.GetMulti(['hi', 'lo']).Get()) - - def testNonEmpty(self): - store = TestObjectStore('namespace') - store.Set('hi', 'bye') - self.assertEqual('bye', store.Get('hi').Get()) - self.assertEqual({'hi': 'bye'}, store.GetMulti(['hi', 'lo']).Get()) - store.Set('hi', 'blah') - self.assertEqual('blah', store.Get('hi').Get()) - self.assertEqual({'hi': 'blah'}, store.GetMulti(['hi', 'lo']).Get()) - store.Del('hi') - self.assertEqual(None, store.Get('hi').Get()) - self.assertEqual({}, store.GetMulti(['hi', 'lo']).Get()) - - def testCheckAndReset(self): - store = TestObjectStore('namespace') - store.Set('x', 'y') - self.assertTrue(*store.CheckAndReset(set_count=1)) - store.Set('x', 'y') - store.Set('x', 'y') - self.assertTrue(*store.CheckAndReset(set_count=2)) - store.Set('x', 'y') - store.Set('x', 'y') - store.Get('x').Get() - store.Get('x').Get() - store.Get('x').Get() - store.Del('x') - self.assertTrue(*store.CheckAndReset(get_count=3, set_count=2, del_count=1)) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/test_patcher.py b/chrome/common/extensions/docs/server2/test_patcher.py deleted file mode 100644 index 6c4b906..0000000 --- a/chrome/common/extensions/docs/server2/test_patcher.py +++ /dev/null
@@ -1,35 +0,0 @@ -# Copyright 2013 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 future import Future -from patcher import Patcher - -class TestPatcher(Patcher): - def __init__(self, version, patched_files, patch_data): - self._version = version - self._patched_files = patched_files - self._patch_data = patch_data - - self.get_version_count = 0 - self.get_patched_files_count = 0 - self.apply_count = 0 - - def GetVersion(self): - self.get_version_count += 1 - return self._version - - def GetPatchedFiles(self, version=None): - self.get_patched_files_count += 1 - return self._patched_files - - def Apply(self, paths, file_system, version=None): - self.apply_count += 1 - try: - return Future(value=dict((path, self._patch_data[path]) - for path in paths)) - except KeyError: - raise FileNotFoundError('One of %s is deleted in the patch.' % paths) - - def GetIdentity(self): - return self.__class__.__name__
diff --git a/chrome/common/extensions/docs/server2/test_servlet.py b/chrome/common/extensions/docs/server2/test_servlet.py deleted file mode 100644 index 6e568d7c..0000000 --- a/chrome/common/extensions/docs/server2/test_servlet.py +++ /dev/null
@@ -1,73 +0,0 @@ -# Copyright 2013 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 extensions_paths import PUBLIC_TEMPLATES -from instance_servlet import ( - InstanceServlet, InstanceServletRenderServletDelegate) -from link_error_detector import LinkErrorDetector, StringifyBrokenLinks -from servlet import Request, Response, Servlet - - -class BrokenLinkTester(object): - '''Run link error detector tests. - ''' - def __init__(self, server_instance, renderer): - self.link_error_detector = LinkErrorDetector( - server_instance.host_file_system_provider.GetMaster(), - renderer, - PUBLIC_TEMPLATES, - root_pages=('extensions/index.html', 'apps/about_apps.html')) - - def TestBrokenLinks(self): - broken_links = self.link_error_detector.GetBrokenLinks() - return ( - len(broken_links), - 'Warning: Found %d broken links:\n%s' % ( - len(broken_links), StringifyBrokenLinks(broken_links))) - - def TestOrphanedPages(self): - orphaned_pages = self.link_error_detector.GetOrphanedPages() - return ( - len(orphaned_pages), - 'Warning: Found %d orphaned pages:\n%s' % ( - len(orphaned_pages), '\n'.join(orphaned_pages))) - - -class TestServlet(Servlet): - '''Runs tests against the live server. Supports running all broken link - detection tests, in parts or all at once. - ''' - def __init__(self, request, delegate_for_test=None): - Servlet.__init__(self, request) - self._delegate = delegate_for_test or InstanceServlet.Delegate() - - def Get(self): - link_error_tests = ('broken_links', 'orphaned_pages', 'link_errors') - - if not self._request.path in link_error_tests: - return Response.NotFound('Test %s not found. Available tests are: %s' % ( - self._request.path, ','.join(link_error_tests))) - - constructor = InstanceServlet.GetConstructor(self._delegate) - def renderer(path): - return constructor(Request(path, '', self._request.headers)).Get() - - link_tester = BrokenLinkTester( - InstanceServletRenderServletDelegate( - self._delegate).CreateServerInstance(), - renderer) - if self._request.path == 'broken_links': - errors, content = link_tester.TestBrokenLinks() - elif self._request.path == 'orphaned_pages': - errors, content = link_tester.TestOrphanedPages() - else: - link_errors, link_content = link_tester.TestBrokenLinks() - orphaned_errors, orphaned_content = link_tester.TestOrphanedPages() - errors = link_errors + orphaned_errors - content = "%s\n%s" % (link_content, orphaned_content) - - if errors: - return Response.InternalError(content=content) - - return Response.Ok(content="%s test passed." % self._request.path)
diff --git a/chrome/common/extensions/docs/server2/test_servlet_test.py b/chrome/common/extensions/docs/server2/test_servlet_test.py deleted file mode 100755 index 4fbeae6..0000000 --- a/chrome/common/extensions/docs/server2/test_servlet_test.py +++ /dev/null
@@ -1,39 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 unittest - -from empty_dir_file_system import EmptyDirFileSystem -from host_file_system_provider import HostFileSystemProvider -from servlet import Request -from test_branch_utility import TestBranchUtility -from fail_on_access_file_system import FailOnAccessFileSystem -from test_servlet import TestServlet - -class _TestDelegate(object): - def CreateBranchUtility(self, object_store_creator): - return TestBranchUtility.CreateWithCannedData() - - def CreateAppSamplesFileSystem(self, object_store_creator): - return EmptyDirFileSystem() - - def CreateHostFileSystemProvider(self, object_store_creator): - return HostFileSystemProvider.ForTest( - FailOnAccessFileSystem(), object_store_creator) - -# This test can't really be useful. The set of valid tests is changing and -# there is no reason to test the tests themselves, they are already tested in -# their respective modules. The only testable behavior TestServlet adds is -# returning a 404 if a test does not exist. -class TestServletTest(unittest.TestCase): - def testTestServlet(self): - request = Request('not_a_real_test_url', 'localhost', {}) - test_servlet = TestServlet(request, _TestDelegate()) - response = test_servlet.Get() - - self.assertEqual(404, response.status) - -if __name__ == '__main__': - unittest.main()
diff --git a/chrome/common/extensions/docs/server2/test_util.py b/chrome/common/extensions/docs/server2/test_util.py deleted file mode 100644 index fb70eae..0000000 --- a/chrome/common/extensions/docs/server2/test_util.py +++ /dev/null
@@ -1,69 +0,0 @@ -# Copyright 2013 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 __future__ import print_function - -from extensions_paths import SERVER2 -import logging -import os -import sys - - -def CaptureLogging(f): - '''Call the function |f|, capturing any logging output generated. |f| must - take no arguments. Returns a list of LogRecords that were emitted. - ''' - output = [] - class Capture(object): - def filter(self, record): - output.append(record) - - cf = Capture() - logging.getLogger('').addFilter(cf) - f() - logging.getLogger('').removeFilter(cf) - - return output - - -def EnableLogging(name): - '''Returns the output of the log with |name| to stdout. - ''' - - return _ReplaceLogging(name, lambda message, *args: print(message % args)) - - -def DisableLogging(name): - '''Disables the log with |name| for the duration of the decorated function. - ''' - return _ReplaceLogging(name, lambda _, *args: None) - - -def _ReplaceLogging(name, replacement): - def decorator(fn): - def impl(*args, **optargs): - saved = getattr(logging, name) - setattr(logging, name, replacement) - try: - return fn(*args, **optargs) - finally: - setattr(logging, name, saved) - return impl - return decorator - - -def ChromiumPath(*path): - abspath = os.path.join( - sys.path[0], '..', '..', '..', '..', '..', *path) - # os.path.relpath kills any trailing '/'. - return os.path.relpath(abspath) + ('/' if abspath.endswith('/') else '') - - -def Server2Path(*path): - return ChromiumPath(SERVER2, *path) - - -def ReadFile(*path, **read_args): - with open(ChromiumPath(*path), **read_args) as f: - return f.read()
diff --git a/chrome/common/extensions/docs/server2/timer.py b/chrome/common/extensions/docs/server2/timer.py deleted file mode 100644 index 139ce81..0000000 --- a/chrome/common/extensions/docs/server2/timer.py +++ /dev/null
@@ -1,58 +0,0 @@ -# Copyright 2013 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 time - - -class Timer(object): - '''A simple timer which starts when constructed and stops when Stop is called. - ''' - - def __init__(self): - self._start = time.time() - self._elapsed = None - - def Stop(self): - '''Stops the timer. Must only be called once. Returns |self|. - ''' - assert self._elapsed is None - self._elapsed = time.time() - self._start - return self - - def With(self, other): - '''Returns a new stopped Timer with this Timer's elapsed time + |other|'s. - Both Timers must already be stopped. - ''' - assert self._elapsed is not None - assert other._elapsed is not None - self_and_other = Timer() - self_and_other._start = min(self._start, other._start) - self_and_other._elapsed = self._elapsed + other._elapsed - return self_and_other - - def FormatElapsed(self): - '''Returns the elapsed time as a string in a pretty format; as a whole - number in either seconds or milliseconds depending on which is more - appropriate. Must already be Stopped. - ''' - assert self._elapsed is not None - elapsed = self._elapsed - if elapsed < 1: - elapsed = int(elapsed * 1000) - unit = 'ms' - else: - elapsed = int(elapsed) - unit = 'second' if elapsed == 1 else 'seconds' - return '%s %s' % (elapsed, unit) - - -def TimerClosure(closure, *args, **optargs): - '''A shorthand for timing a single function call. Returns a tuple of - (closure return value, timer). - ''' - timer = Timer() - try: - return closure(*args, **optargs), timer - finally: - timer.Stop()
diff --git a/chrome/common/extensions/docs/server2/update_cache.py b/chrome/common/extensions/docs/server2/update_cache.py deleted file mode 100644 index 9e106178..0000000 --- a/chrome/common/extensions/docs/server2/update_cache.py +++ /dev/null
@@ -1,206 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import cPickle -import copy -import getopt -import json -import logging -import os.path -import sys -import traceback - -from branch_utility import BranchUtility -from commit_tracker import CommitTracker -from compiled_file_system import CompiledFileSystem -from data_source_registry import CreateDataSources -from environment import GetAppVersion -from environment_wrappers import CreateUrlFetcher, GetAccessToken -from future import All -from gcs_file_system_provider import CloudStorageFileSystemProvider -from host_file_system_provider import HostFileSystemProvider -from local_git_util import ParseRevision -from object_store_creator import ObjectStoreCreator -from persistent_object_store_fake import PersistentObjectStoreFake -from render_refresher import RenderRefresher -from server_instance import ServerInstance -from timer import Timer - - -# The path template to use for flushing the memcached. Should be formatted with -# with the app version. -_FLUSH_MEMCACHE_PATH = ('https://%s-dot-chrome-apps-doc.appspot.com/' - '_flush_memcache') - - -def _UpdateCommitId(commit_name, commit_id): - '''Sets the commit ID for a named commit. This is the final step performed - during update. Once all the appropriate datastore entries have been populated - for a new commit ID, the 'master' commit entry is updated to that ID and the - frontend will begin serving the new data. - - Note that this requires an access token identifying the main service account - for the chrome-apps-doc project. VM instances will get this automatically - from their environment, but if you want to do a local push to prod you will - need to set the DOCSERVER_ACCESS_TOKEN environment variable appropriately. - ''' - commit_tracker = CommitTracker( - ObjectStoreCreator(store_type=PersistentObjectStoreFake, - start_empty=False)) - commit_tracker.Set(commit_name, commit_id).Get() - logging.info('Commit "%s" updated to %s.' % (commit_name, commit_id)) - - -def _GetCachedCommitId(commit_name): - '''Determines which commit ID was last cached. - ''' - commit_tracker = CommitTracker( - ObjectStoreCreator(store_type=PersistentObjectStoreFake, - start_empty=False)) - return commit_tracker.Get(commit_name).Get() - - -def _FlushMemcache(): - '''Requests that the frontend flush its memcached to avoid serving stale data. - ''' - flush_url = _FLUSH_MEMCACHE_PATH % GetAppVersion() - headers = { 'Authorization': 'Bearer %s' % GetAccessToken() } - response = CreateUrlFetcher().Fetch(flush_url, headers) - if response.status_code != 200: - logging.error('Unable to flush memcache: HTTP %s (%s)' % - (response.status_code, response.content)) - else: - logging.info('Memcache flushed.') - - -def _CreateServerInstance(commit): - '''Creates a ServerInstance based on origin/master. - ''' - object_store_creator = ObjectStoreCreator( - start_empty=False, store_type=PersistentObjectStoreFake) - branch_utility = BranchUtility.Create(object_store_creator) - host_file_system_provider = HostFileSystemProvider(object_store_creator, - pinned_commit=commit) - gcs_file_system_provider = CloudStorageFileSystemProvider( - object_store_creator) - return ServerInstance(object_store_creator, - CompiledFileSystem.Factory(object_store_creator), - branch_utility, - host_file_system_provider, - gcs_file_system_provider) - - -def _UpdateDataSource(name, data_source): - try: - class_name = data_source.__class__.__name__ - timer = Timer() - logging.info('Updating %s...' % name) - data_source.Refresh().Get() - except Exception as e: - logging.error('%s: error %s' % (class_name, traceback.format_exc())) - raise e - finally: - logging.info('Updating %s took %s' % (name, timer.Stop().FormatElapsed())) - - -def UpdateCache(single_data_source=None, commit=None): - '''Attempts to populate the datastore with a bunch of information derived from - a given commit. - ''' - server_instance = _CreateServerInstance(commit) - - # This is the thing that would be responsible for refreshing the cache of - # examples. Here for posterity, hopefully it will be added to the targets - # below someday. - # render_refresher = RenderRefresher(server_instance, self._request) - - data_sources = CreateDataSources(server_instance) - data_sources['content_providers'] = server_instance.content_providers - data_sources['platform_bundle'] = server_instance.platform_bundle - if single_data_source: - _UpdateDataSource(single_data_source, data_sources[single_data_source]) - else: - for name, source in data_sources.iteritems(): - _UpdateDataSource(name, source) - - -def _Main(argv): - try: - opts = dict((name[2:], value) for name, value in - getopt.getopt(argv, '', - ['load-file=', 'data-source=', 'commit=', - 'no-refresh', 'no-push', 'save-file=', - 'no-master-update', 'push-all', 'force'])[0]) - except getopt.GetoptError as e: - print '%s\n' % e - print ( - 'Usage: update_cache.py [options]\n\n' - 'Options:\n' - ' --data-source=NAME Limit update to a single data source.\n' - ' --load-file=FILE Load object store data from FILE before\n' - ' starting the update.\n' - ' --save-file=FILE Save object store data to FILE after running\n' - ' the update.\n' - ' --no-refresh Do not attempt to update any data sources.\n' - ' --no-push Do not push to Datastore.\n' - ' --commit=REV Commit ID to use for master update.\n' - ' --no-master-update Do not update the master commit ID.\n' - ' --push-all Push all entities to the Datastore even if\n' - ' they do not differ from the loaded cache.\n\n' - ' --force Force an update even if the latest commit is' - ' already cached.\n') - exit(1) - - logging.getLogger().setLevel(logging.INFO) - - data_source = opts.get('data-source', None) - load_file = opts.get('load-file', None) - save_file = opts.get('save-file', None) - do_refresh = 'no-refresh' not in opts - do_push = 'no-push' not in opts - do_master_update = 'no-master-update' not in opts - push_all = do_push and ('push-all' in opts) - commit = ParseRevision(opts.get('commit', 'origin/HEAD')) - force_update = 'force' in opts - - original_data = {} - if load_file: - logging.info('Loading cache...') - PersistentObjectStoreFake.LoadFromFile(load_file) - if not push_all: - original_data = copy.deepcopy(PersistentObjectStoreFake.DATA) - - last_commit = _GetCachedCommitId('master') - if ParseRevision(commit) == last_commit and not force_update: - logging.info('Latest cache (revision %s) is up to date. Bye.' % commit) - exit(0) - - timer = Timer() - if do_refresh: - logging.info('Starting refresh from commit %s...' % ParseRevision(commit)) - if data_source: - UpdateCache(single_data_source=data_source, - commit=commit) - else: - UpdateCache(commit=commit) - - if do_push: - from datastore_util import PushData - if do_master_update: - _UpdateCommitId('master', commit) - push_timer = Timer() - logging.info('Pushing data into datastore...') - PushData(PersistentObjectStoreFake.DATA, original_data=original_data) - logging.info('Done. Datastore push took %s' % - push_timer.Stop().FormatElapsed()) - _FlushMemcache() - if save_file: - PersistentObjectStoreFake.SaveToFile(save_file) - - logging.info('Update completed in %s' % timer.Stop().FormatElapsed()) - - -if __name__ == '__main__': - _Main(sys.argv[1:]) -
diff --git a/chrome/common/extensions/docs/server2/url_constants.py b/chrome/common/extensions/docs/server2/url_constants.py deleted file mode 100644 index aba48137..0000000 --- a/chrome/common/extensions/docs/server2/url_constants.py +++ /dev/null
@@ -1,16 +0,0 @@ -# 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. - -GITHUB_REPOS = 'https://api.github.com/repos' -GITHUB_BASE = 'https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples' -RAW_GITHUB_BASE = ('https://github.com/GoogleChrome/chrome-app-samples/raw/' - 'master') -OMAHA_PROXY_URL = 'https://omahaproxy.appspot.com/json' -OMAHA_HISTORY = 'https://omahaproxy.appspot.com/history.json' -OMAHA_DEV_HISTORY = '%s?channel=dev&os=win&json=1' % OMAHA_HISTORY -SVN_URL = 'http://src.chromium.org/chrome' -VIEWVC_URL = 'http://src.chromium.org/viewvc/chrome' -EXTENSIONS_SAMPLES = ('https://chromium.googlesource.com/chromium/src/+/master/chrome/' - 'common/extensions/docs/examples') -CODEREVIEW_SERVER = 'https://codereview.chromium.org'
diff --git a/chrome/common/extensions/docs/server2/url_fetcher.py b/chrome/common/extensions/docs/server2/url_fetcher.py deleted file mode 100644 index 0609d9d..0000000 --- a/chrome/common/extensions/docs/server2/url_fetcher.py +++ /dev/null
@@ -1,60 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import posixpath - -from environment import GetAppVersion -from future import Future -from urllib import urlencode -from urlparse import urlparse, parse_qs - -def _MakeHeaders(headers={}): - headers['User-Agent'] = 'Chromium-Docserver/%s' % GetAppVersion() - headers['Cache-Control'] = 'max-age=0' - return headers - - -def _AddQueryToUrl(url, new_query): - """Adds query paramters to a URL. This merges the given set of query params - with any that were already a part of the URL. - """ - parsed_url = urlparse(url) - query = parse_qs(parsed_url.query) - query.update(new_query) - query_string = urlencode(query, True) - return '%s://%s%s?%s#%s' % (parsed_url.scheme, parsed_url.netloc, - parsed_url.path, query_string, parsed_url.fragment) - - -class UrlFetcher(object): - def __init__(self): - self._base_path = None - - def SetBasePath(self, base_path): - assert base_path is None or not base_path.endswith('/'), base_path - self._base_path = base_path - - def Fetch(self, url, headers={}, query={}): - return self.FetchImpl(_AddQueryToUrl(self._FromBasePath(url), query), - _MakeHeaders(headers)) - - def FetchAsync(self, url, headers={}, query={}): - return self.FetchAsyncImpl(_AddQueryToUrl(self._FromBasePath(url), query), - _MakeHeaders(headers)) - - def FetchImpl(self, url, headers): - """Fetches a URL synchronously. - """ - raise NotImplementedError(self.__class__) - - def FetchAsyncImpl(self, url, headers): - """Fetches a URL asynchronously and returns a Future with the result. - """ - raise NotImplementedError(self.__class__) - - def _FromBasePath(self, url): - assert not url.startswith('/'), url - if self._base_path is not None: - url = posixpath.join(self._base_path, url) if url else self._base_path - return url
diff --git a/chrome/common/extensions/docs/server2/url_fetcher_appengine.py b/chrome/common/extensions/docs/server2/url_fetcher_appengine.py deleted file mode 100644 index f5080aeb..0000000 --- a/chrome/common/extensions/docs/server2/url_fetcher_appengine.py +++ /dev/null
@@ -1,43 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import google.appengine.api.urlfetch as urlfetch -import logging -import time -import traceback - -from future import Future -from url_fetcher import UrlFetcher - - -_MAX_RETRIES = 5 -_RETRY_DELAY_SECONDS = 30 - - -class UrlFetcherAppengine(UrlFetcher): - """An implementation of UrlFetcher which uses the GAE urlfetch API to - execute URL fetches. - """ - def __init__(self): - self._retries_left = _MAX_RETRIES - - def FetchImpl(self, url, headers): - return urlfetch.fetch(url, deadline=20, headers=headers) - - def FetchAsyncImpl(self, url, headers): - def process_result(result): - if result.status_code == 429: - if self._retries_left == 0: - logging.error('Still throttled. Giving up.') - return result - self._retries_left -= 1 - logging.info('Throttled. Trying again in %s seconds.' % - _RETRY_DELAY_SECONDS) - time.sleep(_RETRY_DELAY_SECONDS) - return self.FetchAsync(url, username, password, access_token).Get() - return result - - rpc = urlfetch.create_rpc(deadline=20) - urlfetch.make_fetch_call(rpc, url, headers=headers) - return Future(callback=lambda: process_result(rpc.get_result()))
diff --git a/chrome/common/extensions/docs/server2/url_fetcher_fake.py b/chrome/common/extensions/docs/server2/url_fetcher_fake.py deleted file mode 100644 index 0365e3f..0000000 --- a/chrome/common/extensions/docs/server2/url_fetcher_fake.py +++ /dev/null
@@ -1,62 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import logging -import re -import time - -from environment import IsAppEngine -from future import Future -from url_fetcher import UrlFetcher - - -FAKE_URL_FETCHER_CONFIGURATION = None - - -def ConfigureFakeUrlFetch(configuration): - """|configuration| is a dictionary mapping strings to fake urlfetch classes. - A fake urlfetch class just needs to have a fetch method. The keys of the - dictionary are treated as regex, and they are matched with the URL to - determine which fake urlfetch is used. - """ - global FAKE_URL_FETCHER_CONFIGURATION - FAKE_URL_FETCHER_CONFIGURATION = dict( - (re.compile(k), v) for k, v in configuration.iteritems()) - - -def _GetConfiguration(key): - if not FAKE_URL_FETCHER_CONFIGURATION: - raise ValueError('No fake fetch paths have been configured. ' - 'See ConfigureFakeUrlFetch in url_fetcher_fake.py.') - for k, v in FAKE_URL_FETCHER_CONFIGURATION.iteritems(): - if k.match(key): - return v - raise ValueError('No configuration found for %s' % key) - - -class UrlFetcherFake(UrlFetcher): - """A fake UrlFetcher implementation which may be configured with manual URL - overrides for testing. By default this 404s on everything. - """ - class DownloadError(Exception): - pass - - class _Response(object): - def __init__(self, content): - self.content = content - self.headers = {'Content-Type': 'none'} - self.status_code = 200 - - def FetchImpl(self, url, headers): - if IsAppEngine(): - raise ValueError('Attempted to fetch URL from AppEngine: %s' % url) - - url = url.split('?', 1)[0] - response = self._Response(_GetConfiguration(url).fetch(url)) - if response.content is None: - response.status_code = 404 - return response - - def FetchAsyncImpl(self, url, headers): - return Future(callback=lambda: self.FetchImpl(url, headers))
diff --git a/chrome/common/extensions/docs/server2/url_fetcher_urllib2.py b/chrome/common/extensions/docs/server2/url_fetcher_urllib2.py deleted file mode 100644 index 211deaa1..0000000 --- a/chrome/common/extensions/docs/server2/url_fetcher_urllib2.py +++ /dev/null
@@ -1,35 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import logging -import time - -from future import Future -from url_fetcher import UrlFetcher -from urllib2 import urlopen, Request, HTTPError - - -class UrlFetcherUrllib2(UrlFetcher): - """UrlFetcher implementation for use outside of AppEngine. Does NOT support - async fetching, so FetchAsync calls are still blocking. - """ - class _Response(object): - def __init__(self, code, content=None, headers={}): - self.status_code = code - self.content = content - self.headers = headers - - def FetchImpl(self, url, headers): - request = Request(url, headers=headers) - try: - urlresponse = urlopen(request) - response = self._Response(urlresponse.code, urlresponse.read(), - urlresponse.headers.dict) - urlresponse.close() - return response - except HTTPError as e: - return self._Response(e.code, e.reason, e.headers.dict) - - def FetchAsyncImpl(self, url, headers): - return Future(callback=lambda: self.FetchImpl(url, headers))
diff --git a/chrome/common/extensions/docs/server2/whats_new_data_source.py b/chrome/common/extensions/docs/server2/whats_new_data_source.py deleted file mode 100644 index 1ab75b4..0000000 --- a/chrome/common/extensions/docs/server2/whats_new_data_source.py +++ /dev/null
@@ -1,100 +0,0 @@ -# Copyright 2013 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 itertools import groupby -from operator import itemgetter -import posixpath - -from data_source import DataSource -from extensions_paths import JSON_TEMPLATES, PUBLIC_TEMPLATES -from future import Future -from platform_util import GetPlatforms - - -class WhatsNewDataSource(DataSource): - ''' This class creates a list of "what is new" by chrome version. - ''' - - def __init__(self, server_instance, _): - self._parse_cache = server_instance.compiled_fs_factory.ForJson( - server_instance.host_file_system_provider.GetMaster()) - self._object_store = server_instance.object_store_creator.Create( - WhatsNewDataSource) - self._platform_bundle = server_instance.platform_bundle - - def _GenerateChangesListWithVersion(self, platform, whats_new_json): - return [{ - 'id': change_id, - 'type': change['type'], - 'description': change['description'], - 'version': change['version'] - } for change_id, change in whats_new_json.iteritems()] - - def _GetAPIVersion(self, platform, api_name): - version = None - category = self._platform_bundle.GetAPICategorizer(platform).GetCategory( - api_name) - if category == 'chrome': - channel_info = self._platform_bundle.GetAvailabilityFinder( - platform).GetAPIAvailability(api_name).channel_info - channel = channel_info.channel - if channel == 'stable': - version = channel_info.version - return version - - def _GenerateAPIListWithVersion(self, platform): - data = [] - for api_name, api_model in self._platform_bundle.GetAPIModels( - platform).IterModels(): - version = self._GetAPIVersion(platform, api_name) - if version: - api = { - 'name': api_name, - 'description': api_model.description, - 'version' : version, - 'type': 'apis', - } - data.append(api) - data.sort(key=itemgetter('version')) - return data - - def _GenerateWhatsNewDict(self): - whats_new_json_future = self._parse_cache.GetFromFile( - posixpath.join(JSON_TEMPLATES, 'whats_new.json')) - def _MakeDictByPlatform(platform): - whats_new_json = whats_new_json_future.Get() - platform_list = [] - apis = self._GenerateAPIListWithVersion(platform) - apis.extend(self._GenerateChangesListWithVersion(platform, - whats_new_json)) - apis.sort(key=itemgetter('version'), reverse=True) - for version, group in groupby(apis, key=itemgetter('version')): - whats_new_by_version = { - 'version': version, - } - for item in group: - item_type = item['type'] - if item_type not in whats_new_by_version: - whats_new_by_version[item_type] = [] - whats_new_by_version[item_type].append(item) - platform_list.append(whats_new_by_version) - return platform_list - - def resolve(): - return dict((platform, _MakeDictByPlatform(platform)) - for platform in GetPlatforms()) - return Future(callback=resolve) - - def _GetCachedWhatsNewData(self): - data = self._object_store.Get('whats_new_data').Get() - if data is None: - data = self._GenerateWhatsNewDict().Get() - self._object_store.Set('whats_new_data', data) - return data - - def get(self, key): - return self._GetCachedWhatsNewData().get(key) - - def Refresh(self): - return self._GenerateWhatsNewDict()
diff --git a/chrome/common/extensions/docs/server2/whats_new_data_source_test.py b/chrome/common/extensions/docs/server2/whats_new_data_source_test.py deleted file mode 100755 index 9be3972e..0000000 --- a/chrome/common/extensions/docs/server2/whats_new_data_source_test.py +++ /dev/null
@@ -1,99 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 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 json -import os -import unittest -import sys - -from fake_host_file_system_provider import FakeHostFileSystemProvider -from server_instance import ServerInstance -from test_data.canned_data import CANNED_API_FILE_SYSTEM_DATA -from whats_new_data_source import WhatsNewDataSource - - -class WhatsNewDataSourceTest(unittest.TestCase): - def testCreateWhatsNewDataSource(self): - api_fs_creator = FakeHostFileSystemProvider(CANNED_API_FILE_SYSTEM_DATA) - server_instance = ServerInstance.ForTest( - file_system_provider=api_fs_creator) - - whats_new_data_source = WhatsNewDataSource(server_instance, None) - expected_whats_new_changes_list = [ - { - 'version': 22, - 'additionsToExistingApis': [{ - 'version': 22, - 'type': 'additionsToExistingApis', - 'id': 'backgroundpages.to-be-non-persistent', - 'description': 'backgrounds to be non persistent' - } - ], - }, - { - 'version': 21, - 'additionsToExistingApis': [{ - 'version': 21, - 'type': 'additionsToExistingApis', - 'id': 'chromeSetting.set-regular-only-scope', - 'description': 'ChromeSetting.set now has a regular_only scope.' - } - ], - }, - { - 'version': 20, - 'manifestChanges': [{ - 'version': 20, - 'type': 'manifestChanges', - 'id': 'manifest-v1-deprecated', - 'description': 'Manifest version 1 was deprecated in Chrome 18' - } - ], - } - ] - - expected_new_info_of_apps = [ - { - 'version': 26, - 'apis': [{ - 'version': 26, 'type': 'apis', - 'name': u'alarm', - 'description': u'<code>alarm</code>' - }, - { - 'version': 26, 'type': 'apis', - 'name': u'app.window', - 'description': u'<code>app.window</code>' - } - ] - } - ] - expected_new_info_of_apps.extend(expected_whats_new_changes_list) - - expected_new_info_of_extensions = [ - { - 'version': 26, - 'apis': [{ - 'version': 26, 'type': 'apis', - 'name': u'alarm', - 'description': u'<code>alarm</code>' - }, - { - 'version': 26, 'type': 'apis', - 'name': u'browserAction', - 'description': u'<code>browserAction</code>' - } - ] - } - ] - expected_new_info_of_extensions.extend(expected_whats_new_changes_list) - - whats_new_for_apps = whats_new_data_source.get('apps') - whats_new_for_extension = whats_new_data_source.get('extensions') - self.assertEqual(expected_new_info_of_apps, whats_new_for_apps) - self.assertEqual(expected_new_info_of_extensions, whats_new_for_extension) - -if __name__ == '__main__': - unittest.main() \ No newline at end of file
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 5b5c9a83..e5d4c11 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -398,9 +398,6 @@ const char kOnlineEulaURLPath[] = "https://policies.google.com/terms/embedded?hl=%s"; -const char kPhoneHubLearnMoreLink[] = - "https://support.google.com/chromebook?p=phone_hub"; - const char kAdditionalToSOnlineURLPath[] = "https://www.google.com/intl/%s/chrome/terms/";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 9bc91bf..6ad80524 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -364,9 +364,6 @@ extern const char kOnlineEulaURLPath[]; -// The URL for the help center article about PhoneHub. -extern const char kPhoneHubLearnMoreLink[]; - extern const char kAdditionalToSOnlineURLPath[]; // The URL for the "learn more" link for TPM firmware update.
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn index b0c181f..f1302b65b 100644 --- a/chrome/renderer/BUILD.gn +++ b/chrome/renderer/BUILD.gn
@@ -263,6 +263,10 @@ } } + if (is_chromeos_ash) { + deps += [ "//chromeos/constants:constants" ] + } + if (enable_widevine_cdm_component) { deps += [ "//third_party/widevine/cdm:headers" ] }
diff --git a/chrome/renderer/media/DEPS b/chrome/renderer/media/DEPS index a87ac81..f425a01 100644 --- a/chrome/renderer/media/DEPS +++ b/chrome/renderer/media/DEPS
@@ -7,3 +7,9 @@ "+media/capture", # For capture library. "+media/mojo/mojom", # For mojo interfaces. ] + +specific_include_rules = { + "chrome_key_systems.cc" : [ + "+chromeos/constants/chromeos_features.h", + ], +} \ No newline at end of file
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc index 9b9ee3f..2160697 100644 --- a/chrome/renderer/media/chrome_key_systems.cc +++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -40,6 +40,9 @@ // TODO(crbug.com/663554): Needed for WIDEVINE_CDM_MIN_GLIBC_VERSION. // component updated CDM on all desktop platforms and remove this. #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. // nogncheck +#if BUILDFLAG(ENABLE_PLATFORM_HEVC) && BUILDFLAG(IS_CHROMEOS_ASH) +#include "chromeos/constants/chromeos_features.h" +#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC) && BUILDFLAG(IS_CHROMEOS_ASH) // The following must be after widevine_cdm_version.h. #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) #include <gnu/libc-version.h> @@ -179,7 +182,8 @@ #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) #if BUILDFLAG(ENABLE_PLATFORM_HEVC) case media::VideoCodec::kCodecHEVC: - if (is_secure) { + if (is_secure && base::FeatureList::IsEnabled( + chromeos::features::kCdmFactoryDaemon)) { supported_codecs |= media::EME_CODEC_HEVC_PROFILE_MAIN; supported_codecs |= media::EME_CODEC_HEVC_PROFILE_MAIN10; }
diff --git a/chrome/renderer/media/chrome_speech_recognition_client.cc b/chrome/renderer/media/chrome_speech_recognition_client.cc index f8e24813..b7e00816 100644 --- a/chrome/renderer/media/chrome_speech_recognition_client.cc +++ b/chrome/renderer/media/chrome_speech_recognition_client.cc
@@ -215,7 +215,7 @@ if (IsSpeechRecognitionAvailable()) { speech_recognition_recognizer_->SendAudioToSpeechRecognitionService( std::move(audio_data)); - } else { + } else if (is_recognizer_bound_) { speech_recognition_recognizer_->AudioReceivedAfterBubbleClosed( media::AudioTimestampHelper::FramesToTime(audio_data->frame_count, audio_data->sample_rate));
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index d2b4077ce..860f3dfc 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -57,10 +57,6 @@ # into the build. group("test") { testonly = true - - if (enable_extensions) { - deps = [ "//chrome/common/extensions/docs/server2:extension_docserver_python_unittests" ] - } } group("policy_testserver_pyproto") {
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn index e30d9cf9..ca8ee52 100644 --- a/chrome/test/android/BUILD.gn +++ b/chrome/test/android/BUILD.gn
@@ -264,6 +264,7 @@ "$google_play_services_package:google_play_services_basement_java", "//base:base_java", "//base:base_java_test_support", + "//chrome/android:base_module_java", "//chrome/android:chrome_java", "//chrome/browser/flags:java", "//chrome/browser/preferences:java",
diff --git a/chrome/test/data/webui/nearby_share/shared/fake_nearby_contact_manager.js b/chrome/test/data/webui/nearby_share/shared/fake_nearby_contact_manager.js index 632d01b..49ee89c 100644 --- a/chrome/test/data/webui/nearby_share/shared/fake_nearby_contact_manager.js +++ b/chrome/test/data/webui/nearby_share/shared/fake_nearby_contact_manager.js
@@ -15,8 +15,8 @@ constructor() { /** @type {?Array<!nearbyShare.mojom.ContactRecord>} */ this.contactRecords = null; - /** @private {!Array<!string>} */ - this.allowedContacts_ = []; + /** @type {!Array<!string>} */ + this.allowedContacts = []; /** @private {number} */ this.numUnreachable_ = 3; /** @private {?nearbyShare.mojom.DownloadContactsObserverInterface} */ @@ -44,7 +44,7 @@ * @param {!Array<!string>} allowedContacts */ setAllowedContacts(allowedContacts) { - this.allowedContacts_ = allowedContacts; + this.allowedContacts = allowedContacts; } /** @@ -73,7 +73,7 @@ ] } ]; - this.allowedContacts_ = ['1']; + this.allowedContacts = ['1']; } failDownload() { @@ -82,7 +82,7 @@ completeDownload() { this.observer_.onContactsDownloaded( - this.allowedContacts_, this.contactRecords || [], + this.allowedContacts, this.contactRecords || [], /*num_unreachable_contacts_filtered_out=*/ this.numUnreachable_); } }
diff --git a/chrome/test/data/webui/nearby_share/shared/nearby_contact_visibility_test.js b/chrome/test/data/webui/nearby_share/shared/nearby_contact_visibility_test.js index 6b1c0dbb..40867c72 100644 --- a/chrome/test/data/webui/nearby_share/shared/nearby_contact_visibility_test.js +++ b/chrome/test/data/webui/nearby_share/shared/nearby_contact_visibility_test.js
@@ -284,4 +284,43 @@ assertFalse(isUnreachableMessageVisible()); }); + + test( + 'Save persists visibility setting and allowed contacts', + async function() { + fakeContactManager.setupContactRecords(); + fakeContactManager.setNumUnreachable(0); + fakeContactManager.completeDownload(); + visibilityElement.set( + 'settings.visibility', nearbyShare.mojom.Visibility.kAllContacts); + await test_util.waitAfterNextRender(visibilityElement); + + // visibility setting is not immediately updated + visibilityElement.$$('#someContacts').click(); + await test_util.waitAfterNextRender(visibilityElement); + assertTrue(areContactCheckBoxesVisible()); + assertEquals( + visibilityElement.get('settings.visibility'), + nearbyShare.mojom.Visibility.kAllContacts); + + // allow only contact 2, check that allowed contacts are not yet pushed + // to the contact manager + fakeContactManager.setAllowedContacts(['1']); + for (let i = 0; i < visibilityElement.contacts.length; ++i) { + visibilityElement.set( + ['contacts', i, 'checked'], + visibilityElement.contacts[i].id === '2'); + } + await test_util.waitAfterNextRender(visibilityElement); + assertEquals(fakeContactManager.allowedContacts.length, 1); + assertEquals(fakeContactManager.allowedContacts[0], '1'); + + // after save, ui state is persisted + visibilityElement.saveVisibilityAndAllowedContacts(); + assertEquals( + visibilityElement.get('settings.visibility'), + nearbyShare.mojom.Visibility.kSelectedContacts); + assertEquals(fakeContactManager.allowedContacts.length, 1); + assertEquals(fakeContactManager.allowedContacts[0], '2'); + }); });
diff --git a/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js b/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js index 6af9f3c..3e7b5dd 100644 --- a/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js
@@ -50,6 +50,7 @@ internetAddWiFi: 'internetAddWiFi', internetDetailPageTitle: 'internetDetailPageTitle', internetKnownNetworksPageTitle: 'internetKnownNetworksPageTitle', + updatedCellularActivationUi: false, }); mojoApi_ = new FakeNetworkConfig(); @@ -414,7 +415,7 @@ Polymer.dom.flush(); const deepLinkElement = - internetDetailPage.$$('network-siminfo').$$('#simLockButton'); + internetDetailPage.$$('#cellularSimInfo').$$('#simLockButton'); // In this rare case, wait after next render twice due to focus behavior // of the siminfo component.
diff --git a/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js index 122cc154..0a1a73d 100644 --- a/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js +++ b/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
@@ -178,6 +178,31 @@ 'notifySwitchAccessActionAssignmentDialogDetached'); }); + test('Switch access action assignment dialog error state', async function() { + initPage(); + + // Simulate a click on the select link row. + page.$.selectLinkRow.click(); + + await browserProxy.methodCalled( + 'notifySwitchAccessActionAssignmentDialogAttached'); + + // Simulate pressing 'a', and then 'b'. + cr.webUIListenerCallback( + 'switch-access-got-key-press-for-assignment', {key: 'a', keyCode: 65}); + cr.webUIListenerCallback( + 'switch-access-got-key-press-for-assignment', {key: 'b', keyCode: 66}); + + const element = page.$$('#switchAccessActionAssignmentDialog'); + await test_util.waitAfterNextRender(element); + + // This should update the error field at the bottom of the dialog. + const errorText = page.$$('#switchAccessActionAssignmentDialog') + .$$('#error') + .textContent.trim(); + assertEquals('Keys do not match. Press any key to exit.', errorText); + }); + test('Deep link to auto-scan keyboards', async () => { loadTimeData.overrideValues({ isDeepLinkingEnabled: true,
diff --git a/chrome/test/data/webui/signin/profile_picker_main_view_test.js b/chrome/test/data/webui/signin/profile_picker_main_view_test.js index a7beb09..fbe2f58 100644 --- a/chrome/test/data/webui/signin/profile_picker_main_view_test.js +++ b/chrome/test/data/webui/signin/profile_picker_main_view_test.js
@@ -103,18 +103,17 @@ assertTrue(!!profiles[i].$$('profile-card-menu')); profiles[i].$$('cr-button').click(); await browserProxy.whenCalled('launchSelectedProfile'); - const profileCardInfo = - profiles[i].shadowRoot.querySelectorAll('.profile-card-info'); - assertEquals(profileCardInfo.length, 2); - assertEquals( - profileCardInfo[0].innerText, expectedProfiles[i].localProfileName); assertEquals( profiles[i].$$('#forceSigninContainer').hidden, !expectedProfiles[i].needsSignin); - if (!expectedProfiles[i].needsSignin) { - assertEquals( - profileCardInfo[1].innerText, expectedProfiles[i].gaiaName); - } + + const gaiaName = profiles[i].$$('#gaiaName'); + assertEquals(gaiaName.hidden, expectedProfiles[i].needsSignin); + assertEquals(gaiaName.innerText.trim(), expectedProfiles[i].gaiaName); + + assertEquals( + profiles[i].$$('#nameInput').value, + expectedProfiles[i].localProfileName); assertEquals( profiles[i].$$('#iconContainer').hidden, !expectedProfiles[i].isManaged); @@ -163,6 +162,29 @@ profiles, mainViewElement.shadowRoot.querySelectorAll('profile-card')); }); + test('EditLocalProfileName', async function() { + await browserProxy.whenCalled('initializeMainView'); + const profiles = generateProfilesList(1); + webUIListenerCallback('profiles-list-changed', [...profiles]); + flushTasks(); + const localProfileName = + mainViewElement.shadowRoot.querySelector('profile-card') + .$$('#nameInput'); + assertEquals(localProfileName.value, profiles[0].localProfileName); + + // Set to valid profile name. + localProfileName.value = 'Alice'; + localProfileName.fire('change'); + const args = await browserProxy.whenCalled('setProfileName'); + assertEquals(args[0], profiles[0].profilePath); + assertEquals(args[1], 'Alice'); + assertEquals(localProfileName.value, 'Alice'); + + // Set to invalid profile name + localProfileName.value = ''; + assertTrue(localProfileName.invalid); + }); + test('GuestModeDisabled', async function() { loadTimeData.overrideValues({ isGuestModeEnabled: false,
diff --git a/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js b/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js index b5260e3..2296e8da 100644 --- a/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js +++ b/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
@@ -21,6 +21,7 @@ 'getProfileStatistics', 'loadSignInProfileCreationFlow', 'createProfile', + 'setProfileName', ]); /** @type {!AutogeneratedThemeColorInfo} */ @@ -110,4 +111,9 @@ 'createProfile', [profileName, profileColor, avatarUrl, isGeneric, createShortcut]); } + + /** @override */ + setProfileName(profilePath, profileName) { + this.methodCalled('setProfileName', [profilePath, profileName]); + } }
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index ce9cef53..cf57a0f 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -309,6 +309,7 @@ "test/integration_tests.cc", "test/integration_tests.h", "unittest_util_unittest.cc", + "update_service_internal_impl_unittest.cc", "update_service_unittest.cc", "updater_unittest.cc", ]
diff --git a/chrome/updater/constants.h b/chrome/updater/constants.h index c9b2e82..922fa776 100644 --- a/chrome/updater/constants.h +++ b/chrome/updater/constants.h
@@ -212,6 +212,12 @@ // The file downloaded to a temporary location could not be moved. constexpr int kErrorFailedToMoveDownloadedFile = 5; +// TODO(crbug.com/1144151): This constant should be `60` for production code and +// `0.1` for test code. Due to test timeout limitation, the full jitter interval +// (0 to 60 seconds) cannot be tested. A jitter in the interval of 0 to 0.1 +// seconds should be used for testing. +constexpr double kUpdateCheckJitterMultiplier = 0.1; + } // namespace updater #endif // CHROME_UPDATER_CONSTANTS_H_
diff --git a/chrome/updater/update_service_internal_impl.cc b/chrome/updater/update_service_internal_impl.cc index c9b8589..5374f916 100644 --- a/chrome/updater/update_service_internal_impl.cc +++ b/chrome/updater/update_service_internal_impl.cc
@@ -14,6 +14,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/rand_util.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -160,22 +161,26 @@ return; } - update_service->UpdateAll( - base::DoNothing(), + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::BindOnce( - [](base::OnceClosure closure, - scoped_refptr<updater::Configurator> config, - UpdateService::Result result) { - const int exit_code = static_cast<int>(result); - VLOG(0) << "UpdateAll complete: exit_code = " << exit_code; - if (result == UpdateService::Result::kSuccess) { - config->GetPrefService()->SetTime( - kPrefUpdateTime, base::Time::NowFromSystemTime()); - } - std::move(closure).Run(); - }, - base::BindOnce(&CheckForUpdatesTask::MaybeCheckForUpdatesDone, this), - config_)); + &updater::UpdateService::UpdateAll, update_service, base::DoNothing(), + base::BindOnce( + [](base::OnceClosure closure, + scoped_refptr<updater::Configurator> config, + UpdateService::Result result) { + const int exit_code = static_cast<int>(result); + VLOG(0) << "UpdateAll complete: exit_code = " << exit_code; + if (result == UpdateService::Result::kSuccess) { + config->GetPrefService()->SetTime( + kPrefUpdateTime, base::Time::NowFromSystemTime()); + } + std::move(closure).Run(); + }, + base::BindOnce(&CheckForUpdatesTask::MaybeCheckForUpdatesDone, + this), + config_)), + UpdateCheckJitter()); } void CheckForUpdatesTask::MaybeCheckForUpdatesDone() { @@ -266,6 +271,11 @@ } // namespace +base::TimeDelta UpdateCheckJitter() { + return base::TimeDelta::FromSecondsD(base::RandDouble() * + kUpdateCheckJitterMultiplier); +} + UpdateServiceInternalImpl::UpdateServiceInternalImpl( scoped_refptr<updater::Configurator> config) : config_(config) {}
diff --git a/chrome/updater/update_service_internal_impl.h b/chrome/updater/update_service_internal_impl.h index 3527ed9..eec0919b 100644 --- a/chrome/updater/update_service_internal_impl.h +++ b/chrome/updater/update_service_internal_impl.h
@@ -19,6 +19,13 @@ namespace updater { +// Returns a random `TimeDelta` value used to delay the start of the automated +// background tasks such as update checks. This distributes the update server +// load more uniformly and avoids the problem of a large number of clients +// creating load spikes on servers when checking for updates and their system +// time is synchronized by a time server. +base::TimeDelta UpdateCheckJitter(); + class Configurator; // All functions and callbacks must be called on the same sequence.
diff --git a/chrome/updater/update_service_internal_impl_unittest.cc b/chrome/updater/update_service_internal_impl_unittest.cc new file mode 100644 index 0000000..68ad336 --- /dev/null +++ b/chrome/updater/update_service_internal_impl_unittest.cc
@@ -0,0 +1,20 @@ +// 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/updater/update_service_internal_impl.h" + +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace updater { + +TEST(UpdateServiceInternalImplTest, UpdateCheckJitter) { + for (int i = 0; i < 100; ++i) { + base::TimeDelta jitter = UpdateCheckJitter(); + EXPECT_GE(jitter, base::TimeDelta::FromSeconds(0)); + EXPECT_LT(jitter, base::TimeDelta::FromSeconds(60)); + } +} + +} // namespace updater
diff --git a/chromecast/base/cast_features.cc b/chromecast/base/cast_features.cc index f001a653..49382b4 100644 --- a/chromecast/base/cast_features.cc +++ b/chromecast/base/cast_features.cc
@@ -40,13 +40,13 @@ return *features_for_test; } -void SetExperimentIds(const base::ListValue& list) { +void SetExperimentIds(const base::Value& list) { DCHECK(!g_experiment_ids_initialized); + DCHECK(list.is_list()); std::unordered_set<int32_t> ids; - for (size_t i = 0; i < list.GetSize(); ++i) { - int32_t id; - if (list.GetInteger(i, &id)) { - ids.insert(id); + for (const auto& it : list.GetList()) { + if (it.is_int()) { + ids.insert(it.GetInt()); } else { LOG(ERROR) << "Non-integer value found in experiment id list!"; } @@ -172,9 +172,6 @@ &kEnableChromeAudioManagerAndroid, }; -// An iterator for a base::DictionaryValue. Use an alias for brevity in loops. -using Iterator = base::DictionaryValue::Iterator; - std::vector<const base::Feature*> GetInternalFeatures(); const std::vector<const base::Feature*>& GetFeatures() { @@ -192,13 +189,15 @@ return *features; } -void InitializeFeatureList(const base::DictionaryValue& dcs_features, - const base::ListValue& dcs_experiment_ids, +void InitializeFeatureList(const base::Value& dcs_features, + const base::Value& dcs_experiment_ids, const std::string& cmd_line_enable_features, const std::string& cmd_line_disable_features, const std::string& extra_enable_features, const std::string& extra_disable_features) { DCHECK(!base::FeatureList::GetInstance()); + DCHECK(dcs_features.is_dict()); + DCHECK(dcs_experiment_ids.is_list()); // Set the experiments. SetExperimentIds(dcs_experiment_ids); @@ -214,7 +213,7 @@ all_disable_features); // Override defaults from the DCS config. - for (Iterator it(dcs_features); !it.IsAtEnd(); it.Advance()) { + for (const auto& kv : dcs_features.DictItems()) { // Each feature must have its own FieldTrial object. Since experiments are // controlled server-side for Chromecast, and this class is designed with a // client-side experimentation framework in mind, these parameters are @@ -232,24 +231,22 @@ // entropy_provider. However, this value doesn't matter. // - We don't care about the group_id. // - const std::string& feature_name = it.key(); + const std::string& feature_name = kv.first; auto* field_trial = base::FieldTrialList::FactoryGetFieldTrial( feature_name, k100PercentProbability, kDefaultDCSFeaturesGroup, base::FieldTrial::SESSION_RANDOMIZED, nullptr); - bool enabled; - if (it.value().GetAsBoolean(&enabled)) { + if (kv.second.is_bool()) { // A boolean entry simply either enables or disables a feature. feature_list->RegisterFieldTrialOverride( feature_name, - enabled ? base::FeatureList::OVERRIDE_ENABLE_FEATURE - : base::FeatureList::OVERRIDE_DISABLE_FEATURE, + kv.second.GetBool() ? base::FeatureList::OVERRIDE_ENABLE_FEATURE + : base::FeatureList::OVERRIDE_DISABLE_FEATURE, field_trial); continue; } - const base::DictionaryValue* params_dict; - if (it.value().GetAsDictionary(¶ms_dict)) { + if (kv.second.is_dict()) { // A dictionary entry implies that the feature is enabled. feature_list->RegisterFieldTrialOverride( feature_name, base::FeatureList::OVERRIDE_ENABLE_FEATURE, @@ -262,10 +259,9 @@ // Build a map of the FieldTrial parameters and associate it to the // FieldTrial. base::FieldTrialParams params; - for (Iterator p(*params_dict); !p.IsAtEnd(); p.Advance()) { - std::string val; - if (p.value().GetAsString(&val)) { - params[p.key()] = val; + for (const auto& params_kv : kv.second.DictItems()) { + if (params_kv.second.is_string()) { + params[params_kv.first] = params_kv.second.GetString(); } else { LOG(ERROR) << "Entry in params dict for \"" << feature_name << "\"" << " feature is not a string. Skipping."; @@ -282,7 +278,7 @@ // Other base::Value types are not supported. LOG(ERROR) << "A DCS feature mapped to an unsupported value. key: " - << feature_name << " type: " << it.value().type(); + << feature_name << " type: " << kv.second.type(); } base::FeatureList::SetInstance(std::move(feature_list)); @@ -293,43 +289,41 @@ return base::FeatureList::IsEnabled(feature); } -base::DictionaryValue GetOverriddenFeaturesForStorage( - const base::Value& features) { - base::DictionaryValue persistent_dict; +base::Value GetOverriddenFeaturesForStorage(const base::Value& features) { + base::Value persistent_dict(base::Value::Type::DICTIONARY); // |features| maps feature names to either a boolean or a dict of params. for (const auto& feature : features.DictItems()) { if (feature.second.is_bool()) { - persistent_dict.SetBoolean(feature.first, feature.second.GetBool()); + persistent_dict.SetBoolKey(feature.first, feature.second.GetBool()); continue; } - const base::DictionaryValue* params_dict; - if (feature.second.GetAsDictionary(¶ms_dict)) { - auto params = std::make_unique<base::DictionaryValue>(); + if (feature.second.is_dict()) { + const base::Value* params_dict = &feature.second; + base::Value params(base::Value::Type::DICTIONARY); - bool bval; - int ival; - double dval; - std::string sval; - for (Iterator p(*params_dict); !p.IsAtEnd(); p.Advance()) { - const auto& param_key = p.key(); - const auto& param_val = p.value(); - if (param_val.GetAsBoolean(&bval)) { - params->SetString(param_key, bval ? "true" : "false"); - } else if (param_val.GetAsInteger(&ival)) { - params->SetString(param_key, base::NumberToString(ival)); - } else if (param_val.GetAsDouble(&dval)) { - params->SetString(param_key, base::NumberToString(dval)); - } else if (param_val.GetAsString(&sval)) { - params->SetString(param_key, sval); + for (const auto params_kv : params_dict->DictItems()) { + const auto& param_key = params_kv.first; + const auto& param_val = params_kv.second; + if (param_val.is_bool()) { + params.SetStringKey(param_key, + param_val.GetBool() ? "true" : "false"); + } else if (param_val.is_int()) { + params.SetStringKey(param_key, + base::NumberToString(param_val.GetInt())); + } else if (param_val.is_double()) { + params.SetStringKey(param_key, + base::NumberToString(param_val.GetDouble())); + } else if (param_val.is_string()) { + params.SetStringKey(param_key, param_val.GetString()); } else { LOG(ERROR) << "Entry in params dict for \"" << feature.first << "\"" << " is not of a supported type (key: " << param_key << ", type: " << param_val.type(); } } - persistent_dict.Set(feature.first, std::move(params)); + persistent_dict.SetPath(feature.first, std::move(params)); continue; }
diff --git a/chromecast/base/cast_features.h b/chromecast/base/cast_features.h index 064cb97a..fd6f95b 100644 --- a/chromecast/base/cast_features.h +++ b/chromecast/base/cast_features.h
@@ -15,8 +15,6 @@ #include "base/macros.h" namespace base { -class DictionaryValue; -class ListValue; class Value; } // namespace base @@ -49,8 +47,10 @@ // // This function should be called before the browser's main loop. After this is // called, the other functions in this file may be called on any thread. -void InitializeFeatureList(const base::DictionaryValue& dcs_features, - const base::ListValue& dcs_experiment_ids, +// TODO(juke): Keep type info of params by passing in base::flat_map and +// std::vector instead of base::Value. +void InitializeFeatureList(const base::Value& dcs_features, + const base::Value& dcs_experiment_ids, const std::string& cmd_line_enable_features, const std::string& cmd_line_disable_features, const std::string& extra_enable_features, @@ -63,8 +63,7 @@ // Given a dictionary of features, create a copy that is ready to be persisted // to disk. Encodes all values as strings, which is how the FieldTrial // classes expect the param data. -base::DictionaryValue GetOverriddenFeaturesForStorage( - const base::Value& features); +base::Value GetOverriddenFeaturesForStorage(const base::Value& features); // Query the set of experiment ids set for this run. Intended only for metrics // reporting. Must be called after InitializeFeatureList(). May be called on any
diff --git a/chromecast/base/cast_features_unittest.cc b/chromecast/base/cast_features_unittest.cc index 86adcfeb..4133431f 100644 --- a/chromecast/base/cast_features_unittest.cc +++ b/chromecast/base/cast_features_unittest.cc
@@ -60,14 +60,14 @@ {&bool_feature, &bool_feature_2, &bool_feature_3, &bool_feature_4}); // Override those features with DCS configs. - auto experiments = std::make_unique<base::ListValue>(); - auto features = std::make_unique<base::DictionaryValue>(); - features->SetBoolean(kTestBooleanFeatureName, false); - features->SetBoolean(kTestBooleanFeatureName2, false); - features->SetBoolean(kTestBooleanFeatureName3, true); - features->SetBoolean(kTestBooleanFeatureName4, true); + base::Value experiments(base::Value::Type::LIST); + base::Value features(base::Value::Type::DICTIONARY); + features.SetBoolKey(kTestBooleanFeatureName, false); + features.SetBoolKey(kTestBooleanFeatureName2, false); + features.SetBoolKey(kTestBooleanFeatureName3, true); + features.SetBoolKey(kTestBooleanFeatureName4, true); - InitializeFeatureList(*features, *experiments, "", "", "", ""); + InitializeFeatureList(features, experiments, "", "", "", ""); // Test that features are properly enabled (they should match the // DCS config). @@ -84,18 +84,18 @@ chromecast::SetFeaturesForTest({&test_feature}); // Pass params via DCS. - auto experiments = std::make_unique<base::ListValue>(); - auto features = std::make_unique<base::DictionaryValue>(); - auto params = std::make_unique<base::DictionaryValue>(); - params->SetString("foo_key", "foo"); - params->SetString("bar_key", "bar"); - params->SetString("doub_key", "3.14159"); - params->SetString("long_doub_key", "1.23459999999999999"); - params->SetString("int_key", "4242"); - params->SetString("bool_key", "true"); - features->Set(kTestParamsFeatureName, std::move(params)); + base::Value experiments(base::Value::Type::LIST); + base::Value features(base::Value::Type::DICTIONARY); + base::Value params(base::Value::Type::DICTIONARY); + params.SetStringKey("foo_key", "foo"); + params.SetStringKey("bar_key", "bar"); + params.SetStringKey("doub_key", "3.14159"); + params.SetStringKey("long_doub_key", "1.23459999999999999"); + params.SetStringKey("int_key", "4242"); + params.SetStringKey("bool_key", "true"); + features.SetPath(kTestParamsFeatureName, std::move(params)); - InitializeFeatureList(*features, *experiments, "", "", "", ""); + InitializeFeatureList(features, experiments, "", "", "", ""); // Test that this feature is enabled, and params are correct. ASSERT_TRUE(chromecast::IsFeatureEnabled(test_feature)); @@ -125,12 +125,12 @@ base::FEATURE_ENABLED_BY_DEFAULT}; // Override those features with DCS configs. - auto experiments = std::make_unique<base::ListValue>(); - auto features = std::make_unique<base::DictionaryValue>(); - features->SetBoolean(kTestBooleanFeatureName, false); - features->SetBoolean(kTestBooleanFeatureName2, false); - features->SetBoolean(kTestBooleanFeatureName3, true); - features->SetBoolean(kTestBooleanFeatureName4, true); + base::Value experiments(base::Value::Type::LIST); + base::Value features(base::Value::Type::DICTIONARY); + features.SetBoolKey(kTestBooleanFeatureName, false); + features.SetBoolKey(kTestBooleanFeatureName2, false); + features.SetBoolKey(kTestBooleanFeatureName3, true); + features.SetBoolKey(kTestBooleanFeatureName4, true); // Also override a param feature with DCS config. base::Feature params_feature{kTestParamsFeatureName, @@ -139,9 +139,9 @@ &bool_feature_3, &bool_feature_4, ¶ms_feature}); - auto params = std::make_unique<base::DictionaryValue>(); - params->SetString("foo_key", "foo"); - features->Set(kTestParamsFeatureName, std::move(params)); + base::Value params(base::Value::Type::DICTIONARY); + params.SetStringKey("foo_key", "foo"); + features.SetPath(kTestParamsFeatureName, std::move(params)); // Now override with command line flags. Command line flags should have the // final say. @@ -153,7 +153,7 @@ .append(",") .append(kTestParamsFeatureName); - InitializeFeatureList(*features, *experiments, enabled_features, + InitializeFeatureList(features, experiments, enabled_features, disabled_features, "", ""); // Test that features are properly enabled (they should match the @@ -171,127 +171,135 @@ TEST_F(CastFeaturesTest, SetEmptyExperiments) { // Override those features with DCS configs. - auto experiments = std::make_unique<base::ListValue>(); - auto features = std::make_unique<base::DictionaryValue>(); + base::Value experiments(base::Value::Type::LIST); + base::Value features(base::Value::Type::DICTIONARY); - InitializeFeatureList(*features, *experiments, "", "", "", ""); + InitializeFeatureList(features, experiments, "", "", "", ""); ASSERT_EQ(0u, GetDCSExperimentIds().size()); } TEST_F(CastFeaturesTest, SetGoodExperiments) { // Override those features with DCS configs. - auto experiments = std::make_unique<base::ListValue>(); - auto features = std::make_unique<base::DictionaryValue>(); + base::Value experiments(base::Value::Type::LIST); + base::Value features(base::Value::Type::DICTIONARY); int32_t ids[] = {12345678, 123, 0, -1}; std::unordered_set<int32_t> expected; for (int32_t id : ids) { - experiments->AppendInteger(id); + experiments.Append(id); expected.insert(id); } - InitializeFeatureList(*features, *experiments, "", "", "", ""); + InitializeFeatureList(features, experiments, "", "", "", ""); ASSERT_EQ(expected, GetDCSExperimentIds()); } TEST_F(CastFeaturesTest, SetSomeGoodExperiments) { // Override those features with DCS configs. - auto experiments = std::make_unique<base::ListValue>(); - auto features = std::make_unique<base::DictionaryValue>(); - experiments->AppendInteger(1234); - experiments->AppendString("foobar"); - experiments->AppendBoolean(true); - experiments->AppendInteger(1); - experiments->AppendDouble(1.23456); + base::Value experiments(base::Value::Type::LIST); + base::Value features(base::Value::Type::DICTIONARY); + experiments.Append(1234); + experiments.Append("foobar"); + experiments.Append(true); + experiments.Append(1); + experiments.Append(1.23456); std::unordered_set<int32_t> expected; expected.insert(1234); expected.insert(1); - InitializeFeatureList(*features, *experiments, "", "", "", ""); + InitializeFeatureList(features, experiments, "", "", "", ""); ASSERT_EQ(expected, GetDCSExperimentIds()); } TEST_F(CastFeaturesTest, SetAllBadExperiments) { // Override those features with DCS configs. - auto experiments = std::make_unique<base::ListValue>(); - auto features = std::make_unique<base::DictionaryValue>(); - experiments->AppendString("foobar"); - experiments->AppendBoolean(true); - experiments->AppendDouble(1.23456); + base::Value experiments(base::Value::Type::LIST); + base::Value features(base::Value::Type::DICTIONARY); + experiments.Append("foobar"); + experiments.Append(true); + experiments.Append(1.23456); std::unordered_set<int32_t> expected; - InitializeFeatureList(*features, *experiments, "", "", "", ""); + InitializeFeatureList(features, experiments, "", "", "", ""); ASSERT_EQ(expected, GetDCSExperimentIds()); } TEST_F(CastFeaturesTest, GetOverriddenFeaturesForStorage) { - auto features = std::make_unique<base::DictionaryValue>(); - features->SetBoolean("bool_key", false); - features->SetBoolean("bool_key_2", true); + base::Value features(base::Value::Type::DICTIONARY); + features.SetBoolKey("bool_key", false); + features.SetBoolKey("bool_key_2", true); - auto params = std::make_unique<base::DictionaryValue>(); - params->SetString("foo_key", "foo"); - params->SetString("bar_key", "bar"); - params->SetDouble("doub_key", 3.14159); - params->SetDouble("long_doub_key", 1.234599999999999); - params->SetInteger("int_key", 4242); - params->SetInteger("negint_key", -273); - params->SetBoolean("bool_key", true); - features->Set("params_key", std::move(params)); + base::Value params(base::Value::Type::DICTIONARY); + params.SetStringKey("foo_key", "foo"); + params.SetStringKey("bar_key", "bar"); + params.SetDoubleKey("doub_key", 3.14159); + params.SetDoubleKey("long_doub_key", 1.234599999999999); + params.SetIntKey("int_key", 4242); + params.SetIntKey("negint_key", -273); + params.SetBoolKey("bool_key", true); + features.SetPath("params_key", std::move(params)); - auto dict = GetOverriddenFeaturesForStorage(*features); - bool bval; - ASSERT_EQ(3u, dict.size()); - ASSERT_TRUE(dict.GetBoolean("bool_key", &bval)); - ASSERT_EQ(false, bval); - ASSERT_TRUE(dict.GetBoolean("bool_key_2", &bval)); - ASSERT_EQ(true, bval); + auto dict = GetOverriddenFeaturesForStorage(features); + ASSERT_EQ(3u, dict.DictSize()); + auto bval = dict.FindBoolKey("bool_key"); + ASSERT_TRUE(bval.has_value()); + ASSERT_EQ(false, *bval); + bval = dict.FindBoolKey("bool_key_2"); + ASSERT_TRUE(bval.has_value()); + ASSERT_EQ(true, *bval); - const base::DictionaryValue* dval; - std::string sval; - ASSERT_TRUE(dict.GetDictionary("params_key", &dval)); - ASSERT_EQ(7u, dval->size()); - ASSERT_TRUE(dval->GetString("foo_key", &sval)); - ASSERT_EQ("foo", sval); - ASSERT_TRUE(dval->GetString("bar_key", &sval)); - ASSERT_EQ("bar", sval); - ASSERT_TRUE(dval->GetString("doub_key", &sval)); - ASSERT_EQ("3.14159", sval); - ASSERT_TRUE(dval->GetString("long_doub_key", &sval)); - ASSERT_EQ("1.234599999999999", sval); - ASSERT_TRUE(dval->GetString("int_key", &sval)); - ASSERT_EQ("4242", sval); - ASSERT_TRUE(dval->GetString("negint_key", &sval)); - ASSERT_EQ("-273", sval); - ASSERT_TRUE(dval->GetString("bool_key", &sval)); - ASSERT_EQ("true", sval); + const auto* dval = dict.FindDictKey("params_key"); + const std::string* sval = nullptr; + ASSERT_TRUE(dval); + ASSERT_EQ(7u, dval->DictSize()); + sval = dval->FindStringKey("foo_key"); + ASSERT_TRUE(sval); + ASSERT_EQ("foo", *sval); + sval = dval->FindStringKey("bar_key"); + ASSERT_TRUE(sval); + ASSERT_EQ("bar", *sval); + sval = dval->FindStringKey("doub_key"); + ASSERT_TRUE(sval); + ASSERT_EQ("3.14159", *sval); + sval = dval->FindStringKey("long_doub_key"); + ASSERT_TRUE(sval); + ASSERT_EQ("1.234599999999999", *sval); + sval = dval->FindStringKey("int_key"); + ASSERT_TRUE(sval); + ASSERT_EQ("4242", *sval); + sval = dval->FindStringKey("negint_key"); + ASSERT_TRUE(sval); + ASSERT_EQ("-273", *sval); + sval = dval->FindStringKey("bool_key"); + ASSERT_TRUE(sval); + ASSERT_EQ("true", *sval); } TEST_F(CastFeaturesTest, GetOverriddenFeaturesForStorage_BadParams) { - auto features = std::make_unique<base::DictionaryValue>(); - features->SetBoolean("bool_key", false); - features->SetString("str_key", "foobar"); - features->SetInteger("int_key", 12345); - features->SetDouble("doub_key", 4.5678); + base::Value features(base::Value::Type::DICTIONARY); + features.SetBoolKey("bool_key", false); + features.SetStringKey("str_key", "foobar"); + features.SetIntKey("int_key", 12345); + features.SetDoubleKey("doub_key", 4.5678); - auto params = std::make_unique<base::DictionaryValue>(); - params->SetString("foo_key", "foo"); - features->Set("params_key", std::move(params)); + base::Value params(base::Value::Type::DICTIONARY); + params.SetStringKey("foo_key", "foo"); + features.SetPath("params_key", std::move(params)); - auto dict = GetOverriddenFeaturesForStorage(*features); - bool bval; - ASSERT_EQ(2u, dict.size()); - ASSERT_TRUE(dict.GetBoolean("bool_key", &bval)); - ASSERT_EQ(false, bval); + auto dict = GetOverriddenFeaturesForStorage(features); + ASSERT_EQ(2u, dict.DictSize()); + auto bval = dict.FindBoolKey("bool_key"); + ASSERT_TRUE(bval.has_value()); + ASSERT_EQ(false, *bval); - const base::DictionaryValue* dval; - std::string sval; - ASSERT_TRUE(dict.GetDictionary("params_key", &dval)); - ASSERT_EQ(1u, dval->size()); - ASSERT_TRUE(dval->GetString("foo_key", &sval)); - ASSERT_EQ("foo", sval); + const auto* dval = dict.FindDictKey("params_key"); + ASSERT_TRUE(dval); + ASSERT_EQ(1u, dval->DictSize()); + const auto* sval = dval->FindStringKey("foo_key"); + ASSERT_TRUE(sval); + ASSERT_EQ("foo", *sval); } } // namespace chromecast
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn index a3c2f71f..3743bdb 100644 --- a/chromeos/BUILD.gn +++ b/chromeos/BUILD.gn
@@ -269,6 +269,9 @@ tast_test("chrome_all_tast_tests") { # To disable a specific test, add it the following list and cite a bug. tast_disabled_tests = [ + # crbug.com/1162346 + "ui.WindowControl", + # crbug.com/1115622 "ui.ChromeLoginGAIA",
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 88928efe..ca6f125 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -13691.0.0 \ No newline at end of file +13694.0.0 \ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/css/main.css b/chromeos/components/camera_app_ui/resources/css/main.css index 2d9a259..df4586d 100644 --- a/chromeos/components/camera_app_ui/resources/css/main.css +++ b/chromeos/components/camera_app_ui/resources/css/main.css
@@ -47,6 +47,7 @@ overflow: hidden; position: absolute; top: 0; + touch-action: none; width: 100%; } @@ -208,17 +209,13 @@ display: none; } -body.should-handle-intent-result #shutters-group { - bottom: calc((var(--bottom-line) * 2) + 8px + (var(--shutter-size) / 2)); -} - body.tablet-landscape .actions-group { flex-direction: column-reverse; } #mode-selector { - --fade-padding: 16px; - --scrollbar-height: 5px; + --fade-padding: 24px; + --scrollbar-height: 4px; left: calc(var(--left-line) * 2); right: calc(var(--right-line) * 2); @@ -249,7 +246,6 @@ #modes-group { display: block; overflow: auto; - padding: 5px 0; pointer-events: auto; text-align: center; white-space: nowrap; @@ -262,8 +258,8 @@ } #modes-group::-webkit-scrollbar-thumb { - background: gray; - border-radius: 3px/50%; + background: rgba(255, 255, 255, 0.2); + border-radius: 2px; height: auto; width: auto; } @@ -324,7 +320,7 @@ display: inline-block; font-size: 0; /* Remove space between inline-block. */ - margin: calc(var(--focus-ring-gap) + var(--focus-ring-border)) 12px; + margin: calc(var(--focus-ring-gap) + var(--focus-ring-border)) 8px; position: relative; } @@ -799,11 +795,11 @@ #view-camera { --big-icon: 48px; - --bottom-line: 40px; - --left-line: 40px; - --right-line: 56px; + --bottom-line: 44px; + --left-line: 44px; + --right-line: 50px; --small-icon: 40px; - --shutter-vertical-center: calc((var(--bottom-line) * 2) + 204px); + --shutter-vertical-center: 180px; align-items: center; display: flex; @@ -811,10 +807,6 @@ overflow: hidden; } -body.max-wnd #view-camera { - --bottom-line: 56px; -} - #preview-box { align-items: center; bottom: calc(var(--bottom-line) * 2);
diff --git a/chromeos/components/camera_app_ui/resources/js/app_window.js b/chromeos/components/camera_app_ui/resources/js/app_window.js index a8fdeeca..2e6bf1a 100644 --- a/chromeos/components/camera_app_ui/resources/js/app_window.js +++ b/chromeos/components/camera_app_ui/resources/js/app_window.js
@@ -10,11 +10,13 @@ } from './type.js'; import {WaitableEvent} from './waitable_event.js'; -// Default window size when using 4x3 camera preview. -export const DEFAULT_PREVIEW_4X3_WINDOW_SIZE = [788, 570]; +const TOP_BAR_HEIGHT = 32; -// Default window size when using 16x9 camera preview. -export const DEFAULT_PREVIEW_16X9_WINDOW_SIZE = [788, 460]; +// Default window outer size when using 4x3 camera preview. +export const DEFAULT_PREVIEW_4X3_WINDOW_SIZE = [788, 538 + TOP_BAR_HEIGHT]; + +// Default window outer size when using 16x9 camera preview. +export const DEFAULT_PREVIEW_16X9_WINDOW_SIZE = [788, 428 + TOP_BAR_HEIGHT]; /** * Class which is used to coordinate the setup of window between Tast side and
diff --git a/chromeos/components/camera_app_ui/resources/js/nav.js b/chromeos/components/camera_app_ui/resources/js/nav.js index e76382d..0de44a48 100644 --- a/chromeos/components/camera_app_ui/resources/js/nav.js +++ b/chromeos/components/camera_app_ui/resources/js/nav.js
@@ -181,6 +181,11 @@ case 'BrowserBack': windowController.minimize(); break; + case 'Ctrl-=': + case 'Ctrl--': + // Blocks the in-app zoom in/out to avoid unexpected layout. + event.preventDefault(); + break; case 'Ctrl-V': toast.showDebugMessage(browserProxy.getAppVersion()); break;
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_af.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_af.xtb index 17b44063..4886873 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_af.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_af.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="af"> +<translation id="1175958423215084756">Skakel is bespeur. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Galeryprente</translation> <translation id="1430915738399379752">Druk uit</translation> <translation id="1473110567575736769">Afteller van 3 sekondes</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Hulp</translation> <translation id="7658239707568436148">Kanselleer</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Teks is bespeur.</translation> <translation id="8067883171444229417">Speel video</translation> <translation id="8131740175452115882">Bevestig</translation> <translation id="8145038249676204903">Skakel oor na neem van foto</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_am.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_am.xtb index 5a4d819d..1f2911e7 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_am.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_am.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="am"> +<translation id="1175958423215084756">አገናኝ ተገኝቷል። <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">የማዕከለ-ሥዕላት ምስሎች</translation> <translation id="1430915738399379752">አትም</translation> <translation id="1473110567575736769">3 ሰከንዶች መቁጠሪያ</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">እገዛ</translation> <translation id="7658239707568436148">ይቅር</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">ጽሑፍ ተገኝቷል።</translation> <translation id="8067883171444229417">ቪዲዮ አጫውት</translation> <translation id="8131740175452115882">አረጋግጥ</translation> <translation id="8145038249676204903">ፎቶ ለማንሳት ይቀይሩ</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ar.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ar.xtb index bfeb226..571d0c51 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ar.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ar.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="ar"> +<translation id="1175958423215084756">تم رصد الرابط. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">صور المعرض</translation> <translation id="1430915738399379752">طباعة</translation> <translation id="1473110567575736769">مؤقّت لمدة 3 ثوانٍ</translation> @@ -80,6 +81,7 @@ <translation id="7649070708921625228">مساعدة</translation> <translation id="7658239707568436148">إلغاء</translation> <translation id="7670511624014457267">60 لقطة في الثانية</translation> +<translation id="7983668134180549431">تم رصد النص.</translation> <translation id="8067883171444229417">تشغيل الفيديو</translation> <translation id="8131740175452115882">التأكيد</translation> <translation id="8145038249676204903">التبديل لالتقاط صورة</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_bg.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_bg.xtb index 902a6d5..2f803b9 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_bg.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_bg.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="bg"> +<translation id="1175958423215084756">Разпозната е връзка. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Изображения в галерията</translation> <translation id="1430915738399379752">Печат</translation> <translation id="1473110567575736769">Таймер за 3 секунди</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Помощ</translation> <translation id="7658239707568436148">Отказ</translation> <translation id="7670511624014457267">60 кдр/сек</translation> +<translation id="7983668134180549431">Разпознат е текст.</translation> <translation id="8067883171444229417">Възпроизвеждане на видеоклипа</translation> <translation id="8131740175452115882">Потвърждаване</translation> <translation id="8145038249676204903">Превключване към режима за правене на снимки</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_bs.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_bs.xtb index 9d9b612..12b379c 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_bs.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_bs.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="bs"> +<translation id="1175958423215084756">Link je otkriven. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Slike iz Galerije</translation> <translation id="1430915738399379752">Štampaj</translation> <translation id="1473110567575736769">Tajmer za 3 sekunde</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Pomoć</translation> <translation id="7658239707568436148">Otkaži</translation> <translation id="7670511624014457267">60 fps</translation> +<translation id="7983668134180549431">Tekst je otkriven.</translation> <translation id="8067883171444229417">Reproduciraj videozapis</translation> <translation id="8131740175452115882">Potvrdi</translation> <translation id="8145038249676204903">Prebaci na snimanje fotografija</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ca.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ca.xtb index 4cca42f..6615b1ad 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ca.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ca.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="ca"> +<translation id="1175958423215084756">Enllaç detectat. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Imatges de la galeria</translation> <translation id="1430915738399379752">Imprimeix</translation> <translation id="1473110567575736769">Temporitzador de 3 segons</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Ajuda</translation> <translation id="7658239707568436148">Cancel·la</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Text detectat.</translation> <translation id="8067883171444229417">Reprodueix el vídeo</translation> <translation id="8131740175452115882">Confirma</translation> <translation id="8145038249676204903">Canvia al mode per fer fotos</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_cs.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_cs.xtb index 50ad1ad..44ac1726 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_cs.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_cs.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="cs"> +<translation id="1175958423215084756">Byl zjištěn odkaz. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Obrázky v galerii</translation> <translation id="1430915738399379752">Tisk</translation> <translation id="1473110567575736769">3sekundový časovač</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Nápověda</translation> <translation id="7658239707568436148">Zrušit</translation> <translation id="7670511624014457267">60 snímků/s</translation> +<translation id="7983668134180549431">Byl zjištěn text.</translation> <translation id="8067883171444229417">Přehrát video</translation> <translation id="8131740175452115882">Potvrdit</translation> <translation id="8145038249676204903">Přepnout na focení</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_da.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_da.xtb index c52f3e27..e8fe226 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_da.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_da.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="da"> +<translation id="1175958423215084756">Link registreret. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Galleribilleder</translation> <translation id="1430915738399379752">Udskriv</translation> <translation id="1473110567575736769">Timer på 3 sekunder</translation> @@ -80,6 +81,7 @@ <translation id="7649070708921625228">Hjælp</translation> <translation id="7658239707568436148">Annuller</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Tekst er registreret.</translation> <translation id="8067883171444229417">Afspil video</translation> <translation id="8131740175452115882">Bekræft</translation> <translation id="8145038249676204903">Skift for at tage et billede</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_el.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_el.xtb index 764ac56..0c0b8dbb 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_el.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_el.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="el"> +<translation id="1175958423215084756">Εντοπίστηκε σύνδεσμος. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Εικόνες gallery</translation> <translation id="1430915738399379752">Εκτύπωση</translation> <translation id="1473110567575736769">Χρονόμετρο 3 δευτερολέπτων</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Βοήθεια</translation> <translation id="7658239707568436148">Ακύρωση</translation> <translation id="7670511624014457267">60 καρέ ανά δευτερόλεπτο</translation> +<translation id="7983668134180549431">Εντοπίστηκε κείμενο.</translation> <translation id="8067883171444229417">Αναπαραγωγή βίντεο</translation> <translation id="8131740175452115882">Επιβεβαίωση</translation> <translation id="8145038249676204903">Μετάβαση στη λειτουργία λήψης φωτογραφίας</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_en-GB.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_en-GB.xtb index 19d85e6..e03afc58 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_en-GB.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_en-GB.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="en-GB"> +<translation id="1175958423215084756">Link detected. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Gallery images</translation> <translation id="1430915738399379752">Print</translation> <translation id="1473110567575736769">Three seconds timer</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Help</translation> <translation id="7658239707568436148">Cancel</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Text detected.</translation> <translation id="8067883171444229417">Play video</translation> <translation id="8131740175452115882">Confirm</translation> <translation id="8145038249676204903">Switch to take photo</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_es-419.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_es-419.xtb index 7aee395..dcd055d 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_es-419.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_es-419.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="es-419"> +<translation id="1175958423215084756">Se detectó un vínculo. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Imágenes de la galería</translation> <translation id="1430915738399379752">Imprimir</translation> <translation id="1473110567575736769">Temporizador de 3 segundos</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Ayuda</translation> <translation id="7658239707568436148">Cancelar</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Se detectó texto.</translation> <translation id="8067883171444229417">Reproducir video</translation> <translation id="8131740175452115882">Confirmar</translation> <translation id="8145038249676204903">Cambiar al modo para tomar fotos</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_es.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_es.xtb index cfb5466..b445875 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_es.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_es.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="es"> +<translation id="1175958423215084756">Enlace detectado. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Imágenes de la galería</translation> <translation id="1430915738399379752">Imprimir</translation> <translation id="1473110567575736769">Temporizador de 3 segundos</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Ayuda</translation> <translation id="7658239707568436148">Cancelar</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Texto detectado.</translation> <translation id="8067883171444229417">Reproducir vídeo</translation> <translation id="8131740175452115882">Confirmar</translation> <translation id="8145038249676204903">Cambiar al modo de cámara de fotos</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_et.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_et.xtb index 6cc773e..c7236285 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_et.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_et.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="et"> +<translation id="1175958423215084756">Tuvastati link. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Galerii pildid</translation> <translation id="1430915738399379752">Printimine</translation> <translation id="1473110567575736769">3-sekundiline taimer</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Abi</translation> <translation id="7658239707568436148">Tühista</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Tuvastati tekst.</translation> <translation id="8067883171444229417">Esita video</translation> <translation id="8131740175452115882">Kinnita</translation> <translation id="8145038249676204903">Vaheta foto jäädvustamise režiimile</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_fa.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_fa.xtb index 7453d9c..323008f2 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_fa.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_fa.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="fa"> +<translation id="1175958423215084756">پیوند شناسایی شد. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">تصاویر گالری</translation> <translation id="1430915738399379752">چاپ</translation> <translation id="1473110567575736769">زمانسنج ۳ ثانیهای</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">راهنما</translation> <translation id="7658239707568436148">لغو</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">نوشتار شناسایی شد.</translation> <translation id="8067883171444229417">پخش ویدیو</translation> <translation id="8131740175452115882">تأیید</translation> <translation id="8145038249676204903">رفتن به حالت عکسبرداری</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_fil.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_fil.xtb index ab3a098b..7fd8a4b 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_fil.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_fil.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="fil"> +<translation id="1175958423215084756">Na-detect na link. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Mga larawan sa gallery</translation> <translation id="1430915738399379752">I-print</translation> <translation id="1473110567575736769">3 segundong timer</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Tulong</translation> <translation id="7658239707568436148">Kanselahin</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Na-detect na text.</translation> <translation id="8067883171444229417">I-play ang video</translation> <translation id="8131740175452115882">Kumpirmahin</translation> <translation id="8145038249676204903">Lumipat sa pagkuha ng larawan</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_gl.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_gl.xtb index 4035d0d..47b735a 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_gl.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_gl.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="gl"> +<translation id="1175958423215084756">Detectouse unha ligazón. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Imaxes da galería</translation> <translation id="1430915738399379752">Imprimir</translation> <translation id="1473110567575736769">Temporizador de 3 segundos</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Axuda</translation> <translation id="7658239707568436148">Cancelar</translation> <translation id="7670511624014457267">60 fps</translation> +<translation id="7983668134180549431">Detectouse texto.</translation> <translation id="8067883171444229417">Reproducir vídeo</translation> <translation id="8131740175452115882">Confirmar</translation> <translation id="8145038249676204903">Cambiar a modo de cámara de fotos</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_gu.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_gu.xtb index 8d7befeb..92043981 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_gu.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_gu.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="gu"> +<translation id="1175958423215084756">લિંકની જાણકારી મળી. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">ગૅલેરી છબીઓ</translation> <translation id="1430915738399379752">પ્રિન્ટ</translation> <translation id="1473110567575736769">3 સેકન્ડનું ટાઇમર</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">સહાય</translation> <translation id="7658239707568436148">રદ કરો</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">ટેક્સ્ટની જાણકારી મળી.</translation> <translation id="8067883171444229417">વીડિયો ચલાવો</translation> <translation id="8131740175452115882">પુષ્ટિ કરો</translation> <translation id="8145038249676204903">ફોટો લેવા માટે સ્વિચ કરો</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_hr.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_hr.xtb index 05ced0a..1ef8bf43 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_hr.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_hr.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="hr"> +<translation id="1175958423215084756">Veza je prepoznata. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Slike iz galerije</translation> <translation id="1430915738399379752">Ispis</translation> <translation id="1473110567575736769">Odbrojavanje od 3 sekunde</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Pomoć</translation> <translation id="7658239707568436148">Odustani</translation> <translation id="7670511624014457267">60 okv/s</translation> +<translation id="7983668134180549431">Tekst je prepoznat.</translation> <translation id="8067883171444229417">Reproduciraj videozapis</translation> <translation id="8131740175452115882">Potvrdi</translation> <translation id="8145038249676204903">Prijeđi na snimanje fotografije</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_hu.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_hu.xtb index 49f7870..f784b255 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_hu.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_hu.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="hu"> +<translation id="1175958423215084756">Link észlelve. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Galériaképek</translation> <translation id="1430915738399379752">Nyomtatás</translation> <translation id="1473110567575736769">Három másodperces időzítő</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Súgó</translation> <translation id="7658239707568436148">Mégse</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Szöveg észlelve.</translation> <translation id="8067883171444229417">Videó lejátszása</translation> <translation id="8131740175452115882">Megerősítés</translation> <translation id="8145038249676204903">Váltás fotókészítésre</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_is.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_is.xtb index 23d4a1de..9d3e8f0 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_is.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_is.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="is"> +<translation id="1175958423215084756">Tengill greindist. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Myndir úr galleríi</translation> <translation id="1430915738399379752">Prenta</translation> <translation id="1473110567575736769">3 sekúndna teljari</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Hjálp</translation> <translation id="7658239707568436148">Hætta við</translation> <translation id="7670511624014457267">60 rammar/sek.</translation> +<translation id="7983668134180549431">Texti greindist.</translation> <translation id="8067883171444229417">Spila myndskeið</translation> <translation id="8131740175452115882">Staðfesta</translation> <translation id="8145038249676204903">Skipta yfir í myndatöku</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_it.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_it.xtb index 99210d2..f248e9b 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_it.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_it.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="it"> +<translation id="1175958423215084756">Link rilevato. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Immagini della galleria</translation> <translation id="1430915738399379752">Stampa</translation> <translation id="1473110567575736769">Timer di 3 secondi</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Guida</translation> <translation id="7658239707568436148">Annulla</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Testo rilevato.</translation> <translation id="8067883171444229417">Guarda il video</translation> <translation id="8131740175452115882">Conferma</translation> <translation id="8145038249676204903">Passa alla modalità foto</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ja.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ja.xtb index c58c2c14..e02601bd 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ja.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ja.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="ja"> +<translation id="1175958423215084756">リンクが検出されました。<ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">ギャラリー画像</translation> <translation id="1430915738399379752">印刷</translation> <translation id="1473110567575736769">3 秒タイマー</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">ヘルプ</translation> <translation id="7658239707568436148">キャンセル</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">テキストが検出されました。</translation> <translation id="8067883171444229417">動画を再生します</translation> <translation id="8131740175452115882">確認</translation> <translation id="8145038249676204903">写真の撮影に切り替え</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ka.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ka.xtb index 9fe795f..977f646 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ka.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ka.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="ka"> +<translation id="1175958423215084756">აღმოჩენილია ბმული. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">გალერეის სურათები</translation> <translation id="1430915738399379752">ბეჭდვა</translation> <translation id="1473110567575736769">3-წამიანი ტაიმერი</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">დახმარება</translation> <translation id="7658239707568436148">გაუქმება</translation> <translation id="7670511624014457267">60 კადრი/წმ</translation> +<translation id="7983668134180549431">აღმოჩენილია ტექსტი.</translation> <translation id="8067883171444229417">ვიდეოს დაკვრა</translation> <translation id="8131740175452115882">დაადასტურება</translation> <translation id="8145038249676204903">ფოტოს გადაღებაზე გადართვა</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_kk.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_kk.xtb index b8a5ce3..01acda9 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_kk.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_kk.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="kk"> +<translation id="1175958423215084756">Сілтеме анықталды. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Галерея суреттері</translation> <translation id="1430915738399379752">Басып шығару</translation> <translation id="1473110567575736769">3 секундтық таймер</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Анықтама</translation> <translation id="7658239707568436148">Бас тарту</translation> <translation id="7670511624014457267">60 кадр/сек</translation> +<translation id="7983668134180549431">Мәтін анықталды.</translation> <translation id="8067883171444229417">Бейнені ойнату</translation> <translation id="8131740175452115882">Растау</translation> <translation id="8145038249676204903">Суретке түсіруге ауысу</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_lo.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_lo.xtb index 1fc9b5011..151673f 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_lo.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_lo.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="lo"> +<translation id="1175958423215084756">ກວດພົບລິ້ງ. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">ຮູບພາບໃນຄັງ</translation> <translation id="1430915738399379752">ພິມ</translation> <translation id="1473110567575736769">ໂມງນັບຖອຍຫຼັງ 3 ວິນາທີ</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">ຊ່ວຍເຫຼືອ</translation> <translation id="7658239707568436148">ຍົກເລີກ</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">ກວດພົບຂໍ້ຄວາມ.</translation> <translation id="8067883171444229417">ຫຼິ້ນວິດີໂອ</translation> <translation id="8131740175452115882">ຢືນຢັນ</translation> <translation id="8145038249676204903">ປ່ຽນເປັນຖ່າຍຮູບ</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_lt.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_lt.xtb index e6a5835e..6b4e9ef 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_lt.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_lt.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="lt"> +<translation id="1175958423215084756">Aptikta nuoroda. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Galerijos vaizdai</translation> <translation id="1430915738399379752">Spausdinti</translation> <translation id="1473110567575736769">3 sek. laikmatis</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Pagalba</translation> <translation id="7658239707568436148">Atšaukti</translation> <translation id="7670511624014457267">60 KPS</translation> +<translation id="7983668134180549431">Aptiktas tekstas.</translation> <translation id="8067883171444229417">Leisti vaizdo įrašą</translation> <translation id="8131740175452115882">Patvirtinti</translation> <translation id="8145038249676204903">Perjungti į fotografavimo režimą</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_lv.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_lv.xtb index b9ea75a..43e19e5 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_lv.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_lv.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="lv"> +<translation id="1175958423215084756">Konstatēta saite. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Galerijas attēli</translation> <translation id="1430915738399379752">Drukāt</translation> <translation id="1473110567575736769">3 sekunžu taimeris</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Palīdzība</translation> <translation id="7658239707568436148">Atcelt</translation> <translation id="7670511624014457267">60 kadri/s</translation> +<translation id="7983668134180549431">Konstatēts teksts.</translation> <translation id="8067883171444229417">Atskaņot videoklipu</translation> <translation id="8131740175452115882">Apstiprināt</translation> <translation id="8145038249676204903">Pārslēgt, lai uzņemtu fotoattēlu</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ml.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ml.xtb index 6358b58..8292508 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ml.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ml.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="ml"> +<translation id="1175958423215084756">ലിങ്ക് തിരിച്ചറിഞ്ഞു. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">ഗാലറി ചിത്രങ്ങൾ</translation> <translation id="1430915738399379752">അച്ചടിക്കുക</translation> <translation id="1473110567575736769">3 സെക്കൻഡ് ടൈമർ</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">സഹായം</translation> <translation id="7658239707568436148">റദ്ദാക്കൂ</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">ടെക്സ്റ്റ് തിരിച്ചറിഞ്ഞു.</translation> <translation id="8067883171444229417">വീഡിയോ പ്ലേ ചെയ്യുക</translation> <translation id="8131740175452115882">സ്ഥിരീകരിക്കുക</translation> <translation id="8145038249676204903">ഫോട്ടോ എടുക്കുന്നതിലേക്ക് മാറുക</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_mn.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_mn.xtb index db415cb..c581bea 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_mn.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_mn.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="mn"> +<translation id="1175958423215084756">Холбоос илэрсэн. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Галлерейны зураг</translation> <translation id="1430915738399379752">Хэвлэх</translation> <translation id="1473110567575736769">3 секундийн цаг тоологч</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Тусламж</translation> <translation id="7658239707568436148">Болих</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Текст илэрсэн.</translation> <translation id="8067883171444229417">Видео тоглуулах</translation> <translation id="8131740175452115882">Батлах</translation> <translation id="8145038249676204903">Зураг авах руу сэлгэх</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_nl.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_nl.xtb index 454c7303..80b3b23 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_nl.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_nl.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="nl"> +<translation id="1175958423215084756">Link gevonden. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Galerij-afbeeldingen</translation> <translation id="1430915738399379752">Afdrukken</translation> <translation id="1473110567575736769">Timer 3 seconden</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Hulp</translation> <translation id="7658239707568436148">Annuleren</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Tekst gevonden.</translation> <translation id="8067883171444229417">Video afspelen</translation> <translation id="8131740175452115882">Bevestigen</translation> <translation id="8145038249676204903">Naar foto maken</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_no.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_no.xtb index c4c9fc5..7154c6b 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_no.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_no.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="no"> +<translation id="1175958423215084756">Oppdaget link. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Galleribilder</translation> <translation id="1430915738399379752">Skriv ut</translation> <translation id="1473110567575736769">Tre sekunders nedtelling</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Hjelp</translation> <translation id="7658239707568436148">Avbryt</translation> <translation id="7670511624014457267">60 bilder per sekund</translation> +<translation id="7983668134180549431">Oppdaget tekst.</translation> <translation id="8067883171444229417">Spill av videoen</translation> <translation id="8131740175452115882">Bekreft</translation> <translation id="8145038249676204903">Bytt til foto</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_pl.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_pl.xtb index b70caa5..23e002a0 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_pl.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_pl.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="pl"> +<translation id="1175958423215084756">Wykryto link. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Zdjęcia z galerii</translation> <translation id="1430915738399379752">Drukuj</translation> <translation id="1473110567575736769">3-sekundowy samowyzwalacz</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Pomoc</translation> <translation id="7658239707568436148">Anuluj</translation> <translation id="7670511624014457267">60 kl./s</translation> +<translation id="7983668134180549431">Wykryto tekst.</translation> <translation id="8067883171444229417">Odtwórz film</translation> <translation id="8131740175452115882">Potwierdź</translation> <translation id="8145038249676204903">Przełącz, by zrobić zdjęcie</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_pt-BR.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_pt-BR.xtb index 5547ad3..1de031ef 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_pt-BR.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_pt-BR.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="pt-BR"> +<translation id="1175958423215084756">Link detectado. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Imagens da galeria</translation> <translation id="1430915738399379752">Imprimir</translation> <translation id="1473110567575736769">Timer de 3 segundos</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Ajuda</translation> <translation id="7658239707568436148">Cancelar</translation> <translation id="7670511624014457267">60 QPS</translation> +<translation id="7983668134180549431">Texto detectado.</translation> <translation id="8067883171444229417">Assistir vídeo</translation> <translation id="8131740175452115882">Confirmar</translation> <translation id="8145038249676204903">Alternar para tirar foto</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_pt-PT.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_pt-PT.xtb index f5374b4..b8b75af 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_pt-PT.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_pt-PT.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="pt-PT"> +<translation id="1175958423215084756">Link detetado. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Imagens da galeria</translation> <translation id="1430915738399379752">Imprimir</translation> <translation id="1473110567575736769">Temporizador de 3 segundos</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Ajuda</translation> <translation id="7658239707568436148">Cancelar</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Texto detetado.</translation> <translation id="8067883171444229417">Reproduzir vídeo</translation> <translation id="8131740175452115882">Confirmar</translation> <translation id="8145038249676204903">Mudar para tirar foto</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ro.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ro.xtb index 12d37d1e..7e8e6261 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_ro.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_ro.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="ro"> +<translation id="1175958423215084756">A fost detectat un link. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Imagini din galerie</translation> <translation id="1430915738399379752">Printează</translation> <translation id="1473110567575736769">Cronometru de 3 secunde</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Ajutor</translation> <translation id="7658239707568436148">Anulează</translation> <translation id="7670511624014457267">60 CPS</translation> +<translation id="7983668134180549431">A fost detectat text.</translation> <translation id="8067883171444229417">Redă videoclipul</translation> <translation id="8131740175452115882">Confirmați</translation> <translation id="8145038249676204903">Comută pentru a fotografia</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_si.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_si.xtb index d5bbfb90..75368e5 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_si.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_si.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="si"> +<translation id="1175958423215084756">සබැඳිය අනාවරණය කර ගන්නා ලදි. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">ගැලරි රූප</translation> <translation id="1430915738399379752">මුද්රණය කරන්න</translation> <translation id="1473110567575736769">තත්පර 3 කාල ගණකය</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">උදවු</translation> <translation id="7658239707568436148">අවලංගු කරන්න</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">පෙළ අනාවරණය කර ගන්නා ලදි.</translation> <translation id="8067883171444229417">වීඩියෝව ධාවන කරන්න</translation> <translation id="8131740175452115882">තහවුරු කරන්න</translation> <translation id="8145038249676204903">ඡායාරූපය ගැනීමට මාරු වන්න</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sl.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sl.xtb index 95cf7d8..38f75fd 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sl.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sl.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="sl"> +<translation id="1175958423215084756">Zaznana je bila povezava. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Slike v galeriji</translation> <translation id="1430915738399379752">Natisni</translation> <translation id="1473110567575736769">3-sekundni časovnik</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Pomoč</translation> <translation id="7658239707568436148">Prekliči</translation> <translation id="7670511624014457267">60 sličic/s</translation> +<translation id="7983668134180549431">Zaznano je bilo besedilo.</translation> <translation id="8067883171444229417">Predvajanje videa</translation> <translation id="8131740175452115882">Potrdi</translation> <translation id="8145038249676204903">Preklop na fotografiranje</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sr-Latn.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sr-Latn.xtb index eb6966c..f1de1f9 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sr-Latn.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sr-Latn.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="sr-Latn"> +<translation id="1175958423215084756">Link je otkriven. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Slike u galeriji</translation> <translation id="1430915738399379752">Štampaj</translation> <translation id="1473110567575736769">Tajmer za 3 sekunde</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Pomoć</translation> <translation id="7658239707568436148">Otkaži</translation> <translation id="7670511624014457267">60 kadr/s</translation> +<translation id="7983668134180549431">Tekst je otkriven.</translation> <translation id="8067883171444229417">Pusti video</translation> <translation id="8131740175452115882">Potvrdi</translation> <translation id="8145038249676204903">Pređi na režim za snimanje slika</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sr.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sr.xtb index b009a9da3..ba565c2c 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sr.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sr.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="sr"> +<translation id="1175958423215084756">Линк је откривен. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Слике у галерији</translation> <translation id="1430915738399379752">Штампај</translation> <translation id="1473110567575736769">Тајмер за 3 секунде</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Помоћ</translation> <translation id="7658239707568436148">Откажи</translation> <translation id="7670511624014457267">60 кадр/с</translation> +<translation id="7983668134180549431">Текст је откривен.</translation> <translation id="8067883171444229417">Пусти видео</translation> <translation id="8131740175452115882">Потврди</translation> <translation id="8145038249676204903">Пређи на режим за снимање слика</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sv.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sv.xtb index b611822..dd4ca4cc 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sv.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sv.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="sv"> +<translation id="1175958423215084756">Länk har identifierats. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Bilder i galleriet</translation> <translation id="1430915738399379752">Skriv ut</translation> <translation id="1473110567575736769">Timer för 3 sekunder</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Hjälp</translation> <translation id="7658239707568436148">Avbryt</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Text har identifierats.</translation> <translation id="8067883171444229417">Spela upp video</translation> <translation id="8131740175452115882">Bekräfta</translation> <translation id="8145038249676204903">Byt till fotoläge</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sw.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sw.xtb index b810364..5ce2a7c 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_sw.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_sw.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="sw"> +<translation id="1175958423215084756">Kiungo kimetambuliwa. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Picha za matunzio</translation> <translation id="1430915738399379752">Chapisha</translation> <translation id="1473110567575736769">Kipima muda wa sekunde tatu</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Usaidizi</translation> <translation id="7658239707568436148">Ghairi</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Maandishi yametambuliwa.</translation> <translation id="8067883171444229417">Cheza video</translation> <translation id="8131740175452115882">Thibitisha</translation> <translation id="8145038249676204903">Piga picha</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_th.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_th.xtb index cfd09bd..8137e32 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_th.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_th.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="th"> +<translation id="1175958423215084756">ตรวจพบลิงก์ <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">รูปภาพในแกลเลอรี</translation> <translation id="1430915738399379752">พิมพ์</translation> <translation id="1473110567575736769">ตัวจับเวลา 3 วินาที</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">ความช่วยเหลือ</translation> <translation id="7658239707568436148">ยกเลิก</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">ตรวจพบข้อความ</translation> <translation id="8067883171444229417">เล่นวิดีโอ</translation> <translation id="8131740175452115882">ยืนยัน</translation> <translation id="8145038249676204903">เปลี่ยนเป็นโหมดถ่ายภาพ</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_uk.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_uk.xtb index b01cab84..b9bb97d 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_uk.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_uk.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="uk"> +<translation id="1175958423215084756">Виявлене посилання. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Зображення з галереї</translation> <translation id="1430915738399379752">Друк</translation> <translation id="1473110567575736769">Таймер на 3 секунди</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Довідка</translation> <translation id="7658239707568436148">Скасувати</translation> <translation id="7670511624014457267">60 кадрів/с</translation> +<translation id="7983668134180549431">Виявлений текст.</translation> <translation id="8067883171444229417">Дивитися відео</translation> <translation id="8131740175452115882">Підтвердити</translation> <translation id="8145038249676204903">Перейти в режим фотозйомки</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_zh-HK.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_zh-HK.xtb index b0f656d..0b8de07 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_zh-HK.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_zh-HK.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="zh-HK"> +<translation id="1175958423215084756">已偵測到連結。<ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">相片集嘅相</translation> <translation id="1430915738399379752">列印</translation> <translation id="1473110567575736769">3 秒計時器</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">說明</translation> <translation id="7658239707568436148">取消</translation> <translation id="7670511624014457267">每秒畫格數:60</translation> +<translation id="7983668134180549431">已偵測到文字。</translation> <translation id="8067883171444229417">播放影片</translation> <translation id="8131740175452115882">確定</translation> <translation id="8145038249676204903">切換至拍照模式</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_zu.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_zu.xtb index f7c7fb16..57b25ec 100644 --- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_zu.xtb +++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_zu.xtb
@@ -1,6 +1,7 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="zu"> +<translation id="1175958423215084756">Isixhumanisi sitholiwe. <ph name="HOSTNAME" /></translation> <translation id="1276998909102132017">Izithombe zegalari</translation> <translation id="1430915738399379752">Phrinta</translation> <translation id="1473110567575736769">Isibali sikhathi samasekhondi ama-3</translation> @@ -79,6 +80,7 @@ <translation id="7649070708921625228">Usizo</translation> <translation id="7658239707568436148">Khansela</translation> <translation id="7670511624014457267">60 FPS</translation> +<translation id="7983668134180549431">Umbhalo utholiwe.</translation> <translation id="8067883171444229417">Dlala ividiyo</translation> <translation id="8131740175452115882">Qinisekisa</translation> <translation id="8145038249676204903">Shintshela ekuthatheni isithombe</translation>
diff --git a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc index cbabd9f4..4d421f4 100644 --- a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc +++ b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/memory/scoped_refptr.h" +#include "base/metrics/histogram_functions.h" #include "base/time/time.h" #include "media/base/cdm_promise.h" #include "media/base/decoder_buffer.h" @@ -91,6 +92,10 @@ "Mojo connection lost"); } +void ReportSystemCodeUMA(uint32_t system_code) { + base::UmaHistogramSparse("Media.EME.CrosPlatformCdm.SystemCode", system_code); +} + } // namespace namespace chromeos { @@ -539,6 +544,7 @@ void ContentDecryptionModuleAdapter::RejectTrackedPromise( uint32_t promise_id, cdm::mojom::CdmPromiseResultPtr promise_result) { + ReportSystemCodeUMA(promise_result->system_code); cdm_promise_adapter_.RejectPromise(promise_id, promise_result->exception, promise_result->system_code, promise_result->error_message);
diff --git a/chromeos/components/cdm_factory_daemon/output_protection_impl.cc b/chromeos/components/cdm_factory_daemon/output_protection_impl.cc index d186ae7..51b5e23d 100644 --- a/chromeos/components/cdm_factory_daemon/output_protection_impl.cc +++ b/chromeos/components/cdm_factory_daemon/output_protection_impl.cc
@@ -9,6 +9,8 @@ #include "ash/shell.h" #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" @@ -129,6 +131,19 @@ display::DisplayConfigurator* display_configurator_; // Not owned. }; +// These are reported to UMA server. Do not renumber or reuse values. +enum class OutputProtectionStatus { + kQueried = 0, + kNoExternalLink = 1, + kAllExternalLinksProtected = 2, + // Note: Only add new values immediately before this line. + kMaxValue = kAllExternalLinksProtected, +}; + +void ReportOutputProtectionUMA(OutputProtectionStatus status) { + UMA_HISTOGRAM_ENUMERATION("Media.EME.OutputProtection.PlatformCdm", status); +} + } // namespace // static @@ -175,6 +190,8 @@ return; } + ReportOutputProtectionQuery(); + // We want to copy this since we will manipulate it. std::vector<int64_t> remaining_displays = display_id_list_; int64_t curr_display_id = remaining_displays.back(); @@ -286,6 +303,11 @@ return; } + if (aggregate_success) { + ReportOutputProtectionQueryResult(aggregate_link_mask, + aggregate_protection_mask); + } + aggregate_protection_mask &= ~aggregate_no_protection_mask; std::move(callback).Run(aggregate_success, aggregate_link_mask, ConvertProtection(aggregate_protection_mask)); @@ -316,4 +338,48 @@ HandleDisplayChange(); } +void OutputProtectionImpl::ReportOutputProtectionQuery() { + if (uma_for_output_protection_query_reported_) + return; + + ReportOutputProtectionUMA(OutputProtectionStatus::kQueried); + uma_for_output_protection_query_reported_ = true; +} + +void OutputProtectionImpl::ReportOutputProtectionQueryResult( + uint32_t link_mask, + uint32_t protection_mask) { + DCHECK(uma_for_output_protection_query_reported_); + + if (uma_for_output_protection_positive_result_reported_) + return; + + // Report UMAs for output protection query result. + uint32_t external_links = + (link_mask & ~display::DISPLAY_CONNECTION_TYPE_INTERNAL); + + if (!external_links) { + ReportOutputProtectionUMA(OutputProtectionStatus::kNoExternalLink); + uma_for_output_protection_positive_result_reported_ = true; + return; + } + + bool is_unprotectable_link_connected = + (external_links & ~kProtectableConnectionTypes) != 0; + bool is_hdcp_enabled_on_all_protectable_links = + (protection_mask & desired_protection_mask_) != 0; + + if (!is_unprotectable_link_connected && + is_hdcp_enabled_on_all_protectable_links) { + ReportOutputProtectionUMA( + OutputProtectionStatus::kAllExternalLinksProtected); + uma_for_output_protection_positive_result_reported_ = true; + return; + } + + // Do not report a negative result because it could be a false negative. + // Instead, we will calculate number of negatives using the total number of + // queries and positive results. +} + } // namespace chromeos
diff --git a/chromeos/components/cdm_factory_daemon/output_protection_impl.h b/chromeos/components/cdm_factory_daemon/output_protection_impl.h index a8ac4bf..451bbe4c 100644 --- a/chromeos/components/cdm_factory_daemon/output_protection_impl.h +++ b/chromeos/components/cdm_factory_daemon/output_protection_impl.h
@@ -105,6 +105,11 @@ uint32_t changed_metrics) override; void OnDisplayRemoved(const display::Display& display) override; + // Helper methods to report output protection UMAs. + void ReportOutputProtectionQuery(); + void ReportOutputProtectionQueryResult(uint32_t link_mask, + uint32_t protection_mask); + std::unique_ptr<DisplaySystemDelegate> delegate_; display::ContentProtectionManager::ClientId client_id_; @@ -112,6 +117,11 @@ uint32_t desired_protection_mask_{0}; + // Tracks whether an output protection query and a positive query result (no + // unprotected external link) have been reported to UMA. + bool uma_for_output_protection_query_reported_ = false; + bool uma_for_output_protection_positive_result_reported_ = false; + // WeakPtrFactory to use for callbacks. base::WeakPtrFactory<OutputProtectionImpl> weak_factory_{this}; };
diff --git a/chromeos/components/connectivity_diagnostics/BUILD.gn b/chromeos/components/connectivity_diagnostics/BUILD.gn index 37389eca..4f078e87 100644 --- a/chromeos/components/connectivity_diagnostics/BUILD.gn +++ b/chromeos/components/connectivity_diagnostics/BUILD.gn
@@ -14,6 +14,7 @@ deps = [ "../network_ui:network_diagnostics_resource_provider", + "../network_ui:network_health_localized_strings", "//chromeos/components/web_applications", "//chromeos/constants", "//chromeos/resources:connectivity_diagnostics_resources",
diff --git a/chromeos/components/connectivity_diagnostics/connectivity_diagnostics_ui.cc b/chromeos/components/connectivity_diagnostics/connectivity_diagnostics_ui.cc index 35b571c..7828902 100644 --- a/chromeos/components/connectivity_diagnostics/connectivity_diagnostics_ui.cc +++ b/chromeos/components/connectivity_diagnostics/connectivity_diagnostics_ui.cc
@@ -8,9 +8,11 @@ #include "chromeos/components/connectivity_diagnostics/url_constants.h" #include "chromeos/components/network_ui/network_diagnostics_resource_provider.h" +#include "chromeos/components/network_ui/network_health_localized_strings.h" #include "chromeos/grit/connectivity_diagnostics_resources.h" #include "chromeos/grit/connectivity_diagnostics_resources_map.h" #include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom.h" +#include "chromeos/services/network_health/public/mojom/network_health.mojom.h" #include "chromeos/strings/grit/chromeos_strings.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" @@ -47,11 +49,17 @@ ConnectivityDiagnosticsUI::ConnectivityDiagnosticsUI( content::WebUI* web_ui, BindNetworkDiagnosticsServiceCallback bind_network_diagnostics_callback, + BindNetworkHealthServiceCallback bind_network_health_callback, SendFeedbackReportCallback send_feedback_report_callback) : ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true), bind_network_diagnostics_service_callback_( std::move(bind_network_diagnostics_callback)), + bind_network_health_service_callback_( + std::move(bind_network_health_callback)), send_feedback_report_callback_(std::move(send_feedback_report_callback)) { + DCHECK(bind_network_diagnostics_service_callback_); + DCHECK(bind_network_health_service_callback_); + DCHECK(send_feedback_report_callback_); web_ui->RegisterMessageCallback( "sendFeedbackReport", base::BindRepeating(&ConnectivityDiagnosticsUI::SendFeedbackReportRequest, @@ -77,6 +85,7 @@ source->AddLocalizedString("sendFeedbackBtn", IDS_CONNECTIVITY_DIAGNOSTICS_SEND_FEEDBACK); network_diagnostics::AddResources(source); + network_health::AddLocalizedStrings(source); content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(), source); @@ -87,15 +96,17 @@ void ConnectivityDiagnosticsUI::BindInterface( mojo::PendingReceiver< network_diagnostics::mojom::NetworkDiagnosticsRoutines> receiver) { - if (bind_network_diagnostics_service_callback_) - bind_network_diagnostics_service_callback_.Run(std::move(receiver)); + bind_network_diagnostics_service_callback_.Run(std::move(receiver)); +} + +void ConnectivityDiagnosticsUI::BindInterface( + mojo::PendingReceiver<network_health::mojom::NetworkHealthService> + receiver) { + bind_network_health_service_callback_.Run(std::move(receiver)); } void ConnectivityDiagnosticsUI::SendFeedbackReportRequest( const base::ListValue* value) { - if (!send_feedback_report_callback_) - return; - std::string extra_diagnostics = ""; auto values = value->GetList(); if (values.size() && values[0].is_string())
diff --git a/chromeos/components/connectivity_diagnostics/connectivity_diagnostics_ui.h b/chromeos/components/connectivity_diagnostics/connectivity_diagnostics_ui.h index 54be4b7..86d1fc4 100644 --- a/chromeos/components/connectivity_diagnostics/connectivity_diagnostics_ui.h +++ b/chromeos/components/connectivity_diagnostics/connectivity_diagnostics_ui.h
@@ -10,6 +10,7 @@ #include "base/memory/weak_ptr.h" #include "base/values.h" #include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom-forward.h" +#include "chromeos/services/network_health/public/mojom/network_health.mojom-forward.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "ui/webui/mojo_web_ui_controller.h" @@ -21,12 +22,16 @@ mojo::PendingReceiver< network_diagnostics::mojom::NetworkDiagnosticsRoutines>)>; + using BindNetworkHealthServiceCallback = base::RepeatingCallback<void( + mojo::PendingReceiver<network_health::mojom::NetworkHealthService>)>; + using SendFeedbackReportCallback = base::RepeatingCallback<void(const std::string& extra_diagnostics)>; explicit ConnectivityDiagnosticsUI( content::WebUI* web_ui, BindNetworkDiagnosticsServiceCallback bind_network_diagnostics_callback, + BindNetworkHealthServiceCallback bind_network_health_callback, SendFeedbackReportCallback send_feeback_report_callback); ~ConnectivityDiagnosticsUI() override; ConnectivityDiagnosticsUI(const ConnectivityDiagnosticsUI&) = delete; @@ -39,12 +44,20 @@ mojo::PendingReceiver< network_diagnostics::mojom::NetworkDiagnosticsRoutines> receiver); + // Instantiates implementation of the mojom::NetworkHealthService mojo + // interface passing the pending receiver that will be bound. + void BindInterface( + mojo::PendingReceiver<network_health::mojom::NetworkHealthService> + receiver); + void SendFeedbackReportRequest(const base::ListValue* value); private: const BindNetworkDiagnosticsServiceCallback bind_network_diagnostics_service_callback_; + const BindNetworkHealthServiceCallback bind_network_health_service_callback_; + const SendFeedbackReportCallback send_feedback_report_callback_; base::WeakPtrFactory<ConnectivityDiagnosticsUI> weak_factory_{this};
diff --git a/chromeos/components/connectivity_diagnostics/resources/BUILD.gn b/chromeos/components/connectivity_diagnostics/resources/BUILD.gn index 813957f..893615a 100644 --- a/chromeos/components/connectivity_diagnostics/resources/BUILD.gn +++ b/chromeos/components/connectivity_diagnostics/resources/BUILD.gn
@@ -20,6 +20,8 @@ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/cr_components/chromeos/network_health:network_diagnostics.m", "//ui/webui/resources/cr_components/chromeos/network_health:network_diagnostics_mojo.m", + "//ui/webui/resources/cr_components/chromeos/network_health:network_health_summary.m", + "//ui/webui/resources/cr_components/chromeos/network_health:network_health_mojo.m", "//ui/webui/resources/js:i18n_behavior.m", ]
diff --git a/chromeos/components/connectivity_diagnostics/resources/connectivity_diagnostics.html b/chromeos/components/connectivity_diagnostics/resources/connectivity_diagnostics.html index a115108..7b9f0dc 100644 --- a/chromeos/components/connectivity_diagnostics/resources/connectivity_diagnostics.html +++ b/chromeos/components/connectivity_diagnostics/resources/connectivity_diagnostics.html
@@ -31,6 +31,7 @@ <div class="app"> <h1 id="appTitle">[[i18n('appTitle')]]</h1> <div class="content"> + <network-health-summary id="network-health"></network-health-summary> <network-diagnostics id="network-diagnostics"></network-diagnostics> </div> <div class="button-group">
diff --git a/chromeos/components/connectivity_diagnostics/resources/connectivity_diagnostics.js b/chromeos/components/connectivity_diagnostics/resources/connectivity_diagnostics.js index 420dc90..5e128bdb 100644 --- a/chromeos/components/connectivity_diagnostics/resources/connectivity_diagnostics.js +++ b/chromeos/components/connectivity_diagnostics/resources/connectivity_diagnostics.js
@@ -3,6 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_components/chromeos/network_health/network_diagnostics.m.js'; +import 'chrome://resources/cr_components/chromeos/network_health/network_health_summary.m.js'; import 'chrome://resources/cr_elements/shared_style_css.m.js'; import './strings.m.js';
diff --git a/chromeos/components/file_manager/file_manager_ui.cc b/chromeos/components/file_manager/file_manager_ui.cc index 88fe6278..7e79f1026 100644 --- a/chromeos/components/file_manager/file_manager_ui.cc +++ b/chromeos/components/file_manager/file_manager_ui.cc
@@ -73,9 +73,18 @@ delegate_->PopulateLoadTimeData(source); source->UseStringsJs(); - // Shared worker security policy. + // Script security policy. source->OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::WorkerSrc, "worker-src 'self' ;"); + network::mojom::CSPDirectiveName::ScriptSrc, + "script-src chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj " + "chrome://resources " + "'self' ;"); + + // Metadata Shared Worker security policy. + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::WorkerSrc, + "worker-src chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj " + "'self' ;"); // TODO(crbug.com/1098685): Trusted Type remaining WebUI. source->DisableTrustedTypesCSP();
diff --git a/chromeos/components/file_manager/resources/file_manager_fakes.js b/chromeos/components/file_manager/resources/file_manager_fakes.js index 47702725..c27992d 100644 --- a/chromeos/components/file_manager/resources/file_manager_fakes.js +++ b/chromeos/components/file_manager/resources/file_manager_fakes.js
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(crbug.com/1113981) rename to file_manager_api_proxy.js or similar. - /** @suppress {checkTypes} */ window.chrome.extension = { inIncognitoContext: false, @@ -197,30 +195,6 @@ } } -window.DriveSyncHandler = class extends EventTarget { - /** - * Returns the completed event name. - * @return {string} - */ - getCompletedEventName() {} - - /** - * Returns whether the Drive sync is currently suppressed or not. - * @return {boolean} - */ - isSyncSuppressed() {} - - /** - * Shows a notification that Drive sync is disabled on cellular networks. - */ - showDisabledMobileSyncNotification() {} - - /** - * @return {boolean} Whether the handler is syncing items or not. - */ - get syncing() {} -} - window.VolumeManager = class { constructor() { /** @@ -230,8 +204,6 @@ this.volumeInfoList = new VolumeInfoListFake(); } - addEventListener() {} - /** * Disposes the instance. After the invocation of this method, any other * method should not be called. @@ -409,6 +381,30 @@ } } +window.DriveSyncHandler = class extends EventTarget { + /** + * Returns the completed event name. + * @return {string} + */ + getCompletedEventName() {} + + /** + * Returns whether the Drive sync is currently suppressed or not. + * @return {boolean} + */ + isSyncSuppressed() {} + + /** + * Shows a notification that Drive sync is disabled on cellular networks. + */ + showDisabledMobileSyncNotification() {} + + /** + * @return {boolean} Whether the handler is syncing items or not. + */ + get syncing() {} +} + window.Crostini = class { /** * Initialize enabled settings.
diff --git a/chromeos/components/phonehub/BUILD.gn b/chromeos/components/phonehub/BUILD.gn index 7a8d62b..06fea63 100644 --- a/chromeos/components/phonehub/BUILD.gn +++ b/chromeos/components/phonehub/BUILD.gn
@@ -82,6 +82,8 @@ "tether_controller.h", "tether_controller_impl.cc", "tether_controller_impl.h", + "url_constants.cc", + "url_constants.h", "user_action_recorder.h", "user_action_recorder_impl.cc", "user_action_recorder_impl.h",
diff --git a/chromeos/components/phonehub/fake_find_my_device_controller.cc b/chromeos/components/phonehub/fake_find_my_device_controller.cc index 8b184e03..b8ec463 100644 --- a/chromeos/components/phonehub/fake_find_my_device_controller.cc +++ b/chromeos/components/phonehub/fake_find_my_device_controller.cc
@@ -19,20 +19,15 @@ NotifyPhoneRingingStateChanged(); } -void FakeFindMyDeviceController::SetIsPhoneRingingInternal( - bool is_phone_ringing) { - Status phone_ringing_status = - is_phone_ringing ? Status::kRingingOn : Status::kRingingOff; - - if (phone_ringing_status_ == Status::kRingingNotAvailable) - return; - - SetPhoneRingingState(phone_ringing_status); +void FakeFindMyDeviceController::SetPhoneRingingStatusInternal(Status status) { + SetPhoneRingingState(status); } void FakeFindMyDeviceController::RequestNewPhoneRingingState(bool ringing) { - if (!should_request_fail_) - SetIsPhoneRingingInternal(ringing); + if (!should_request_fail_) { + SetPhoneRingingStatusInternal(ringing ? Status::kRingingOn + : Status::kRingingOff); + } } FindMyDeviceController::Status
diff --git a/chromeos/components/phonehub/fake_find_my_device_controller.h b/chromeos/components/phonehub/fake_find_my_device_controller.h index 5e8d4be..078f8fe9 100644 --- a/chromeos/components/phonehub/fake_find_my_device_controller.h +++ b/chromeos/components/phonehub/fake_find_my_device_controller.h
@@ -18,7 +18,7 @@ void SetPhoneRingingState(Status status); // FindMyDeviceController: - void SetIsPhoneRingingInternal(bool is_phone_ringing) override; + void SetPhoneRingingStatusInternal(Status status) override; void RequestNewPhoneRingingState(bool ringing) override; Status GetPhoneRingingStatus() override;
diff --git a/chromeos/components/phonehub/find_my_device_controller.h b/chromeos/components/phonehub/find_my_device_controller.h index 14ba954..c1f72c9 100644 --- a/chromeos/components/phonehub/find_my_device_controller.h +++ b/chromeos/components/phonehub/find_my_device_controller.h
@@ -55,9 +55,9 @@ FindMyDeviceController(); - // This only sets the internal state of the whether the phone is ringin + // This only sets the internal state of the whether the phone is ringing // and does not send a request to start ringing the the remote phone device. - virtual void SetIsPhoneRingingInternal(bool is_phone_ringing) = 0; + virtual void SetPhoneRingingStatusInternal(Status status) = 0; void NotifyPhoneRingingStateChanged(); private:
diff --git a/chromeos/components/phonehub/find_my_device_controller_impl.cc b/chromeos/components/phonehub/find_my_device_controller_impl.cc index d2c9d27..915aaf6 100644 --- a/chromeos/components/phonehub/find_my_device_controller_impl.cc +++ b/chromeos/components/phonehub/find_my_device_controller_impl.cc
@@ -12,26 +12,24 @@ namespace phonehub { FindMyDeviceControllerImpl::FindMyDeviceControllerImpl( - DoNotDisturbController* do_not_disturb_controller, MessageSender* message_sender, UserActionRecorder* user_action_recorder) - : do_not_disturb_controller_(do_not_disturb_controller), - message_sender_(message_sender), + : message_sender_(message_sender), user_action_recorder_(user_action_recorder) { - DCHECK(do_not_disturb_controller_); DCHECK(message_sender_); - - do_not_disturb_controller_->AddObserver(this); } -FindMyDeviceControllerImpl::~FindMyDeviceControllerImpl() { - do_not_disturb_controller_->RemoveObserver(this); -} +FindMyDeviceControllerImpl::~FindMyDeviceControllerImpl() = default; -void FindMyDeviceControllerImpl::SetIsPhoneRingingInternal( - bool is_phone_ringing) { - is_phone_ringing_ = is_phone_ringing; - UpdateStatus(); +void FindMyDeviceControllerImpl::SetPhoneRingingStatusInternal(Status status) { + if (phone_ringing_status_ == status) + return; + + PA_LOG(INFO) << "Find My Device ringing status update: " + << phone_ringing_status_ << " => " << status; + phone_ringing_status_ = status; + + NotifyPhoneRingingStateChanged(); } FindMyDeviceController::Status @@ -52,31 +50,5 @@ message_sender_->SendRingDeviceRequest(ringing); } -void FindMyDeviceControllerImpl::OnDndStateChanged() { - UpdateStatus(); -} - -FindMyDeviceController::Status FindMyDeviceControllerImpl::ComputeStatus() - const { - if (do_not_disturb_controller_->IsDndEnabled()) { - PA_LOG(WARNING) << "Cannot set ringing status because DoNotDisturb mode is " - << "enabled."; - return Status::kRingingNotAvailable; - } - return is_phone_ringing_ ? Status::kRingingOn : Status::kRingingOff; -} - -void FindMyDeviceControllerImpl::UpdateStatus() { - Status status = ComputeStatus(); - if (phone_ringing_status_ == status) - return; - - PA_LOG(INFO) << "Find My Device ringing status update: " - << phone_ringing_status_ << " => " << status; - phone_ringing_status_ = status; - - NotifyPhoneRingingStateChanged(); -} - } // namespace phonehub } // namespace chromeos
diff --git a/chromeos/components/phonehub/find_my_device_controller_impl.h b/chromeos/components/phonehub/find_my_device_controller_impl.h index 28c0edc5..ed7d5ac7 100644 --- a/chromeos/components/phonehub/find_my_device_controller_impl.h +++ b/chromeos/components/phonehub/find_my_device_controller_impl.h
@@ -16,32 +16,22 @@ // Responsible for sending and receiving updates in regards to the Find My // Device feature which involves ringing the user's remote phone. -class FindMyDeviceControllerImpl : public FindMyDeviceController, - public DoNotDisturbController::Observer { +class FindMyDeviceControllerImpl : public FindMyDeviceController { public: - FindMyDeviceControllerImpl(DoNotDisturbController* do_not_disturb_controller, - MessageSender* message_sender, + FindMyDeviceControllerImpl(MessageSender* message_sender, UserActionRecorder* user_action_recorder); ~FindMyDeviceControllerImpl() override; private: friend class FindMyDeviceControllerImplTest; - Status ComputeStatus() const; - void UpdateStatus(); - // FindMyDeviceController: - void SetIsPhoneRingingInternal(bool is_phone_ringing) override; + void SetPhoneRingingStatusInternal(Status status) override; void RequestNewPhoneRingingState(bool ringing) override; Status GetPhoneRingingStatus() override; - // DoNotDisturbController::Observer: - void OnDndStateChanged() override; - - bool is_phone_ringing_ = false; Status phone_ringing_status_ = Status::kRingingOff; - DoNotDisturbController* do_not_disturb_controller_; MessageSender* message_sender_; UserActionRecorder* user_action_recorder_; };
diff --git a/chromeos/components/phonehub/find_my_device_controller_impl_unittest.cc b/chromeos/components/phonehub/find_my_device_controller_impl_unittest.cc index a01395e..51a85ea7 100644 --- a/chromeos/components/phonehub/find_my_device_controller_impl_unittest.cc +++ b/chromeos/components/phonehub/find_my_device_controller_impl_unittest.cc
@@ -6,7 +6,6 @@ #include <memory> -#include "chromeos/components/phonehub/fake_do_not_disturb_controller.h" #include "chromeos/components/phonehub/fake_message_sender.h" #include "chromeos/components/phonehub/fake_user_action_recorder.h" #include "chromeos/components/phonehub/find_my_device_controller.h" @@ -44,8 +43,7 @@ // testing::Test: void SetUp() override { controller_ = std::make_unique<FindMyDeviceControllerImpl>( - &fake_do_not_disturb_controller_, &fake_message_sender_, - &fake_user_action_recorder_); + &fake_message_sender_, &fake_user_action_recorder_); controller_->AddObserver(&fake_observer_); } @@ -55,8 +53,8 @@ return controller_->GetPhoneRingingStatus(); } - void SetIsPhoneRingingInternal(bool is_phone_ringing) { - controller_->SetIsPhoneRingingInternal(is_phone_ringing); + void SetPhoneRingingStatusInternal(FindMyDeviceController::Status status) { + controller_->SetPhoneRingingStatusInternal(status); } void RequestNewPhoneRingingState(bool ringing) { @@ -66,7 +64,6 @@ size_t GetNumObserverCalls() const { return fake_observer_.num_calls(); } protected: - FakeDoNotDisturbController fake_do_not_disturb_controller_; FakeMessageSender fake_message_sender_; FakeUserActionRecorder fake_user_action_recorder_; @@ -79,34 +76,27 @@ EXPECT_EQ(FindMyDeviceController::Status::kRingingOff, GetPhoneRingingStatus()); - // Simulate flipping DoNotDisturb mode to enabled, this should set the - // FindMyPhone status to kRingingNotAvailable. - fake_do_not_disturb_controller_.SetDoNotDisturbStateInternal( - /*is_dnd_enabled=*/true, /*can_request_new_dnd_state=*/true); - EXPECT_EQ(FindMyDeviceController::Status::kRingingNotAvailable, - GetPhoneRingingStatus()); - // Simulate initiating phone ringing when DoNotDisturb mode is enabled. This - // will not update the internal status. - SetIsPhoneRingingInternal(/*is_phone_ringing=*/true); - EXPECT_EQ(FindMyDeviceController::Status::kRingingNotAvailable, + SetPhoneRingingStatusInternal(FindMyDeviceController::Status::kRingingOn); + EXPECT_EQ(FindMyDeviceController::Status::kRingingOn, GetPhoneRingingStatus()); EXPECT_EQ(1u, GetNumObserverCalls()); - // Flip DoNotDisturb back to disabled, expect status to reset back to its - // previous state. - fake_do_not_disturb_controller_.SetDoNotDisturbStateInternal( - /*is_dnd_enabled=*/false, /*can_request_new_dnd_state=*/true); - // Since we previously recorded that the phone should be ringing during - // DoNotDisturb mode was enabled, we return to that state once DoNotDisturb - // is disabled. - EXPECT_EQ(FindMyDeviceController::Status::kRingingOn, + SetPhoneRingingStatusInternal( + FindMyDeviceController::Status::kRingingNotAvailable); + EXPECT_EQ(FindMyDeviceController::Status::kRingingNotAvailable, GetPhoneRingingStatus()); EXPECT_EQ(2u, GetNumObserverCalls()); - // Attempt to set ringing status with the same previous state. Expect that no - // observer calls were made. - SetIsPhoneRingingInternal(/*is_phone_ringing=*/true); - EXPECT_EQ(2u, GetNumObserverCalls()); + SetPhoneRingingStatusInternal(FindMyDeviceController::Status::kRingingOff); + EXPECT_EQ(FindMyDeviceController::Status::kRingingOff, + GetPhoneRingingStatus()); + EXPECT_EQ(3u, GetNumObserverCalls()); + + // Set the current value; observers should not be notified. + SetPhoneRingingStatusInternal(FindMyDeviceController::Status::kRingingOff); + EXPECT_EQ(FindMyDeviceController::Status::kRingingOff, + GetPhoneRingingStatus()); + EXPECT_EQ(3u, GetNumObserverCalls()); } TEST_F(FindMyDeviceControllerImplTest, RequestNewRingStatus) { @@ -115,25 +105,20 @@ EXPECT_EQ(1u, fake_message_sender_.GetRingDeviceRequestCallCount()); EXPECT_TRUE(fake_message_sender_.GetRecentRingDeviceRequest()); - // Simulate flipping DoNotDisturb mode to enabled, this should set the - // FindMyPhone status to kRingingNotAvailable and not send any new messages. - fake_do_not_disturb_controller_.SetDoNotDisturbStateInternal( - /*is_dnd_enabled=*/true, /*can_request_new_dnd_state=*/true); + // Change status to "not available". + SetPhoneRingingStatusInternal( + FindMyDeviceController::Status::kRingingNotAvailable); EXPECT_EQ(FindMyDeviceController::Status::kRingingNotAvailable, GetPhoneRingingStatus()); - RequestNewPhoneRingingState(/*ringing=*/false); + // Requesting new state should fail since it is unavailable. + RequestNewPhoneRingingState(/*ringing=*/true); EXPECT_EQ(1u, fake_user_action_recorder_.num_find_my_device_attempts()); EXPECT_EQ(1u, fake_message_sender_.GetRingDeviceRequestCallCount()); - // No new messages were sent, expect that the last request was still the - // previous "true" value. - EXPECT_TRUE(fake_message_sender_.GetRecentRingDeviceRequest()); - // Flip DoNotDisturb mode to disabled, expect that messages are able to be - // sent again. - fake_do_not_disturb_controller_.SetDoNotDisturbStateInternal( - /*is_dnd_enabled=*/false, /*can_request_new_dnd_state=*/true); - EXPECT_EQ(FindMyDeviceController::Status::kRingingOff, + // Change out of "not available". + SetPhoneRingingStatusInternal(FindMyDeviceController::Status::kRingingOn); + EXPECT_EQ(FindMyDeviceController::Status::kRingingOn, GetPhoneRingingStatus()); RequestNewPhoneRingingState(/*ringing=*/false);
diff --git a/chromeos/components/phonehub/phone_hub_manager_impl.cc b/chromeos/components/phonehub/phone_hub_manager_impl.cc index d5c6265c..44abab8 100644 --- a/chromeos/components/phonehub/phone_hub_manager_impl.cc +++ b/chromeos/components/phonehub/phone_hub_manager_impl.cc
@@ -64,7 +64,6 @@ connection_manager_.get(), feature_status_provider_.get())), find_my_device_controller_(std::make_unique<FindMyDeviceControllerImpl>( - do_not_disturb_controller_.get(), message_sender_.get(), user_action_recorder_.get())), notification_access_manager_(
diff --git a/chromeos/components/phonehub/phone_status_processor.cc b/chromeos/components/phonehub/phone_status_processor.cc index f9c6070..7bcf0a78 100644 --- a/chromeos/components/phonehub/phone_status_processor.cc +++ b/chromeos/components/phonehub/phone_status_processor.cc
@@ -124,6 +124,20 @@ return NotificationAccessManager::AccessStatus::kAvailableButNotGranted; } +FindMyDeviceController::Status ComputeFindMyDeviceStatus( + const proto::PhoneProperties& phone_properties) { + if (phone_properties.find_my_device_capability() == + proto::FindMyDeviceCapability::NOT_ALLOWED) { + return FindMyDeviceController::Status::kRingingNotAvailable; + } + + bool is_ringing = + phone_properties.ring_status() == proto::FindMyDeviceRingStatus::RINGING; + + return is_ringing ? FindMyDeviceController::Status::kRingingOn + : FindMyDeviceController::Status::kRingingOff; +} + base::Optional<Notification> ProcessNotificationProto( const proto::Notification& proto) { // Only process notifications that are messaging apps with inline-replies. @@ -247,8 +261,8 @@ notification_access_manager_->SetAccessStatusInternal( ComputeNotificationAccessState(phone_properties)); - find_my_device_controller_->SetIsPhoneRingingInternal( - phone_properties.ring_status() == proto::FindMyDeviceRingStatus::RINGING); + find_my_device_controller_->SetPhoneRingingStatusInternal( + ComputeFindMyDeviceStatus(phone_properties)); } void PhoneStatusProcessor::MaybeSetPhoneModelName(
diff --git a/chromeos/components/phonehub/phone_status_processor_unittest.cc b/chromeos/components/phonehub/phone_status_processor_unittest.cc index f362912..7684d5e 100644 --- a/chromeos/components/phonehub/phone_status_processor_unittest.cc +++ b/chromeos/components/phonehub/phone_status_processor_unittest.cc
@@ -182,10 +182,12 @@ expected_phone_properties->set_notification_mode( proto::NotificationMode::DO_NOT_DISTURB_ON); expected_phone_properties->set_profile_type(proto::ProfileType::WORK_PROFILE); + expected_phone_properties->set_find_my_device_capability( + proto::FindMyDeviceCapability::NOT_ALLOWED); expected_phone_properties->set_notification_access_state( proto::NotificationAccessState::ACCESS_GRANTED); expected_phone_properties->set_ring_status( - proto::FindMyDeviceRingStatus::RINGING); + proto::FindMyDeviceRingStatus::NOT_RINGING); expected_phone_properties->set_battery_percentage(24u); expected_phone_properties->set_charging_state( proto::ChargingState::CHARGING_AC); @@ -214,7 +216,7 @@ *mutable_phone_model_->phone_name()); EXPECT_TRUE(fake_do_not_disturb_controller_->IsDndEnabled()); EXPECT_FALSE(fake_do_not_disturb_controller_->CanRequestNewDndState()); - EXPECT_EQ(FindMyDeviceController::Status::kRingingOn, + EXPECT_EQ(FindMyDeviceController::Status::kRingingNotAvailable, fake_find_my_device_controller_->GetPhoneRingingStatus()); EXPECT_EQ(NotificationAccessManager::AccessStatus::kProhibited, fake_notification_access_manager_->GetAccessStatus()); @@ -235,6 +237,10 @@ expected_update.add_removed_notification_ids(0u); expected_update.mutable_properties()->set_profile_type( proto::ProfileType::DEFAULT_PROFILE); + expected_update.mutable_properties()->set_find_my_device_capability( + proto::FindMyDeviceCapability::NORMAL); + expected_update.mutable_properties()->set_ring_status( + proto::FindMyDeviceRingStatus::RINGING); fake_message_receiver_->NotifyPhoneStatusUpdateReceived(expected_update); EXPECT_EQ(0u, fake_notification_manager_->num_notifications());
diff --git a/chromeos/components/phonehub/proto/phonehub_api.proto b/chromeos/components/phonehub/proto/phonehub_api.proto index e451435..70e366d 100644 --- a/chromeos/components/phonehub/proto/phonehub_api.proto +++ b/chromeos/components/phonehub/proto/phonehub_api.proto
@@ -90,6 +90,11 @@ WORK_PROFILE = 1; } +enum FindMyDeviceCapability { + NORMAL = 0; + NOT_ALLOWED = 1; +} + message PhoneProperties { int32 battery_percentage = 1; ChargingState charging_state = 2; @@ -107,6 +112,8 @@ FindMyDeviceRingStatus ring_status = 9; ProfileType profile_type = 10; + + FindMyDeviceCapability find_my_device_capability = 11; } message App {
diff --git a/chromeos/components/phonehub/tether_controller.cc b/chromeos/components/phonehub/tether_controller.cc index 311d4ecc..7b5c569 100644 --- a/chromeos/components/phonehub/tether_controller.cc +++ b/chromeos/components/phonehub/tether_controller.cc
@@ -47,6 +47,9 @@ case TetherController::Status::kConnected: stream << "[Connected]"; break; + case TetherController::Status::kNoReception: + stream << "[No Reception]"; + break; } return stream; }
diff --git a/chromeos/components/phonehub/tether_controller.h b/chromeos/components/phonehub/tether_controller.h index bac524a..1739302 100644 --- a/chromeos/components/phonehub/tether_controller.h +++ b/chromeos/components/phonehub/tether_controller.h
@@ -26,9 +26,10 @@ // Instant Tethering is available for use, but currently a connection is // unavailable. There are a variety of reasons why this may be the case: - // the feature could have been disabled in settings, the phone may not have - // cellular reception, or the phone may not have Google Play Services - // notifications enabled, which are required for the feature. + // the feature could have been disabled in settings, or the phone may not + // have Google Play Services notifications enabled, which are required + // for the feature. Note that the phone having no reception or no SIM card + // does not count in this case; instead, kNoReception is used. kConnectionUnavailable = 1, // It is possible to connect, but no connection is active or in progress. @@ -40,7 +41,10 @@ kConnecting = 3, // Connected via Instant Tethering. - kConnected = 4 + kConnected = 4, + + // The phone has no reception (including no SIM). + kNoReception = 5, }; class Observer : public base::CheckedObserver {
diff --git a/chromeos/components/phonehub/tether_controller_impl.cc b/chromeos/components/phonehub/tether_controller_impl.cc index 6229d22f..670cc78 100644 --- a/chromeos/components/phonehub/tether_controller_impl.cc +++ b/chromeos/components/phonehub/tether_controller_impl.cc
@@ -403,22 +403,27 @@ } TetherController::Status TetherControllerImpl::ComputeStatus() const { - bool does_sim_exist_with_reception = - phone_model_->phone_status_model().has_value() && - phone_model_->phone_status_model()->mobile_status() == - PhoneStatusModel::MobileStatus::kSimWithReception; - - if (!does_sim_exist_with_reception) - return Status::kIneligibleForFeature; - FeatureState feature_state = multidevice_setup_client_->GetFeatureState(Feature::kInstantTethering); if (feature_state != FeatureState::kDisabledByUser && feature_state != FeatureState::kEnabledByUser) { + // Tethering may be for instance, prohibited by policy or not supported + // by the phone or Chromebook. return Status::kIneligibleForFeature; } + if (phone_model_->phone_status_model().has_value()) { + // If the phone status exists, and it indicates that the phone + // does not have reception, the status becomes no kNoReception. + bool does_sim_exist_with_reception = + phone_model_->phone_status_model()->mobile_status() == + PhoneStatusModel::MobileStatus::kSimWithReception; + + if (!does_sim_exist_with_reception) + return Status::kNoReception; + } + if (connect_disconnect_status_ == ConnectDisconnectStatus::kTurningOnInstantTethering || connect_disconnect_status_ ==
diff --git a/chromeos/components/phonehub/tether_controller_impl_unittest.cc b/chromeos/components/phonehub/tether_controller_impl_unittest.cc index 9d4e43c..9872ad9f 100644 --- a/chromeos/components/phonehub/tether_controller_impl_unittest.cc +++ b/chromeos/components/phonehub/tether_controller_impl_unittest.cc
@@ -365,19 +365,55 @@ // Phone status changed to no reception. phone_model()->SetPhoneStatusModel(CreateFakePhoneStatusModel( PhoneStatusModel::MobileStatus::kSimButNoReception)); - EXPECT_EQ(GetStatus(), TetherController::Status::kIneligibleForFeature); + EXPECT_EQ(GetStatus(), TetherController::Status::kNoReception); EXPECT_EQ(GetNumObserverStatusChanged(), 7U); + // Phone status changed to no SIM. + phone_model()->SetPhoneStatusModel( + CreateFakePhoneStatusModel(PhoneStatusModel::MobileStatus::kNoSim)); + EXPECT_EQ(GetStatus(), TetherController::Status::kNoReception); + EXPECT_EQ(GetNumObserverStatusChanged(), 7U); + + // Tether feature becomes unsupported, + SetMultideviceSetupFeatureState(FeatureState::kNotSupportedByPhone); + EXPECT_EQ(GetStatus(), TetherController::Status::kIneligibleForFeature); + EXPECT_EQ(GetNumObserverStatusChanged(), 8U); + + // Tether feature becomes supported, the status becomes kNoReception again. + SetMultideviceSetupFeatureState(FeatureState::kEnabledByUser); + EXPECT_EQ(GetStatus(), TetherController::Status::kNoReception); + EXPECT_EQ(GetNumObserverStatusChanged(), 9U); + // Phone status changed to having reception. Connection is still unavailable. phone_model()->SetPhoneStatusModel(CreateFakePhoneStatusModel( PhoneStatusModel::MobileStatus::kSimWithReception)); EXPECT_EQ(GetStatus(), TetherController::Status::kConnectionUnavailable); - EXPECT_EQ(GetNumObserverStatusChanged(), 8U); + EXPECT_EQ(GetNumObserverStatusChanged(), 10U); - // Phone Model is lost. + // Phone Model is lost, connection is still unavailable. phone_model()->SetPhoneStatusModel(base::nullopt); - EXPECT_EQ(GetStatus(), TetherController::Status::kIneligibleForFeature); - EXPECT_EQ(GetNumObserverStatusChanged(), 9U); + EXPECT_EQ(GetStatus(), TetherController::Status::kConnectionUnavailable); + EXPECT_EQ(GetNumObserverStatusChanged(), 10U); + + // Even though there is no Phone Model, adding a visible tether network + // will cause the controller to indicate a connection is available. + AddVisibleTetherNetwork(); + EXPECT_EQ(GetStatus(), TetherController::Status::kConnectionAvailable); + EXPECT_EQ(GetNumObserverStatusChanged(), 11U); + + // Even though there is no Phone Model, connecting to a visible tether network + // externally (e.g via OS Settings) will cause the controller to indicate a + // connecting tether state. + SetTetherNetworkStateConnecting(); + EXPECT_EQ(GetStatus(), TetherController::Status::kConnecting); + EXPECT_EQ(GetNumObserverStatusChanged(), 12U); + + // Even though there is no Phone Model, a connection to a visible tether + // network externally (e.g via OS Settings) will cause the controller to + // indicate a connected tether state. + SetTetherNetworkStateConnected(); + EXPECT_EQ(GetStatus(), TetherController::Status::kConnected); + EXPECT_EQ(GetNumObserverStatusChanged(), 13U); } TEST_F(TetherControllerImplTest, AttemptConnectDisconnect) {
diff --git a/chromeos/components/phonehub/url_constants.cc b/chromeos/components/phonehub/url_constants.cc new file mode 100644 index 0000000..ab32e2e --- /dev/null +++ b/chromeos/components/phonehub/url_constants.cc
@@ -0,0 +1,14 @@ +// 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 "chromeos/components/phonehub/url_constants.h" + +namespace chromeos { +namespace phonehub { + +const char kPhoneHubLearnMoreLink[] = + "https://support.google.com/chromebook?p=phone_hub"; + +} // namespace phonehub +} // namespace chromeos
diff --git a/chromeos/components/phonehub/url_constants.h b/chromeos/components/phonehub/url_constants.h new file mode 100644 index 0000000..5128a98 --- /dev/null +++ b/chromeos/components/phonehub/url_constants.h
@@ -0,0 +1,17 @@ +// 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 CHROMEOS_COMPONENTS_PHONEHUB_URL_CONSTANTS_H_ +#define CHROMEOS_COMPONENTS_PHONEHUB_URL_CONSTANTS_H_ + +namespace chromeos { +namespace phonehub { + +// The URL for the help center article about Phone Hub. +extern const char kPhoneHubLearnMoreLink[]; + +} // namespace phonehub +} // namespace chromeos + +#endif // CHROMEOS_COMPONENTS_PHONEHUB_URL_CONSTANTS_H_
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 0041977..af60935 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -287,7 +287,7 @@ // Enables the OOBE ChromeVox hint dialog and announcement feature. const base::Feature kEnableOobeChromeVoxHint{"EnableOobeChromeVoxHint", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // Enables Device End Of Lifetime warning notifications. const base::Feature kEolWarningNotifications{"EolWarningNotifications", @@ -447,10 +447,6 @@ const base::Feature kLoginDeviceManagementDisclosure{ "LoginDeviceManagementDisclosure", base::FEATURE_ENABLED_BY_DEFAULT}; -// Enables or disables the display password button on login / lock screen. -const base::Feature kLoginDisplayPasswordButton{ - "LoginDisplayPasswordButton", base::FEATURE_ENABLED_BY_DEFAULT}; - // Controls whether to enable the requirement of a minimum chrome version on the // device through the policy DeviceMinimumVersion. If the requirement is // not met and the warning time in the policy has expired, the user is @@ -788,10 +784,6 @@ return base::FeatureList::IsEnabled(kLoginDeviceManagementDisclosure); } -bool IsLoginDisplayPasswordButtonEnabled() { - return base::FeatureList::IsEnabled(kLoginDisplayPasswordButton); -} - bool IsMinimumChromeVersionEnabled() { return base::FeatureList::IsEnabled(kMinimumChromeVersion); }
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h index 27b8ffd..d5d5f4c 100644 --- a/chromeos/constants/chromeos_features.h +++ b/chromeos/constants/chromeos_features.h
@@ -199,8 +199,6 @@ extern const base::Feature kLanguageSettingsUpdate; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kLoginDeviceManagementDisclosure; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) -extern const base::Feature kLoginDisplayPasswordButton; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kMediaApp; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kMediaAppAnnotation; @@ -346,7 +344,6 @@ COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsKerberosSettingsSectionEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsLoginDeviceManagementDisclosureEnabled(); -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsLoginDisplayPasswordButtonEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsMinimumChromeVersionEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsNewOobeLayoutEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsClipboardHistoryEnabled();
diff --git a/chromeos/services/assistant/service.cc b/chromeos/services/assistant/service.cc index f0f8684..92863153 100644 --- a/chromeos/services/assistant/service.cc +++ b/chromeos/services/assistant/service.cc
@@ -216,10 +216,10 @@ Service::Service(std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_url_loader_factory, signin::IdentityManager* identity_manager) - : identity_manager_(identity_manager), + : context_(std::make_unique<Context>(this)), + identity_manager_(identity_manager), token_refresh_timer_(std::make_unique<base::OneShotTimer>()), main_task_runner_(base::SequencedTaskRunnerHandle::Get()), - context_(std::make_unique<Context>(this)), pending_url_loader_factory_(std::move(pending_url_loader_factory)) { DCHECK(identity_manager_); chromeos::PowerManagerClient* power_manager_client =
diff --git a/chromeos/services/assistant/service.h b/chromeos/services/assistant/service.h index 5a450e7..028df907 100644 --- a/chromeos/services/assistant/service.h +++ b/chromeos/services/assistant/service.h
@@ -154,6 +154,12 @@ // for the device. bool ShouldEnableHotword(); + // |ServiceContext| object passed to child classes so they can access some of + // our functionality without depending on us. + // Note: this is used by the other members here, so it must be defined first + // so it is destroyed last. + std::unique_ptr<ServiceContext> context_; + signin::IdentityManager* const identity_manager_; std::unique_ptr<ScopedAshSessionObserver> scoped_ash_session_observer_; ScopedObserver<ash::AmbientUiModel, ash::AmbientUiModelObserver> @@ -183,10 +189,6 @@ base::Optional<std::string> access_token_; - // |ServiceContext| object passed to child classes so they can access some of - // our functionality without depending on us. - std::unique_ptr<ServiceContext> context_; - // non-null until |assistant_manager_service_| is created. std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_url_loader_factory_;
diff --git a/chromeos/services/secure_channel/BUILD.gn b/chromeos/services/secure_channel/BUILD.gn index 3f47864..3299e6d5 100644 --- a/chromeos/services/secure_channel/BUILD.gn +++ b/chromeos/services/secure_channel/BUILD.gn
@@ -110,6 +110,8 @@ "nearby_connection_manager.h", "nearby_connection_manager_impl.cc", "nearby_connection_manager_impl.h", + "nearby_connection_metrics_recorder.cc", + "nearby_connection_metrics_recorder.h", "nearby_initiator_connection_attempt.cc", "nearby_initiator_connection_attempt.h", "nearby_initiator_failure_type.cc", @@ -302,6 +304,7 @@ "foreground_eid_generator_unittest.cc", "multiplexed_channel_impl_unittest.cc", "nearby_connection_manager_impl_unittest.cc", + "nearby_connection_metrics_recorder_unittest.cc", "nearby_connection_unittest.cc", "nearby_initiator_operation_unittest.cc", "pending_ble_connection_request_base_unittest.cc",
diff --git a/chromeos/services/secure_channel/nearby_connection_metrics_recorder.cc b/chromeos/services/secure_channel/nearby_connection_metrics_recorder.cc new file mode 100644 index 0000000..38f6baa --- /dev/null +++ b/chromeos/services/secure_channel/nearby_connection_metrics_recorder.cc
@@ -0,0 +1,77 @@ +// 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 "chromeos/services/secure_channel/nearby_connection_metrics_recorder.h" + +#include "base/metrics/histogram_functions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" + +namespace chromeos { +namespace secure_channel { +namespace { + +static constexpr base::TimeDelta kEffectiveSuccessRateTimeout = + base::TimeDelta::FromMinutes(1); + +void RecordEffectiveConnectionResult(bool success) { + base::UmaHistogramBoolean( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", success); +} + +} // namespace + +NearbyConnectionMetricsRecorder::NearbyConnectionMetricsRecorder() = default; + +NearbyConnectionMetricsRecorder::~NearbyConnectionMetricsRecorder() = default; + +void NearbyConnectionMetricsRecorder::HandleConnectionSuccess( + const DeviceIdPair& device_id_pair) { + RecordEffectiveConnectionResult(/*success=*/true); + + // If there was a previous unsuccessful attempt, clear the unsuccessful + // timestamp since there was a successful retry. + id_pair_to_first_unsuccessful_timestamp_map_[device_id_pair] = base::Time(); +} + +void NearbyConnectionMetricsRecorder::HandleConnectionFailure( + const DeviceIdPair& device_id_pair) { + base::Time& first_unsuccessful_time = + id_pair_to_first_unsuccessful_timestamp_map_[device_id_pair]; + + // If the first unsuccessful timstamp for this ID pair is already set, return + // early to ensure that we do not log multiple repeated failures. + if (!first_unsuccessful_time.is_null()) + return; + + // Set the current time as the first unsuccessful timestamp. + first_unsuccessful_time = base::Time::Now(); + + // Start a timeout period; if no successful attempts occur before this period, + // we'll log a failure. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&NearbyConnectionMetricsRecorder::OnTimeout, + weak_ptr_factory_.GetWeakPtr(), device_id_pair), + kEffectiveSuccessRateTimeout); +} + +void NearbyConnectionMetricsRecorder::OnTimeout( + const DeviceIdPair& device_id_pair) { + const base::Time& first_unsuccessful_time = + id_pair_to_first_unsuccessful_timestamp_map_[device_id_pair]; + + // There was a successful retry during the timeout period; do not log a + // failure result. + if (first_unsuccessful_time.is_null() || + base::Time::Now() - first_unsuccessful_time < + kEffectiveSuccessRateTimeout) { + return; + } + + RecordEffectiveConnectionResult(/*success=*/false); +} + +} // namespace secure_channel +} // namespace chromeos
diff --git a/chromeos/services/secure_channel/nearby_connection_metrics_recorder.h b/chromeos/services/secure_channel/nearby_connection_metrics_recorder.h new file mode 100644 index 0000000..cc31468 --- /dev/null +++ b/chromeos/services/secure_channel/nearby_connection_metrics_recorder.h
@@ -0,0 +1,46 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_NEARBY_CONNECTION_METRICS_RECORDER_H_ +#define CHROMEOS_SERVICES_SECURE_CHANNEL_NEARBY_CONNECTION_METRICS_RECORDER_H_ + +#include "base/containers/flat_map.h" +#include "base/memory/weak_ptr.h" +#include "chromeos/services/secure_channel/device_id_pair.h" + +namespace chromeos { +namespace secure_channel { + +// Records the effective success rate for Nearby Connections attempts. In this +// context, "effective" means that (1) a failure followed by a successful retry +// is counted as a success, and (2) repeated failures (e.g., due to users stuck +// in an unrecoverable state due to Bluetooth issues) are only counted as a +// single failure. +// +// To implement this metric, we log every successful attempt as a success. When +// a failure occurs, we wait one minute to see whether a retry succeeds before +// that point. If there was no success in that time frame, we then log a +// failure. +class NearbyConnectionMetricsRecorder { + public: + NearbyConnectionMetricsRecorder(); + ~NearbyConnectionMetricsRecorder(); + + void HandleConnectionSuccess(const DeviceIdPair& device_id_pair); + void HandleConnectionFailure(const DeviceIdPair& device_id_pair); + + private: + void OnTimeout(const DeviceIdPair& device_id_pair); + + // Stores a null Time when the last attempt was successful. + base::flat_map<DeviceIdPair, base::Time> + id_pair_to_first_unsuccessful_timestamp_map_; + + base::WeakPtrFactory<NearbyConnectionMetricsRecorder> weak_ptr_factory_{this}; +}; + +} // namespace secure_channel +} // namespace chromeos + +#endif // CHROMEOS_SERVICES_SECURE_CHANNEL_NEARBY_CONNECTION_METRICS_RECORDER_H_
diff --git a/chromeos/services/secure_channel/nearby_connection_metrics_recorder_unittest.cc b/chromeos/services/secure_channel/nearby_connection_metrics_recorder_unittest.cc new file mode 100644 index 0000000..4414888 --- /dev/null +++ b/chromeos/services/secure_channel/nearby_connection_metrics_recorder_unittest.cc
@@ -0,0 +1,112 @@ +// 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 "chromeos/services/secure_channel/nearby_connection_metrics_recorder.h" + +#include <memory> + +#include "base/bind.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/task_environment.h" +#include "base/test/test_simple_task_runner.h" +#include "base/time/time.h" +#include "chromeos/services/secure_channel/device_id_pair.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { +namespace secure_channel { + +const char kTestRemoteDeviceId[] = "testRemoteDeviceId"; +const char kTestLocalDeviceId[] = "testLocalDeviceId"; + +class SecureChannelNearbyConnectionMetricsRecorderTest : public testing::Test { + protected: + SecureChannelNearbyConnectionMetricsRecorderTest() + : device_id_pair_(kTestRemoteDeviceId, kTestLocalDeviceId) {} + SecureChannelNearbyConnectionMetricsRecorderTest( + const SecureChannelNearbyConnectionMetricsRecorderTest&) = delete; + SecureChannelNearbyConnectionMetricsRecorderTest& operator=( + const SecureChannelNearbyConnectionMetricsRecorderTest&) = delete; + ~SecureChannelNearbyConnectionMetricsRecorderTest() override = default; + + const DeviceIdPair device_id_pair_; + base::test::TaskEnvironment task_environment_{ + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + base::HistogramTester histogram_tester_; + + NearbyConnectionMetricsRecorder recorder_; +}; + +TEST_F(SecureChannelNearbyConnectionMetricsRecorderTest, Test) { + // Succeed; metric should be logged. + recorder_.HandleConnectionSuccess(device_id_pair_); + histogram_tester_.ExpectBucketCount( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", + /*sample=*/true, + /*count=*/1); + + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10)); + + // Succeed again; should be logged. + recorder_.HandleConnectionSuccess(device_id_pair_); + histogram_tester_.ExpectBucketCount( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", + /*sample=*/true, + /*count=*/2); + + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10)); + + // Fail; nothing should be logged since the failure just occurred. + recorder_.HandleConnectionFailure(device_id_pair_); + histogram_tester_.ExpectBucketCount( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", + /*sample=*/false, + /*count=*/0); + + // Fast forward 59 seconds (under 1min). + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(59)); + + // Fail; still nothing should have been logged. + recorder_.HandleConnectionFailure(device_id_pair_); + histogram_tester_.ExpectBucketCount( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", + /*sample=*/false, + /*count=*/0); + + // Fast forward 1 more second; a minute has passed, so a failure should have + // been logged. + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1)); + histogram_tester_.ExpectBucketCount( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", + /*sample=*/false, + /*count=*/1); + + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10)); + + // Succeed; this should reset any ongoing timer. + recorder_.HandleConnectionSuccess(device_id_pair_); + histogram_tester_.ExpectBucketCount( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", + /*sample=*/true, + /*count=*/3); + + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10)); + + // Fail; nothing should be logged. + recorder_.HandleConnectionFailure(device_id_pair_); + histogram_tester_.ExpectBucketCount( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", + /*sample=*/false, + /*count=*/1); + + // Move forward another minute and verify that another failure was logged. + task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(1)); + histogram_tester_.ExpectBucketCount( + "MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult", + /*sample=*/false, + /*count=*/2); +} + +} // namespace secure_channel +} // namespace chromeos
diff --git a/chromeos/services/secure_channel/nearby_initiator_operation.cc b/chromeos/services/secure_channel/nearby_initiator_operation.cc index a8d3b1f..ba0e917a 100644 --- a/chromeos/services/secure_channel/nearby_initiator_operation.cc +++ b/chromeos/services/secure_channel/nearby_initiator_operation.cc
@@ -6,9 +6,11 @@ #include "base/bind.h" #include "base/memory/ptr_util.h" +#include "base/no_destructor.h" #include "chromeos/services/secure_channel/authenticated_channel.h" #include "chromeos/services/secure_channel/connection_metrics_logger.h" #include "chromeos/services/secure_channel/nearby_connection_manager.h" +#include "chromeos/services/secure_channel/nearby_connection_metrics_recorder.h" namespace chromeos { @@ -32,6 +34,17 @@ } } +void RecordConnectionMetrics(const DeviceIdPair& device_id_pair, + NearbyInitiatorConnectionResult result) { + LogNearbyInitiatorConnectionResult(result); + + static base::NoDestructor<NearbyConnectionMetricsRecorder> recorder; + if (result == NearbyInitiatorConnectionResult::kConnectionSuccess) + recorder->HandleConnectionSuccess(device_id_pair); + else + recorder->HandleConnectionFailure(device_id_pair); +} + } // namespace // static @@ -112,15 +125,16 @@ void NearbyInitiatorOperation::OnSuccessfulConnection( std::unique_ptr<AuthenticatedChannel> authenticated_channel) { + RecordConnectionMetrics(device_id_pair(), + NearbyInitiatorConnectionResult::kConnectionSuccess); OnSuccessfulConnectionAttempt(std::move(authenticated_channel)); - LogNearbyInitiatorConnectionResult( - NearbyInitiatorConnectionResult::kConnectionSuccess); } void NearbyInitiatorOperation::OnConnectionFailure( NearbyInitiatorFailureType failure_type) { + RecordConnectionMetrics(device_id_pair(), + GetMetricsConnectionResult(failure_type)); OnFailedConnectionAttempt(failure_type); - LogNearbyInitiatorConnectionResult(GetMetricsConnectionResult(failure_type)); } } // namespace secure_channel
diff --git a/chromeos/strings/chromeos_strings_pl.xtb b/chromeos/strings/chromeos_strings_pl.xtb index 59228613..5ff98e4 100644 --- a/chromeos/strings/chromeos_strings_pl.xtb +++ b/chromeos/strings/chromeos_strings_pl.xtb
@@ -105,7 +105,7 @@ <translation id="4378373042927530923">Nie wykonano</translation> <translation id="4382484599443659549">PDF</translation> <translation id="4425149324548788773">Mój dysk</translation> -<translation id="4429881212383817840">Bilet Kerberos wkrótce straci ważność</translation> +<translation id="4429881212383817840">Zgłoszenie Kerberos wkrótce straci ważność</translation> <translation id="445059817448385655">Stare hasło</translation> <translation id="4454245904991689773">Skanuj do</translation> <translation id="4479639480957787382">Ethernet</translation> @@ -264,7 +264,7 @@ <translation id="8970109610781093811">Uruchom ponownie</translation> <translation id="9074739597929991885">Bluetooth</translation> <translation id="9088306295921699330">Obecne wykorzystanie</translation> -<translation id="910415269708673980">Odśwież bilet przypisany do konta <ph name="PRINCIPAL_NAME" />.</translation> +<translation id="910415269708673980">Odśwież zgłoszenie przypisane do konta <ph name="PRINCIPAL_NAME" />.</translation> <translation id="9106415115617144481">Skanowanie strony <ph name="PAGE_NUMBER" /></translation> <translation id="9111102763498581341">Odblokuj</translation> <translation id="9149391708638971077">Przeprowadź test pamięci</translation>
diff --git a/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc b/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc index 42f6041..64f4490 100644 --- a/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc +++ b/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
@@ -80,6 +80,8 @@ std::unique_ptr<net::test_server::HttpResponse> MockCrashEndpoint::HandleRequest(const net::test_server::HttpRequest& request) { GURL absolute_url = test_server_->GetURL(request.relative_url); + LOG(INFO) << "MockCrashEndpoint::HandleRequest(" << absolute_url.spec() + << ")"; if (absolute_url.path() != kTestCrashEndpoint) { return nullptr; }
diff --git a/components/domain_reliability/quic_error_mapping.cc b/components/domain_reliability/quic_error_mapping.cc index e3259f8..bff8a2e4 100644 --- a/components/domain_reliability/quic_error_mapping.cc +++ b/components/domain_reliability/quic_error_mapping.cc
@@ -433,6 +433,7 @@ {quic::QUIC_MAX_AGE_TIMEOUT, "quic.quic_max_age_timeout"}, {quic::QUIC_INVALID_0RTT_PACKET_NUMBER_OUT_OF_ORDER, "quic.quic_invalid_0rtt_packet_number_out_of_order"}, + {quic::QUIC_INVALID_PRIORITY_UPDATE, "quic::quic_invalid_priority_update"}, // No error. Used as bound while iterating. {quic::QUIC_LAST_ERROR, "quic.last_error"}};
diff --git a/components/policy/resources/policy_templates_es-419.xtb b/components/policy/resources/policy_templates_es-419.xtb index d2f6c41..b130c4580 100644 --- a/components/policy/resources/policy_templates_es-419.xtb +++ b/components/policy/resources/policy_templates_es-419.xtb
@@ -5456,6 +5456,9 @@ <translation id="8834641112681661892">Si estableces la política, se especificará la demora máxima (expresada en milisegundos) entre que se invalida una política y se recupera la nueva política del servicio de administración de dispositivos. Los valores válidos son de 1,000 (1 segundo) a 300,000 (5 minutos). Los valores fuera de este rango se ajustarán conforme al límite correspondiente. Si no estableces la política, <ph name="PRODUCT_NAME" /> utilizará el valor predeterminado de 10 segundos.</translation> +<translation id="8835322836315560274">Si estableces la política, controlarás el comando que se utilizará para abrir las URL en un navegador alternativo. La política puede establecerse como una ruta de archivo o uno de estos valores: <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" />, <ph name="FIREFOX_VALUE_PLACEHOLDER" />, <ph name="SAFARI_VALUE_PLACEHOLDER" />, <ph name="OPERA_VALUE_PLACEHOLDER" /> o <ph name="EDGE_VALUE_PLACEHOLDER" />. Si la estableces como una ruta de archivo, ese archivo se usará como ejecutable. <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" /> solo está disponible en <ph name="MS_WIN_NAME" />. <ph name="SAFARI_VALUE_PLACEHOLDER" /> y <ph name="EDGE_VALUE_PLACEHOLDER" /> solo están disponibles en <ph name="MS_WIN_NAME" /> y <ph name="MAC_OS_NAME" />. + + Si no estableces la política, se utilizará la configuración predeterminada específica de la plataforma: <ph name="IE_PRODUCT_NAME" /> para <ph name="MS_WIN_NAME" /> o <ph name="SAFARI_PRODUCT_NAME" /> para <ph name="MAC_OS_NAME" />. En <ph name="LINUX_OS_NAME" />, se producirá un error al intentar ejecutar un navegador alternativo.</translation> <translation id="885147810817138322">Muestra recomendaciones de contenido multimedia para el usuario</translation> <translation id="8852579753940989645">Habilitar la integridad del código del renderizador</translation> <translation id="8854571659927427063">Si habilitas la política, se importarán los favoritos del navegador predeterminado anterior en la primera ejecución. Si la inhabilitas o no la estableces, no se importará ningún favorito en la primera ejecución.
diff --git a/components/policy/resources/policy_templates_es.xtb b/components/policy/resources/policy_templates_es.xtb index 54ae4c6..1e8dbfb 100644 --- a/components/policy/resources/policy_templates_es.xtb +++ b/components/policy/resources/policy_templates_es.xtb
@@ -5461,6 +5461,9 @@ <translation id="8834641112681661892">Si se asigna un valor a esta política, se especificará el retraso máximo (en milisegundos) entre la recepción de la invalidación de una política y la obtención de la nueva política desde el servicio de gestión del dispositivo. Los valores válidos están comprendidos entre 1000 (1 segundo) y 300.000 (5 minutos). Cualquier valor fuera de este intervalo se ajustará al límite correspondiente. Si no se le asigna ningún valor a esta política, <ph name="PRODUCT_NAME" /> usará el valor predeterminado (10 segundos).</translation> +<translation id="8835322836315560274">Esta política controla el comando que se utilizará para abrir URLs en un navegador alternativo. Se le puede asignar uno de estos valores: <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" />, <ph name="FIREFOX_VALUE_PLACEHOLDER" />, <ph name="SAFARI_VALUE_PLACEHOLDER" />, <ph name="OPERA_VALUE_PLACEHOLDER" />, <ph name="EDGE_VALUE_PLACEHOLDER" /> o una ruta de archivo. Si se asigna una ruta de archivo a esta política, el archivo se usará como ejecutable. <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" /> solo está disponible en <ph name="MS_WIN_NAME" />. <ph name="SAFARI_VALUE_PLACEHOLDER" /> y <ph name="EDGE_VALUE_PLACEHOLDER" /> solo están disponibles en <ph name="MS_WIN_NAME" /> y <ph name="MAC_OS_NAME" />. + + Si no se asigna ningún valor a esta política, se usará el navegador predeterminado según el sistema operativo: <ph name="IE_PRODUCT_NAME" /> en <ph name="MS_WIN_NAME" /> o <ph name="SAFARI_PRODUCT_NAME" /> en <ph name="MAC_OS_NAME" />. No se podrá abrir ningún navegador alternativo en <ph name="LINUX_OS_NAME" />.</translation> <translation id="885147810817138322">Mostrar recomendaciones de contenido multimedia al usuario</translation> <translation id="8852579753940989645">Habilitar la integridad del código del renderizador</translation> <translation id="8854571659927427063">Si se asigna el valor "Habilitada" a esta política, se importarán los marcadores del navegador predeterminado anterior al ejecutarse por primera vez. Si se le asigna el valor "Inhabilitada" o no se le asigna ninguno, no se importará ningún marcador al ejecutarse por primera vez.
diff --git a/components/policy/resources/policy_templates_id.xtb b/components/policy/resources/policy_templates_id.xtb index ba21536..100f62aa 100644 --- a/components/policy/resources/policy_templates_id.xtb +++ b/components/policy/resources/policy_templates_id.xtb
@@ -3920,7 +3920,9 @@ CATATAN: Perilaku default untuk perangkat pelanggan dan perusahaan berbeda: pada perangkat pelanggan, pengguna yang dilindungi diaktifkan secara default, namun pada perangkat perusahaan, pengguna yang dilindungi dinonaktifkan secara default.</translation> <translation id="6652197835259177259">Setelan pengguna yang dikelola secara lokal</translation> -<translation id="6653897159826215341">Setting the policy to Enabled has <ph name="PRODUCT_NAME" /> open the system print dialog instead of the built-in print preview when users request a printout.</translation> +<translation id="6653897159826215341">Jika kebijakan disetel ke Aktif, <ph name="PRODUCT_NAME" /> akan membuka dialog cetak sistem, bukan pratinjau cetak bawaan saat pengguna meminta hasil cetak. + + Jika kebijakan disetel ke Nonaktif atau tidak disetel, perintah cetak akan memicu layar pratinjau cetak.</translation> <translation id="6658245400435704251">Menentukan jumlah waktu (dalam detik) sebuah perangkat dapat menunda download pembaruannya secara acak dari saat pembaruan tersebut pertama kali didorong ke server. Perangkat dapat menunggu dengan sebagian dari waktu ini dari segi prediksi waktu penyelesaian tugas dan sisa waktunya dari segi jumlah pemeriksaan pembaruan. Dalam keadaan apa pun, penyebaran dibatasi dengan jumlah waktu yang konstan sehingga perangkat tidak akan terus menunggu download pembaruan selamanya.</translation> <translation id="6665670272107384733">Setel seberapa sering pengguna harus memasukkan sandi untuk menggunakan buka kunci cepat.</translation> <translation id="6667586534922258705">Memperlihatkan tombol tampilkan sandi pada layar login dan layar kunci</translation>
diff --git a/components/policy/resources/policy_templates_it.xtb b/components/policy/resources/policy_templates_it.xtb index d8db051..382b785e 100644 --- a/components/policy/resources/policy_templates_it.xtb +++ b/components/policy/resources/policy_templates_it.xtb
@@ -5429,6 +5429,9 @@ <translation id="8834641112681661892">L'impostazione del criterio specifica il ritardo massimo in millisecondi tra la ricezione dell'invalidamento di un criterio e il recupero del nuovo criterio da parte del servizio di gestione dei dispositivi. I valori validi di questo criterio sono compresi tra 1000 (1 secondo) e 300.000 (5 minuti). I valori che non rientrano in questo intervallo verranno bloccati al relativo limite. Se il criterio non viene impostato, <ph name="PRODUCT_NAME" /> usa il valore predefinito di 10 secondi.</translation> +<translation id="8835322836315560274">La configurazione del criterio consente di stabilire il comando da usare per aprire gli URL in un browser alternativo. Per il criterio è possibile impostare i valori <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" />, <ph name="FIREFOX_VALUE_PLACEHOLDER" />, <ph name="SAFARI_VALUE_PLACEHOLDER" />, <ph name="OPERA_VALUE_PLACEHOLDER" />, <ph name="EDGE_VALUE_PLACEHOLDER" /> oppure un percorso file. Se per questo criterio viene impostato un percorso file, tale file viene usato come eseguibile. Il valore <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" /> è disponibile soltanto su <ph name="MS_WIN_NAME" />. I valori <ph name="SAFARI_VALUE_PLACEHOLDER" /> e <ph name="EDGE_VALUE_PLACEHOLDER" /> sono disponibili soltanto su <ph name="MS_WIN_NAME" /> e <ph name="MAC_OS_NAME" />. + + Se il criterio non viene configurato, viene usato un valore predefinito specifico della piattaforma: <ph name="IE_PRODUCT_NAME" /> per <ph name="MS_WIN_NAME" /> oppure <ph name="SAFARI_PRODUCT_NAME" /> per <ph name="MAC_OS_NAME" />. Su <ph name="LINUX_OS_NAME" /> non è possibile aprire un browser alternativo.</translation> <translation id="885147810817138322">Mostra all'utente consigli di contenuti multimediali</translation> <translation id="8852579753940989645">Attiva l'integrità del codice del renderer</translation> <translation id="8854571659927427063">Se il criterio viene impostato su Attivato, i preferiti del precedente browser predefinito verranno importati alla prima esecuzione. Se il criterio viene impostato su Disattivato o se non viene configurato, i preferiti non verranno importati alla prima esecuzione.
diff --git a/components/policy/resources/policy_templates_ja.xtb b/components/policy/resources/policy_templates_ja.xtb index b74d0751..eaef296 100644 --- a/components/policy/resources/policy_templates_ja.xtb +++ b/components/policy/resources/policy_templates_ja.xtb
@@ -5332,6 +5332,9 @@ <translation id="8834641112681661892">このポリシーでは、デバイス管理サービスからポリシーの無効化を受け取ってから新しいポリシーを取得するまでの最大時間(ミリ秒単位)を指定できます。有効な値の範囲は 1,000(1 秒)~300,000(5 分)です。この範囲外の値を指定すると、最も近い範囲内の値に修正されます。 このポリシーを未設定のままにした場合、<ph name="PRODUCT_NAME" /> ではデフォルト値である 10 秒が使用されます。</translation> +<translation id="8835322836315560274">このポリシーの設定により、代替ブラウザで URL を開くときに使用するコマンドを管理できます。このポリシーは <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" />、<ph name="FIREFOX_VALUE_PLACEHOLDER" />、<ph name="SAFARI_VALUE_PLACEHOLDER" />、<ph name="OPERA_VALUE_PLACEHOLDER" />、<ph name="EDGE_VALUE_PLACEHOLDER" />、またはファイルパスのいずれかに設定できます。このポリシーをファイルパスに設定すると、そのファイルが実行ファイルとして使用されます。<ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" /> は <ph name="MS_WIN_NAME" /> でのみ使用できます。<ph name="SAFARI_VALUE_PLACEHOLDER" /> と <ph name="EDGE_VALUE_PLACEHOLDER" /> は <ph name="MS_WIN_NAME" /> と <ph name="MAC_OS_NAME" /> でのみ使用できます。 + + このポリシーを未設定のままにすると、プラットフォーム固有のデフォルトが使用されます。すなわち、<ph name="MS_WIN_NAME" /> の場合は <ph name="IE_PRODUCT_NAME" />、<ph name="MAC_OS_NAME" /> の場合は <ph name="SAFARI_PRODUCT_NAME" /> が使用されます。<ph name="LINUX_OS_NAME" /> では、代替ブラウザの起動は失敗します。</translation> <translation id="885147810817138322">おすすめメディアをユーザーに表示する</translation> <translation id="8852579753940989645">レンダラコードの整合性チェックを有効にする</translation> <translation id="8854571659927427063">このポリシーを有効に設定した場合、初回実行時に以前の既定のブラウザからブックマークが読み込まれます。このポリシーを無効に設定するか未設定のままにした場合、初回実行時にブックマークは読み込まれません。
diff --git a/components/policy/resources/policy_templates_nl.xtb b/components/policy/resources/policy_templates_nl.xtb index cca0bf32..5e5e3e8 100644 --- a/components/policy/resources/policy_templates_nl.xtb +++ b/components/policy/resources/policy_templates_nl.xtb
@@ -5417,6 +5417,9 @@ <translation id="8834641112681661892">Als je het beleid instelt, wordt de maximumvertraging in milliseconden gespecificeerd tussen het ontvangen van een ongeldigverklaring van een beleid en het ophalen van het nieuwe beleid uit de apparaatbeheerservice. Geldige waarden liggen tussen 1000 (1 seconde) en 300.000 (5 minuten). Waarden buiten dit bereik worden vast ingesteld op de respectieve grenswaarde. Als je het beleid niet instelt, gebruikt <ph name="PRODUCT_NAME" /> de standaardwaarde van 10 seconden.</translation> +<translation id="8835322836315560274">Met dit beleid bepaal je welke opdracht moet worden gebruikt om URL's te openen in een alternatieve browser. Je kunt dit beleid instellen op <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" />, <ph name="FIREFOX_VALUE_PLACEHOLDER" />, <ph name="SAFARI_VALUE_PLACEHOLDER" />, <ph name="OPERA_VALUE_PLACEHOLDER" />, <ph name="EDGE_VALUE_PLACEHOLDER" /> of een bestandspad. Als je dit beleid instelt op een bestandspad, wordt dat bestand als uitvoerbaar bestand gebruikt. <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" /> is alleen beschikbaar op <ph name="MS_WIN_NAME" />. <ph name="SAFARI_VALUE_PLACEHOLDER" /> en <ph name="EDGE_VALUE_PLACEHOLDER" /> zijn alleen beschikbaar op <ph name="MS_WIN_NAME" /> en <ph name="MAC_OS_NAME" />. + + Als je het beleid niet instelt, wordt er een platformspecifieke standaard-app gebruikt: <ph name="IE_PRODUCT_NAME" /> voor <ph name="MS_WIN_NAME" /> en <ph name="SAFARI_PRODUCT_NAME" /> voor <ph name="MAC_OS_NAME" />. In <ph name="LINUX_OS_NAME" /> werkt het starten van een alternatieve browser niet.</translation> <translation id="885147810817138322">Media-aanbevelingen tonen aan gebruikers</translation> <translation id="8852579753940989645">Code-integriteit van weergaveprogramma inschakelen</translation> <translation id="8854571659927427063">Als je het beleid inschakelt, worden de bookmarks van de vorige standaardbrowser geïmporteerd bij de eerste uitvoering. Als je het beleid uitschakelt of niet instelt, worden de bookmarks niet geïmporteerd bij de eerste uitvoering.
diff --git a/components/policy/resources/policy_templates_pt-BR.xtb b/components/policy/resources/policy_templates_pt-BR.xtb index 32ecafc73..33239b0 100644 --- a/components/policy/resources/policy_templates_pt-BR.xtb +++ b/components/policy/resources/policy_templates_pt-BR.xtb
@@ -5416,6 +5416,9 @@ <translation id="8834641112681661892">A definição da política especifica o atraso máximo em milissegundos entre o recebimento de uma invalidação de política e a busca de uma nova política pelo serviço de gerenciamento do dispositivo. O intervalo de valores válidos é de 1.000 (1 segundo) até 300.000 (5 minutos). Valores fora desse intervalo serão ajustados para o respectivo limite. Se a política não for definida, o valor padrão de 10 segundos será usado pelo <ph name="PRODUCT_NAME" />.</translation> +<translation id="8835322836315560274">Se a política for definida, ela controlará o comando usado para abrir URLs em um navegador alternativo. Ela pode ser definida como <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" />, <ph name="FIREFOX_VALUE_PLACEHOLDER" />, <ph name="SAFARI_VALUE_PLACEHOLDER" />, <ph name="OPERA_VALUE_PLACEHOLDER" />, <ph name="EDGE_VALUE_PLACEHOLDER" /> ou um caminho de arquivo. Quando esta política é definida como um caminho de arquivo, o arquivo em questão é usado como um executável. O <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" /> está disponível apenas no <ph name="MS_WIN_NAME" />. O <ph name="SAFARI_VALUE_PLACEHOLDER" /> e o <ph name="EDGE_VALUE_PLACEHOLDER" /> estão disponíveis apenas no <ph name="MS_WIN_NAME" /> e <ph name="MAC_OS_NAME" />. + + Se a política não for definida, o padrão usado seguirá a plataforma: <ph name="IE_PRODUCT_NAME" /> para <ph name="MS_WIN_NAME" /> ou <ph name="SAFARI_PRODUCT_NAME" /> para <ph name="MAC_OS_NAME" />. No <ph name="LINUX_OS_NAME" />, não será possível abrir um navegador alternativo.</translation> <translation id="885147810817138322">Exibir recomendações de mídia aos usuários</translation> <translation id="8852579753940989645">Ativar integridade do código renderizador</translation> <translation id="8854571659927427063">Se a política for definida como ativada, os favoritos serão importados do navegador padrão anterior durante a primeira execução. Se a política for definida como desativada ou não for definida, nenhum favorito será importado durante a primeira execução.
diff --git a/components/policy/resources/policy_templates_th.xtb b/components/policy/resources/policy_templates_th.xtb index 42c9bb0f..ea6b800 100644 --- a/components/policy/resources/policy_templates_th.xtb +++ b/components/policy/resources/policy_templates_th.xtb
@@ -5410,6 +5410,9 @@ <translation id="8834641112681661892">การตั้งค่านโยบายจะระบุการหน่วงเวลาสูงสุดเป็นมิลลิวินาทีสำหรับช่วงเวลาระหว่างการรับข้อมูลการลบล้างนโยบายและการดึงข้อมูลนโยบายใหม่จากบริการจัดการอุปกรณ์ ค่าที่ใช้ได้จะอยู่ในช่วง 1,000 (1 วินาที) ถึง 300,000 (5 นาที) ค่าที่ไม่ได้อยู่ในช่วงนี้จะถูกบีบให้อยู่ภายในขอบเขตที่เกี่ยวข้อง การไม่ตั้งค่านโยบายจะทำให้ <ph name="PRODUCT_NAME" /> ใช้ค่าเริ่มต้นเป็น 10 วินาที</translation> +<translation id="8835322836315560274">การตั้งค่านโยบายนี้จะควบคุมคำสั่งที่จะใช้เปิด URL ในเบราว์เซอร์สำรอง นโยบายนี้จะตั้งค่าเป็นอย่างใดอย่างหนึ่งได้ระหว่าง <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" />, <ph name="FIREFOX_VALUE_PLACEHOLDER" />, <ph name="SAFARI_VALUE_PLACEHOLDER" />, <ph name="OPERA_VALUE_PLACEHOLDER" />, <ph name="EDGE_VALUE_PLACEHOLDER" /> หรือเส้นทางของไฟล์ เมื่อตั้งค่านโยบายนี้เป็นเส้นทางของไฟล์ ระบบจะใช้ไฟล์นั้นเป็นไฟล์ที่ดำเนินการได้ <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" /> จะมีเฉพาะใน <ph name="MS_WIN_NAME" /> <ph name="SAFARI_VALUE_PLACEHOLDER" /> และ <ph name="EDGE_VALUE_PLACEHOLDER" /> จะมีเฉพาะใน <ph name="MS_WIN_NAME" /> และ <ph name="MAC_OS_NAME" /> + + การไม่ตั้งค่านโยบายนี้จะทำให้ระบบใช้ค่าเริ่มต้นเฉพาะแพลตฟอร์มนั้นๆ ได้แก่ <ph name="IE_PRODUCT_NAME" /> สำหรับ <ph name="MS_WIN_NAME" /> หรือ <ph name="SAFARI_PRODUCT_NAME" /> สำหรับ <ph name="MAC_OS_NAME" /> ส่วนใน <ph name="LINUX_OS_NAME" /> การเปิดเบราว์เซอร์สำรองจะทำไม่สำเร็จ</translation> <translation id="885147810817138322">แสดงคำแนะนำสื่อให้แก่ผู้ใช้</translation> <translation id="8852579753940989645">เปิดใช้ฟีเจอร์ความสมบูรณ์ของโค้ดในการแสดงผล</translation> <translation id="8854571659927427063">การตั้งค่านโยบายเป็น "เปิดใช้" จะนำเข้าบุ๊กมาร์กจากเบราว์เซอร์เริ่มต้นก่อนหน้าเมื่อเรียกใช้ครั้งแรก การตั้งค่านโยบายเป็น "ปิดใช้" หรือไม่ได้ตั้งค่า หมายความว่าจะไม่มีการนำเข้าบุ๊กมาร์กเมื่อเรียกใช้ครั้งแรก
diff --git a/components/policy/resources/policy_templates_uk.xtb b/components/policy/resources/policy_templates_uk.xtb index 36d785e..e2b936c 100644 --- a/components/policy/resources/policy_templates_uk.xtb +++ b/components/policy/resources/policy_templates_uk.xtb
@@ -5452,6 +5452,9 @@ <translation id="8834641112681661892">За допомогою цього правила можна вказати максимальну затримку в мілісекундах між анулюванням правила й отриманням нового правила від сервісу керування пристроєм. Дійсні значення – від 1000 (1 секунда) до 300 000 (5 хвилин). Значення поза цим діапазоном прив'язуються до відповідної межі. Якщо це правило не налаштовано, <ph name="PRODUCT_NAME" /> використовує значення за умовчанням – 10 секунд.</translation> +<translation id="8835322836315560274">Налаштування цього правила визначають, яка команда відкриває URL-адреси в альтернативному веб-переглядачі. У цьому правилі можна вказати <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" />, <ph name="FIREFOX_VALUE_PLACEHOLDER" />, <ph name="SAFARI_VALUE_PLACEHOLDER" />, <ph name="OPERA_VALUE_PLACEHOLDER" />, <ph name="EDGE_VALUE_PLACEHOLDER" /> або шлях файлу. Якщо для цього правила вказано шлях файлу, такий файл використовується як виконуваний. Веб-переглядач <ph name="INTERNET_EXPLORER_VALUE_PLACEHOLDER" /> доступний лише для <ph name="MS_WIN_NAME" />. Веб-переглядачі <ph name="SAFARI_VALUE_PLACEHOLDER" /> та <ph name="EDGE_VALUE_PLACEHOLDER" /> доступні лише для <ph name="MS_WIN_NAME" /> і <ph name="MAC_OS_NAME" />. + + Якщо це правило не налаштовано, застосовуються значення за умовчанням для конкретних платформ: <ph name="IE_PRODUCT_NAME" /> для <ph name="MS_WIN_NAME" /> або <ph name="SAFARI_PRODUCT_NAME" /> для <ph name="MAC_OS_NAME" />. У <ph name="LINUX_OS_NAME" /> альтернативний веб-переглядач не запускатиметься.</translation> <translation id="885147810817138322">Показувати користувачу рекомендації щодо медіаконтенту</translation> <translation id="8852579753940989645">Увімкнути цілісність коду засобу обробки відео</translation> <translation id="8854571659927427063">Якщо це правило активовано, закладки з попереднього веб-переглядача за умовчанням імпортуються під час першого запуску. Якщо це правило деактивовано або не налаштовано, закладки не імпортуються під час першого запуску.
diff --git a/components/strings/components_strings_bn.xtb b/components/strings/components_strings_bn.xtb index 87b7d1b0..cd4ae0a 100644 --- a/components/strings/components_strings_bn.xtb +++ b/components/strings/components_strings_bn.xtb
@@ -157,7 +157,7 @@ <translation id="1513706915089223971">ইতিহাসে এন্ট্রির তালিকা</translation> <translation id="1517433312004943670">ফোন নম্বর আবশ্যক</translation> <translation id="1519264250979466059">নির্মাণের তারিখ</translation> -<translation id="1521655867290435174">Google পত্রক</translation> +<translation id="1521655867290435174">Google Sheets</translation> <translation id="1527263332363067270">সংযোগের জন্য অপেক্ষা করা হচ্ছে...</translation> <translation id="1529521330346880926">10x15 (Envelope)</translation> <translation id="1529789484829130889">ট্রে ৮</translation>
diff --git a/components/strings/components_strings_en-GB.xtb b/components/strings/components_strings_en-GB.xtb index bc2760bf..c18c65a4 100644 --- a/components/strings/components_strings_en-GB.xtb +++ b/components/strings/components_strings_en-GB.xtb
@@ -401,7 +401,7 @@ <translation id="2495093607237746763">If ticked, Chromium will store a copy of your card on this device for faster form filling.</translation> <translation id="2498091847651709837">Scan new card</translation> <translation id="2501278716633472235">Go back</translation> -<translation id="2505268675989099013">Protect Account</translation> +<translation id="2505268675989099013">Protect account</translation> <translation id="2515629240566999685">Checking the signal in your area</translation> <translation id="2521385132275182522">Staple bottom right</translation> <translation id="2523886232349826891">Saved on this device only</translation> @@ -494,7 +494,7 @@ <translation id="2916038427272391327">Close other programmes</translation> <translation id="2922350208395188000">Server's certificate cannot be checked.</translation> <translation id="2925673989565098301">Delivery Method</translation> -<translation id="2928905813689894207">Billing Address</translation> +<translation id="2928905813689894207">Billing address</translation> <translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> more}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> more}}</translation> <translation id="2930577230479659665">Trim after each copy</translation> <translation id="2932085390869194046">Suggest password...</translation>
diff --git a/components/strings/components_strings_gu.xtb b/components/strings/components_strings_gu.xtb index 8bfb06c1..250f1b2 100644 --- a/components/strings/components_strings_gu.xtb +++ b/components/strings/components_strings_gu.xtb
@@ -157,7 +157,7 @@ <translation id="1513706915089223971">ઇતિહાસના એન્ટ્રીની સૂચિ</translation> <translation id="1517433312004943670">ફોન નંબર આવશ્યક</translation> <translation id="1519264250979466059">નિર્માણ તારીખ</translation> -<translation id="1521655867290435174">Google શીટ</translation> +<translation id="1521655867290435174">Google Sheets</translation> <translation id="1527263332363067270">કનેક્શનની રાહ જોઈ રહ્યાં છીએ...</translation> <translation id="1529521330346880926">10x15 (એન્વલપ)</translation> <translation id="1529789484829130889">ટ્રે 8</translation> @@ -931,7 +931,7 @@ <translation id="4675657451653251260">અતિથિ મોડમાં તમને Chrome પ્રોફાઇલની કોઈપણ માહિતી દેખાશે નહીં. તમારા Google એકાઉન્ટની માહિતી જેમકે પાસવર્ડ અને ચુકવણી પદ્ધતિઓ ઍક્સેસ કરવા માટે, તમે <ph name="LINK_BEGIN" />સાઇન ઇન<ph name="LINK_END" /> કરી શકો છો.</translation> <translation id="467662567472608290">આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેના સુરક્ષા પ્રમાણપત્રમાં ભૂલો છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઈ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.</translation> <translation id="4677585247300749148"><ph name="URL" /> ઍક્સેસિબિલિટી ઇવેન્ટનો જવાબ આપવા માગે છે</translation> -<translation id="467809019005607715">Google સ્લાઇડ</translation> +<translation id="467809019005607715">Google Slides</translation> <translation id="4680804919228900307">હમણાં જ કોઈ છેતરામણી સાઇટ પર તમે તમારો પાસવર્ડ દાખલ કર્યો. <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> અને હવે તમે આ પાસવર્ડનો જ્યાં ઉપયોગ કરતા હો તે અન્ય સાઇટ પરના તમે સાચવેલા પાસવર્ડ ચેક કરવાનો Chromium સુઝાવ આપે છે.</translation> <translation id="4690462567478992370">અમાન્ય પ્રમાણપત્રનો ઉપયોગ કરવાનું બંધ કરો</translation> <translation id="4691835149146451662">સ્થાપત્ય-A (એન્વલપ)</translation>
diff --git a/components/strings/components_strings_hi.xtb b/components/strings/components_strings_hi.xtb index d4428d9..a23ab0cb 100644 --- a/components/strings/components_strings_hi.xtb +++ b/components/strings/components_strings_hi.xtb
@@ -157,7 +157,7 @@ <translation id="1513706915089223971">इतिहास एंट्री की सूची</translation> <translation id="1517433312004943670">फ़ोन नंबर आवश्यक है</translation> <translation id="1519264250979466059">बिल्ड तारीख</translation> -<translation id="1521655867290435174">Google पत्रक</translation> +<translation id="1521655867290435174">Google Sheets</translation> <translation id="1527263332363067270">कनेक्शन का इंतज़ार हो रहा है</translation> <translation id="1529521330346880926">10x15 (एन्वेलप)</translation> <translation id="1529789484829130889">ट्रे 8</translation>
diff --git a/components/strings/components_strings_kn.xtb b/components/strings/components_strings_kn.xtb index ba683047..91eb6a2 100644 --- a/components/strings/components_strings_kn.xtb +++ b/components/strings/components_strings_kn.xtb
@@ -919,7 +919,7 @@ <translation id="4675657451653251260">ಅತಿಥಿ ಮೋಡ್ನಲ್ಲಿ ನಿಮಗೆ ಯಾವುದೇ Chrome ಪ್ರೊಫೈಲ್ನ ಮಾಹಿತಿ ಗೋಚರಿಸುವುದಿಲ್ಲ. ಪಾಸ್ವರ್ಡ್ಗಳು ಮತ್ತು ಪಾವತಿ ವಿಧಾನಗಳಂತಹ ನಿಮ್ಮ Google ಖಾತೆಯ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ನೀವು <ph name="LINK_BEGIN" />ಸೈನ್ ಇನ್<ph name="LINK_END" /> ಮಾಡಬಹುದು.</translation> <translation id="467662567472608290">ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರದಲ್ಲಿ ಸಾಕಷ್ಟು ದೋಷಗಳಿವೆ. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.</translation> <translation id="4677585247300749148">ಪ್ರವೇಶಿಸುವಿಕೆ ಈವೆಂಟ್ಗಳಿಗೆ <ph name="URL" /> ಪ್ರತಿಕ್ರಿಯಿಸಲು ಬಯಸುತ್ತದೆ</translation> -<translation id="467809019005607715">Google ಸ್ಲೈಡ್ಗಳು</translation> +<translation id="467809019005607715">Google Slides</translation> <translation id="4680804919228900307">ವಂಚನೆ ಮಾಡುವ ಸೈಟ್ನಲ್ಲಿ, ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ಈಗಷ್ಟೇ ನೀವು ನಮೂದಿಸಿದ್ದೀರಿ. <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> ಮತ್ತು ಈ ಪಾಸ್ವರ್ಡ್ ಬಳಸುವ ಇತರ ವೆಬ್ಸೈಟ್ಗಳಲ್ಲಿ ನಿಮ್ಮ ಉಳಿಸಿದ ಪಾಸ್ವರ್ಡ್ಗಳನ್ನು ಈಗಲೇ ಪರಿಶೀಲಿಸುವಂತೆ Chromium ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ.</translation> <translation id="4690462567478992370">ಅಮಾನ್ಯ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಬಳಸಿಕೊಂಡು ನಿಲ್ಲಿಸಿ</translation> <translation id="4691835149146451662">Architecture-A (Envelope)</translation>
diff --git a/components/strings/components_strings_ml.xtb b/components/strings/components_strings_ml.xtb index 2acfd67..77f66fb 100644 --- a/components/strings/components_strings_ml.xtb +++ b/components/strings/components_strings_ml.xtb
@@ -157,7 +157,7 @@ <translation id="1513706915089223971">ചരിത്ര എൻട്രികളുടെ ലിസ്റ്റ്</translation> <translation id="1517433312004943670">ഫോൺ നമ്പർ ആവശ്യമാണ്</translation> <translation id="1519264250979466059">ബിൽഡ് തീയതി</translation> -<translation id="1521655867290435174">Google ഷീറ്റ്</translation> +<translation id="1521655867290435174">Google Sheets</translation> <translation id="1527263332363067270">കണക്ഷനുവേണ്ടി കാക്കുന്നു…</translation> <translation id="1529521330346880926">10x15 (എൻവലപ്പ്)</translation> <translation id="1529789484829130889">ട്രേ 8</translation>
diff --git a/components/strings/components_strings_mr.xtb b/components/strings/components_strings_mr.xtb index 3ecc812..66b96f9 100644 --- a/components/strings/components_strings_mr.xtb +++ b/components/strings/components_strings_mr.xtb
@@ -930,7 +930,7 @@ <translation id="4675657451653251260">तुम्हाला अतिथी मोडमध्ये Chrome प्रोफाइलची कोणतीही माहिती दिसणार नाही. पासवर्ड आणि पेमेंट पद्धती यांसारखी तुमची Google खाते माहिती अॅक्सेस करण्यासाठी तुम्ही <ph name="LINK_BEGIN" />साइन इन<ph name="LINK_END" /> करू शकता.</translation> <translation id="467662567472608290">हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याच्या सुरक्षितता सर्टिफिकेटमध्ये एरर आहेत. हे कदाचित एका चुकीच्या कॉंफिगरेशनमुळे किंवा हल्लेखोराने तुमचे कनेक्शन इंटरसेप्ट केल्यामुळे झाले असू शकते.</translation> <translation id="4677585247300749148"><ph name="URL" /> ला ॲक्सेसिबिलिटी इव्हेंटना प्रतिसाद द्यायचा आहे</translation> -<translation id="467809019005607715">Google स्लाइड</translation> +<translation id="467809019005607715">Google Slides</translation> <translation id="4680804919228900307">तुम्ही आताच एका फसव्या साइटवर तुमचा पासवर्ड एंटर केला. तुम्ही हा पासवर्ड आता जेथे वापरता अशा <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> आणि इतर साइटसाठी तुमचे सेव्ह केलेले पासवर्ड तपासण्याची Chromium शिफारस करते.</translation> <translation id="4690462567478992370">चुकीचे सर्टिफिकेट वापरणे थांबवा</translation> <translation id="4691835149146451662">Architecture-A (Envelope)</translation>
diff --git a/components/strings/components_strings_nl.xtb b/components/strings/components_strings_nl.xtb index 51f62cf5..765d031 100644 --- a/components/strings/components_strings_nl.xtb +++ b/components/strings/components_strings_nl.xtb
@@ -519,7 +519,7 @@ <translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, druk op Tab en daarna op Enter om de suggestie te verwijderen.</translation> <translation id="3023071826883856138">You4 (envelop)</translation> <translation id="3024663005179499861">Onjuist beleidstype</translation> -<translation id="3037605927509011580">Helaas.</translation> +<translation id="3037605927509011580">Asjemenou!</translation> <translation id="3041612393474885105">Certificaatgegevens</translation> <translation id="3060227939791841287">C9 (envelop)</translation> <translation id="3061707000357573562">Patchservice</translation>
diff --git a/components/strings/components_strings_or.xtb b/components/strings/components_strings_or.xtb index 144df1de..d9c6566d 100644 --- a/components/strings/components_strings_or.xtb +++ b/components/strings/components_strings_or.xtb
@@ -157,7 +157,7 @@ <translation id="1513706915089223971">ଏଣ୍ଟ୍ରି କରାଯାଉଥିବା ଇତିହାସର ତାଲିକା</translation> <translation id="1517433312004943670">ଫୋନ୍ ନମ୍ବର ଆବଶ୍ୟକ ଅଟେ</translation> <translation id="1519264250979466059">ବିଲ୍ଡ ତାରିଖ</translation> -<translation id="1521655867290435174">Google ସିଟ୍ସ</translation> +<translation id="1521655867290435174">Google Sheets</translation> <translation id="1527263332363067270">ସଂଯୋଗ ପାଇଁ ଅପେକ୍ଷାରତ…</translation> <translation id="1529521330346880926">10x15 (ଏନଭଲପ୍)</translation> <translation id="1529789484829130889">ଟ୍ରେ 8</translation>
diff --git a/components/strings/components_strings_pa.xtb b/components/strings/components_strings_pa.xtb index 39416a4..2569e14 100644 --- a/components/strings/components_strings_pa.xtb +++ b/components/strings/components_strings_pa.xtb
@@ -918,7 +918,7 @@ <translation id="4675657451653251260">ਤੁਹਾਨੂੰ ਮਹਿਮਾਨ ਮੋਡ ਵਿੱਚ Chrome ਪ੍ਰੋਫਾਈਲ ਦੀ ਕੋਈ ਜਾਣਕਾਰੀ ਨਹੀਂ ਦਿਸੇਗੀ। ਤੁਸੀਂ ਪਾਸਵਰਡਾਂ ਅਤੇ ਭੁਗਤਾਨ ਵਿਧੀਆਂ ਵਰਗੀ ਆਪਣੀ Google ਖਾਤੇ ਦੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ <ph name="LINK_BEGIN" />ਸਾਈਨ-ਇਨ<ph name="LINK_END" /> ਕਰ ਸਕਦੇ ਹੋ।</translation> <translation id="467662567472608290">ਇਹ ਸਰਵਰ ਇਹ ਸਾਬਤ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦੇ ਸੁਰੱਖਿਆ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਵਿੱਚ ਗੜਬੜੀਆਂ ਹਨ। ਇਹ ਇੱਕ ਗਲਤ ਸੰਰੂਪਣ ਕਾਰਨ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਕੋਈ ਹਮਲਾਵਰ ਤੁਹਾਡੇ ਕਨੈਕਸ਼ਨ ਨੂੰ ਰਾਹ ਵਿੱਚ ਰੋਕ ਰਿਹਾ ਹੈ।</translation> <translation id="4677585247300749148"><ph name="URL" /> ਦੀ ਪਹੁੰਚਯੋਗਤਾ ਇਵੈਂਟਾਂ 'ਤੇ ਪ੍ਰਤਿਕਿਰਿਆ ਕਰਨ ਦੀ ਇੱਛਾ ਹੈ</translation> -<translation id="467809019005607715">Google ਸਲਾਈਡਾਂ</translation> +<translation id="467809019005607715">Google Slides</translation> <translation id="4680804919228900307">ਤੁਸੀਂ ਹੁਣੇ-ਹੁਣੇ ਕਿਸੇ ਭਰਮਪੂਰਨ ਸਾਈਟ 'ਤੇ ਆਪਣਾ ਪਾਸਵਰਡ ਦਾਖਲ ਕੀਤਾ ਹੈ। Chromium ਵੱਲੋਂ <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> ਅਤੇ ਉਹਨਾਂ ਹੋਰ ਸਾਈਟਾਂ 'ਤੇ ਆਪਣੇ ਰੱਖਿਅਤ ਪਾਸਵਰਡਾਂ ਨੂੰ ਜਾਂਚਣ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਜਿੱਥੇ ਹੁਣ ਤੁਸੀਂ ਇਹ ਪਾਸਵਰਡ ਵਰਤਦੇ ਹੋ।</translation> <translation id="4690462567478992370">ਅਵੈਧ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਵਰਤਣਾ ਬੰਦ ਕਰੋ</translation> <translation id="4691835149146451662">Architecture-A (ਲਿਫ਼ਾਫ਼ਾ)</translation>
diff --git a/components/strings/components_strings_ta.xtb b/components/strings/components_strings_ta.xtb index f628800..b379664 100644 --- a/components/strings/components_strings_ta.xtb +++ b/components/strings/components_strings_ta.xtb
@@ -157,7 +157,7 @@ <translation id="1513706915089223971">வரலாற்று உள்ளீடுகளின் பட்டியல்</translation> <translation id="1517433312004943670">ஃபோன் எண் தேவை</translation> <translation id="1519264250979466059">உருவாக்கிய தேதி</translation> -<translation id="1521655867290435174">Google விரிதாள்</translation> +<translation id="1521655867290435174">Google Sheets</translation> <translation id="1527263332363067270">இணைப்பிற்காகக் காத்திருக்கிறது…</translation> <translation id="1529521330346880926">10x15 (என்வலப்)</translation> <translation id="1529789484829130889">தட்டு 8</translation>
diff --git a/components/strings/components_strings_te.xtb b/components/strings/components_strings_te.xtb index ee08466..cf5b2708 100644 --- a/components/strings/components_strings_te.xtb +++ b/components/strings/components_strings_te.xtb
@@ -159,7 +159,7 @@ <translation id="1513706915089223971">చరిత్ర నమోదుల జాబితా</translation> <translation id="1517433312004943670">ఫోన్ నంబర్ అవసరం</translation> <translation id="1519264250979466059">బిల్డ్ తేదీ</translation> -<translation id="1521655867290435174">Google షీట్లు</translation> +<translation id="1521655867290435174">Google Sheets</translation> <translation id="1527263332363067270">కనెక్షన్ కోసం వేచి ఉన్నాము...</translation> <translation id="1529521330346880926">10x15 (ఎన్వలప్)</translation> <translation id="1529789484829130889">ట్రే 8</translation>
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker.cc b/components/url_formatter/spoof_checks/idn_spoof_checker.cc index d73192b1..ea6a306 100644 --- a/components/url_formatter/spoof_checks/idn_spoof_checker.cc +++ b/components/url_formatter/spoof_checks/idn_spoof_checker.cc
@@ -228,7 +228,7 @@ {"am"}}, {// Cyrillic "[[:Cyrl:]]", - "[аысԁеԍһіюјӏорԗԛѕԝхуъЬҽпгѵѡ]", + "[аысԁеԍһіюјӏорԗԛѕԝхуъьҽпгѵѡ]", // TLDs containing most of the Cyrillic domains. {"bg", "by", "kz", "pyc", "ru", "su", "ua", "uz"}}, {// Ethiopic (Ge'ez). Variants of these characters such as ሁ and ሡ could @@ -302,8 +302,19 @@ auto all_letters = std::make_unique<icu::UnicodeSet>( icu::UnicodeString::fromUTF8(data.script_regex), status); DCHECK(U_SUCCESS(status)); + + // Lookalike letter list must be all lower case letters. Domain name labels + // are canonicalized to lower case, so having upper case letters in this + // list will result in a non-match. + const icu::UnicodeString latin_lookalike_letters = + icu::UnicodeString::fromUTF8(data.latin_lookalike_letters); + icu::UnicodeString latin_lookalike_letters_lowercase = + latin_lookalike_letters; + latin_lookalike_letters_lowercase.toLower(); + DCHECK(latin_lookalike_letters == latin_lookalike_letters_lowercase); auto latin_lookalikes = std::make_unique<icu::UnicodeSet>( - icu::UnicodeString::fromUTF8(data.latin_lookalike_letters), status); + latin_lookalike_letters_lowercase, status); + DCHECK(U_SUCCESS(status)); auto script = std::make_unique<WholeScriptConfusable>( std::move(all_letters), std::move(latin_lookalikes), data.allowed_tlds); @@ -730,12 +741,14 @@ // An alternative approach is to include [0-9] and [_-] in script.all_letters // and checking if it contains all letters of |label|. However, this would not // work if a label has non-letters outside ASCII. + icu::UnicodeSet label_characters_belonging_to_script; icu::StringCharacterIterator it(label); for (it.setToStart(); it.hasNext();) { const UChar32 c = it.next32PostInc(); - if (script.all_letters->contains(c)) + if (script.all_letters->contains(c)) { label_characters_belonging_to_script.add(c); + } } return !label_characters_belonging_to_script.isEmpty() && script.latin_lookalike_letters->containsAll(
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc index b44c024..a47a33dc 100644 --- a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc +++ b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
@@ -443,6 +443,10 @@ // сю.com is Cyrillic with Latin lookalikes. {"xn--q1a0a.com", L"\x0441\x044e.com", kUnsafe}, + // Regression test for lowercase letters in whole script confusable + // lookalike character lists. + {"xn--80a8a6a.com", L"аьс.com", kUnsafe}, + // googlе.한국 where е is Cyrillic. This tests the generic case when one // label is not allowed but other labels in the domain name are still // decoded. Here, googlе is left in punycode but the TLD is decoded.
diff --git a/components/viz/service/display/overlay_processor_mac.cc b/components/viz/service/display/overlay_processor_mac.cc index 710cfbac..969907a 100644 --- a/components/viz/service/display/overlay_processor_mac.cc +++ b/components/viz/service/display/overlay_processor_mac.cc
@@ -58,7 +58,6 @@ // Clear to get ready to handle output surface as overlay. output_surface_already_handled_ = false; - previous_frame_full_bounding_rect_ = render_pass->output_rect; // Skip overlay processing if we have copy request. if (!render_pass->copy_requests.empty()) @@ -69,19 +68,30 @@ if (!enable_ca_overlay_) return; - // If ca overlay system didn't succeed, we fall back to surfaceless. - if (!ca_layer_overlay_processor_->ProcessForCALayerOverlays( + // First, try to use ProcessForCALayerOverlays to replace all DrawQuads in + // |render_pass->quad_list| with CALayerOverlays in |candidates|. + if (ca_layer_overlay_processor_->ProcessForCALayerOverlays( resource_provider, gfx::RectF(render_pass->output_rect), render_pass->quad_list, render_pass_filters, - render_pass_backdrop_filters, candidates)) - return; + render_pass_backdrop_filters, candidates)) { + // Mark the output surface as already handled (there is no output surface + // anymore). + output_surface_already_handled_ = true; - // CALayer overlays are all-or-nothing. If all quads were replaced with - // layers then mark the output surface as already handled. - output_surface_already_handled_ = true; - ca_overlay_damage_rect_ = render_pass->output_rect; - previous_frame_full_bounding_rect_ = ca_overlay_damage_rect_; - *damage_rect = gfx::Rect(); + // Set |last_overlay_damage_| to be everything, so that the next + // frame that we draw to the output surface will do a full re-draw. + ca_overlay_damage_rect_ = render_pass->output_rect; + + // Everything in |render_pass->quad_list| has been moved over to + // |candidates|. Ideally we would clear |render_pass->quad_list|, but some + // RenderPass overlays still point into that list. So instead, to avoid + // drawing the root RenderPass, we set |damage_rect| to be empty. + *damage_rect = gfx::Rect(); + } + + // TODO(https://crbug.com/1152849): If there is any HDR or protected content, + // use an underlay strategy to move those to |candidates| and replace them + // with transparent quads in |render_pass->quad_list|. } void OverlayProcessorMac::AdjustOutputSurfaceOverlay(
diff --git a/components/viz/service/display/overlay_processor_mac.h b/components/viz/service/display/overlay_processor_mac.h index dfcd8a5..e25740a 100644 --- a/components/viz/service/display/overlay_processor_mac.h +++ b/components/viz/service/display/overlay_processor_mac.h
@@ -67,8 +67,10 @@ private: const bool enable_ca_overlay_; + + // The damage that should be added the next frame for drawing to the output + // surface. gfx::Rect ca_overlay_damage_rect_; - gfx::Rect previous_frame_full_bounding_rect_; protected: // Protected for testing.
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 6fce0778..2b7a492 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -231,6 +231,7 @@ "//ui/base/clipboard", "//ui/base/cursor:cursor_base", "//ui/base/cursor/mojom:cursor_type", + "//ui/base/dragdrop/mojom", "//ui/base/idle", "//ui/base/ime/init", "//ui/display", @@ -263,6 +264,7 @@ "//third_party/blink/public/mojom:embedded_frame_sink_mojo_bindings", "//third_party/blink/public/mojom:mojom_broadcastchannel_bindings", "//third_party/leveldatabase", + "//ui/base/dragdrop/mojom:mojom_headers", ] sources = [
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm index ed70b7dd..27e64e0 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm +++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -71,7 +71,7 @@ } if (show_ids()) { - AddPropertyFilter(property_filters, "id"); + AddPropertyFilter(property_filters, "ChromeAXNodeId"); } } @@ -160,15 +160,9 @@ base::Value* dict) const { // Chromium tree special processing if (IsBrowserAccessibilityCocoa(node)) { + // Position (no size since it's exposed as standard AXSize attribute) BrowserAccessibilityCocoa* cocoa_node = static_cast<BrowserAccessibilityCocoa*>(node); - - // DOM element id - BrowserAccessibility* owner_node = [cocoa_node owner]; - dict->SetKey("id", - base::Value(base::NumberToString16(owner_node->GetId()))); - - // Position (no size since it's exposed as standard AXSize attribute) dict->SetPath(kPositionDictAttr, PopulatePosition(cocoa_node)); }
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index b30b7d4c..cf69c486 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -222,6 +222,7 @@ @"AXTextMarkerNodeDebugDescription"; // Other private attributes. +NSString* const NSAccessibilityIdentifierChromeAttribute = @"ChromeAXNodeId"; NSString* const NSAccessibilitySelectTextWithCriteriaParameterizedAttribute = @"AXSelectTextWithCriteria"; NSString* const NSAccessibilityIndexForChildUIElementParameterizedAttribute = @@ -803,6 +804,7 @@ {NSAccessibilityAutocompleteValueAttribute, @"autocompleteValue"}, {NSAccessibilityBlockQuoteLevelAttribute, @"blockQuoteLevel"}, {NSAccessibilityChildrenAttribute, @"children"}, + {NSAccessibilityIdentifierChromeAttribute, @"internalId"}, {NSAccessibilityColumnsAttribute, @"columns"}, {NSAccessibilityColumnHeaderUIElementsAttribute, @"columnHeaders"}, {NSAccessibilityColumnIndexRangeAttribute, @"columnIndexRange"}, @@ -3394,6 +3396,7 @@ NSMutableArray* ret = [NSMutableArray arrayWithObjects:NSAccessibilityBlockQuoteLevelAttribute, NSAccessibilityChildrenAttribute, + NSAccessibilityIdentifierChromeAttribute, NSAccessibilityDescriptionAttribute, NSAccessibilityDOMClassList, NSAccessibilityDOMIdentifierAttribute, @@ -3859,6 +3862,10 @@ return _owner->GetId(); } +- (NSString*)internalId { + return [@(_owner->GetId()) stringValue]; +} + - (BOOL)accessibilityNotifiesWhenDestroyed { TRACE_EVENT0("accessibility", "BrowserAccessibilityCocoa::accessibilityNotifiesWhenDestroyed");
diff --git a/content/browser/file_system/file_system_manager_impl.cc b/content/browser/file_system/file_system_manager_impl.cc index 15c0289..1e4c18e 100644 --- a/content/browser/file_system/file_system_manager_impl.cc +++ b/content/browser/file_system/file_system_manager_impl.cc
@@ -8,10 +8,8 @@ #include "base/bind.h" #include "base/check_op.h" -#include "base/feature_list.h" #include "base/files/file_path.h" #include "base/macros.h" -#include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/notreached.h" #include "base/sequenced_task_runner.h" @@ -26,7 +24,6 @@ #include "content/browser/file_system/browser_file_system_helper.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "content/public/common/content_features.h" #include "ipc/ipc_platform_file.h" #include "net/base/mime_util.h" #include "storage/browser/blob/blob_data_builder.h" @@ -39,7 +36,6 @@ #include "storage/common/file_system/file_system_info.h" #include "storage/common/file_system/file_system_types.h" #include "storage/common/file_system/file_system_util.h" -#include "third_party/blink/public/common/features.h" #include "url/gurl.h" #include "url/origin.h" @@ -217,20 +213,9 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); if (!security_policy_->CanAccessDataForOrigin(process_id_, origin)) { - const std::string& scheme = - origin.GetTupleOrPrecursorTupleIfOpaque().scheme(); - bool is_http_based_scheme = - (scheme == url::kHttpsScheme) || (scheme == url::kHttpsScheme); - UMA_HISTOGRAM_BOOLEAN( - "SiteIsolation.FileSystemApi.CanAccessDataForOriginFailure." - "IsHttpBasedScheme", - is_http_based_scheme); - - if (base::FeatureList::IsEnabled( - features::kSiteIsolationEnforcementForFileSystemApi)) { - receivers_.ReportBadMessage("FSMI_OPEN_INVALID_ORIGIN"); - return; - } + NOTREACHED(); + receivers_.ReportBadMessage("FSMI_OPEN_INVALID_ORIGIN"); + return; } if (file_system_type == blink::mojom::FileSystemType::kTemporary) {
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc index 8dd0326..38eabbde 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.cc +++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -135,13 +135,13 @@ // BLOCK_SHUTDOWN to support clearing session-only storage. base::TaskShutdownBehavior::BLOCK_SHUTDOWN}))), dispatcher_host_(this, std::move(io_task_runner)), + data_path_(data_path.empty() ? base::FilePath() + : data_path.Append(kIndexedDBDirectory)), force_keep_session_state_(false), quota_manager_proxy_(quota_manager_proxy), clock_(clock), filesystem_proxy_(storage::CreateFilesystemProxy()) { IDB_TRACE("init"); - if (!data_path.empty()) - data_path_ = data_path.Append(kIndexedDBDirectory); quota_manager_proxy->RegisterClient( base::MakeRefCounted<IndexedDBQuotaClient>(this), storage::QuotaClientType::kIndexedDatabase, @@ -434,18 +434,35 @@ } void IndexedDBContextImpl::SetForceKeepSessionState() { - force_keep_session_state_ = true; + idb_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + [](IndexedDBContextImpl* context) { + context->force_keep_session_state_ = true; + }, + // As |this| is destroyed on the IDBTaskRunner it is safe to post raw. + base::Unretained(this))); } void IndexedDBContextImpl::ApplyPolicyUpdates( std::vector<storage::mojom::IndexedDBStoragePolicyUpdatePtr> policy_updates) { - for (const auto& update : policy_updates) { - if (!update->purge_on_shutdown) - origins_to_purge_on_shutdown_.erase(update->origin); - else - origins_to_purge_on_shutdown_.insert(std::move(update->origin)); - } + idb_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + [](IndexedDBContextImpl* context, + std::vector<storage::mojom::IndexedDBStoragePolicyUpdatePtr> + policy_updates) { + for (const auto& update : policy_updates) { + if (!update->purge_on_shutdown) + context->origins_to_purge_on_shutdown_.erase(update->origin); + else + context->origins_to_purge_on_shutdown_.insert( + std::move(update->origin)); + } + }, + // As |this| is destroyed on the IDBTaskRunner it is safe to post raw. + base::Unretained(this), std::move(policy_updates))); } void IndexedDBContextImpl::BindTestInterface( @@ -802,13 +819,9 @@ indexeddb_factory_->ContextDestroyed(); } -void IndexedDBContextImpl::Shutdown() { - // Important: This function is NOT called on the IDB Task Runner. All variable - // access must be thread-safe. - if (is_incognito()) - return; +void IndexedDBContextImpl::ShutdownOnIDBSequence() { + DCHECK(idb_task_runner_->RunsTasksInCurrentSequence()); - // TODO(dmurph): Make this variable atomic. if (force_keep_session_state_) return; @@ -816,29 +829,32 @@ if (origins_to_purge_on_shutdown_.empty()) return; - IDBTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce( - [](scoped_refptr<IndexedDBContextImpl> context) { - std::vector<Origin> origins; - std::vector<base::FilePath> file_paths; - // This function only needs the factory, and not the context, but - // the context is used because passing that is thread-safe. - IndexedDBFactoryImpl* factory = context->GetIDBFactory(); - GetAllOriginsAndPaths(context->data_path_, &origins, &file_paths); - DCHECK_EQ(origins.size(), file_paths.size()); + std::vector<Origin> origins; + std::vector<base::FilePath> file_paths; + IndexedDBFactoryImpl* factory = GetIDBFactory(); + GetAllOriginsAndPaths(data_path_, &origins, &file_paths); + DCHECK_EQ(origins.size(), file_paths.size()); - auto file_path = file_paths.cbegin(); - auto origin = origins.cbegin(); - for (; origin != origins.cend(); ++origin, ++file_path) { - if (context->origins_to_purge_on_shutdown_.find(*origin) == - context->origins_to_purge_on_shutdown_.end()) - continue; - factory->ForceClose(*origin, false); - context->filesystem_proxy_->DeletePathRecursively(*file_path); - } - }, - base::WrapRefCounted(this))); + auto file_path = file_paths.cbegin(); + auto origin = origins.cbegin(); + for (; origin != origins.cend(); ++origin, ++file_path) { + if (origins_to_purge_on_shutdown_.find(*origin) == + origins_to_purge_on_shutdown_.end()) + continue; + factory->ForceClose(*origin, false); + filesystem_proxy_->DeletePathRecursively(*file_path); + } +} + +void IndexedDBContextImpl::Shutdown() { + // Important: This function is NOT called on the IDB Task Runner. All variable + // access must be thread-safe. + if (is_incognito()) + return; + + idb_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&IndexedDBContextImpl::ShutdownOnIDBSequence, + base::WrapRefCounted(this))); } base::FilePath IndexedDBContextImpl::GetBlobStorePath(
diff --git a/content/browser/indexed_db/indexed_db_context_impl.h b/content/browser/indexed_db/indexed_db_context_impl.h index 88a5f31..65b51285 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.h +++ b/content/browser/indexed_db/indexed_db_context_impl.h
@@ -178,16 +178,11 @@ // order. std::vector<base::FilePath> GetStoragePaths(const url::Origin& origin) const; - base::FilePath data_path() const { return data_path_; } + const base::FilePath& data_path() const { return data_path_; } bool IsInMemoryContext() const { return data_path_.empty(); } size_t GetConnectionCountSync(const url::Origin& origin); int GetOriginBlobFileCount(const url::Origin& origin); - // For unit tests allow to override the |data_path_|. - void set_data_path_for_testing(const base::FilePath& data_path) { - data_path_ = data_path; - } - bool is_incognito() const { return data_path_.empty(); } storage::mojom::BlobStorageContext* blob_storage_context() const { @@ -220,6 +215,8 @@ ~IndexedDBContextImpl() override; + void ShutdownOnIDBSequence(); + base::FilePath GetBlobStorePath(const url::Origin& origin) const; base::FilePath GetLevelDBPath(const url::Origin& origin) const; @@ -246,7 +243,7 @@ // If |data_path_| is empty then this is an incognito session and the backing // store will be held in-memory rather than on-disk. - base::FilePath data_path_; + const base::FilePath data_path_; // If true, nothing (not even session-only data) should be deleted on exit. bool force_keep_session_state_;
diff --git a/content/browser/indexed_db/indexed_db_external_object.h b/content/browser/indexed_db/indexed_db_external_object.h index 069c949..868c86092 100644 --- a/content/browser/indexed_db/indexed_db_external_object.h +++ b/content/browser/indexed_db/indexed_db_external_object.h
@@ -64,10 +64,11 @@ const base::Time& last_modified, const int64_t size); // These are for Native File System handles. - IndexedDBExternalObject( + explicit IndexedDBExternalObject( mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token_remote); - IndexedDBExternalObject(std::vector<uint8_t> native_file_system_token); + explicit IndexedDBExternalObject( + std::vector<uint8_t> native_file_system_token); IndexedDBExternalObject(const IndexedDBExternalObject& other); ~IndexedDBExternalObject();
diff --git a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc index 8bc64a8..fcf0249 100644 --- a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc +++ b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
@@ -67,10 +67,7 @@ void CreateTempDir() { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } void SetupTempDir() { - base::FilePath indexeddb_dir = - temp_dir_.GetPath().Append(IndexedDBContextImpl::kIndexedDBDirectory); - ASSERT_TRUE(base::CreateDirectory(indexeddb_dir)); - idb_context()->set_data_path_for_testing(indexeddb_dir); + ASSERT_TRUE(base::CreateDirectory(idb_context_->data_path())); } ~IndexedDBQuotaClientTest() override {
diff --git a/content/browser/media/media_interface_proxy.cc b/content/browser/media/media_interface_proxy.cc index 40e72bdd..ea236e8 100644 --- a/content/browser/media/media_interface_proxy.cc +++ b/content/browser/media/media_interface_proxy.cc
@@ -233,6 +233,18 @@ #if BUILDFLAG(ENABLE_LIBRARY_CDMS) && BUILDFLAG(IS_CHROMEOS_ASH) constexpr char kChromeOsCdmFileSystemId[] = "application_chromeos-cdm-factory-daemon"; + +// These are reported to UMA server. Do not renumber or reuse values. +enum class CrosCdmType { + kChromeCdm = 0, + kPlatformCdm = 1, + // Note: Only add new values immediately before this line. + kMaxValue = kPlatformCdm, +}; + +void ReportCdmTypeUMA(CrosCdmType cdm_type) { + UMA_HISTOGRAM_ENUMERATION("Media.EME.CrosCdmType", cdm_type); +} #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) && BUILDFLAG(IS_CHROMEOS_ASH) // The amount of time to allow the secondary Media Service instance to idle @@ -455,6 +467,7 @@ return; } } + ReportCdmTypeUMA(CrosCdmType::kChromeCdm); #endif // BUILDFLAG(IS_CHROMEOS_ASH) auto* factory = GetCdmFactory(key_system); #elif BUILDFLAG(ENABLE_CAST_RENDERER) @@ -577,6 +590,7 @@ mojo::PendingRemote<media::mojom::Decryptor> decryptor, const std::string& error_message) { if (receiver) { + ReportCdmTypeUMA(CrosCdmType::kPlatformCdm); // Success case, just pass it back through the callback. std::move(callback).Run(std::move(receiver), cdm_id, std::move(decryptor), error_message); @@ -592,6 +606,7 @@ mojo::NullRemote(), "Unable to find a CDM factory"); return; } + ReportCdmTypeUMA(CrosCdmType::kChromeCdm); factory->CreateCdm(key_system, cdm_config, std::move(callback)); } #endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc index 9c681c5..3d5bd23 100644 --- a/content/browser/media/media_web_contents_observer.cc +++ b/content/browser/media/media_web_contents_observer.cc
@@ -525,11 +525,14 @@ MediaPlayerId(render_frame_host, delegate_id), raw_device_id); } -mojo::Remote<media::mojom::MediaPlayer>& -MediaWebContentsObserver::GetMediaPlayerRemote(const MediaPlayerId& player_id) { - DCHECK(media_player_remotes_.contains(player_id)); - DCHECK(media_player_remotes_[player_id].is_bound()); - return media_player_remotes_.at(player_id); +media::mojom::MediaPlayer* MediaWebContentsObserver::GetMediaPlayerRemote( + const MediaPlayerId& player_id) { + if (media_player_remotes_.contains(player_id)) { + DCHECK(media_player_remotes_[player_id].is_bound()); + return media_player_remotes_.at(player_id).get(); + } + + return nullptr; } void MediaWebContentsObserver::OnMediaPlayerHostDisconnected(
diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h index a1ee47e..c2c65e3 100644 --- a/content/browser/media/media_web_contents_observer.h +++ b/content/browser/media/media_web_contents_observer.h
@@ -110,9 +110,11 @@ int delegate_id, const std::string& raw_device_id); - // Return an already bound mojo Remote for the MediaPlayer mojo interface. It - // is an error to call this method if no MediaPlayer with |player_id| exists. - mojo::Remote<media::mojom::MediaPlayer>& GetMediaPlayerRemote( + // Return an already bound mojo Remote for the MediaPlayer mojo interface. + // Return null if no player with |player_id| exists. + // TODO(https://crbug.com/1161551): Revert to returning a reference and make + // it an error to call this method if no MediaPlayer with |player_id| exists. + media::mojom::MediaPlayer* GetMediaPlayerRemote( const MediaPlayerId& player_id); // Creates a new MediaPlayerObserverHostImpl associated to |player_id| if
diff --git a/content/browser/media/session/media_session_controller.cc b/content/browser/media/session/media_session_controller.cc index 90b5962..a92a949 100644 --- a/content/browser/media/session/media_session_controller.cc +++ b/content/browser/media/session/media_session_controller.cc
@@ -50,34 +50,62 @@ void MediaSessionController::OnSuspend(int player_id) { DCHECK_EQ(player_id_, player_id); + + media::mojom::MediaPlayer* remote = + web_contents_->media_web_contents_observer()->GetMediaPlayerRemote(id_); + if (!remote) { + // TODO(https://crbug.com/1161551): Remove this when lifetime bug is fixed. + NOTREACHED() << "Controller should not outlive remote MediaPlayer"; + return; + } + // TODO(crbug.com/953645): Set triggered_by_user to true ONLY if that action // was actually triggered by user as this will activate the frame. - web_contents_->media_web_contents_observer() - ->GetMediaPlayerRemote(id_) - ->RequestPause(/*triggered_by_user=*/true); + remote->RequestPause(/*triggered_by_user=*/true); } void MediaSessionController::OnResume(int player_id) { DCHECK_EQ(player_id_, player_id); - web_contents_->media_web_contents_observer() - ->GetMediaPlayerRemote(id_) - ->RequestPlay(); + + media::mojom::MediaPlayer* remote = + web_contents_->media_web_contents_observer()->GetMediaPlayerRemote(id_); + if (!remote) { + // TODO(https://crbug.com/1161551): Remove this when lifetime bug is fixed. + NOTREACHED() << "Controller should not outlive remote MediaPlayer"; + return; + } + + remote->RequestPlay(); } void MediaSessionController::OnSeekForward(int player_id, base::TimeDelta seek_time) { DCHECK_EQ(player_id_, player_id); - web_contents_->media_web_contents_observer() - ->GetMediaPlayerRemote(id_) - ->RequestSeekForward(seek_time); + + media::mojom::MediaPlayer* remote = + web_contents_->media_web_contents_observer()->GetMediaPlayerRemote(id_); + if (!remote) { + // TODO(https://crbug.com/1161551): Remove this when lifetime bug is fixed. + NOTREACHED() << "Controller should not outlive remote MediaPlayer"; + return; + } + + remote->RequestSeekForward(seek_time); } void MediaSessionController::OnSeekBackward(int player_id, base::TimeDelta seek_time) { DCHECK_EQ(player_id_, player_id); - web_contents_->media_web_contents_observer() - ->GetMediaPlayerRemote(id_) - ->RequestSeekBackward(seek_time); + + media::mojom::MediaPlayer* remote = + web_contents_->media_web_contents_observer()->GetMediaPlayerRemote(id_); + if (!remote) { + // TODO(https://crbug.com/1161551): Remove this when lifetime bug is fixed. + NOTREACHED() << "Controller should not outlive remote MediaPlayer"; + return; + } + + remote->RequestSeekBackward(seek_time); } void MediaSessionController::OnSetVolumeMultiplier(int player_id, @@ -91,17 +119,29 @@ void MediaSessionController::OnEnterPictureInPicture(int player_id) { DCHECK_EQ(player_id_, player_id); - web_contents_->media_web_contents_observer() - ->GetMediaPlayerRemote(id_) - ->RequestEnterPictureInPicture(); + media::mojom::MediaPlayer* remote = + web_contents_->media_web_contents_observer()->GetMediaPlayerRemote(id_); + if (!remote) { + // TODO(https://crbug.com/1161551): Remove this when lifetime bug is fixed. + NOTREACHED() << "Controller should not outlive remote MediaPlayer"; + return; + } + + remote->RequestEnterPictureInPicture(); } void MediaSessionController::OnExitPictureInPicture(int player_id) { DCHECK_EQ(player_id_, player_id); - web_contents_->media_web_contents_observer() - ->GetMediaPlayerRemote(id_) - ->RequestExitPictureInPicture(); + media::mojom::MediaPlayer* remote = + web_contents_->media_web_contents_observer()->GetMediaPlayerRemote(id_); + if (!remote) { + // TODO(https://crbug.com/1161551): Remove this when lifetime bug is fixed. + NOTREACHED() << "Controller should not outlive remote MediaPlayer"; + return; + } + + remote->RequestExitPictureInPicture(); } void MediaSessionController::OnSetAudioSinkId(
diff --git a/content/browser/renderer_host/frame_tree.cc b/content/browser/renderer_host/frame_tree.cc index 0fb5c15..fd0c5c2 100644 --- a/content/browser/renderer_host/frame_tree.cc +++ b/content/browser/renderer_host/frame_tree.cc
@@ -395,11 +395,12 @@ scoped_refptr<RenderViewHostImpl> FrameTree::CreateRenderViewHost( SiteInstance* site_instance, int32_t main_frame_routing_id, - bool swapped_out) { + bool swapped_out, + bool renderer_initiated_creation) { RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(RenderViewHostFactory::Create( site_instance, render_view_delegate_, render_widget_delegate_, - main_frame_routing_id, swapped_out)); + main_frame_routing_id, swapped_out, renderer_initiated_creation)); return base::WrapRefCounted(rvh); }
diff --git a/content/browser/renderer_host/frame_tree.h b/content/browser/renderer_host/frame_tree.h index bbf18355..da1aa9c 100644 --- a/content/browser/renderer_host/frame_tree.h +++ b/content/browser/renderer_host/frame_tree.h
@@ -216,7 +216,8 @@ scoped_refptr<RenderViewHostImpl> CreateRenderViewHost( SiteInstance* site_instance, int32_t main_frame_routing_id, - bool swapped_out); + bool swapped_out, + bool renderer_initiated_creation); // Returns the existing RenderViewHost for a new RenderFrameHost. // There should always be such a RenderViewHost, because the main frame
diff --git a/content/browser/renderer_host/input/mouse_latency_browsertest.cc b/content/browser/renderer_host/input/mouse_latency_browsertest.cc index 577579a..23d7f29 100644 --- a/content/browser/renderer_host/input/mouse_latency_browsertest.cc +++ b/content/browser/renderer_host/input/mouse_latency_browsertest.cc
@@ -85,6 +85,7 @@ agent_scheduling_group, routing_id, hidden, + /*renderer_initiated_creation=*/false, std::make_unique<FrameTokenMessageQueue>()) {} void OnMouseEventAck(
diff --git a/content/browser/renderer_host/mock_render_widget_host.cc b/content/browser/renderer_host/mock_render_widget_host.cc index f4d0e2e..3487f74 100644 --- a/content/browser/renderer_host/mock_render_widget_host.cc +++ b/content/browser/renderer_host/mock_render_widget_host.cc
@@ -80,6 +80,7 @@ agent_scheduling_group, routing_id, /*hidden=*/false, + /*renderer_initiated_creation=*/false, std::make_unique<FrameTokenMessageQueue>()), new_content_rendering_timeout_fired_(false), fling_scheduler_(std::make_unique<FlingScheduler>(this)) {
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 5a0c257..f8ebe33 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1115,7 +1115,8 @@ DCHECK_EQ(nullptr, GetLocalRenderWidgetHost()); owned_render_widget_host_ = RenderWidgetHostFactory::Create( frame_tree_->render_widget_delegate(), agent_scheduling_group_, - widget_routing_id, /*hidden=*/true); + widget_routing_id, /*hidden=*/true, + /*renderer_initiated_creation=*/false); #if defined(OS_ANDROID) owned_render_widget_host_->SetForceEnableZoom( delegate_->GetOrCreateWebPreferences().force_enable_zoom); @@ -2431,6 +2432,7 @@ CHECK(!delegate_->IsBeingDestroyed()); bool was_created = render_frame_created_; + DCHECK(!was_created); render_frame_created_ = true; // Clear all the user data associated with this RenderFrameHost when its @@ -2443,26 +2445,25 @@ // Clearing of user data should be called before RenderFrameCreated to ensure: // - a) new new state set in RenderFrameCreated doesn't get deleted. // - b) the old state is not leaked to a new RenderFrameHost. - if (!was_created && was_render_frame_ever_created_) + if (was_render_frame_ever_created_) document_associated_data_.ClearAllUserData(); - was_render_frame_ever_created_ = true; - // If the current status is different than the new status, the delegate - // needs to be notified. - if (!was_created) { - SetUpMojoIfNeeded(); - delegate_->RenderFrameCreated(this); - } - // TODO(http://crbug.com/1014212): Change to DCHECK. - CHECK(frame_); - + // Initialize the RenderWidgetHost which marks it and the RenderViewHost as + // live before calling to the `delegate_`. if (GetLocalRenderWidgetHost()) { GetLocalRenderWidgetHost()->input_router()->SetFrameTreeNodeId( frame_tree_node_->frame_tree_node_id()); - GetLocalRenderWidgetHost()->InitForFrame(); + GetLocalRenderWidgetHost()->RendererWidgetCreated( + /*for_frame_widget=*/true); } + // Set up mojo connections to the renderer from the `frame_` connection before + // notifying the delegate. + SetUpMojoIfNeeded(); + + delegate_->RenderFrameCreated(this); + if (enabled_bindings_) GetFrameBindingsControl()->AllowBindings(enabled_bindings_); @@ -2489,11 +2490,18 @@ } void RenderFrameHostImpl::Init() { - ResumeBlockedRequestsForFrame(); - if (!waiting_for_init_) - return; + // This is only called on the main frame, for renderer-created windows. These + // windows wait for the renderer to signal that we can show them and begin + // navigations. + DCHECK(is_main_frame()); + DCHECK(waiting_for_init_); waiting_for_init_ = false; + + GetLocalRenderWidgetHost()->Init(); + + ResumeBlockedRequestsForFrame(); + if (pending_navigate_) { frame_tree_node()->navigator().OnBeginNavigation( frame_tree_node(), std::move(pending_navigate_->common_params), @@ -5342,6 +5350,11 @@ std::move(callback).Run(mojom::CreateNewWindowStatus::kSuccess, std::move(reply)); + + // The mojom reply callback with kSuccess causes the renderer to create the + // renderer-side objects. + main_frame->render_view_host()->DispatchRenderViewCreated(); + main_frame->RenderFrameCreated(); } void RenderFrameHostImpl::CreatePortal( @@ -5430,6 +5443,9 @@ agent_scheduling_group_, widget_route_id, std::move(blink_popup_widget_host), std::move(blink_widget_host), std::move(blink_widget)); + // The renderer-owned widget was created before sending the IPC received here. + widget->RendererWidgetCreated(/*for_frame_widget=*/false); + if (create_new_popup_widget_callback_) create_new_popup_widget_callback_.Run(widget); }
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index d64d426..7a8caa6 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -494,8 +494,8 @@ void RenderFrameCreated(); void RenderFrameDeleted(); - // Called for renderer-created windows to resume requests from this frame, - // after they are blocked in RenderWidgetHelper::CreateNewWindow. + // Signals that the renderer has requested for this main-frame's window to be + // shown, at which point we can service navigation requests. void Init(); // This needs to be called to make sure that the parent-child relationship @@ -2900,9 +2900,10 @@ mojo::AssociatedReceiver<blink::mojom::LocalMainFrameHost> local_main_frame_host_receiver_{this}; - // If this is true then this object was created in response to a renderer - // initiated request. Init() will be called, and until then navigation - // requests should be queued. + // If this is true then this main-frame object was created in response to a + // renderer initiated request. Init() will be called when the renderer wants + // the frame to become visible and to perform navigation requests. Until then + // navigation requests should be queued. bool waiting_for_init_; // If true then this frame's document has a focused element which is editable.
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc index 7abf0e5..4af1f8e 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -2339,6 +2339,9 @@ DCHECK_EQ(frame_tree_node_->parent()->GetSiteInstance(), site_instance); // The RenderViewHost must already exist for the parent's SiteInstance. DCHECK(render_view_host); + // Only main frames can be marked as renderer-initiated, as it refers to + // a renderer-created window. + DCHECK(!renderer_initiated_creation); break; case CreateFrameCase::kInitRoot: DCHECK(frame_tree_node_->IsMainFrame()); @@ -2353,12 +2356,16 @@ // // A speculative frame should be replacing an existing frame. DCHECK(render_frame_host_); + // Only the initial main frame can be marked as renderer-initiated, as it + // refers to a renderer-created window. A speculative frame is always + // created later by the browser. + DCHECK(!renderer_initiated_creation); break; } if (!render_view_host) { - render_view_host = - frame_tree->CreateRenderViewHost(site_instance, frame_routing_id, - /*swapped_out=*/false); + render_view_host = frame_tree->CreateRenderViewHost( + site_instance, frame_routing_id, + /*swapped_out=*/false, renderer_initiated_creation); } CHECK(render_view_host); // Lifecycle state of newly created RenderFrameHostImpl. @@ -2469,6 +2476,10 @@ // If we are reusing the RenderViewHost and it doesn't already have a // RenderWidgetHostView, we need to create one if this is the main frame. if (!render_view_host->GetWidget()->GetView()) { + // TODO(crbug.com/1161585): The RenderWidgetHostView should be created + // *before* we create the renderer-side objects through InitRenderView(). + // Then we should remove the null-check for the RenderWidgetHostView in + // RenderWidgetHostImpl::RendererWidgetCreated(). delegate_->CreateRenderWidgetHostViewForRenderManager(render_view_host); // If we are recovering a crashed frame in the same SiteInstance and we // are not skipping early commit then we will create a proxy and that will @@ -2530,7 +2541,7 @@ // exists for |instance|, as it creates the page level structure in Blink. render_view_host = frame_tree_node_->frame_tree()->CreateRenderViewHost( instance, /*frame_routing_id=*/MSG_ROUTING_NONE, - /*swapped_out=*/true); + /*swapped_out=*/true, /*renderer_initiated_creation=*/false); } proxy = CreateRenderFrameProxyHost(instance, std::move(render_view_host)); }
diff --git a/content/browser/renderer_host/render_view_host_delegate_view.h b/content/browser/renderer_host/render_view_host_delegate_view.h index c26f230..e633ce9 100644 --- a/content/browser/renderer_host/render_view_host_delegate_view.h +++ b/content/browser/renderer_host/render_view_host_delegate_view.h
@@ -15,6 +15,7 @@ #include "third_party/blink/public/mojom/choosers/popup_menu.mojom.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" #include "third_party/blink/public/mojom/page/drag.mojom-forward.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" namespace blink { class WebGestureEvent; @@ -62,7 +63,7 @@ // The page wants to update the mouse cursor during a drag & drop operation. // |operation| describes the current operation (none, move, copy, link.) - virtual void UpdateDragCursor(blink::DragOperation operation) {} + virtual void UpdateDragCursor(ui::mojom::DragOperation operation) {} // Notification that view for this delegate got the focus. virtual void GotFocus(RenderWidgetHostImpl* render_widget_host) {}
diff --git a/content/browser/renderer_host/render_view_host_factory.cc b/content/browser/renderer_host/render_view_host_factory.cc index 6765235..08a7eb9 100644 --- a/content/browser/renderer_host/render_view_host_factory.cc +++ b/content/browser/renderer_host/render_view_host_factory.cc
@@ -27,7 +27,8 @@ RenderViewHostDelegate* delegate, RenderWidgetHostDelegate* widget_delegate, int32_t main_frame_routing_id, - bool swapped_out) { + bool swapped_out, + bool renderer_initiated_creation) { int32_t routing_id = instance->GetProcess()->GetNextRoutingID(); int32_t widget_routing_id = instance->GetProcess()->GetNextRoutingID(); if (factory_) { @@ -42,7 +43,7 @@ widget_delegate, static_cast<SiteInstanceImpl*>(instance)->GetAgentSchedulingGroup(), widget_routing_id, - /*hidden=*/true), + /*hidden=*/true, renderer_initiated_creation), delegate, routing_id, main_frame_routing_id, swapped_out, true /* has_initialized_audio_host */); return view_host;
diff --git a/content/browser/renderer_host/render_view_host_factory.h b/content/browser/renderer_host/render_view_host_factory.h index 862f96e..84bb005 100644 --- a/content/browser/renderer_host/render_view_host_factory.h +++ b/content/browser/renderer_host/render_view_host_factory.h
@@ -28,7 +28,8 @@ RenderViewHostDelegate* delegate, RenderWidgetHostDelegate* widget_delegate, int32_t main_frame_routing_id, - bool swapped_out); + bool swapped_out, + bool renderer_initiated_creation); // Returns true if there is currently a globally-registered factory. static bool has_factory() {
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 300d69f..6f61782 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -424,8 +424,6 @@ const FrameTreeNode* const frame_tree_node = main_rfh ? main_rfh->frame_tree_node() : main_rfph->frame_tree_node(); - GetWidget()->set_renderer_initialized(true); - mojom::CreateViewParamsPtr params = mojom::CreateViewParams::New(); params->renderer_preferences = delegate_->GetRendererPrefs(); RenderViewHostImpl::GetPlatformSpecificPrefs(¶ms->renderer_preferences); @@ -505,11 +503,19 @@ // Let our delegate know that we created a RenderView. DispatchRenderViewCreated(); - // Since this method can create the main RenderFrame in the renderer process, - // set the proper state on its corresponding RenderFrameHost. + // If there is a main frame in this RenderViewHost, then the renderer-side + // main frame will be created along with the RenderView. The RenderFrameHost + // initializes its RenderWidgetHost as well, if it exists. Otherwise we must + // mark the non-frame-attached RenderWidgetHost as live in order for the + // RenderViewHost to be considered live. if (main_rfh) main_rfh->RenderFrameCreated(); + else + GetWidget()->SetRendererWidgetCreatedForInactiveRenderView(); + GetWidget()->delegate()->SendScreenRects(); + // This must be posted after the RenderViewHost is marked live, which is done + // above by RenderFrameCreated() or set_renderer_initialized(). PostRenderViewReady(); return true; @@ -518,6 +524,10 @@ void RenderViewHostImpl::SetMainFrameRoutingId(int routing_id) { main_frame_routing_id_ = routing_id; GetWidget()->UpdatePriority(); + // TODO(crbug.com/419087): If a local main frame is no longer attached to this + // RenderView then the RenderWidgetHostImpl owned by this class should be + // informed that its renderer widget is no longer created. The RenderViewHost + // will need to track its own live-ness then. } void RenderViewHostImpl::EnterBackForwardCache() { @@ -757,10 +767,6 @@ return delegate_->OnMessageReceived(this, msg); } -void RenderViewHostImpl::RenderWidgetDidInit() { - PostRenderViewReady(); -} - void RenderViewHostImpl::OnDidContentsPreferredSizeChange( const gfx::Size& new_size) { delegate_->UpdatePreferredSize(new_size);
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index 5a95c4b3..6505440 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -325,7 +325,6 @@ ~RenderViewHostImpl() override; // RenderWidgetHostOwnerDelegate overrides. - void RenderWidgetDidInit() override; void RenderWidgetDidFirstVisuallyNonEmptyPaint() override; void RenderWidgetGotFocus() override; void RenderWidgetLostFocus() override;
diff --git a/content/browser/renderer_host/render_widget_host_factory.cc b/content/browser/renderer_host/render_widget_host_factory.cc index 8b576dc..c79c654 100644 --- a/content/browser/renderer_host/render_widget_host_factory.cc +++ b/content/browser/renderer_host/render_widget_host_factory.cc
@@ -17,14 +17,15 @@ RenderWidgetHostDelegate* delegate, AgentSchedulingGroupHost& agent_scheduling_group, int32_t routing_id, - bool hidden) { + bool hidden, + bool renderer_initiated_creation) { if (factory_) { return factory_->CreateRenderWidgetHost(delegate, agent_scheduling_group, routing_id, hidden); } return RenderWidgetHostImpl::Create( delegate, agent_scheduling_group, routing_id, hidden, - std::make_unique<FrameTokenMessageQueue>()); + renderer_initiated_creation, std::make_unique<FrameTokenMessageQueue>()); } // static
diff --git a/content/browser/renderer_host/render_widget_host_factory.h b/content/browser/renderer_host/render_widget_host_factory.h index 770615b..e21cb8d 100644 --- a/content/browser/renderer_host/render_widget_host_factory.h +++ b/content/browser/renderer_host/render_widget_host_factory.h
@@ -29,7 +29,8 @@ RenderWidgetHostDelegate* delegate, AgentSchedulingGroupHost& agent_scheduling_group, int32_t routing_id, - bool hidden); + bool hidden, + bool renderer_initiated_creation); // Returns true if there is currently a globally-registered factory. static bool has_factory() { return !!factory_; }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 4ca1acd9..2db1e25 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -115,6 +115,7 @@ #include "third_party/blink/public/mojom/input/touch_event.mojom.h" #include "third_party/blink/public/mojom/page/drag.mojom.h" #include "ui/base/clipboard/clipboard_constants.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #include "ui/base/ui_base_switches.h" #include "ui/display/display_switches.h" #include "ui/display/screen.h" @@ -143,7 +144,6 @@ using base::TimeDelta; using base::TimeTicks; -using blink::DragOperation; using blink::DragOperationsMask; using blink::WebGestureEvent; using blink::WebInputEvent; @@ -333,10 +333,11 @@ AgentSchedulingGroupHost& agent_scheduling_host, int32_t routing_id, bool hidden, + bool renderer_initiated_creation, std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue) { return base::WrapUnique(new RenderWidgetHostImpl( /*self_owned=*/false, delegate, agent_scheduling_host, routing_id, hidden, - std::move(frame_token_message_queue))); + renderer_initiated_creation, std::move(frame_token_message_queue))); } // static @@ -348,6 +349,7 @@ std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue) { return new RenderWidgetHostImpl(/*self_owned=*/true, delegate, agent_scheduling_host, routing_id, hidden, + /*renderer_initiated_creation=*/true, std::move(frame_token_message_queue)); } @@ -357,8 +359,10 @@ AgentSchedulingGroupHost& agent_scheduling_group, int32_t routing_id, bool hidden, + bool renderer_initiated_creation, std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue) : self_owned_(self_owned), + waiting_for_init_(renderer_initiated_creation), delegate_(delegate), agent_scheduling_group_(agent_scheduling_group), routing_id_(routing_id), @@ -495,6 +499,20 @@ view_ = view->GetWeakPtr(); if (!create_frame_sink_callback_.is_null()) std::move(create_frame_sink_callback_).Run(view_->GetFrameSinkId()); + + // SendScreenRects() and SynchronizeVisualProperties() delay until a view + // is set, however we come here with a newly created `view` that is not + // initialized and ready to be used. + // The portal codepath comes here because it replaces the view while the + // renderer-side widget is already created. In that case the renderer will + // hear about geometry changes from the view being moved/resized as a result + // of the change. + // Speculative RenderViews also end up setting a `view` after creating the + // renderer-side widget, as per https://crbug.com/1161585. That path must + // be responsible for updating the renderer geometry itself, which it does + // because it will start hidden, and will send them when shown. + // TODO(crbug.com/1161585): Once RendererWidgetCreated() is always called + // with a non-null `view` then this comment can go away. :) } else { view_.reset(); } @@ -521,18 +539,26 @@ } void RenderWidgetHostImpl::SendScreenRects() { - if (!renderer_initialized_ || !blink_widget_ || waiting_for_screen_rects_ack_) + // Sending screen rects are deferred until we have a connection to a + // renderer-side Widget to send them to. Further, if we're waiting for the + // renderer to show (aka Init()) the widget then we defer sending updates + // until the renderer is ready. + if (!renderer_widget_created_ || waiting_for_init_) return; - + // TODO(danakj): The `renderer_widget_created_` flag is set to true for + // widgets owned by inactive RenderViewHosts, even though there is no widget + // created. In that case the `view_` will not be created. + if (!view_) + return; + // Throttle to one update at a time. + if (waiting_for_screen_rects_ack_) + return; if (is_hidden_) { // On GTK, this comes in for backgrounded tabs. Ignore, to match what // happens on Win & Mac, and when the view is shown it'll call this again. return; } - if (!view_) - return; - last_view_screen_rect_ = view_->GetViewBounds(); last_window_screen_rect_ = view_->GetBoundsInRootWindow(); view_->WillSendScreenRects(); @@ -564,35 +590,6 @@ GetProcess()->UpdateClientPriority(this); } -void RenderWidgetHostImpl::Init() { - DCHECK(GetProcess()->IsInitializedAndNotDead()); - - set_renderer_initialized(true); - - blink_widget_->GetWidgetInputHandler( - widget_input_handler_.BindNewPipeAndPassReceiver(), - input_router_->BindNewHost()); - // If this is for a frame be sure to connect that handler too. - if (blink_frame_widget_) { - widget_input_handler_->GetFrameWidgetInputHandler( - frame_widget_input_handler_.BindNewEndpointAndPassReceiver()); - blink_frame_widget_->BindInputTargetClient( - input_target_client_.BindNewPipeAndPassReceiver()); - } - - SendScreenRects(); - SynchronizeVisualProperties(); - - if (owner_delegate_) - owner_delegate_->RenderWidgetDidInit(); - - if (view_) - view_->OnRenderWidgetInit(); - - if (pending_show_closure_) - std::move(pending_show_closure_).Run(); -} - std::pair<mojo::PendingAssociatedRemote<blink::mojom::WidgetHost>, mojo::PendingAssociatedReceiver<blink::mojom::Widget>> RenderWidgetHostImpl::BindNewWidgetInterfaces() { @@ -655,27 +652,54 @@ blink_frame_widget_.Bind(std::move(frame_widget)); } -void RenderWidgetHostImpl::InitForFrame() { +void RenderWidgetHostImpl::RendererWidgetCreated(bool for_frame_widget) { DCHECK(GetProcess()->IsInitializedAndNotDead()); - set_renderer_initialized(true); - // In situations where RenderFrameHostImpl::CreateNewFrame calls this - // the |blink_widget_| will not be bound before this method is called. - // However RenderWidgetHostImpl::Init will be called once the widget - // is shown and these handlers will be bound there. - if (blink_widget_) { - blink_widget_->GetWidgetInputHandler( - widget_input_handler_.BindNewPipeAndPassReceiver(), - input_router_->BindNewHost()); + renderer_widget_created_ = true; + + blink_widget_->GetWidgetInputHandler( + widget_input_handler_.BindNewPipeAndPassReceiver(), + input_router_->BindNewHost()); + if (for_frame_widget) { widget_input_handler_->GetFrameWidgetInputHandler( frame_widget_input_handler_.BindNewEndpointAndPassReceiver()); blink_frame_widget_->BindInputTargetClient( input_target_client_.BindNewPipeAndPassReceiver()); } + // TODO(crbug.com/1161585): The `view_` can be null. :( Speculative + // RenderViews along with the main frame and its widget before the + // RenderWidgetHostView is created. Normally the RenderWidgetHostView should + // come first. Historically, unit tests also set things up in the wrong order + // and could get here with a null, but that is no longer the case (hopefully + // that remains true). if (view_) - view_->OnRenderWidgetInit(); + view_->OnRendererWidgetCreated(); + // These two methods avoid running until `renderer_widget_created_` is true, + // so we run them here after we set it. + SendScreenRects(); + SynchronizeVisualProperties(); +} + +void RenderWidgetHostImpl::SetRendererWidgetCreatedForInactiveRenderView() { + renderer_widget_created_ = true; +} + +void RenderWidgetHostImpl::Init() { + DCHECK(renderer_widget_created_); + DCHECK(waiting_for_init_); + + waiting_for_init_ = false; + + // These two methods avoid running while we are `waiting_for_init_`, so we + // run them here after we clear it. + SendScreenRects(); + SynchronizeVisualProperties(); + // Show/Hide state is not given to the renderer while we are + // `waiting_for_init_`, but Init() signals that the renderer is ready to + // receive them. This closure will inform the renderer that the widget is + // shown. if (pending_show_closure_) std::move(pending_show_closure_).Run(); } @@ -714,12 +738,17 @@ // Don't bother reporting hung state when we aren't active. StopInputEventAckTimeout(); - // If we have bound the blink widget interface, then inform it that we are - // being hidden so it can reduce its resource utilization. - if (blink_widget_) - blink_widget_->WasHidden(); - else + // Show/Hide state is not sent to the renderer when it has requested for us to + // wait until it requests them via Init(). + if (pending_show_closure_) { pending_show_closure_.Reset(); + } else { + // Widgets start out hidden, so we must have previously been shown to get + // here, and we'd have a `pending_show_closure_` if we are + // `waiting_for_init_`. + DCHECK(!waiting_for_init_); + blink_widget_->WasHidden(); + } // Tell the RenderProcessHost we were hidden. GetProcess()->UpdateClientPriority(this); @@ -745,14 +774,20 @@ // If we navigated in background, clear the displayed graphics of the // previous page before going visible. ForceFirstFrameAfterNavigationTimeout(); - - SendScreenRects(); RestartInputEventAckTimeoutIfNecessary(); + // This methods avoids running when the widget is hidden, so we run it here + // once it is no longer hidden. + SendScreenRects(); + // SendScreenRects() and SynchronizeVisualProperties() should happen + // together as one message, but we send them back-to-back for now so that + // all state gets to the renderer as close together as possible. + SynchronizeVisualProperties(); + auto show_request_timestamp = record_tab_switch_time_request ? base::TimeTicks::Now() : base::TimeTicks(); - if (blink_widget_) { + if (!waiting_for_init_) { blink_widget_->WasShown(show_request_timestamp, view_->is_evicted(), std::move(record_tab_switch_time_request)); } else { @@ -1059,22 +1094,26 @@ // inactive, so there is no focused node, or anything to scroll and display. if (owner_delegate_ && !owner_delegate_->IsMainFrameActive()) return false; - // This is similar to the above but when the renderer process has crashed, so - // more objects are gone than the RenderWidget. - if (!renderer_initialized_) + // Sending VisualProperties are deferred until we have a connection to a + // renderer-side Widget to send them to. Further, if we're waiting for the + // renderer to show (aka Init()) the widget then we defer sending updates + // until the renderer is ready. + if (!renderer_widget_created_ || waiting_for_init_) return false; - - // If we have not bound the blink widget interface put this request off. - // SynchronizeVisualProperties will get called after the channel is bound. - if (!blink_widget_) + // TODO(danakj): The `renderer_widget_created_` flag is set to true for + // widgets owned by inactive RenderViewHosts, even though there is no widget + // created. In that case the `view_` will not be created. + if (!view_) + return false; + // Throttle to one update at a time. + if (visual_properties_ack_pending_) return false; // Skip if the |delegate_| has already been detached because it's web contents // is being deleted, or if LocalSurfaceId is suppressed, as we are // first updating our internal state from a child's request, before // subsequently merging ids to send. - if (visual_properties_ack_pending_ || - !GetProcess()->IsInitializedAndNotDead() || !view_ || !view_->HasSize() || + if (!GetProcess()->IsInitializedAndNotDead() || !view_->HasSize() || !delegate_ || surface_id_allocation_suppressed_ || !view_->CanSynchronizeVisualProperties()) { return false; @@ -1842,9 +1881,10 @@ } } -void RenderWidgetHostImpl::DragSourceEndedAt(const gfx::PointF& client_point, - const gfx::PointF& screen_point, - blink::DragOperation operation) { +void RenderWidgetHostImpl::DragSourceEndedAt( + const gfx::PointF& client_point, + const gfx::PointF& screen_point, + ui::mojom::DragOperation operation) { // TODO(https://crbug.com/1102769): Replace with a for_frame() check. if (blink_frame_widget_) { blink_frame_widget_->DragSourceEndedAt( @@ -1995,19 +2035,22 @@ focus_dir, is_anchor_first); } -void RenderWidgetHostImpl::OnUpdateDragCursor(DragOperation current_op) { +void RenderWidgetHostImpl::OnUpdateDragCursor( + ui::mojom::DragOperation current_op) { RenderViewHostDelegateView* view = delegate_->GetDelegateView(); if (view) view->UpdateDragCursor(current_op); } void RenderWidgetHostImpl::RendererExited() { - if (!renderer_initialized_) + if (!renderer_widget_created_) return; // Clearing this flag causes us to re-create the renderer when recovering // from a crashed renderer. - set_renderer_initialized(false); + renderer_widget_created_ = false; + // This flag is set when creating the renderer widget. + waiting_for_init_ = false; // After the renderer crashes, the view is destroyed and so the // RenderWidgetHost cannot track its visibility anymore. We assume such @@ -2231,7 +2274,6 @@ blink_popup_widget_host_receiver_.reset(); render_process_blocked_state_changed_subscription_ = {}; - pending_show_closure_.Reset(); GetProcess()->RemovePriorityClient(this); GetProcess()->RemoveObserver(this); g_routing_id_widget_map.Get().erase(
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 0fd5dd389f..3dd95dc 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -64,6 +64,7 @@ #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" #include "third_party/blink/public/mojom/page/record_content_to_visible_time_request.mojom-forward.h" #include "third_party/blink/public/mojom/page/widget.mojom.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" #include "ui/base/ime/text_input_mode.h" #include "ui/base/ime/text_input_type.h" #include "ui/base/ui_base_types.h" @@ -154,6 +155,7 @@ AgentSchedulingGroupHost& agent_scheduling_host, int32_t routing_id, bool hidden, + bool renderer_initiated_creation, std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue); // See the constructor for documentations. @@ -264,7 +266,7 @@ int key_modifiers) override; void DragSourceEndedAt(const gfx::PointF& client_pt, const gfx::PointF& screen_pt, - blink::DragOperation operation) override; + ui::mojom::DragOperation operation) override; void DragSourceSystemDragEnded() override; void FilterDropData(DropData* drop_data) override; void SetCursor(const ui::Cursor& cursor) override; @@ -327,11 +329,6 @@ RenderWidgetHostDelegate* delegate() const { return delegate_; } - // Called when a renderer object already been created for this host, and we - // just need to be attached to it. Used for window.open, <select> dropdown - // menus, and other times when the renderer initiates creating an object. - void Init(); - // Allocate and bind new widget interfaces. std::pair<mojo::PendingAssociatedRemote<blink::mojom::WidgetHost>, mojo::PendingAssociatedReceiver<blink::mojom::Widget>> @@ -358,8 +355,28 @@ frame_widget_host, mojo::PendingAssociatedRemote<blink::mojom::FrameWidget> frame_widget); - // Initializes a RenderWidgetHost that is attached to a RenderFrameHost. - void InitForFrame(); + // The Bind*Interfaces() methods are called before creating the renderer-side + // Widget object, and RendererWidgetCreated() is called afterward. At that + // point the bound mojo interfaces are connected to the renderer Widget. The + // `for_frame_widget` informs if this widget should enable frame-specific + // behaviour and mojo connections. + void RendererWidgetCreated(bool for_frame_widget); + + // Renderer-created top-level widgets (either for a main frame or for a popup) + // wait to be shown until the renderer requests it. When that condition is + // satisfied we are notified through Init(). This will always happen after + // RendererWidgetCreated(). + void Init(); + + // OH NO DO NOT CALL THIS. + // This is called from RenderViewHost in order to mark itself as "live" even + // though there is actually no Widget created in the renderer, as there is no + // main frame attached to the RenderViewHost. + // TODO(crbug.com/419087): Remove this, and have RenderViewHost track its own + // live-ness. Then checks for a null `view_` in this class can just check + // `renderer_widget_created_` instead. And have RenderViewHost tell this class + // when the main frame goes away and thus the renderer widget along with it. + void SetRendererWidgetCreatedForInactiveRenderView(); // Returns true if the frame content needs be stored before being evicted. bool ShouldShowStaleContentOnEviction(); @@ -616,10 +633,6 @@ void RejectMouseLockOrUnlockIfNecessary( blink::mojom::PointerLockResult reason); - void set_renderer_initialized(bool renderer_initialized) { - renderer_initialized_ = renderer_initialized; - } - // Store values received in a child frame RenderWidgetHost from a parent // RenderWidget, in order to pass them to the renderer and continue their // propagation down the RenderWidget tree. @@ -671,7 +684,7 @@ size_t in_flight_event_count() const { return in_flight_event_count_; } - bool renderer_initialized() const { return renderer_initialized_; } + bool renderer_initialized() const { return renderer_widget_created_; } base::WeakPtr<RenderWidgetHostImpl> GetWeakPtr() { return weak_factory_.GetWeakPtr(); @@ -820,6 +833,7 @@ AgentSchedulingGroupHost& agent_scheduling_host, int32_t routing_id, bool hidden, + bool renderer_initiated_creation, std::unique_ptr<FrameTokenMessageQueue> frame_token_message_queue); // --------------------------------------------------------------------------- // The following method is overridden by RenderViewHost to send upwards to @@ -917,7 +931,7 @@ // IPC message handlers void OnClose(); void OnUpdateScreenRectsAck(); - void OnUpdateDragCursor(blink::DragOperation current_op); + void OnUpdateDragCursor(ui::mojom::DragOperation current_op); // blink::mojom::FrameWidgetHost overrides. void AnimateDoubleTapZoomInMainFrame(const gfx::Point& tap_point, @@ -1085,10 +1099,14 @@ // ShutdownAndDestroyWidget(true /* also_delete */); bool self_owned_; - // true if a renderer has once been valid. We use this flag to display a sad - // tab only when we lose our renderer and not if a paint occurs during - // initialization. - bool renderer_initialized_ = false; + // True while there is an established connection to a renderer-side Widget + // object. + bool renderer_widget_created_ = false; + // When the renderer widget is created, if created by the renderer, it may + // request to avoid showing the widget until requested. In that case, this + // value is set to true, and we defer WasShown() events until the request + // arrives which is signaled by Init(). + bool waiting_for_init_; // True if |Destroy()| has been called. bool destroyed_ = false;
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc b/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc index 3a3045d4..55f6a8f 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
@@ -235,7 +235,8 @@ widget_host_root_ = RenderWidgetHostImpl::Create( &delegate_, *agent_scheduling_group_host_root_, process_host_root_->GetNextRoutingID(), - /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>()); + /*hidden=*/false, /*renderer_initiated_creation=*/false, + std::make_unique<FrameTokenMessageQueue>()); mojo::AssociatedRemote<blink::mojom::WidgetHost> blink_widget_host; mojo::AssociatedRemote<blink::mojom::Widget> blink_widget; @@ -292,7 +293,8 @@ child.widget_host = RenderWidgetHostImpl::Create( &delegate_, *child.agent_scheduling_group_host, child.process_host->GetNextRoutingID(), - /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>()); + /*hidden=*/false, /*renderer_initiated_creation=*/false, + std::make_unique<FrameTokenMessageQueue>()); child.view = std::make_unique<TestRenderWidgetHostViewChildFrame>( child.widget_host.get()); child.frame_connector = std::make_unique<MockFrameConnector>(
diff --git a/content/browser/renderer_host/render_widget_host_owner_delegate.h b/content/browser/renderer_host/render_widget_host_owner_delegate.h index 7747d7d..81ebf0c9 100644 --- a/content/browser/renderer_host/render_widget_host_owner_delegate.h +++ b/content/browser/renderer_host/render_widget_host_owner_delegate.h
@@ -28,9 +28,6 @@ // and http://crbug.com/478281. class CONTENT_EXPORT RenderWidgetHostOwnerDelegate { public: - // The RenderWidgetHost has been initialized. - virtual void RenderWidgetDidInit() = 0; - // The RenderWidget finished the first visually non-empty paint. virtual void RenderWidgetDidFirstVisuallyNonEmptyPaint() = 0;
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 568a0b7..1aa67f46 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -52,6 +52,7 @@ #include "content/test/mock_widget_input_handler.h" #include "content/test/stub_render_widget_host_owner_delegate.h" #include "content/test/test_render_view_host.h" +#include "content/test/test_render_widget_host.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" @@ -561,8 +562,6 @@ host_->GetInitialVisualProperties(); EXPECT_CALL(mock_owner_delegate_, IsMainFrameActive()) .WillRepeatedly(Return(true)); - // Init() happens once the navigation completes. - host_->Init(); mojo::PendingRemote<cc::mojom::RenderFrameMetadataObserver> renderer_render_frame_metadata_observer_remote; @@ -581,6 +580,15 @@ host_->RegisterRenderFrameMetadataObserver( std::move(render_frame_metadata_observer_client_receiver), std::move(renderer_render_frame_metadata_observer_remote)); + + // The blink::mojom::Widget is already set during MockRenderWidgetHost + // construction. + host_->BindFrameWidgetInterfaces( + mojo::PendingAssociatedRemote<blink::mojom::FrameWidgetHost>() + .InitWithNewEndpointAndPassReceiver(), + TestRenderWidgetHost::CreateStubFrameWidgetRemote()); + + host_->RendererWidgetCreated(/*for_frame_widget=*/true); } void TearDown() override { @@ -616,15 +624,12 @@ widget_host.BindNewEndpointAndPassDedicatedReceiver(), widget_.GetNewRemote()); - mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host; - mojo::AssociatedRemote<blink::mojom::FrameWidget> frame_widget; - auto frame_widget_receiver = - frame_widget.BindNewEndpointAndPassDedicatedReceiver(); host_->BindFrameWidgetInterfaces( - frame_widget_host.BindNewEndpointAndPassDedicatedReceiver(), - frame_widget.Unbind()); + mojo::AssociatedRemote<blink::mojom::FrameWidgetHost>() + .BindNewEndpointAndPassDedicatedReceiver(), + TestRenderWidgetHost::CreateStubFrameWidgetRemote()); - host_->Init(); + host_->RendererWidgetCreated(/*for_frame_widget=*/true); } base::TimeTicks GetNextSimulatedEventTime() {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 5e2fa4b..85be5451 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1163,7 +1163,7 @@ sync_compositor_ = SynchronousCompositorHost::Create(this, host()->GetFrameSinkId()); view_.SetCopyOutputCallback(sync_compositor_->GetCopyViewCallback()); - if (render_widget_initialized_) + if (renderer_widget_created_) sync_compositor_->InitMojo(); } } @@ -2040,8 +2040,8 @@ return local_surface_id_allocator_.GetCurrentLocalSurfaceId(); } -void RenderWidgetHostViewAndroid::OnRenderWidgetInit() { - render_widget_initialized_ = true; +void RenderWidgetHostViewAndroid::OnRendererWidgetCreated() { + renderer_widget_created_ = true; if (sync_compositor_) sync_compositor_->InitMojo(); }
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index bd3a6ac..9eec9e9 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -164,7 +164,7 @@ TouchSelectionControllerClientManager* GetTouchSelectionControllerClientManager() override; const viz::LocalSurfaceId& GetLocalSurfaceId() const override; - void OnRenderWidgetInit() override; + void OnRendererWidgetCreated() override; void TakeFallbackContentFrom(RenderWidgetHostView* view) override; void OnSynchronizedDisplayPropertiesChanged() override; base::Optional<SkColor> GetBackgroundColor() override; @@ -551,7 +551,15 @@ // If true, then the next allocated surface should be embedded. bool navigation_while_hidden_ = false; - bool render_widget_initialized_ = false; + // False at creation time until the connection to the renderer process is + // established. If the connection is lost (ie. renderer process crash) then + // this object will be destroyed and recreated for the new process. + // NOTE: Due to unfortunate circumstances, the RenderWidgetHost and the + // RenderWidgetHostView will outlive the renderer-side object if a + // cross-process navigation occurs and the main frame moves out of the + // process. At that time this value would remain true though there is no + // Widget anymore associated with it. See https://crbug.com/419087. + bool renderer_widget_created_ = false; // Tracks whether we are in SynchronousCopyContents to avoid repeated calls // into DevTools capture logic.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index 87a6d20e..a516ed1 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -250,7 +250,7 @@ this, base::WrapUnique(delegated_frame_host_client_)); } - ~FakeRenderWidgetHostViewAura() override {} + ~FakeRenderWidgetHostViewAura() override = default; void UseFakeDispatcher() { aura::WindowTreeHost* host = window()->GetHost(); @@ -426,6 +426,7 @@ agent_scheduling_group, routing_id, /*hidden=*/false, + /*renderer_initiated_creation=*/false, std::make_unique<FrameTokenMessageQueue>()) { lastWheelOrTouchEventLatencyInfo = ui::LatencyInfo(); mojo::AssociatedRemote<blink::mojom::WidgetHost> blink_widget_host; @@ -505,12 +506,12 @@ FakeRenderWidgetHostViewAura* CreateView() { int32_t routing_id = process_host_->GetNextRoutingID(); - delegates_.push_back(base::WrapUnique(new MockRenderWidgetHostDelegate)); + delegates_.push_back(std::make_unique<MockRenderWidgetHostDelegate>()); auto* widget_host = MockRenderWidgetHostImpl::Create( delegates_.back().get(), *agent_scheduling_group_host_, routing_id); delegates_.back()->set_widget_host(widget_host); delegates_.back()->set_frame_tree(GetFrameTree()); - widget_host->Init(); + return new FakeRenderWidgetHostViewAura(widget_host); } @@ -550,6 +551,15 @@ delegates_.push_back(std::make_unique<MockRenderWidgetHostDelegate>()); parent_host_ = MockRenderWidgetHostImpl::Create( delegates_.back().get(), *agent_scheduling_group_host_, routing_id); + delegates_.back()->set_widget_host(parent_host_); + delegates_.back()->set_frame_tree(GetFrameTree()); + + parent_view_ = new RenderWidgetHostViewAura(parent_host_); + parent_view_->InitAsChild(nullptr); + aura::client::ParentWindowWithContext(parent_view_->GetNativeView(), + aura_test_helper_->GetContext(), + gfx::Rect()); + mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> parent_frame_widget_host; auto parent_frame_widget_host_receiver = @@ -560,26 +570,46 @@ parent_host_->BindFrameWidgetInterfaces( std::move(parent_frame_widget_host_receiver), parent_frame_widget.Unbind()); - delegates_.back()->set_widget_host(parent_host_); - delegates_.back()->set_frame_tree(GetFrameTree()); - parent_view_ = new RenderWidgetHostViewAura(parent_host_); - parent_view_->InitAsChild(nullptr); - aura::client::ParentWindowWithContext(parent_view_->GetNativeView(), - aura_test_helper_->GetContext(), - gfx::Rect()); + parent_host_->RendererWidgetCreated(/*for_frame_widget=*/true); + // The RenderWidgetHostImpl sets up additional connections over mojo to the + // renderer widget, which we need to complete before the test runs. + base::RunLoop().RunUntilIdle(); + view_ = CreateView(); widget_host_ = static_cast<MockRenderWidgetHostImpl*>(view_->host()); - mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host; - auto frame_widget_host_receiver = - frame_widget_host.BindNewEndpointAndPassDedicatedReceiver(); - mojo::AssociatedRemote<blink::mojom::FrameWidget> frame_widget; - auto frame_widget_receiver = - frame_widget.BindNewEndpointAndPassDedicatedReceiver(); - widget_host_->BindFrameWidgetInterfaces( - std::move(frame_widget_host_receiver), frame_widget.Unbind()); + // This `view_` is left uninitialzed, and the `widget_host_` does not have + // its renderer connections set up. These are done by the InitViewForPopup() + // or InitViewForFrame() helpers. + // Set the mouse_wheel_phase_handler_ timer timeout to 100ms. view_->event_handler()->set_mouse_wheel_wheel_phase_handler_timeout( base::TimeDelta::FromMilliseconds(100)); + } + + void InitViewForPopup(RenderWidgetHostViewAura* parent_view, + const gfx::Rect& bounds_in_screen) { + view_->SetWidgetType(WidgetType::kPopup); + view_->InitAsPopup(parent_view, bounds_in_screen); + + widget_host_->RendererWidgetCreated(/*for_frame_widget=*/false); + // The RenderWidgetHostImpl sets up additional connections over mojo to the + // renderer widget, which we need to complete before the test runs. + base::RunLoop().RunUntilIdle(); + } + + void InitViewForFrame(gfx::NativeView parent_native_view) { + view_->InitAsChild(parent_native_view); + + // The blink::mojom::Widget interfaces are bound during + // MockRenderWidgetHostImpl construction. + widget_host_->BindFrameWidgetInterfaces( + mojo::PendingAssociatedRemote<blink::mojom::FrameWidgetHost>() + .InitWithNewEndpointAndPassReceiver(), + TestRenderWidgetHost::CreateStubFrameWidgetRemote()); + + widget_host_->RendererWidgetCreated(/*for_frame_widget=*/true); + // The RenderWidgetHostImpl sets up additional connections over mojo to the + // renderer widget, which we need to complete before the test runs. base::RunLoop().RunUntilIdle(); } @@ -782,7 +812,7 @@ overscroll_delegate_.reset(new TestOverscrollDelegate(display_size)); view_->overscroll_controller()->set_delegate(overscroll_delegate_.get()); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->SetBounds(gfx::Rect(0, 0, 400, 200)); view_->Show(); @@ -1052,12 +1082,6 @@ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraShutdownTest); }; -// Checks that RenderWidgetHostViewAura can be destroyed before it is properly -// initialized. -TEST_F(RenderWidgetHostViewAuraTest, DestructionBeforeProperInitialization) { - // Terminate the test without initializing |view_|. -} - // Checks that a popup is positioned correctly relative to its parent using // screen coordinates. TEST_F(RenderWidgetHostViewAuraTest, PositionChildPopup) { @@ -1069,8 +1093,7 @@ // Verify that when the popup is initialized for the first time, it correctly // treats the input bounds as screen coordinates. - view_->SetWidgetType(WidgetType::kPopup); - view_->InitAsPopup(parent_view_, bounds_in_screen); + InitViewForPopup(parent_view_, bounds_in_screen); gfx::Rect final_bounds_in_screen = view_->GetViewBounds(); EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString()); @@ -1092,7 +1115,7 @@ // Checks that moving parent sends new screen bounds. TEST_F(RenderWidgetHostViewAuraTest, ParentMovementUpdatesScreenRect) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::Window* root = parent_view_->GetNativeView()->GetRootWindow(); @@ -1149,8 +1172,7 @@ parent_view_->Focus(); EXPECT_TRUE(parent_view_->HasFocus()); - view_->SetWidgetType(WidgetType::kPopup); - view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); + InitViewForPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); aura::Window* window = view_->GetNativeView(); ASSERT_TRUE(window != nullptr); @@ -1177,8 +1199,7 @@ parent_view_->Focus(); EXPECT_TRUE(parent_view_->HasFocus()); - view_->SetWidgetType(WidgetType::kPopup); - view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); + InitViewForPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); aura::Window* window = view_->GetNativeView(); ASSERT_TRUE(window != nullptr); @@ -1211,8 +1232,7 @@ parent_view_->GetNativeView()->GetRootWindow(), gfx::Point(300, 300)); generator.PressLeftButton(); - view_->SetWidgetType(WidgetType::kPopup); - view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); + InitViewForPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); ASSERT_TRUE(view_->NeedsMouseCapture()); aura::Window* window = view_->GetNativeView(); EXPECT_TRUE(window->HasCapture()); @@ -1229,8 +1249,7 @@ parent_view_->Focus(); EXPECT_TRUE(parent_view_->HasFocus()); - view_->SetWidgetType(WidgetType::kPopup); - view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); + InitViewForPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); aura::Window* popup_window = view_->GetNativeView(); TestWindowObserver observer(popup_window); @@ -1253,7 +1272,7 @@ // Checks that IME-composition-event state is maintained correctly. TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); ActivateViewForTextInputManager(view_, ui::TEXT_INPUT_TYPE_TEXT); @@ -1297,7 +1316,7 @@ // Checks that we reset has_composition_text_ to false upon when the focused // node is changed. TEST_F(RenderWidgetHostViewAuraTest, FocusedNodeChanged) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); ActivateViewForTextInputManager(view_, ui::TEXT_INPUT_TYPE_TEXT); @@ -1313,7 +1332,7 @@ // Checks that sequence of IME-composition-event and mouse-event when mouse // clicking to cancel the composition. TEST_F(RenderWidgetHostViewAuraTest, FinishCompositionByMouse) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); ActivateViewForTextInputManager(view_, ui::TEXT_INPUT_TYPE_TEXT); @@ -1355,7 +1374,7 @@ // Checks that WasOcculded/WasUnOccluded notifies RenderWidgetHostImpl. TEST_F(RenderWidgetHostViewAuraTest, WasOccluded) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); EXPECT_FALSE(widget_host_->is_hidden()); @@ -1392,7 +1411,7 @@ // Checks that touch-event state is maintained correctly. TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); // Start with no touch-event handler in the renderer. @@ -1503,7 +1522,7 @@ TEST_F(RenderWidgetHostViewAuraTest, KeyEventRoutingWithKeyboardLockActiveForOneKey) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); auto test_hook = std::make_unique<TestScopedKeyboardHook>(); @@ -1552,7 +1571,7 @@ TEST_F(RenderWidgetHostViewAuraTest, KeyEventRoutingWithKeyboardLockActiveForEscKey) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); auto test_hook = std::make_unique<TestScopedKeyboardHook>(); @@ -1588,7 +1607,7 @@ TEST_F(RenderWidgetHostViewAuraTest, KeyEventRoutingWithKeyboardLockActiveForAllKeys) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); auto test_hook = std::make_unique<TestScopedKeyboardHook>(); @@ -1647,8 +1666,7 @@ parent_view_->Focus(); ASSERT_TRUE(parent_view_->HasFocus()); - view_->SetWidgetType(WidgetType::kPopup); - view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); + InitViewForPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); ASSERT_NE(nullptr, view_->GetNativeView()); view_->Show(); @@ -1706,7 +1724,7 @@ } TEST_F(RenderWidgetHostViewAuraTest, TimerBasedWheelEventPhaseInfo) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -1795,7 +1813,7 @@ view_->event_handler()->set_mouse_wheel_wheel_phase_handler_timeout( TestTimeouts::action_max_timeout()); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -1861,7 +1879,7 @@ view_->event_handler()->set_mouse_wheel_wheel_phase_handler_timeout( TestTimeouts::action_max_timeout()); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -1924,7 +1942,7 @@ view_->event_handler()->set_mouse_wheel_wheel_phase_handler_timeout( TestTimeouts::action_max_timeout()); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -1978,7 +1996,7 @@ view_->event_handler()->set_mouse_wheel_wheel_phase_handler_timeout( TestTimeouts::action_max_timeout()); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -2026,7 +2044,7 @@ TEST_F(RenderWidgetHostViewAuraTest, TouchpadFlingStartResetsWheelPhaseState) { // Calling InitAsChild so it will create aura::Window. This will be queried by // fling controller to get the root viewport size when it receives GFS. - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->SetSize(gfx::Size(100, 100)); // Set the mouse_wheel_phase_handler_ timer timeout to a large value to make // sure that the timer is still running when the touchpad fling start is sent. @@ -2143,7 +2161,7 @@ view_->event_handler()->set_mouse_wheel_wheel_phase_handler_timeout( TestTimeouts::action_max_timeout()); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -2197,7 +2215,7 @@ view_->event_handler()->set_mouse_wheel_wheel_phase_handler_timeout( TestTimeouts::action_max_timeout()); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -2381,7 +2399,7 @@ // Checks that touch-event state is maintained correctly for multiple touch // points. TEST_F(RenderWidgetHostViewAuraTest, MultiTouchPointsStates) { - view_->InitAsChild(parent_view_->GetNativeView()); + InitViewForFrame(parent_view_->GetNativeView()); view_->Focus(); view_->Show(); view_->UseFakeDispatcher(); @@ -2495,7 +2513,7 @@ // Checks that touch-events are queued properly when there is a touch-event // handler on the page. TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); auto touch_event_consumers = blink::mojom::TouchEventConsumers::New( @@ -2535,7 +2553,7 @@ } TEST_F(RenderWidgetHostViewAuraTest, CompositorViewportPixelSizeWithScale) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), @@ -2620,7 +2638,7 @@ // blink::mojom::Widget::UpdateVisualProperties message is sent when ScreenInfo // changes and that message contains the latest ScreenInfo. TEST_F(RenderWidgetHostViewAuraTest, AutoResizeWithScale) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -2692,7 +2710,7 @@ // blink::mojom::Widget::UpdateVisualProperties message is sent when size // changes. TEST_F(RenderWidgetHostViewAuraTest, AutoResizeWithBrowserInitiatedResize) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -2758,7 +2776,7 @@ // This test verifies that in AutoResize mode a child-allocated // viz::LocalSurfaceId will be properly routed and stored in the parent. TEST_F(RenderWidgetHostViewAuraTest, ChildAllocationAcceptedInParent) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -2791,7 +2809,7 @@ // not send a blink::mojom::Widget::UpdateVisualProperties back to the child. TEST_F(RenderWidgetHostViewAuraTest, ChildAllocationAcceptedInParentWhileHidden) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -2828,7 +2846,7 @@ // This test verifies that when the child and parent both allocate their own // viz::LocalSurfaceId the resulting conflict is resolved. TEST_F(RenderWidgetHostViewAuraTest, ConflictingAllocationsResolve) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -2865,7 +2883,7 @@ // Checks that WidgetInputHandler::CursorVisibilityChange IPC messages are // dispatched to the renderer at the correct times. TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), @@ -2947,7 +2965,7 @@ } TEST_F(RenderWidgetHostViewAuraTest, UpdateCursorIfOverSelf) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), @@ -2996,7 +3014,8 @@ viz::LocalSurfaceId local_surface_id = parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId(); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); + ASSERT_EQ(1u, widget_host_->visual_properties().size()); // Set an empty size. aura::client::ParentWindowWithContext( @@ -3009,7 +3028,9 @@ // Update to the renderer. base::RunLoop().RunUntilIdle(); - ASSERT_EQ(1u, widget_host_->visual_properties().size()); + + // The renderer received the update with a new surface LocalSurfaceId. + ASSERT_EQ(2u, widget_host_->visual_properties().size()); { blink::VisualProperties visual_properties = widget_host_->visual_properties().at(0); @@ -3027,7 +3048,7 @@ viz::LocalSurfaceId local_surface_id = parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId(); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -3047,7 +3068,7 @@ TEST_F(RenderWidgetHostViewAuraTest, BackgroundColorOrder) { // If the default background color is not available, then use the theme // background color. - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->SetBackgroundColor(SK_ColorBLUE); ASSERT_TRUE(view_->GetBackgroundColor()); EXPECT_EQ(static_cast<unsigned>(SK_ColorBLUE), *view_->GetBackgroundColor()); @@ -3071,7 +3092,7 @@ constexpr gfx::Size size2(200, 200); aura::Window* root_window = parent_view_->GetNativeView()->GetRootWindow(); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), root_window, gfx::Rect(size1)); view_->Show(); @@ -3114,7 +3135,7 @@ // This test verifies that the primary SurfaceId is populated on resize. TEST_F(RenderWidgetHostViewAuraTest, SurfaceChanges) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -3131,7 +3152,7 @@ // This test verifies that the primary SurfaceId is updated on device scale // factor changes. TEST_F(RenderWidgetHostViewAuraTest, DeviceScaleFactorChanges) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -3178,7 +3199,7 @@ delegates_.back().get(), *agent_scheduling_group_host_, routing_id); delegates_.back()->set_widget_host(hosts[i]); delegates_.back()->set_frame_tree(GetFrameTree()); - hosts[i]->Init(); + views[i] = new FakeRenderWidgetHostViewAura(hosts[i]); // Prevent frames from being skipped due to resize, this test does not // run a UI compositor so the DelegatedFrameHost doesn't get the chance @@ -3188,6 +3209,15 @@ aura::client::ParentWindowWithContext( views[i]->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); + + // The blink::mojom::Widget interfaces are bound during + // MockRenderWidgetHostImpl construction. + hosts[i]->BindFrameWidgetInterfaces( + mojo::PendingAssociatedRemote<blink::mojom::FrameWidgetHost>() + .InitWithNewEndpointAndPassReceiver(), + TestRenderWidgetHost::CreateStubFrameWidgetRemote()); + hosts[i]->RendererWidgetCreated(/*for_frame_widget=*/true); + views[i]->SetSize(view_rect.size()); EXPECT_HAS_FRAME(views[i]); } @@ -3291,7 +3321,17 @@ delegates_.back().get(), *agent_scheduling_group_host_, routing_id); delegates_.back()->set_widget_host(hosts[i]); delegates_.back()->set_frame_tree(GetFrameTree()); - hosts[i]->Init(); + + hosts[i]->BindWidgetInterfaces( + mojo::PendingAssociatedRemote<blink::mojom::WidgetHost>() + .InitWithNewEndpointAndPassReceiver(), + TestRenderWidgetHost::CreateStubWidgetRemote()); + hosts[i]->BindFrameWidgetInterfaces( + mojo::PendingAssociatedRemote<blink::mojom::FrameWidgetHost>() + .InitWithNewEndpointAndPassReceiver(), + TestRenderWidgetHost::CreateStubFrameWidgetRemote()); + hosts[i]->RendererWidgetCreated(/*for_frame_widget=*/true); + views[i] = new FakeRenderWidgetHostViewAura(hosts[i]); views[i]->InitAsChild(nullptr); aura::client::ParentWindowWithContext( @@ -3354,7 +3394,7 @@ TEST_F(RenderWidgetHostViewAuraTest, VisibleViewportTest) { gfx::Rect view_rect(100, 100); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), @@ -3405,7 +3445,7 @@ const float kX = 30.58f; const float kY = 50.23f; - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(), @@ -4876,7 +4916,7 @@ TEST_F(RenderWidgetHostViewAuraTest, VirtualKeyboardFocusEnsureCaretInRect) { // TODO (oshima): Test that overscroll occurs. - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::Window* root_window = parent_view_->GetNativeView()->GetRootWindow(); aura::client::ParentWindowWithContext(view_->GetNativeView(), root_window, gfx::Rect()); @@ -4914,7 +4954,7 @@ // synchronously. TEST_F(RenderWidgetHostViewAuraTest, InvalidEventsHaveSyncHandlingDisabled) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); auto touch_event_consumers = blink::mojom::TouchEventConsumers::New( @@ -4952,7 +4992,7 @@ // Checks key event codes. TEST_F(RenderWidgetHostViewAuraTest, KeyEvent) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::US_A, @@ -4967,7 +5007,7 @@ } TEST_F(RenderWidgetHostViewAuraTest, KeyEventsHandled) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); ui::KeyEvent key_event1(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE); @@ -4985,7 +5025,7 @@ } TEST_F(RenderWidgetHostViewAuraTest, SetCanScrollForWebMouseWheelEvent) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -5059,7 +5099,7 @@ // Ensures that the mapping from ui::TouchEvent to blink::WebTouchEvent doesn't // lose track of the number of acks required. TEST_F(RenderWidgetHostViewAuraTest, CorrectNumberOfAcksAreDispatched) { - view_->InitAsChild(parent_view_->GetNativeView()); + InitViewForFrame(parent_view_->GetNativeView()); view_->Focus(); view_->Show(); view_->UseFakeDispatcher(); @@ -5191,7 +5231,7 @@ std::unique_ptr<aura::Window> parent(new aura::Window(&delegate)); parent->Init(ui::LAYER_TEXTURED); root->AddChild(parent.get()); - view_->InitAsChild(parent.get()); + InitViewForFrame(parent.get()); // Simulate mouse events, ensure they are forwarded to delegate. ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), @@ -5309,7 +5349,7 @@ static_cast<ui::WindowEventTarget*>(&event_target)); // Initialize the view. - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -5398,7 +5438,7 @@ ->set_max_time_between_phase_ended_and_momentum_phase_began( TestTimeouts::action_max_timeout()); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); sink_->ClearMessages(); @@ -5469,7 +5509,7 @@ TEST_F(RenderWidgetHostViewAuraTest, GestureTapFromStylusHasPointerType) { // TODO(flackr): This test fails as the gesture events are not generated // unless the `view_` is parented directly to the root window. - view_->InitAsChild(parent_view_->GetNativeView()->GetRootWindow()); + InitViewForFrame(parent_view_->GetNativeView()->GetRootWindow()); view_->Focus(); view_->Show(); @@ -5505,7 +5545,7 @@ TEST_F(RenderWidgetHostViewAuraTest, NewContentRenderingTimeout) { constexpr base::TimeDelta kTimeout = base::TimeDelta::FromMicroseconds(10); - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -5553,7 +5593,7 @@ // If a tab is evicted, allocate a new LocalSurfaceId next time it's shown. TEST_F(RenderWidgetHostViewAuraTest, AllocateLocalSurfaceIdOnEviction) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); // View has to not be empty in order for frame eviction to be invoked. view_->SetSize(gfx::Size(54, 32)); aura::client::ParentWindowWithContext( @@ -5572,7 +5612,7 @@ // If a tab was resized while it's hidden, drop the fallback so next time it's // visible we show blank. TEST_F(RenderWidgetHostViewAuraTest, DropFallbackIfResizedWhileHidden) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -5588,7 +5628,7 @@ // If a tab is hidden and shown without being resized in the meantime, the // fallback SurfaceId has to be preserved. TEST_F(RenderWidgetHostViewAuraTest, DontDropFallbackIfNotResizedWhileHidden) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -5610,7 +5650,7 @@ // background color from the previous view to the new view. TEST_F(RenderWidgetHostViewAuraTest, TakeFallbackContent) { // Initialize the first view. - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura::client::ParentWindowWithContext( view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); @@ -5882,7 +5922,7 @@ // This will initialize |window_| in RenderWidgetHostViewAura. It is needed // for RenderWidgetHostViewAura::GetInputMethod() to work. void InitializeAura() { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); view_->Show(); } @@ -6732,7 +6772,7 @@ // Compositor when DelegatedInkTrails should be drawn, and stops forwarding when // they no longer should be drawn. TEST_P(DelegatedInkPointTest, EventForwardedToCompositor) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura_test_helper_->GetTestScreen()->SetDeviceScaleFactor(1.0f); ui::Compositor* old_compositor = @@ -6874,7 +6914,7 @@ // Confirm that the interface is rebound if the receiver disconnects. TEST_P(DelegatedInkPointTest, MojoInterfaceReboundOnDisconnect) { - view_->InitAsChild(nullptr); + InitViewForFrame(nullptr); aura_test_helper_->GetTestScreen()->SetDeviceScaleFactor(1.0f); ui::Compositor* old_compositor =
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 1d5bd270..63c4db6 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -495,8 +495,9 @@ virtual void DidNavigate(); - // Called when the RenderWidgetHostImpl has be initialized. - virtual void OnRenderWidgetInit() {} + // Called when the RenderWidgetHostImpl establishes a connection to the + // renderer process Widget. + virtual void OnRendererWidgetCreated() {} virtual WebContentsAccessibility* GetWebContentsAccessibility();
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc index 058e36f..b572402 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
@@ -126,7 +126,8 @@ widget_host_ = RenderWidgetHostImpl::Create( &delegate_, *agent_scheduling_group_host_, routing_id, - /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>()); + /*hidden=*/false, /*renderer_initiated_creation=*/false, + std::make_unique<FrameTokenMessageQueue>()); mojo::AssociatedRemote<blink::mojom::WidgetHost> blink_widget_host; widget_host_->BindWidgetInterfaces( @@ -245,7 +246,7 @@ std::move(blink_frame_widget_host_receiver), blink_frame_widget.Unbind()); FakeFrameWidget fake_frame_widget(std::move(blink_frame_widget_receiver)); - widget_host_->Init(); + widget_host_->RendererWidgetCreated(/*for_frame_widget=*/true); base::RunLoop().RunUntilIdle(); @@ -301,7 +302,7 @@ static_cast<MockRenderProcessHost*>(widget_host_->GetProcess()); process->Init(); - widget_host_->Init(); + widget_host_->RendererWidgetCreated(/*for_frame_widget=*/true); constexpr gfx::Rect compositor_viewport_pixel_rect(100, 100); constexpr gfx::Rect screen_space_rect(compositor_viewport_pixel_rect);
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm index 6bf39a6..6164b5a 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
@@ -152,7 +152,8 @@ std::unique_ptr<RenderWidgetHostImpl> render_widget = RenderWidgetHostImpl::Create( &delegate, *agent_scheduling_group_host, routing_id, - /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>()); + /*hidden=*/false, /*renderer_initiated_creation=*/false, + std::make_unique<FrameTokenMessageQueue>()); ui::WindowResizeHelperMac::Get()->Init(base::ThreadTaskRunnerHandle::Get());
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm index dd2d0107..b9ce9ac 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -44,6 +44,7 @@ #include "content/test/mock_widget_input_handler.h" #include "content/test/stub_render_widget_host_owner_delegate.h" #include "content/test/test_render_view_host.h" +#include "content/test/test_render_widget_host.h" #include "gpu/ipc/common/gpu_messages.h" #include "gpu/ipc/service/image_transport_surface.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -361,17 +362,13 @@ agent_scheduling_group_host, routing_id, /*hidden=*/false, + /*renderer_initiated_creation=*/false, std::make_unique<FrameTokenMessageQueue>()) { - mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host; - auto frame_widget_host_receiver = - frame_widget_host.BindNewEndpointAndPassDedicatedReceiver(); - mojo::AssociatedRemote<blink::mojom::FrameWidget> frame_widget; - auto frame_widget_receiver = - frame_widget.BindNewEndpointAndPassDedicatedReceiver(); - BindFrameWidgetInterfaces(std::move(frame_widget_host_receiver), - frame_widget.Unbind()); + mojo::AssociatedRemote<blink::mojom::WidgetHost> widget_host; + BindWidgetInterfaces(widget_host.BindNewEndpointAndPassDedicatedReceiver(), + TestRenderWidgetHost::CreateStubWidgetRemote()); - set_renderer_initialized(true); + SetRendererWidgetCreatedForInactiveRenderView(); lastWheelEventLatencyInfo = ui::LatencyInfo(); ON_CALL(*this, Focus()) @@ -496,14 +493,11 @@ host_ = MockRenderWidgetHostImpl::Create(&delegate_, *agent_scheduling_group_host_, process_host_->GetNextRoutingID()); + // MockRenderWidgetHostImpl already bound the Widget mojom interfaces. mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host; - auto frame_widget_host_receiver = - frame_widget_host.BindNewEndpointAndPassDedicatedReceiver(); - mojo::AssociatedRemote<blink::mojom::FrameWidget> frame_widget; - auto frame_widget_receiver = - frame_widget.BindNewEndpointAndPassDedicatedReceiver(); - host_->BindFrameWidgetInterfaces(std::move(frame_widget_host_receiver), - frame_widget.Unbind()); + host_->BindFrameWidgetInterfaces( + frame_widget_host.BindNewEndpointAndPassDedicatedReceiver(), + TestRenderWidgetHost::CreateStubFrameWidgetRemote()); host_->set_owner_delegate(&mock_owner_delegate_); rwhv_mac_ = new RenderWidgetHostViewMac(host_.get()); rwhv_cocoa_.reset([rwhv_mac_->GetInProcessNSView() retain]);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index cffe0a7..09375e57 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -173,6 +173,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/accessibility/ax_tree_combiner.h" #include "ui/base/device_form_factor.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #if defined(USE_AURA) #include "ui/aura/window.h" #endif @@ -2172,7 +2173,6 @@ // before attaching. If the browser side is already initialized, the calls // below will just early return. inner_render_manager->InitRenderView(inner_render_view_host, nullptr); - inner_main_frame->Init(); if (!inner_render_manager->GetRenderWidgetHostView()) { inner_web_contents_impl->CreateRenderWidgetHostViewForRenderManager( inner_render_view_host); @@ -2769,15 +2769,6 @@ for (auto& i : g_created_callbacks.Get()) i.Run(this); - // If the WebContents creation was renderer-initiated, it means that the - // corresponding RenderView and main RenderFrame have already been created. - // Ensure observers are notified about this. - if (params.renderer_initiated_creation) { - GetRenderViewHost()->GetWidget()->set_renderer_initialized(true); - GetRenderViewHost()->DispatchRenderViewCreated(); - GetRenderManager()->current_frame_host()->RenderFrameCreated(); - } - // Create the renderer process in advance if requested. if (params.desired_renderer_state == CreateParams::kInitializeAndWarmupRendererProcess) { @@ -2792,14 +2783,6 @@ // happens after RenderFrameHostManager::Init. NotifySwappedFromRenderManager( nullptr, GetRenderManager()->current_frame_host(), true); - - // For WebContents that are never shown, do critical initialization here which - // would normally only happen when the WebContents is shown. - if (params.is_never_visible) { - // This has just been created so there can only be one frame. Thus it is - // safe to initialize the root. - GetMainFrame()->Init(); - } } void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) { @@ -3831,6 +3814,8 @@ widget_host_view->InitAsPopup(view, transformed_rect); RenderWidgetHostImpl* render_widget_host_impl = widget_host_view->host(); + // Renderer-owned popup widgets wait for the renderer to request for them + // to be shown. We signal that this condition is satisfied by calling Init(). render_widget_host_impl->Init(); } @@ -4684,7 +4669,7 @@ float client_y, float screen_x, float screen_y, - blink::DragOperation operation, + ui::mojom::DragOperation operation, RenderWidgetHost* source_rwh) { OPTIONAL_TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("content.verbose"), "WebContentsImpl::DragSourceEndedAt"); @@ -5060,11 +5045,11 @@ return; } - // Resume blocked requests for both the RenderViewHost and RenderFrameHost. - // TODO(brettw): It seems bogus to reach into here and initialize the host. + // Renderer-created main frames wait for the renderer to request for them to + // perform navigations and to be shown. We signal that this condition is + // satisfied by calling Init(). if (is_resume_pending_) { is_resume_pending_ = false; - GetRenderViewHost()->GetWidget()->Init(); GetMainFrame()->Init(); } }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 983fd6d4..67dcd117 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -65,7 +65,6 @@ #include "services/metrics/public/cpp/ukm_recorder.h" #include "services/network/public/mojom/fetch_api.mojom-forward.h" #include "third_party/blink/public/common/frame/transient_allow_fullscreen.h" -#include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" #include "third_party/blink/public/mojom/choosers/color_chooser.mojom.h" @@ -76,6 +75,7 @@ #include "third_party/blink/public/mojom/page/display_cutout.mojom.h" #include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h" #include "ui/accessibility/ax_mode.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" #include "ui/base/page_transition_types.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/size.h" @@ -239,7 +239,7 @@ float client_y, float screen_x, float screen_y, - blink::DragOperation operation, + ui::mojom::DragOperation operation, RenderWidgetHost* source_rwh); // Notification that the RenderViewHost's load state changed.
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc index 03bcbd25..2fc1f24 100644 --- a/content/browser/web_contents/web_contents_view_android.cc +++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -31,6 +31,7 @@ #include "ui/android/overscroll_refresh_handler.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/clipboard_constants.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #include "ui/display/screen.h" #include "ui/events/android/drag_event_android.h" #include "ui/events/android/gesture_event_android.h" @@ -349,7 +350,7 @@ } } -void WebContentsViewAndroid::UpdateDragCursor(blink::DragOperation op) { +void WebContentsViewAndroid::UpdateDragCursor(ui::mojom::DragOperation op) { // Intentional no-op because Android does not have cursor. } @@ -455,7 +456,7 @@ void WebContentsViewAndroid::OnDragEnded() { web_contents_->GetRenderViewHost()->GetWidget()->DragSourceEndedAt( - drag_location_, drag_screen_location_, blink::kDragOperationNone); + drag_location_, drag_screen_location_, ui::mojom::DragOperation::kNone); OnSystemDragEnded(); drag_location_ = gfx::PointF();
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h index f46951b2..78aafdce2 100644 --- a/content/browser/web_contents/web_contents_view_android.h +++ b/content/browser/web_contents/web_contents_view_android.h
@@ -99,7 +99,7 @@ const gfx::Vector2d& image_offset, const blink::mojom::DragEventSourceInfo& event_info, RenderWidgetHostImpl* source_rwh) override; - void UpdateDragCursor(blink::DragOperation operation) override; + void UpdateDragCursor(ui::mojom::DragOperation operation) override; void GotFocus(RenderWidgetHostImpl* render_widget_host) override; void LostFocus(RenderWidgetHostImpl* render_widget_host) override; void TakeFocus(bool reverse) override;
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc index fdeba37..b68f7734 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -70,6 +70,7 @@ #include "ui/base/clipboard/custom_data_helper.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drop_target_event.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/dragdrop/os_exchange_data_provider_factory.h" #include "ui/base/hit_test.h" @@ -378,13 +379,13 @@ return static_cast<blink::DragOperationsMask>(web_drag_op); } -blink::DragOperation ConvertToDragOperation(int drag_ops) { +ui::mojom::DragOperation ConvertToDragOperation(int drag_ops) { int op_mask = ConvertToDragOperationsMask(drag_ops); DCHECK(op_mask == blink::kDragOperationNone || op_mask == blink::kDragOperationCopy || op_mask == blink::kDragOperationLink || op_mask == blink::kDragOperationMove); - return static_cast<blink::DragOperation>(op_mask); + return static_cast<ui::mojom::DragOperation>(op_mask); } GlobalRoutingID GetRenderViewHostID(RenderViewHost* rvh) { @@ -695,7 +696,7 @@ WebContentsViewDelegate* delegate) : web_contents_(web_contents), delegate_(delegate), - current_drag_op_(blink::kDragOperationNone), + current_drag_op_(ui::mojom::DragOperation::kNone), drag_dest_delegate_(nullptr), current_rvh_for_drag_(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE), @@ -725,7 +726,7 @@ void WebContentsViewAura::EndDrag( base::WeakPtr<RenderWidgetHostImpl> source_rwh_weak_ptr, - blink::DragOperation op) { + ui::mojom::DragOperation op) { drag_start_process_id_ = ChildProcessHost::kInvalidUniqueID; drag_start_view_id_ = GlobalRoutingID(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); @@ -1090,7 +1091,7 @@ } } -void WebContentsViewAura::UpdateDragCursor(blink::DragOperation operation) { +void WebContentsViewAura::UpdateDragCursor(ui::mojom::DragOperation operation) { current_drag_op_ = operation; }
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h index 49bbcc0..583f3ce 100644 --- a/content/browser/web_contents/web_contents_view_aura.h +++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -30,6 +30,7 @@ #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" #include "ui/base/dragdrop/drop_target_event.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" namespace ui { class DropTargetEvent; @@ -110,7 +111,7 @@ ~WebContentsViewAura() override; void EndDrag(base::WeakPtr<RenderWidgetHostImpl> source_rwh_weak_ptr, - blink::DragOperation op); + ui::mojom::DragOperation op); void InstallOverscrollControllerDelegate(RenderWidgetHostViewAura* view); @@ -166,7 +167,7 @@ const gfx::Vector2d& image_offset, const blink::mojom::DragEventSourceInfo& event_info, RenderWidgetHostImpl* source_rwh) override; - void UpdateDragCursor(blink::DragOperation operation) override; + void UpdateDragCursor(ui::mojom::DragOperation operation) override; void GotFocus(RenderWidgetHostImpl* render_widget_host) override; void LostFocus(RenderWidgetHostImpl* render_widget_host) override; void TakeFocus(bool reverse) override; @@ -291,7 +292,7 @@ std::unique_ptr<WebContentsViewDelegate> delegate_; - blink::DragOperation current_drag_op_; + ui::mojom::DragOperation current_drag_op_; std::unique_ptr<DropData> current_drop_data_;
diff --git a/content/browser/web_contents/web_contents_view_child_frame.cc b/content/browser/web_contents/web_contents_view_child_frame.cc index fc8c3560..ecc85a7 100644 --- a/content/browser/web_contents/web_contents_view_child_frame.cc +++ b/content/browser/web_contents/web_contents_view_child_frame.cc
@@ -11,10 +11,10 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/web_contents_view_delegate.h" #include "third_party/blink/public/mojom/input/focus_type.mojom.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" -using blink::DragOperation; using blink::DragOperationsMask; namespace content { @@ -134,7 +134,8 @@ return nullptr; } -void WebContentsViewChildFrame::UpdateDragCursor(DragOperation operation) { +void WebContentsViewChildFrame::UpdateDragCursor( + ui::mojom::DragOperation operation) { if (auto* view = GetOuterDelegateView()) view->UpdateDragCursor(operation); }
diff --git a/content/browser/web_contents/web_contents_view_child_frame.h b/content/browser/web_contents/web_contents_view_child_frame.h index 41bfb394..479277c 100644 --- a/content/browser/web_contents/web_contents_view_child_frame.h +++ b/content/browser/web_contents/web_contents_view_child_frame.h
@@ -58,7 +58,7 @@ const gfx::Vector2d& image_offset, const blink::mojom::DragEventSourceInfo& event_info, RenderWidgetHostImpl* source_rwh) override; - void UpdateDragCursor(blink::DragOperation operation) override; + void UpdateDragCursor(ui::mojom::DragOperation operation) override; void GotFocus(RenderWidgetHostImpl* render_widget_host) override; void TakeFocus(bool reverse) override;
diff --git a/content/browser/web_contents/web_contents_view_mac.h b/content/browser/web_contents/web_contents_view_mac.h index 54ce224..ac2a35d0 100644 --- a/content/browser/web_contents/web_contents_view_mac.h +++ b/content/browser/web_contents/web_contents_view_mac.h
@@ -92,7 +92,7 @@ const gfx::Vector2d& image_offset, const blink::mojom::DragEventSourceInfo& event_info, RenderWidgetHostImpl* source_rwh) override; - void UpdateDragCursor(blink::DragOperation operation) override; + void UpdateDragCursor(ui::mojom::DragOperation operation) override; void GotFocus(RenderWidgetHostImpl* render_widget_host) override; void LostFocus(RenderWidgetHostImpl* render_widget_host) override; void TakeFocus(bool reverse) override;
diff --git a/content/browser/web_contents/web_contents_view_mac.mm b/content/browser/web_contents/web_contents_view_mac.mm index 01eb255..93f71fb 100644 --- a/content/browser/web_contents/web_contents_view_mac.mm +++ b/content/browser/web_contents/web_contents_view_mac.mm
@@ -33,14 +33,14 @@ #include "mojo/public/cpp/bindings/pending_associated_receiver.h" #include "mojo/public/cpp/bindings/pending_associated_remote.h" #include "ui/base/cocoa/cocoa_base_utils.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #include "ui/gfx/mac/coordinate_conversion.h" -using blink::DragOperation; using blink::DragOperationsMask; using remote_cocoa::mojom::DraggingInfoPtr; using remote_cocoa::mojom::SelectionDirection; -// Ensure that the blink::DragOperation enum values stay in sync with +// Ensure that the blink::DragOperationsMask enum values stay in sync with // NSDragOperation constants, since the code below static_casts between 'em. #define STATIC_ASSERT_ENUM(a, b) \ static_assert(static_cast<int>(a) == static_cast<int>(b), \ @@ -215,8 +215,8 @@ return [drag_dest_ currentDropData]; } -void WebContentsViewMac::UpdateDragCursor(DragOperation operation) { - [drag_dest_ setCurrentOperation:operation]; +void WebContentsViewMac::UpdateDragCursor(ui::mojom::DragOperation operation) { + [drag_dest_ setCurrentOperation:static_cast<NSDragOperation>(operation)]; } void WebContentsViewMac::GotFocus(RenderWidgetHostImpl* render_widget_host) { @@ -560,7 +560,7 @@ web_contents_->DragSourceEndedAt( transformed_point.x(), transformed_point.y(), transformed_screen_point.x(), transformed_screen_point.y(), - static_cast<blink::DragOperation>(drag_operation), + static_cast<ui::mojom::DragOperation>(drag_operation), drag_source_start_rwh_.get()); }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTest.java index 6a317eb..8e8eb0a5 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTest.java
@@ -37,6 +37,7 @@ import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.UrlUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils; @@ -542,6 +543,7 @@ */ @Test @MediumTest + @DisabledTest @MinAndroidSdkLevel(Build.VERSION_CODES.M) @TargetApi(Build.VERSION_CODES.M) public void testMaxContentChangedEventsFired_default() throws Throwable { @@ -574,6 +576,7 @@ */ @Test @MediumTest + @DisabledTest @MinAndroidSdkLevel(Build.VERSION_CODES.M) @TargetApi(Build.VERSION_CODES.M) public void testMaxContentChangedEventsFired_largeLimit() throws Throwable {
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index e5f75f7..51b1046 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -444,13 +444,14 @@ "//services/tracing/public/mojom", "//services/video_capture/public/mojom", "//services/viz/public/mojom", - "//third_party/webrtc_overrides:webrtc_component", # We expose skia headers in the public API. "//skia", # We expose storage headers for quota and blob storage context in the public API. "//storage/browser", + "//third_party/webrtc_overrides:webrtc_component", + "//ui/base/dragdrop/mojom:mojom_headers", ] deps = [ "//build:chromeos_buildflags",
diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h index c011ff1..b52c080 100644 --- a/content/public/browser/render_widget_host.h +++ b/content/public/browser/render_widget_host.h
@@ -24,6 +24,7 @@ #include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/public/common/widget/screen_info.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" #include "ui/base/ui_base_types.h" #include "ui/surface/transport_dib.h" @@ -316,7 +317,7 @@ // either in a drop or by being cancelled. virtual void DragSourceEndedAt(const gfx::PointF& client_pt, const gfx::PointF& screen_pt, - blink::DragOperation operation) {} + ui::mojom::DragOperation operation) {} // Notifies the renderer that we're done with the drag and drop operation. // This allows the renderer to reset some state.
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index 8f4b2c9..17ff224 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h
@@ -15,7 +15,6 @@ #include "ipc/ipc_message_macros.h" #include "services/network/public/cpp/network_ipc_param_traits.h" #include "services/network/public/mojom/referrer_policy.mojom.h" -#include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" #include "third_party/blink/public/common/security/security_style.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" @@ -154,7 +153,6 @@ #endif IPC_STRUCT_TRAITS_END() -IPC_ENUM_TRAITS(blink::DragOperation) // Bitmask. IPC_ENUM_TRAITS_MAX_VALUE(content::DropData::Kind, content::DropData::Kind::LAST)
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 8c10cc7..e738dd1 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -657,13 +657,6 @@ const base::Feature kWebOTPAssertionFeaturePolicy{ "WebOTPAssertionFeaturePolicy", base::FEATURE_DISABLED_BY_DEFAULT}; -// Controls whether Site Isolation protects against spoofing of origin in -// mojom::FileSystemManager::Open IPC from compromised renderer processes. See -// also https://crbug.com/917457. -const base::Feature kSiteIsolationEnforcementForFileSystemApi{ - "SiteIsolationEnforcementForFileSystemApi", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Controls whether SpareRenderProcessHostManager tries to always have a warm // spare renderer process around for the most recently requested BrowserContext. // This feature is only consulted in site-per-process mode.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 3e9bfcf..3f6019a 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -155,8 +155,6 @@ CONTENT_EXPORT extern const base::Feature kSignedHTTPExchange; CONTENT_EXPORT extern const base::Feature kSignedHTTPExchangePingValidity; CONTENT_EXPORT extern const base::Feature - kSiteIsolationEnforcementForFileSystemApi; -CONTENT_EXPORT extern const base::Feature kSkipEarlyCommitPendingForCrashedFrame; CONTENT_EXPORT extern const base::Feature kWebOTP; CONTENT_EXPORT extern const base::Feature kWebOTPAssertionFeaturePolicy;
diff --git a/content/public/test/fake_frame_widget.h b/content/public/test/fake_frame_widget.h index 13e4cad..65ca492 100644 --- a/content/public/test/fake_frame_widget.h +++ b/content/public/test/fake_frame_widget.h
@@ -42,7 +42,7 @@ const gfx::PointF& screen_point, blink::DragOperationsMask operations_allowed, uint32_t key_modifiers, - base::OnceCallback<void(blink::DragOperation)> callback) override {} + base::OnceCallback<void(ui::mojom::DragOperation)> callback) override {} void DragTargetDragOver(const gfx::PointF& point_in_viewport, const gfx::PointF& screen_point, blink::DragOperationsMask operations_allowed, @@ -56,7 +56,7 @@ uint32_t key_modifiers) override {} void DragSourceEndedAt(const gfx::PointF& client_point, const gfx::PointF& screen_point, - blink::DragOperation operation) override {} + ui::mojom::DragOperation operation) override {} void DragSourceSystemDragEnded() override {} void SetBackgroundOpaque(bool value) override {} void SetTextDirection(base::i18n::TextDirection direction) override;
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index 56f5922..686cb4b 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -502,26 +502,6 @@ SerializeNameAndDescriptionAttributes(src, dst); - if (accessibility_mode_.has_mode(ui::AXMode::kScreenReader) || - accessibility_mode_.has_mode(ui::AXMode::kPDF)) { - // Heading level. - if (ui::IsHeading(dst->role) && src.HeadingLevel()) { - dst->AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, - src.HeadingLevel()); - } - - WebAXObject parent = ParentObjectUnignored(src); - if (src.Language().length()) { - // TODO(chrishall): should we still trim redundant languages off here? - if (parent.IsNull() || parent.Language() != src.Language()) { - TruncateAndAddStringAttribute( - dst, ax::mojom::StringAttribute::kLanguage, src.Language().Utf8()); - } - } - - SerializeListAttributes(src, dst); - } - if (accessibility_mode_.has_mode(ui::AXMode::kPDF)) { // Return early. None of the following attributes are needed for PDFs. return; @@ -725,15 +705,6 @@ src.ContainerLiveRegionRelevant().Utf8()); } -void BlinkAXTreeSource::SerializeListAttributes(WebAXObject src, - ui::AXNodeData* dst) const { - if (src.SetSize()) - dst->AddIntAttribute(ax::mojom::IntAttribute::kSetSize, src.SetSize()); - - if (src.PosInSet()) - dst->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, src.PosInSet()); -} - void BlinkAXTreeSource::SerializeScrollAttributes(WebAXObject src, ui::AXNodeData* dst) const { // Only mark as scrollable if user has actual scrollbars to use.
diff --git a/content/renderer/accessibility/blink_ax_tree_source.h b/content/renderer/accessibility/blink_ax_tree_source.h index cb8a9bb..4a2e02f 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.h +++ b/content/renderer/accessibility/blink_ax_tree_source.h
@@ -144,8 +144,6 @@ ui::AXNodeData* dst) const; void SerializeLiveRegionAttributes(blink::WebAXObject src, ui::AXNodeData* dst) const; - void SerializeListAttributes(blink::WebAXObject src, - ui::AXNodeData* dst) const; void SerializeScrollAttributes(blink::WebAXObject src, ui::AXNodeData* dst) const; void SerializeChooserPopupAttributes(blink::WebAXObject src,
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index a8800b2..35d3d67 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -2039,7 +2039,7 @@ } if (texture_layer_) { - container_->SetCcLayer(nullptr, false); + container_->SetCcLayer(nullptr); texture_layer_->ClearClient(); texture_layer_ = nullptr; } @@ -2065,7 +2065,7 @@ } if (texture_layer_) { - container_->SetCcLayer(texture_layer_.get(), true); + container_->SetCcLayer(texture_layer_.get()); } layer_is_hardware_ = want_3d_layer;
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc index 9b704bd..89ee038 100644 --- a/content/shell/browser/shell.cc +++ b/content/shell/browser/shell.cc
@@ -144,6 +144,12 @@ g_platform->SetContents(shell); g_platform->DidCreateOrAttachWebContents(shell, raw_web_contents); + // If the RenderFrame was created during WebContents construction (as happens + // for windows opened from the renderer) then the Shell won't hear about the + // main frame being created as a WebContentsObservers. This gives the delegate + // a chance to act on the main frame accordingly. + if (raw_web_contents->GetMainFrame()->IsRenderFrameCreated()) + g_platform->MainFrameCreated(shell); return shell; } @@ -222,8 +228,9 @@ return shell; } -void Shell::RenderViewReady() { - g_platform->RenderViewReady(this); +void Shell::RenderFrameCreated(RenderFrameHost* frame_host) { + if (frame_host == web_contents_->GetMainFrame()) + g_platform->MainFrameCreated(this); } void Shell::LoadURL(const GURL& url) {
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h index 2b766a2b..1542442 100644 --- a/content/shell/browser/shell.h +++ b/content/shell/browser/shell.h
@@ -209,7 +209,7 @@ void LoadProgressChanged(double progress) override; #endif void TitleWasSet(NavigationEntry* entry) override; - void RenderViewReady() override; + void RenderFrameCreated(RenderFrameHost* frame_host) override; void OnDevToolsWebContentsDestroyed();
diff --git a/content/shell/browser/shell_platform_delegate.h b/content/shell/browser/shell_platform_delegate.h index 3c831b856..7d5e31bb 100644 --- a/content/shell/browser/shell_platform_delegate.h +++ b/content/shell/browser/shell_platform_delegate.h
@@ -68,9 +68,10 @@ // Set the title of shell window virtual void SetTitle(Shell* shell, const base::string16& title); - // Called when a RenderView is created for a renderer process; forwarded from - // WebContentsObserver. - virtual void RenderViewReady(Shell* shell); + // Called when the main frame is created in the renderer process; forwarded + // from WebContentsObserver. If navigation creates a new main frame, this may + // occur more than once. + virtual void MainFrameCreated(Shell* shell); // Allows platforms to override the JavascriptDialogManager. By default // returns null, which signals that the Shell should use its own instance.
diff --git a/content/shell/browser/shell_platform_delegate_android.cc b/content/shell/browser/shell_platform_delegate_android.cc index 263d1ee..e00a178 100644 --- a/content/shell/browser/shell_platform_delegate_android.cc +++ b/content/shell/browser/shell_platform_delegate_android.cc
@@ -109,7 +109,7 @@ void ShellPlatformDelegate::SetTitle(Shell* shell, const base::string16& title) {} -void ShellPlatformDelegate::RenderViewReady(Shell* shell) {} +void ShellPlatformDelegate::MainFrameCreated(Shell* shell) {} bool ShellPlatformDelegate::DestroyShell(Shell* shell) { return false; // Shell destroys itself.
diff --git a/content/shell/browser/shell_platform_delegate_aura.cc b/content/shell/browser/shell_platform_delegate_aura.cc index 12f62d2..61006b9 100644 --- a/content/shell/browser/shell_platform_delegate_aura.cc +++ b/content/shell/browser/shell_platform_delegate_aura.cc
@@ -82,7 +82,7 @@ void ShellPlatformDelegate::SetTitle(Shell* shell, const base::string16& title) {} -void ShellPlatformDelegate::RenderViewReady(Shell* shell) {} +void ShellPlatformDelegate::MainFrameCreated(Shell* shell) {} bool ShellPlatformDelegate::DestroyShell(Shell* shell) { return false; // Shell destroys itself.
diff --git a/content/shell/browser/shell_platform_delegate_mac.mm b/content/shell/browser/shell_platform_delegate_mac.mm index c711843d..0a1ec51 100644 --- a/content/shell/browser/shell_platform_delegate_mac.mm +++ b/content/shell/browser/shell_platform_delegate_mac.mm
@@ -304,8 +304,7 @@ [shell_data.window.GetNativeNSWindow() setTitle:title_string]; } -void ShellPlatformDelegate::RenderViewReady(Shell* shell) { -} +void ShellPlatformDelegate::MainFrameCreated(Shell* shell) {} bool ShellPlatformDelegate::DestroyShell(Shell* shell) { DCHECK(base::Contains(shell_data_map_, shell));
diff --git a/content/shell/browser/shell_platform_delegate_views.cc b/content/shell/browser/shell_platform_delegate_views.cc index a2ef741..2f46922 100644 --- a/content/shell/browser/shell_platform_delegate_views.cc +++ b/content/shell/browser/shell_platform_delegate_views.cc
@@ -432,7 +432,7 @@ shell_data.window_widget->widget_delegate()->SetTitle(title); } -void ShellPlatformDelegate::RenderViewReady(Shell* shell) {} +void ShellPlatformDelegate::MainFrameCreated(Shell* shell) {} bool ShellPlatformDelegate::DestroyShell(Shell* shell) { DCHECK(base::Contains(shell_data_map_, shell));
diff --git a/content/test/data/accessibility/html/ignored-selection-between-text-expected-win.txt b/content/test/data/accessibility/html/ignored-selection-between-text-expected-win.txt index 1d2a902..a498c55 100644 --- a/content/test/data/accessibility/html/ignored-selection-between-text-expected-win.txt +++ b/content/test/data/accessibility/html/ignored-selection-between-text-expected-win.txt
@@ -3,6 +3,6 @@ ++++ROLE_SYSTEM_STATICTEXT name='before selection' n_selections=0 ++IA2_ROLE_SECTION n_selections=1 selection_start=0 selection_end=24 ++++ROLE_SYSTEM_STATICTEXT name='this text is not ignored' n_selections=1 selection_start=0 selection_end=24 -++IA2_ROLE_SECTION caret_offset=0 n_selections=0 -++++ROLE_SYSTEM_STATICTEXT name='after selection' caret_offset=0 n_selections=0 +++IA2_ROLE_SECTION n_selections=0 +++++ROLE_SYSTEM_STATICTEXT name='after selection' n_selections=0 ++ROLE_SYSTEM_STATICTEXT name='Done' n_selections=0
diff --git a/content/test/data/accessibility/html/ignored-selection-expected-win.txt b/content/test/data/accessibility/html/ignored-selection-expected-win.txt index 64b3bfad..47622e9 100644 --- a/content/test/data/accessibility/html/ignored-selection-expected-win.txt +++ b/content/test/data/accessibility/html/ignored-selection-expected-win.txt
@@ -1,5 +1,5 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE caret_offset=24 n_selections=1 selection_start=0 selection_end=24 ++ROLE_SYSTEM_STATICTEXT name='this text is not ignored' n_selections=1 selection_start=0 selection_end=24 -++IA2_ROLE_SECTION caret_offset=0 n_selections=0 -++++ROLE_SYSTEM_STATICTEXT name='after selection' caret_offset=0 n_selections=0 +++IA2_ROLE_SECTION n_selections=0 +++++ROLE_SYSTEM_STATICTEXT name='after selection' n_selections=0 ++ROLE_SYSTEM_STATICTEXT name='Done' n_selections=0
diff --git a/content/test/stub_render_widget_host_owner_delegate.h b/content/test/stub_render_widget_host_owner_delegate.h index b10f9042..64d1b9b 100644 --- a/content/test/stub_render_widget_host_owner_delegate.h +++ b/content/test/stub_render_widget_host_owner_delegate.h
@@ -11,7 +11,6 @@ class StubRenderWidgetHostOwnerDelegate : public RenderWidgetHostOwnerDelegate { public: - void RenderWidgetDidInit() override {} void RenderWidgetDidFirstVisuallyNonEmptyPaint() override {} void RenderWidgetGotFocus() override {} void RenderWidgetLostFocus() override {}
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc index a96e8fb6..3fce0a1c 100644 --- a/content/test/test_render_view_host.cc +++ b/content/test/test_render_view_host.cc
@@ -266,12 +266,13 @@ int proxy_route_id, bool window_was_created_with_opener) { DCHECK(!IsRenderViewLive()); - GetWidget()->set_renderer_initialized(true); - DCHECK(IsRenderViewLive()); - opener_frame_token_ = opener_frame_token; + RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(GetMainFrame()); if (main_frame && is_active()) { + // Pretend that we started a renderer process and created the renderer Frame + // with its Widget. We bind all the mojom interfaces, but they all just talk + // into the void. mojo::AssociatedRemote<blink::mojom::WidgetHost> blink_widget_host; mojo::AssociatedRemote<blink::mojom::Widget> blink_widget; auto blink_widget_receiver = @@ -288,9 +289,14 @@ frame_widget_host.BindNewEndpointAndPassDedicatedReceiver(), frame_widget.Unbind()); + // This also initializes the RenderWidgetHost attached to the frame. main_frame->RenderFrameCreated(); + } else { + GetWidget()->SetRendererWidgetCreatedForInactiveRenderView(); } + DCHECK(IsRenderViewLive()); + opener_frame_token_ = opener_frame_token; return true; }
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h index 86d9438a..f8ce533 100644 --- a/content/test/test_render_view_host.h +++ b/content/test/test_render_view_host.h
@@ -186,12 +186,22 @@ int32_t routing_id, int32_t main_frame_routing_id, bool swapped_out); - // RenderViewHostTester implementation. Note that CreateRenderView - // is not specified since it is synonymous with the one from - // RenderViewHostImpl, see below. + // RenderViewHostImpl overrides. + MockRenderProcessHost* GetProcess() override; + bool CreateRenderView( + const base::Optional<base::UnguessableToken>& opener_frame_token, + int proxy_route_id, + bool window_was_created_with_opener) override; + bool IsTestRenderViewHost() const override; + + // RenderViewHostTester implementation. void SimulateWasHidden() override; void SimulateWasShown() override; blink::web_pref::WebPreferences TestComputeWebPreferences() override; + bool CreateTestRenderView( + const base::Optional<base::UnguessableToken>& opener_frame_token, + int proxy_route_id, + bool window_was_created_with_opener) override; void TestOnUpdateStateWithFile(const base::FilePath& file_path); @@ -207,23 +217,6 @@ return opener_frame_token_; } - // RenderWidgetHost overrides (same value, but in the Mock* type) - MockRenderProcessHost* GetProcess() override; - - bool CreateTestRenderView( - const base::Optional<base::UnguessableToken>& opener_frame_token, - int proxy_route_id, - bool window_was_created_with_opener) override; - - // RenderViewHost: - bool CreateRenderView( - const base::Optional<base::UnguessableToken>& opener_frame_token, - int proxy_route_id, - bool window_was_created_with_opener) override; - - // RenderViewHostImpl: - bool IsTestRenderViewHost() const override; - private: FRIEND_TEST_ALL_PREFIXES(RenderViewHostTest, FilterNavigate);
diff --git a/content/test/test_render_widget_host.cc b/content/test/test_render_widget_host.cc index 35a7278d..63bcb90 100644 --- a/content/test/test_render_widget_host.cc +++ b/content/test/test_render_widget_host.cc
@@ -30,6 +30,7 @@ agent_scheduling_group, routing_id, hidden, + /*renderer_initiated_creation=*/false, std::make_unique<FrameTokenMessageQueue>()) { mojo::AssociatedRemote<blink::mojom::WidgetHost> blink_widget_host; mojo::AssociatedRemote<blink::mojom::Widget> blink_widget; @@ -50,4 +51,24 @@ return &input_handler_; } +// static +mojo::PendingAssociatedRemote<blink::mojom::FrameWidget> +TestRenderWidgetHost::CreateStubFrameWidgetRemote() { + // There's no renderer to pass the receiver to in these tests. + mojo::AssociatedRemote<blink::mojom::FrameWidget> widget_remote; + mojo::PendingAssociatedReceiver<blink::mojom::FrameWidget> widget_receiver = + widget_remote.BindNewEndpointAndPassDedicatedReceiver(); + return widget_remote.Unbind(); +} + +// static +mojo::PendingAssociatedRemote<blink::mojom::Widget> +TestRenderWidgetHost::CreateStubWidgetRemote() { + // There's no renderer to pass the receiver to in these tests. + mojo::AssociatedRemote<blink::mojom::Widget> widget_remote; + mojo::PendingAssociatedReceiver<blink::mojom::Widget> widget_receiver = + widget_remote.BindNewEndpointAndPassDedicatedReceiver(); + return widget_remote.Unbind(); +} + } // namespace content
diff --git a/content/test/test_render_widget_host.h b/content/test/test_render_widget_host.h index 15a8ce16..f6fd319 100644 --- a/content/test/test_render_widget_host.h +++ b/content/test/test_render_widget_host.h
@@ -28,6 +28,11 @@ MockWidgetInputHandler* GetMockWidgetInputHandler(); + static mojo::PendingAssociatedRemote<blink::mojom::Widget> + CreateStubWidgetRemote(); + static mojo::PendingAssociatedRemote<blink::mojom::FrameWidget> + CreateStubFrameWidgetRemote(); + private: TestRenderWidgetHost(RenderWidgetHostDelegate* delegate, AgentSchedulingGroupHost& agent_scheduling_group,
diff --git a/content/web_test/BUILD.gn b/content/web_test/BUILD.gn index 1b0597a..53a147ff 100644 --- a/content/web_test/BUILD.gn +++ b/content/web_test/BUILD.gn
@@ -305,6 +305,7 @@ "//third_party/blink/public:test_headers", "//third_party/blink/renderer/core/web_test", "//ui/accessibility:ax_base", + "//ui/base/dragdrop/mojom", "//ui/base/ime:ime_types", "//ui/display", "//ui/events:dom_keycode_converter",
diff --git a/content/web_test/browser/web_test_shell_platform_delegate.h b/content/web_test/browser/web_test_shell_platform_delegate.h index 0221a3e..198795b 100644 --- a/content/web_test/browser/web_test_shell_platform_delegate.h +++ b/content/web_test/browser/web_test_shell_platform_delegate.h
@@ -29,7 +29,7 @@ bool is_enabled) override; void SetAddressBarURL(Shell* shell, const GURL& url) override; void SetTitle(Shell* shell, const base::string16& title) override; - void RenderViewReady(Shell* shell) override; + void MainFrameCreated(Shell* shell) override; std::unique_ptr<JavaScriptDialogManager> CreateJavaScriptDialogManager( Shell* shell) override; bool HandleRequestToLockMouse(Shell* shell,
diff --git a/content/web_test/browser/web_test_shell_platform_delegate_aura.cc b/content/web_test/browser/web_test_shell_platform_delegate_aura.cc index e06b8f3..ca258f6 100644 --- a/content/web_test/browser/web_test_shell_platform_delegate_aura.cc +++ b/content/web_test/browser/web_test_shell_platform_delegate_aura.cc
@@ -57,8 +57,8 @@ ShellPlatformDelegate::SetTitle(shell, title); } -void WebTestShellPlatformDelegate::RenderViewReady(Shell* shell) { - ShellPlatformDelegate::RenderViewReady(shell); +void WebTestShellPlatformDelegate::MainFrameCreated(Shell* shell) { + ShellPlatformDelegate::MainFrameCreated(shell); } bool WebTestShellPlatformDelegate::DestroyShell(Shell* shell) {
diff --git a/content/web_test/browser/web_test_shell_platform_delegate_mac.mm b/content/web_test/browser/web_test_shell_platform_delegate_mac.mm index 64c0700..d29751b 100644 --- a/content/web_test/browser/web_test_shell_platform_delegate_mac.mm +++ b/content/web_test/browser/web_test_shell_platform_delegate_mac.mm
@@ -96,9 +96,9 @@ } } -void WebTestShellPlatformDelegate::RenderViewReady(Shell* shell) { +void WebTestShellPlatformDelegate::MainFrameCreated(Shell* shell) { if (!IsHeadless()) { - ShellPlatformDelegate::RenderViewReady(shell); + ShellPlatformDelegate::MainFrameCreated(shell); return; }
diff --git a/content/web_test/browser/web_test_shell_platform_delegate_views.cc b/content/web_test/browser/web_test_shell_platform_delegate_views.cc index 9b6433cc6..ca73d086 100644 --- a/content/web_test/browser/web_test_shell_platform_delegate_views.cc +++ b/content/web_test/browser/web_test_shell_platform_delegate_views.cc
@@ -116,9 +116,9 @@ // Nothing in headless mode. } -void WebTestShellPlatformDelegate::RenderViewReady(Shell* shell) { +void WebTestShellPlatformDelegate::MainFrameCreated(Shell* shell) { // No difference in headless mode. - ShellPlatformDelegate::RenderViewReady(shell); + ShellPlatformDelegate::MainFrameCreated(shell); } bool WebTestShellPlatformDelegate::DestroyShell(Shell* shell) {
diff --git a/content/web_test/renderer/event_sender.cc b/content/web_test/renderer/event_sender.cc index c6bb577..7016992 100644 --- a/content/web_test/renderer/event_sender.cc +++ b/content/web_test/renderer/event_sender.cc
@@ -49,6 +49,7 @@ #include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/public/web/web_page_popup.h" #include "third_party/blink/public/web/web_view.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #include "ui/events/blink/blink_event_util.h" #include "ui/events/keycodes/dom/keycode_converter.h" #include "ui/events/keycodes/keyboard_codes.h" @@ -1260,7 +1261,7 @@ void EventSender::Reset() { current_drag_data_ = base::nullopt; - current_drag_effect_ = blink::kDragOperationNone; + current_drag_effect_ = ui::mojom::DragOperation::kNone; current_drag_effects_allowed_ = blink::kDragOperationNone; current_pointer_state_.clear(); is_drag_mode_ = true; @@ -1330,7 +1331,7 @@ current_pointer_state_[kRawMousePointerId].modifiers_, current_pointer_state_[kRawMousePointerId].current_buttons_), base::BindOnce( - [](base::WeakPtr<EventSender> sender, blink::DragOperation op) { + [](base::WeakPtr<EventSender> sender, ui::mojom::DragOperation op) { if (sender) sender->current_drag_effect_ = op; }, @@ -1682,7 +1683,7 @@ current_pointer_state_[kRawMousePointerId].current_buttons_, current_pointer_state_[kRawMousePointerId].last_pos_, click_count_, &event); - FinishDragAndDrop(event, blink::kDragOperationNone); + FinishDragAndDrop(event, ui::mojom::DragOperation::kNone); } web_frame_widget_->ClearEditCommands(); @@ -2465,7 +2466,7 @@ current_pointer_state_[kRawMousePointerId].current_buttons_, gfx::PointF(x, y), click_count_, &mouse_event); - FinishDragAndDrop(mouse_event, blink::kDragOperationNone); + FinishDragAndDrop(mouse_event, ui::mojom::DragOperation::kNone); } args->Return(result != WebInputEventResult::kNotHandled); } @@ -2624,13 +2625,13 @@ } void EventSender::FinishDragAndDrop(const WebMouseEvent& event, - blink::DragOperation drag_effect) { + ui::mojom::DragOperation drag_effect) { // Bail if cancelled. if (!current_drag_data_) return; current_drag_effect_ = drag_effect; - if (current_drag_effect_) { + if (current_drag_effect_ != ui::mojom::DragOperation::kNone) { // Specifically pass any keyboard modifiers to the drop method. This allows // tests to control the drop type (i.e. copy or move). MainFrameWidget()->DragTargetDrop( @@ -2671,7 +2672,7 @@ event.PositionInWidget(), event.PositionInScreen(), current_drag_effects_allowed_, event.GetModifiers(), base::BindOnce( - [](base::WeakPtr<EventSender> sender, blink::DragOperation op) { + [](base::WeakPtr<EventSender> sender, ui::mojom::DragOperation op) { if (sender) sender->current_drag_effect_ = op; },
diff --git a/content/web_test/renderer/event_sender.h b/content/web_test/renderer/event_sender.h index bcf216e8..65a521a 100644 --- a/content/web_test/renderer/event_sender.h +++ b/content/web_test/renderer/event_sender.h
@@ -24,6 +24,7 @@ #include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/public/platform/web_drag_data.h" #include "third_party/blink/public/platform/web_input_event_result.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" #include "ui/gfx/geometry/point.h" namespace blink { @@ -193,7 +194,7 @@ float* radius_x, float* radius_y); - void FinishDragAndDrop(const blink::WebMouseEvent&, blink::DragOperation); + void FinishDragAndDrop(const blink::WebMouseEvent&, ui::mojom::DragOperation); int ModifiersForPointer(int pointer_id); void DoDragAfterMouseUp(const blink::WebMouseEvent&); @@ -316,7 +317,7 @@ // Used to determine whether the click count continues to increment or not. static blink::WebMouseEvent::Button last_button_type_; - blink::DragOperation current_drag_effect_; + ui::mojom::DragOperation current_drag_effect_; base::TimeDelta time_offset_; int click_count_;
diff --git a/content/web_test/renderer/test_plugin.cc b/content/web_test/renderer/test_plugin.cc index e476d17..1fd587b 100644 --- a/content/web_test/renderer/test_plugin.cc +++ b/content/web_test/renderer/test_plugin.cc
@@ -188,8 +188,7 @@ return false; layer_ = cc::TextureLayer::CreateForMailbox(this); - bool prevent_contents_opaque_changes = false; - container_->SetCcLayer(layer_.get(), prevent_contents_opaque_changes); + container_->SetCcLayer(layer_.get()); if (re_request_touch_events_) { container_->RequestTouchEventType( blink::WebPluginContainer::kTouchEventRequestTypeSynthesizedMouse); @@ -205,7 +204,7 @@ if (layer_.get()) layer_->ClearTexture(); if (container_) - container_->SetCcLayer(nullptr, false); + container_->SetCcLayer(nullptr); layer_ = nullptr; DestroyScene();
diff --git a/content/web_test/renderer/web_ax_object_proxy.cc b/content/web_test/renderer/web_ax_object_proxy.cc index a7d269cf..54f563d 100644 --- a/content/web_test/renderer/web_ax_object_proxy.cc +++ b/content/web_test/renderer/web_ax_object_proxy.cc
@@ -1095,12 +1095,12 @@ int WebAXObjectProxy::PosInSet() { UpdateLayout(); - return accessibility_object_.PosInSet(); + return GetAXNodeData().GetIntAttribute(ax::mojom::IntAttribute::kPosInSet); } int WebAXObjectProxy::SetSize() { UpdateLayout(); - return accessibility_object_.SetSize(); + return GetAXNodeData().GetIntAttribute(ax::mojom::IntAttribute::kSetSize); } int WebAXObjectProxy::ClickPointX() {
diff --git a/device/gamepad/nintendo_data_fetcher_unittest.cc b/device/gamepad/nintendo_data_fetcher_unittest.cc index 9fdd9c1..466e0c5 100644 --- a/device/gamepad/nintendo_data_fetcher_unittest.cc +++ b/device/gamepad/nintendo_data_fetcher_unittest.cc
@@ -97,11 +97,17 @@ TEST_F(NintendoDataFetcherTest, UnsupportedDeviceIsIgnored) { // Simulate an unsupported, non-Nintendo HID device. + HidDeviceInfo::PlatformDeviceIdMap platform_device_id_map; + platform_device_id_map.emplace_back(base::flat_set<uint8_t>{0}, + kTestDeviceId); + std::vector<mojom::HidCollectionInfoPtr> collections; auto collection = mojom::HidCollectionInfo::New(); collection->usage = mojom::HidUsageAndPage::New(0, 0); + collections.push_back(std::move(collection)); scoped_refptr<HidDeviceInfo> device_info(new HidDeviceInfo( - kTestDeviceId, kPhysicalDeviceId, 0x1234, 0xabcd, "Invalipad", "", - mojom::HidBusType::kHIDBusTypeUSB, std::move(collection), 0, 0, 0)); + std::move(platform_device_id_map), kPhysicalDeviceId, 0x1234, 0xabcd, + "Invalipad", "", mojom::HidBusType::kHIDBusTypeUSB, + std::move(collections), 0, 0, 0)); // Add the device to the mock HID service. The HID service should notify the // data fetcher. @@ -118,11 +124,17 @@ TEST_F(NintendoDataFetcherTest, AddAndRemoveSwitchPro) { // Simulate a Switch Pro over USB. + HidDeviceInfo::PlatformDeviceIdMap platform_device_id_map; + platform_device_id_map.emplace_back(base::flat_set<uint8_t>{0}, + kTestDeviceId); + std::vector<mojom::HidCollectionInfoPtr> collections; auto collection = mojom::HidCollectionInfo::New(); collection->usage = mojom::HidUsageAndPage::New(0, 0); + collections.push_back(std::move(collection)); scoped_refptr<HidDeviceInfo> device_info(new HidDeviceInfo( - kTestDeviceId, kPhysicalDeviceId, 0x057e, 0x2009, "Switch Pro Controller", - "", mojom::HidBusType::kHIDBusTypeUSB, std::move(collection), 0, 63, 0)); + std::move(platform_device_id_map), kPhysicalDeviceId, 0x057e, 0x2009, + "Switch Pro Controller", "", mojom::HidBusType::kHIDBusTypeUSB, + std::move(collections), 0, 63, 0)); // Add the device to the mock HID service. The HID service should notify the // data fetcher.
diff --git a/device/gamepad/xbox_hid_controller.cc b/device/gamepad/xbox_hid_controller.cc index 969af72..ee509a1b 100644 --- a/device/gamepad/xbox_hid_controller.cc +++ b/device/gamepad/xbox_hid_controller.cc
@@ -20,6 +20,11 @@ // static bool XboxHidController::IsXboxHid(GamepadId gamepad_id) { + // TODO(crbug/1030841): Detect haptics functionality through HID usages + // instead of relying on a hard-coded list of supported device IDs. + // Bluetooth-connected Xbox One gamepads expose usages from the Physical + // Interface Device usage page. + // https://www.usb.org/document-library/device-class-definition-pid-10 return gamepad_id == GamepadId::kMicrosoftProduct02e0 || gamepad_id == GamepadId::kMicrosoftProduct02fd || gamepad_id == GamepadId::kMicrosoftProduct0b05;
diff --git a/extensions/browser/api/feedback_private/feedback_private_api.cc b/extensions/browser/api/feedback_private/feedback_private_api.cc index 0bdb186..6791a87 100644 --- a/extensions/browser/api/feedback_private/feedback_private_api.cc +++ b/extensions/browser/api/feedback_private/feedback_private_api.cc
@@ -412,8 +412,8 @@ service->SendFeedback( feedback_data, - base::Bind(&FeedbackPrivateSendFeedbackFunction::OnCompleted, this, - GetLandingPageType(*feedback_data))); + base::BindOnce(&FeedbackPrivateSendFeedbackFunction::OnCompleted, this, + GetLandingPageType(*feedback_data))); } #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc b/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc index d760fcc..936993b 100644 --- a/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc +++ b/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc
@@ -27,6 +27,7 @@ using feedback::FeedbackData; using testing::_; using testing::DoAll; +using testing::Invoke; using testing::SaveArg; // Converts |params| to a string containing a JSON dictionary within an argument @@ -126,12 +127,11 @@ scoped_refptr<FeedbackData> actual_feedback_data; EXPECT_CALL(*mock, SendFeedback(_, _)) - .WillOnce( - DoAll(testing::SaveArg<0>(&actual_feedback_data), - [](scoped_refptr<FeedbackData> feedback_data, - const FeedbackService::SendFeedbackCallback& callback) { - callback.Run(true); - })); + .WillOnce(Invoke([&](scoped_refptr<FeedbackData> feedback_data, + FeedbackService::SendFeedbackCallback callback) { + actual_feedback_data = feedback_data; + std::move(callback).Run(true); + })); FeedbackPrivateAPI::GetFactoryInstance() ->Get(browser_context())
diff --git a/extensions/browser/api/feedback_private/feedback_service.cc b/extensions/browser/api/feedback_private/feedback_service.cc index d9e4861..209908e 100644 --- a/extensions/browser/api/feedback_private/feedback_service.cc +++ b/extensions/browser/api/feedback_private/feedback_service.cc
@@ -37,7 +37,8 @@ FeedbackService::~FeedbackService() = default; void FeedbackService::SendFeedback(scoped_refptr<FeedbackData> feedback_data, - const SendFeedbackCallback& callback) { + SendFeedbackCallback callback) { + send_feedback_callback_ = std::move(callback); feedback_data->set_locale( ExtensionsBrowserClient::Get()->GetApplicationLocale()); feedback_data->set_user_agent(ExtensionsBrowserClient::Get()->GetUserAgent()); @@ -45,45 +46,42 @@ if (!feedback_data->attached_file_uuid().empty()) { BlobReader::Read(browser_context_, feedback_data->attached_file_uuid(), base::BindOnce(&FeedbackService::AttachedFileCallback, - AsWeakPtr(), feedback_data, callback)); + AsWeakPtr(), feedback_data)); } if (!feedback_data->screenshot_uuid().empty()) { BlobReader::Read(browser_context_, feedback_data->screenshot_uuid(), base::BindOnce(&FeedbackService::ScreenshotCallback, - AsWeakPtr(), feedback_data, callback)); + AsWeakPtr(), feedback_data)); } - CompleteSendFeedback(feedback_data, callback); + CompleteSendFeedback(feedback_data); } void FeedbackService::AttachedFileCallback( scoped_refptr<feedback::FeedbackData> feedback_data, - const SendFeedbackCallback& callback, std::unique_ptr<std::string> data, int64_t /* total_blob_length */) { feedback_data->set_attached_file_uuid(std::string()); if (data) feedback_data->AttachAndCompressFileData(std::move(*data)); - CompleteSendFeedback(feedback_data, callback); + CompleteSendFeedback(feedback_data); } void FeedbackService::ScreenshotCallback( scoped_refptr<feedback::FeedbackData> feedback_data, - const SendFeedbackCallback& callback, std::unique_ptr<std::string> data, int64_t /* total_blob_length */) { feedback_data->set_screenshot_uuid(std::string()); if (data) feedback_data->set_image(std::move(*data)); - CompleteSendFeedback(feedback_data, callback); + CompleteSendFeedback(feedback_data); } void FeedbackService::CompleteSendFeedback( - scoped_refptr<feedback::FeedbackData> feedback_data, - const SendFeedbackCallback& callback) { + scoped_refptr<feedback::FeedbackData> feedback_data) { // A particular data collection is considered completed if, // a.) The blob URL is invalid - this will either happen because we never had // a URL and never needed to read this data, or that the data read failed @@ -114,7 +112,7 @@ // TODO(rkc): Change this once we have FeedbackData/Util refactored to // report the status of the report being sent. - callback.Run(result); + std::move(send_feedback_callback_).Run(result); } }
diff --git a/extensions/browser/api/feedback_private/feedback_service.h b/extensions/browser/api/feedback_private/feedback_service.h index 42faf9220..c0828f6 100644 --- a/extensions/browser/api/feedback_private/feedback_service.h +++ b/extensions/browser/api/feedback_private/feedback_service.h
@@ -29,30 +29,30 @@ // True will be passed to indicate that it is being successfully sent now, // and false to indicate that it will be delayed (usually due to being // offline). - using SendFeedbackCallback = base::Callback<void(bool)>; + using SendFeedbackCallback = base::OnceCallback<void(bool)>; explicit FeedbackService(content::BrowserContext* browser_context); virtual ~FeedbackService(); // Sends a feedback report. virtual void SendFeedback(scoped_refptr<feedback::FeedbackData> feedback_data, - const SendFeedbackCallback& callback); + SendFeedbackCallback callback); private: // Callbacks to receive blob data. void AttachedFileCallback(scoped_refptr<feedback::FeedbackData> feedback_data, - const SendFeedbackCallback& callback, std::unique_ptr<std::string> data, int64_t total_blob_length); void ScreenshotCallback(scoped_refptr<feedback::FeedbackData> feedback_data, - const SendFeedbackCallback& callback, std::unique_ptr<std::string> data, int64_t total_blob_length); // Checks if we have read all the blobs we need to; signals the feedback // data object once all the requisite data has been populated. - void CompleteSendFeedback(scoped_refptr<feedback::FeedbackData> feedback_data, - const SendFeedbackCallback& callback); + void CompleteSendFeedback( + scoped_refptr<feedback::FeedbackData> feedback_data); + + SendFeedbackCallback send_feedback_callback_; content::BrowserContext* browser_context_;
diff --git a/extensions/browser/api/feedback_private/log_source_access_manager.cc b/extensions/browser/api/feedback_private/log_source_access_manager.cc index 9a6b641..ca25f93f 100644 --- a/extensions/browser/api/feedback_private/log_source_access_manager.cc +++ b/extensions/browser/api/feedback_private/log_source_access_manager.cc
@@ -223,8 +223,8 @@ // passed in as part of a callback. resource_manager->Get(extension_id, resource_id) ->set_unregister_callback( - base::Bind(&LogSourceAccessManager::RemoveHandle, - weak_factory_.GetWeakPtr(), resource_id)); + base::BindOnce(&LogSourceAccessManager::RemoveHandle, + weak_factory_.GetWeakPtr(), resource_id)); open_handles_.emplace( resource_id, std::make_unique<SourceAndExtension>(source, extension_id));
diff --git a/extensions/browser/api/feedback_private/log_source_resource.cc b/extensions/browser/api/feedback_private/log_source_resource.cc index cbb1bf4..5e8aad2 100644 --- a/extensions/browser/api/feedback_private/log_source_resource.cc +++ b/extensions/browser/api/feedback_private/log_source_resource.cc
@@ -27,7 +27,7 @@ LogSourceResource::~LogSourceResource() { if (!unregister_callback_.is_null()) - unregister_callback_.Run(); + std::move(unregister_callback_).Run(); } } // namespace extensions
diff --git a/extensions/browser/api/feedback_private/log_source_resource.h b/extensions/browser/api/feedback_private/log_source_resource.h index d1118dd..87b89e1 100644 --- a/extensions/browser/api/feedback_private/log_source_resource.h +++ b/extensions/browser/api/feedback_private/log_source_resource.h
@@ -31,8 +31,8 @@ system_logs::SystemLogsSource* GetLogSource() const { return source_.get(); } - void set_unregister_callback(const base::Closure& unregister_callback) { - unregister_callback_ = unregister_callback; + void set_unregister_callback(base::OnceClosure unregister_callback) { + unregister_callback_ = std::move(unregister_callback); } private: @@ -43,7 +43,7 @@ // This unregisters the LogSourceResource from a LogSourceAccessManager when // this resource is cleaned up. - base::Closure unregister_callback_; + base::OnceClosure unregister_callback_; DISALLOW_COPY_AND_ASSIGN(LogSourceResource); };
diff --git a/extensions/browser/api/feedback_private/mock_feedback_service.h b/extensions/browser/api/feedback_private/mock_feedback_service.h index b3c6b79c1..9fac573 100644 --- a/extensions/browser/api/feedback_private/mock_feedback_service.h +++ b/extensions/browser/api/feedback_private/mock_feedback_service.h
@@ -17,7 +17,7 @@ MOCK_METHOD2(SendFeedback, void(scoped_refptr<feedback::FeedbackData>, - const FeedbackService::SendFeedbackCallback&)); + FeedbackService::SendFeedbackCallback)); }; } // namespace extensions
diff --git a/extensions/browser/api/media_perception_private/media_perception_api_manager.cc b/extensions/browser/api/media_perception_private/media_perception_api_manager.cc index a06c5c7..ed1ce5a7 100644 --- a/extensions/browser/api/media_perception_private/media_perception_api_manager.cc +++ b/extensions/browser/api/media_perception_private/media_perception_api_manager.cc
@@ -358,10 +358,10 @@ } void MediaPerceptionAPIManager::GetDiagnostics( - const APIGetDiagnosticsCallback& callback) { + APIGetDiagnosticsCallback callback) { chromeos::MediaAnalyticsClient::Get()->GetDiagnostics( base::BindOnce(&MediaPerceptionAPIManager::GetDiagnosticsCallback, - weak_ptr_factory_.GetWeakPtr(), callback)); + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } void MediaPerceptionAPIManager::UpstartStartProcessCallback( @@ -566,16 +566,17 @@ } void MediaPerceptionAPIManager::GetDiagnosticsCallback( - const APIGetDiagnosticsCallback& callback, + APIGetDiagnosticsCallback callback, base::Optional<mri::Diagnostics> result) { if (!result.has_value()) { - callback.Run(GetDiagnosticsForServiceError( + std::move(callback).Run(GetDiagnosticsForServiceError( extensions::api::media_perception_private:: SERVICE_ERROR_SERVICE_UNREACHABLE)); return; } - callback.Run(extensions::api::media_perception_private::DiagnosticsProtoToIdl( - result.value())); + std::move(callback).Run( + extensions::api::media_perception_private::DiagnosticsProtoToIdl( + result.value())); } void MediaPerceptionAPIManager::OnDetectionSignal(
diff --git a/extensions/browser/api/media_perception_private/media_perception_api_manager.h b/extensions/browser/api/media_perception_private/media_perception_api_manager.h index 0110b9ab..8eded3f 100644 --- a/extensions/browser/api/media_perception_private/media_perception_api_manager.h +++ b/extensions/browser/api/media_perception_private/media_perception_api_manager.h
@@ -34,7 +34,7 @@ using APIStateCallback = base::OnceCallback<void( extensions::api::media_perception_private::State state)>; - using APIGetDiagnosticsCallback = base::Callback<void( + using APIGetDiagnosticsCallback = base::OnceCallback<void( extensions::api::media_perception_private::Diagnostics diagnostics)>; explicit MediaPerceptionAPIManager(content::BrowserContext* context); @@ -64,7 +64,7 @@ void GetState(APIStateCallback callback); void SetState(const extensions::api::media_perception_private::State& state, APIStateCallback callback); - void GetDiagnostics(const APIGetDiagnosticsCallback& callback); + void GetDiagnostics(APIGetDiagnosticsCallback callback); // For testing purposes only. Allows the unittest to set the mount_point to // something non-empty. @@ -102,7 +102,7 @@ // Callback for GetDiagnostics D-Bus method calls to the media analytics // process. - void GetDiagnosticsCallback(const APIGetDiagnosticsCallback& callback, + void GetDiagnosticsCallback(APIGetDiagnosticsCallback callback, base::Optional<mri::Diagnostics> diagnostics); // Callbacks for Upstart command to start media analytics process.
diff --git a/extensions/browser/api/media_perception_private/media_perception_api_manager_unittest.cc b/extensions/browser/api/media_perception_private/media_perception_api_manager_unittest.cc index 9bca642..2fc20b8 100644 --- a/extensions/browser/api/media_perception_private/media_perception_api_manager_unittest.cc +++ b/extensions/browser/api/media_perception_private/media_perception_api_manager_unittest.cc
@@ -147,8 +147,8 @@ base::RunLoop run_loop; media_perception::ServiceError service_error; manager->GetDiagnostics( - base::Bind(&RecordServiceErrorFromDiagnosticsAndRunClosure, - run_loop.QuitClosure(), &service_error)); + base::BindOnce(&RecordServiceErrorFromDiagnosticsAndRunClosure, + run_loop.QuitClosure(), &service_error)); run_loop.Run(); return service_error; }
diff --git a/extensions/browser/api/media_perception_private/media_perception_private_api.cc b/extensions/browser/api/media_perception_private/media_perception_private_api.cc index 9580e93..d9477c3 100644 --- a/extensions/browser/api/media_perception_private/media_perception_private_api.cc +++ b/extensions/browser/api/media_perception_private/media_perception_private_api.cc
@@ -108,7 +108,7 @@ MediaPerceptionPrivateGetDiagnosticsFunction::Run() { MediaPerceptionAPIManager* manager = MediaPerceptionAPIManager::Get(browser_context()); - manager->GetDiagnostics(base::Bind( + manager->GetDiagnostics(base::BindOnce( &MediaPerceptionPrivateGetDiagnosticsFunction::GetDiagnosticsCallback, this)); return RespondLater();
diff --git a/extensions/browser/api/messaging/message_service.cc b/extensions/browser/api/messaging/message_service.cc index 0a54cc7..0623a2a 100644 --- a/extensions/browser/api/messaging/message_service.cc +++ b/extensions/browser/api/messaging/message_service.cc
@@ -363,8 +363,8 @@ // This check may show a dialog. messaging_delegate_->QueryIncognitoConnectability( context, target_extension, source_contents, source_url, - base::Bind(&MessageService::OnOpenChannelAllowed, - weak_factory_.GetWeakPtr(), base::Passed(¶ms))); + base::BindOnce(&MessageService::OnOpenChannelAllowed, + weak_factory_.GetWeakPtr(), base::Passed(¶ms))); return; }
diff --git a/extensions/browser/api/messaging/messaging_delegate.cc b/extensions/browser/api/messaging/messaging_delegate.cc index 8de25f0d..9553d4363 100644 --- a/extensions/browser/api/messaging/messaging_delegate.cc +++ b/extensions/browser/api/messaging/messaging_delegate.cc
@@ -58,9 +58,9 @@ const Extension* target_extension, content::WebContents* source_contents, const GURL& source_url, - const base::Callback<void(bool)>& callback) { + base::OnceCallback<void(bool)> callback) { NOTIMPLEMENTED(); - callback.Run(false); + std::move(callback).Run(false); } } // namespace extensions
diff --git a/extensions/browser/api/messaging/messaging_delegate.h b/extensions/browser/api/messaging/messaging_delegate.h index 36d448b..538a8ba9 100644 --- a/extensions/browser/api/messaging/messaging_delegate.h +++ b/extensions/browser/api/messaging/messaging_delegate.h
@@ -86,7 +86,7 @@ const Extension* extension, content::WebContents* web_contents, const GURL& url, - const base::Callback<void(bool)>& callback); + base::OnceCallback<void(bool)> callback); }; } // namespace extensions
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc index 6dd770b1..a544a3c 100644 --- a/extensions/browser/extension_function_dispatcher.cc +++ b/extensions/browser/extension_function_dispatcher.cc
@@ -338,6 +338,10 @@ if (function->source_context_type() == Feature::WEBUI_CONTEXT) { base::UmaHistogramSparse("Extensions.Functions.WebUICalls", function->histogram_value()); + } else if (function->source_context_type() == + Feature::WEBUI_UNTRUSTED_CONTEXT) { + base::UmaHistogramSparse("Extensions.Functions.WebUIUntrustedCalls", + function->histogram_value()); } // Skip the quota, event page, activity logging stuff if there
diff --git a/gpu/command_buffer/tests/webgpu_fence_unittest.cc b/gpu/command_buffer/tests/webgpu_fence_unittest.cc index 228eb9e..ccc5bdb 100644 --- a/gpu/command_buffer/tests/webgpu_fence_unittest.cc +++ b/gpu/command_buffer/tests/webgpu_fence_unittest.cc
@@ -2,19 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "build/build_config.h" #include "gpu/command_buffer/client/webgpu_implementation.h" #include "gpu/command_buffer/tests/webgpu_test.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -// TODO(crbug.com/1162117): gl_tests failing on Linux -#if defined(OS_LINUX) -#define MAYBE(test_name) DISABLED_##test_name -#else -#define MAYBE(test_name) test_name -#endif - namespace { class MockFenceOnCompletionCallback { @@ -56,7 +48,7 @@ }; // Test that getting the value of the fence is the initial value. -TEST_F(WebGPUFenceTest, MAYBE(InitialValue)) { +TEST_F(WebGPUFenceTest, InitialValue) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped"; return; @@ -79,7 +71,7 @@ } // Test that after signaling a fence, its completed value gets updated. -TEST_F(WebGPUFenceTest, MAYBE(GetCompletedValue)) { +TEST_F(WebGPUFenceTest, GetCompletedValue) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped"; return; @@ -98,7 +90,7 @@ // Test that a fence's OnCompletion handler is called after the signal value // is completed. -TEST_F(WebGPUFenceTest, MAYBE(OnCompletion)) { +TEST_F(WebGPUFenceTest, OnCompletion) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped"; return; @@ -120,7 +112,7 @@ } // Test signaling a fence a million times. -TEST_F(WebGPUFenceTest, MAYBE(SignalManyTimes)) { +TEST_F(WebGPUFenceTest, SignalManyTimes) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped"; return;
diff --git a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc index 594df47f..0077b08 100644 --- a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc +++ b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
@@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "build/build_config.h" #include "components/viz/test/test_gpu_service_holder.h" #include "gpu/command_buffer/client/shared_image_interface.h" #include "gpu/command_buffer/client/webgpu_implementation.h" @@ -14,13 +13,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/color_space.h" -// TODO(crbug.com/1162117): gl_tests failing on Linux -#if defined(OS_LINUX) -#define MAYBE(test_name) DISABLED_##test_name -#else -#define MAYBE(test_name) test_name -#endif - namespace gpu { namespace { @@ -96,7 +88,7 @@ } }; -TEST_F(WebGPUMailboxTest, MAYBE(AssociateMailboxCmd)) { +TEST_F(WebGPUMailboxTest, AssociateMailboxCmd) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -214,7 +206,7 @@ GetGpuServiceHolder()->gpu_thread_task_runner()->RunsTasksInCurrentSequence(); } -TEST_F(WebGPUMailboxTest, MAYBE(DissociateMailboxCmd)) { +TEST_F(WebGPUMailboxTest, DissociateMailboxCmd) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -282,7 +274,7 @@ // For simplicity of the test the image is shared between a Dawn device and // itself: we render to it using the Dawn device, then re-associate it to a // Dawn texture and read back the values that were written. -TEST_F(WebGPUMailboxTest, MAYBE(WriteToMailboxThenReadFromIt)) { +TEST_F(WebGPUMailboxTest, WriteToMailboxThenReadFromIt) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -394,7 +386,7 @@ } // Tests that using a shared image aftr it is dissociated produces an error. -TEST_F(WebGPUMailboxTest, MAYBE(ErrorWhenUsingTextureAfterDissociate)) { +TEST_F(WebGPUMailboxTest, ErrorWhenUsingTextureAfterDissociate) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -456,7 +448,7 @@ // the move-assignment operator to be called. In this case the defaulted // move-assignment would first move `representation` then `access`. Causing // incorrect member destruction order for the move-to object. -TEST_F(WebGPUMailboxTest, MAYBE(UseA_UseB_DestroyA_DestroyB)) { +TEST_F(WebGPUMailboxTest, UseA_UseB_DestroyA_DestroyB) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -509,7 +501,7 @@ // images was stored globally instead of per-device. This meant that of two // devices tried to create shared images with the same (id, generation) (which // is possible because they can be on different Dawn wires) they would conflict. -TEST_F(WebGPUMailboxTest, MAYBE(AssociateOnTwoDevicesAtTheSameTime)) { +TEST_F(WebGPUMailboxTest, AssociateOnTwoDevicesAtTheSameTime) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return;
diff --git a/gpu/command_buffer/tests/webgpu_test.cc b/gpu/command_buffer/tests/webgpu_test.cc index d56c8f3..58f8e24 100644 --- a/gpu/command_buffer/tests/webgpu_test.cc +++ b/gpu/command_buffer/tests/webgpu_test.cc
@@ -19,13 +19,6 @@ #include "gpu/ipc/webgpu_in_process_context.h" #include "testing/gtest/include/gtest/gtest.h" -// TODO(crbug.com/1162117): gl_tests failing on Linux -#if defined(OS_LINUX) -#define MAYBE(test_name) DISABLED_##test_name -#else -#define MAYBE(test_name) test_name -#endif - namespace gpu { namespace { @@ -181,7 +174,7 @@ return result; } -TEST_F(WebGPUTest, MAYBE(FlushNoCommands)) { +TEST_F(WebGPUTest, FlushNoCommands) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -193,7 +186,7 @@ } // Referred from GLES2ImplementationTest/ReportLoss -TEST_F(WebGPUTest, MAYBE(ReportLoss)) { +TEST_F(WebGPUTest, ReportLoss) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -213,7 +206,7 @@ } // Referred from GLES2ImplementationTest/ReportLossReentrant -TEST_F(WebGPUTest, MAYBE(ReportLossReentrant)) { +TEST_F(WebGPUTest, ReportLossReentrant) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -232,7 +225,7 @@ EXPECT_EQ(0, lost_count); } -TEST_F(WebGPUTest, MAYBE(RequestAdapterAfterContextLost)) { +TEST_F(WebGPUTest, RequestAdapterAfterContextLost) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return; @@ -246,7 +239,7 @@ base::BindOnce(&OnRequestAdapterCallback))); } -TEST_F(WebGPUTest, MAYBE(RequestDeviceAfterContextLost)) { +TEST_F(WebGPUTest, RequestDeviceAfterContextLost) { if (!WebGPUSupported()) { LOG(ERROR) << "Test skipped because WebGPU isn't supported"; return;
diff --git a/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb b/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb index 567c1d5..cbcdae1 100644 --- a/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb
@@ -65,7 +65,7 @@ <translation id="1535268707340844072">Your current setting may cause some sites to break. To manage cookies for all sites, see <ph name="BEGIN_LINK" />Cookie settings<ph name="END_LINK" />.</translation> <translation id="1540800554400757039">Address 1</translation> <translation id="1545749641540134597">Scan QR Code</translation> -<translation id="1552525382687785070">Sync is Disabled by your Administrator</translation> +<translation id="1552525382687785070">Sync is disabled by your administrator</translation> <translation id="1554477036522844996">New window</translation> <translation id="1580715474678097352">Stay protected from dangerous websites</translation> <translation id="1580783302095112590">Mail sent.</translation> @@ -110,7 +110,7 @@ <translation id="2073572773299281212">Active <ph name="DAYS" /> days ago</translation> <translation id="2074131957428911366">You can always choose what to sync in <ph name="BEGIN_LINK" />settings<ph name="END_LINK" />.</translation> <translation id="2079545284768500474">Undo</translation> -<translation id="209018056901015185">Request Desktop Site</translation> +<translation id="209018056901015185">Request desktop site</translation> <translation id="2103075008456228677">Open history.google.com</translation> <translation id="2116625576999540962"><ph name="NUMBER_OF_SELECTED_BOOKMARKS" /> items moved</translation> <translation id="2118594521750010466">Fix now</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_fa.xtb b/ios/chrome/app/strings/resources/ios_strings_fa.xtb index d04681af..0f0631b 100644 --- a/ios/chrome/app/strings/resources/ios_strings_fa.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_fa.xtb
@@ -578,7 +578,7 @@ <translation id="6973630695168034713">پوشهها</translation> <translation id="6979158407327259162">Google Drive</translation> <translation id="6988572888918530647">مدیریت «حساب Google»</translation> -<translation id="6995899638241819463">اگر گذرواژهها به دلیل نقض داده لو رفته باشد، هشدار میدهد</translation> +<translation id="6995899638241819463">اگر گذرواژهها دراثر سرقت اطلاعات شبکه لورفته باشند، به شما اطلاع داده شود</translation> <translation id="6998989275928107238">به</translation> <translation id="7004499039102548441">برگههای جدید</translation> <translation id="7006788746334555276">تنظیمات محتوا</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_nl.xtb b/ios/chrome/app/strings/resources/ios_strings_nl.xtb index 736b40ba..d0dbdbc 100644 --- a/ios/chrome/app/strings/resources/ios_strings_nl.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_nl.xtb
@@ -200,7 +200,7 @@ <translation id="2975121486251958312">Alleen de incognitomodus is beschikbaar</translation> <translation id="298306318844797842">Betaalmethode toevoegen…</translation> <translation id="2989805286512600854">Openen op nieuw tabblad</translation> -<translation id="3037605927509011580">Helaas.</translation> +<translation id="3037605927509011580">Asjemenou!</translation> <translation id="3080525922482950719">Je kunt pagina's opslaan en later of offline lezen</translation> <translation id="3081338492074632642">Zorg ervoor dat het wachtwoord dat je opslaat, overeenkomt met je wachtwoord voor <ph name="WEBSITE" /></translation> <translation id="3112556859945124369">Markeren…</translation>
diff --git a/ios/chrome/browser/crash_report/BUILD.gn b/ios/chrome/browser/crash_report/BUILD.gn index 590e4be..4da69bc8 100644 --- a/ios/chrome/browser/crash_report/BUILD.gn +++ b/ios/chrome/browser/crash_report/BUILD.gn
@@ -76,6 +76,7 @@ "//ios/chrome/browser/sessions:restoration_agent", "//ios/chrome/browser/sessions:serialisation", "//ios/chrome/browser/sessions:session_service", + "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/main:scene_state_header", "//ios/chrome/browser/ui/util:multiwindow_util", "//ios/chrome/browser/web:tab_id_tab_helper",
diff --git a/ios/chrome/browser/crash_report/crash_restore_helper.mm b/ios/chrome/browser/crash_report/crash_restore_helper.mm index d9ce0fa..de2a90c1 100644 --- a/ios/chrome/browser/crash_report/crash_restore_helper.mm +++ b/ios/chrome/browser/crash_report/crash_restore_helper.mm
@@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "base/feature_list.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" @@ -35,6 +36,7 @@ #import "ios/chrome/browser/sessions/session_window_ios.h" #import "ios/chrome/browser/ui/main/scene_state.h" #import "ios/chrome/browser/ui/main/scene_state_browser_agent.h" +#include "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/multi_window_support.h" #include "ios/chrome/browser/web_state_list/web_state_list.h" #include "ios/chrome/grit/ios_theme_resources.h" @@ -141,6 +143,7 @@ base::string16 GetButtonLabel(InfoBarButton button) const override; bool Accept() override; void InfoBarDismissed() override; + bool ShouldExpire(const NavigationDetails& details) const override; int GetIconId() const override; // TimeInterval when the delegate was created. @@ -215,6 +218,15 @@ forInfobarConfirmType:InfobarConfirmType::kInfobarConfirmTypeRestore]; } +bool SessionCrashedInfoBarDelegate::ShouldExpire( + const NavigationDetails& details) const { + if (base::FeatureList::IsEnabled(kIOSPersistCrashRestore)) { + return false; + } else { + return InfoBarDelegate::ShouldExpire(details); + } +} + int SessionCrashedInfoBarDelegate::GetIconId() const { return IDR_IOS_INFOBAR_RESTORE_SESSION; }
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 793e727c..51f966e9 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -583,6 +583,10 @@ flag_descriptions::kIOSSharedHighlightingColorChangeName, flag_descriptions::kIOSSharedHighlightingColorChangeDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kIOSSharedHighlightingColorChange)}, + {"ios-persist-crash-restore-infobar", + flag_descriptions::kIOSPersistCrashRestoreName, + flag_descriptions::kIOSPersistCrashRestoreDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(kIOSPersistCrashRestore)}, }; bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index f1c022d..5282ccd 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -265,6 +265,11 @@ "that use legacy TLS connections, and subresources using legacy TLS " "connections will be blocked."; +const char kIOSPersistCrashRestoreName[] = "Persist Crash Restore Infobar"; +const char kIOSPersistCrashRestoreDescription[] = + "When enabled, the Crash Restore Infobar will persist through navigations " + "instead of dismissing."; + const char kIOSSharedHighlightingColorChangeName[] = "IOS Shared Highlighting color change"; const char kIOSSharedHighlightingColorChangeDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index f4f5384..24da849d 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -227,6 +227,11 @@ extern const char kIOSLegacyTLSInterstitialsName[]; extern const char kIOSLegacyTLSInterstitialsDescription[]; +// Title and description for the flag to persist the Crash Restore Infobar +// across navigations. +extern const char kIOSPersistCrashRestoreName[]; +extern const char kIOSPersistCrashRestoreDescription[]; + // Title and description for the flag to enable Shared Highlighting color // change in iOS. extern const char kIOSSharedHighlightingColorChangeName[];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller_egtest.mm index b930948..32ca1da 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller_egtest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller_egtest.mm
@@ -282,6 +282,12 @@ // Tests that the "Add Credit Cards..." action works on OTR. - (void)testOTRAddCreditCardsActionOpensAddCreditCardSettings { + // TODO(crbug.com/1162354): Re-enable this test for iPad after fixing this + // issue. + if ([ChromeEarlGrey isIPadIdiom]) { + EARL_GREY_TEST_DISABLED(@"Test disabled on iPad."); + } + [AutofillAppInterface saveLocalCreditCard]; // Open a tab in incognito.
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller_egtest.mm index 5e3382e5..9061c10 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller_egtest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller_egtest.mm
@@ -85,6 +85,12 @@ // Tests that normal fields have Manual Fallback icons after tapping a readonly // field. - (void)testNormalFieldHasManualFallbackIconsAfterReadonlyField { + // TODO(crbug.com/1162301): Re-enable this test for iPad after fixing this + // issue. + if ([ChromeEarlGrey isIPadIdiom]) { + EARL_GREY_TEST_DISABLED(@"Test disabled on iPad."); + } + // Tap the readonly field. [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] performAction:TapWebElementWithId(kFormElementReadonly)];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm index 599e008..fdcc7f33 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -438,7 +438,8 @@ // Tests that the Password View Controller is dismissed when tapping the outside // the popover on iPad. -- (void)testIPadTappingOutsidePopOverDismissPasswordController { +// TODO(crbug.com/1162296): Re-enable this test after this issue is fixed. +- (void)DISABLED_testIPadTappingOutsidePopOverDismissPasswordController { if (![ChromeEarlGrey isIPadIdiom]) { return; }
diff --git a/ios/chrome/browser/ui/badges/badge_mediator.mm b/ios/chrome/browser/ui/badges/badge_mediator.mm index 4e2f091..3881902 100644 --- a/ios/chrome/browser/ui/badges/badge_mediator.mm +++ b/ios/chrome/browser/ui/badges/badge_mediator.mm
@@ -396,16 +396,18 @@ if (base::FeatureList::IsEnabled(kInfobarOverlayUI)) { DCHECK(self.webState); InfoBarIOS* infobar = [self infobarWithType:infobarType]; - DCHECK(infobar); - InfobarOverlayRequestInserter::CreateForWebState(self.webState); - InsertParams params(infobar); - params.overlay_type = InfobarOverlayType::kModal; - params.insertion_index = OverlayRequestQueue::FromWebState( - self.webState, OverlayModality::kInfobarModal) - ->size(); - params.source = InfobarOverlayInsertionSource::kBadge; - InfobarOverlayRequestInserter::FromWebState(self.webState) - ->InsertOverlayRequest(params); + if (infobar) { + InfobarOverlayRequestInserter::CreateForWebState(self.webState); + InsertParams params(infobar); + params.overlay_type = InfobarOverlayType::kModal; + params.insertion_index = + OverlayRequestQueue::FromWebState(self.webState, + OverlayModality::kInfobarModal) + ->size(); + params.source = InfobarOverlayInsertionSource::kBadge; + InfobarOverlayRequestInserter::FromWebState(self.webState) + ->InsertOverlayRequest(params); + } } else { [self.dispatcher displayModalInfobar:infobarType]; }
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc index 3e15622..1cd9a99 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.cc +++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -69,3 +69,6 @@ const base::Feature kIOSSharedHighlightingColorChange{ "IOSSharedHighlightingColorChange", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kIOSPersistCrashRestore{"IOSPersistCrashRestore", + base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h index 46c2012c..1cd42eea 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.h +++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -74,4 +74,8 @@ // Feature flag that enable Shared Highlighting color change in iOS. extern const base::Feature kIOSSharedHighlightingColorChange; +// Feature flag that enables persisting the Crash Restore Infobar across +// navigations. +extern const base::Feature kIOSPersistCrashRestore; + #endif // IOS_CHROME_BROWSER_UI_UI_FEATURE_FLAGS_H_
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 df58cf8b..8baf067b 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 @@ -f94bc73d1f0fa567f30485fdcdfb01ec07d3fac7 \ No newline at end of file +cc2aaca81a52f29fa16be010b95d9fc3fb50fe0d \ 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 9a998db..99b99bf1 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 @@ -174ffb5b73782973b5b5b93c853fed958d90d2d7 \ No newline at end of file +592610a0485b3827fc55c37345c5f3c77a625f91 \ 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 7925b00..64c852b3 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 @@ -63754aaeeba3ec66798f70c4999ef53e3a6647b4 \ No newline at end of file +41a931b60603e2b720057ca3a49a2e9df301ef49 \ 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 e96e1ea9..df61a23 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 @@ -a48a84baea68c5860b5695c428f644f685d72004 \ No newline at end of file +79413ef54869f2f934f42bb2b8203d22c23f96a6 \ 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 0ed5055..c31cb8d 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 @@ -86b6f5f67621adb36cf3e24da2d41cd8af5da379 \ No newline at end of file +b5e2759972d023b06837d79d7f1ecd5feeb536fa \ 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 17a263b6..0b36a79 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 @@ -10797cb7c116e1df8bc0fa01e4498aa3e6af192b \ No newline at end of file +b4187075e753899aad0867e238bf75c0d6f50718 \ 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 b4e599e..4dc8675 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 @@ -df98399ea129985745809834bbf8063ba721f540 \ No newline at end of file +05f9f2a9fadffa1c6eee41dde275d248daca42c9 \ 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 e9c4d73..085d4c4 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 @@ -5b2cc3a41a722a171be64f0102c1aae45f01bb9e \ No newline at end of file +c1b4de8e6fdc560fd001d9a7d477d0ddaea6a969 \ No newline at end of file
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn index 530b02d..69d2ee5 100644 --- a/ios/third_party/material_components_ios/BUILD.gn +++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -235,6 +235,7 @@ "src/components/List/src/MDCBaseCell.h", "src/components/List/src/MDCSelfSizingLayoutAttributes.h", "src/components/List/src/MDCSelfSizingStereoCell.h", + "src/components/List/src/MDCSelfSizingStereoCellImageViewVerticalPosition.h", "src/components/List/src/MaterialList.h", "src/components/List/src/Theming/MDCBaseCell+MaterialTheming.h", "src/components/List/src/Theming/MDCSelfSizingStereoCell+MaterialTheming.h", @@ -1045,6 +1046,7 @@ "src/components/List/src/MDCSelfSizingLayoutAttributes.h", "src/components/List/src/MDCSelfSizingStereoCell.h", "src/components/List/src/MDCSelfSizingStereoCell.m", + "src/components/List/src/MDCSelfSizingStereoCellImageViewVerticalPosition.h", "src/components/List/src/MaterialList.h", "src/components/List/src/Theming/MDCBaseCell+MaterialTheming.h", "src/components/List/src/Theming/MDCBaseCell+MaterialTheming.m",
diff --git a/net/BUILD.gn b/net/BUILD.gn index 6c73771..d214ac4 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -761,9 +761,6 @@ "http2/platform/impl/http2_bug_tracker_impl.h", "http2/platform/impl/http2_containers_impl.h", "http2/platform/impl/http2_estimate_memory_usage_impl.h", - "http2/platform/impl/http2_flag_utils_impl.h", - "http2/platform/impl/http2_flags_impl.cc", - "http2/platform/impl/http2_flags_impl.h", "http2/platform/impl/http2_logging_impl.h", "http2/platform/impl/http2_macros_impl.h", "http2/platform/impl/http2_string_utils_impl.h", @@ -951,6 +948,9 @@ "quic/quic_transport_error.cc", "quic/quic_transport_error.h", "quiche/common/platform/impl/quiche_export_impl.h", + "quiche/common/platform/impl/quiche_flag_utils_impl.h", + "quiche/common/platform/impl/quiche_flags_impl.cc", + "quiche/common/platform/impl/quiche_flags_impl.h", "quiche/common/platform/impl/quiche_logging_impl.h", "quiche/common/platform/impl/quiche_map_util_impl.h", "quiche/common/platform/impl/quiche_str_cat_impl.h", @@ -1037,7 +1037,6 @@ "spdy/platform/impl/spdy_bug_tracker_impl.h", "spdy/platform/impl/spdy_containers_impl.h", "spdy/platform/impl/spdy_estimate_memory_usage_impl.h", - "spdy/platform/impl/spdy_flags_impl.h", "spdy/platform/impl/spdy_logging_impl.h", "spdy/platform/impl/spdy_macros_impl.h", "spdy/platform/impl/spdy_mem_slice_impl.cc",
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc index b5e4f31..74d4fa3 100644 --- a/net/cookies/cookie_util.cc +++ b/net/cookies/cookie_util.cc
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/check.h" #include "base/feature_list.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "base/stl_util.h" @@ -313,6 +314,16 @@ return base::Time(); } + // Log metrics for use of abbreviated, 2-digit, year numbers to determine + // compat impact of fixing behavior for year 69. + // (crbug.com/907610) We currently treat 69 as 1969, whereas the spec says to + // treat it as 2069: + // https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-07#page-17 + if (exploded.year >= 0 && exploded.year <= 99) { + base::UmaHistogramExactLinear("Cookie.AbbreviatedExpirationYear", + exploded.year, 100); + } + // Normalize the year to expand abbreviated years to the full year. if (exploded.year >= 69 && exploded.year <= 99) exploded.year += 1900;
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc index e79bc5d..b773b0e 100644 --- a/net/disk_cache/backend_unittest.cc +++ b/net/disk_cache/backend_unittest.cc
@@ -4570,7 +4570,7 @@ InitCache(); // We don't know what it will pick, but it's limited to what // disk_cache::PreferredCacheSize would return, scaled by the size experiment, - // which only goes as much as 2x. It definitely should not be MAX_UINT64. + // which only goes as much as 4x. It definitely should not be MAX_UINT64. EXPECT_NE(simple_cache_impl_->index()->max_size(), std::numeric_limits<uint64_t>::max()); @@ -4580,6 +4580,26 @@ ASSERT_GE(max_default_size, 0); EXPECT_LT(simple_cache_impl_->index()->max_size(), static_cast<unsigned>(max_default_size)); + + uint64_t max_size_without_scaling = simple_cache_impl_->index()->max_size(); + + // Scale to 200%. The size should be twice of |max_size_without_scaling| but + // since that's capped on 20% of available size, checking for the size to be + // between max_size_without_scaling and max_size_without_scaling*2. + { + base::test::ScopedFeatureList scoped_feature_list; + std::map<std::string, std::string> field_trial_params; + field_trial_params["percent_relative_size"] = "200"; + scoped_feature_list.InitAndEnableFeatureWithParameters( + disk_cache::kChangeDiskCacheSizeExperiment, field_trial_params); + + InitCache(); + + uint64_t max_size_scaled = simple_cache_impl_->index()->max_size(); + + EXPECT_GE(max_size_scaled, max_size_without_scaling); + EXPECT_LE(max_size_scaled, 2 * max_size_without_scaling); + } } TEST_F(DiskCacheBackendTest, SimpleLastModified) {
diff --git a/net/disk_cache/cache_util.cc b/net/disk_cache/cache_util.cc index 79b260da..2a4c34d 100644 --- a/net/disk_cache/cache_util.cc +++ b/net/disk_cache/cache_util.cc
@@ -10,6 +10,7 @@ #include "base/files/file_enumerator.h" #include "base/files/file_util.h" #include "base/location.h" +#include "base/metrics/field_trial_params.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -85,6 +86,9 @@ const int kDefaultCacheSize = 80 * 1024 * 1024; +const base::Feature kChangeDiskCacheSizeExperiment{ + "ChangeDiskCacheSize", base::FEATURE_DISABLED_BY_DEFAULT}; + void DeleteCache(const base::FilePath& path, bool remove_folder) { if (remove_folder) { if (!base::DeletePathRecursively(path)) @@ -152,11 +156,42 @@ // Returns the preferred maximum number of bytes for the cache given the // number of available bytes. int PreferredCacheSize(int64_t available, net::CacheType type) { + // Percent of cache size to use, relative to the default size. "100" means to + // use 100% of the default size. + int percent_relative_size = 100; + + if (base::FeatureList::IsEnabled( + disk_cache::kChangeDiskCacheSizeExperiment) && + type == net::DISK_CACHE) { + percent_relative_size = base::GetFieldTrialParamByFeatureAsInt( + disk_cache::kChangeDiskCacheSizeExperiment, "percent_relative_size", + 100 /* default value */); + } + + // Cap scaling, as a safety check, to avoid overflow. + if (percent_relative_size > 400) + percent_relative_size = 400; + else if (percent_relative_size < 100) + percent_relative_size = 100; + + int64_t scaled_default_disk_cache_size = + (static_cast<int64_t>(disk_cache::kDefaultCacheSize) * + percent_relative_size) / + 100; + if (available < 0) - return kDefaultCacheSize; + return static_cast<int32_t>(scaled_default_disk_cache_size); int64_t preferred_cache_size = PreferredCacheSizeInternal(available); + // If the preferred cache size is less than 20% of the available space, scale + // for the field trial, capping the scaled value at 20% of the available + // space. + if (preferred_cache_size < available / 5) { + preferred_cache_size = std::min( + (preferred_cache_size * percent_relative_size) / 100, available / 5); + } + // Limit cache size to somewhat less than kint32max to avoid potential // integer overflows in cache backend implementations. // @@ -164,7 +199,7 @@ // from the blockfile backend with the following explanation: // "Let's not use more than the default size while we tune-up the performance // of bigger caches. " - int64_t size_limit = static_cast<int64_t>(kDefaultCacheSize) * 4; + int64_t size_limit = scaled_default_disk_cache_size * 4; // Native code entries can be large, so we would like a larger cache. // Make the size limit 50% larger in that case. if (type == net::GENERATED_NATIVE_CODE_CACHE) {
diff --git a/net/disk_cache/cache_util.h b/net/disk_cache/cache_util.h index 2cfea3eb..6a84dcd 100644 --- a/net/disk_cache/cache_util.h +++ b/net/disk_cache/cache_util.h
@@ -17,6 +17,10 @@ namespace disk_cache { +// Experiment to increase the cache size to see the impact on various +// performance metrics. +NET_EXPORT_PRIVATE extern const base::Feature kChangeDiskCacheSizeExperiment; + // Moves the cache files from the given path to another location. // Fails if the destination exists already, or if it doesn't have // permission for the operation. This is basically a rename operation
diff --git a/net/disk_cache/cache_util_unittest.cc b/net/disk_cache/cache_util_unittest.cc index aa2023a..7f8df01e 100644 --- a/net/disk_cache/cache_util_unittest.cc +++ b/net/disk_cache/cache_util_unittest.cc
@@ -8,6 +8,8 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" #include "build/chromeos_buildflags.h" #include "net/disk_cache/cache_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -101,38 +103,53 @@ TEST_F(CacheUtilTest, PreferredCacheSize) { const struct TestCase { int64_t available; - int expected; + int expected_without_trial; + int expected_with_200_trial; + int expected_with_250_trial; + int expected_with_300_trial; } kTestCases[] = { // Weird negative value for available --- return the "default" - {-1000LL, 80 * 1024 * 1024}, - {-1LL, 80 * 1024 * 1024}, + {-1000LL, 80 * 1024 * 1024, 160 * 1024 * 1024, 200 * 1024 * 1024, + 240 * 1024 * 1024}, + {-1LL, 80 * 1024 * 1024, 160 * 1024 * 1024, 200 * 1024 * 1024, + 240 * 1024 * 1024}, // 0 produces 0. - {0LL, 0}, + {0LL, 0, 0, 0, 0}, // Cache is 80% of available space, when default cache size is larger than // 80% of available space.. - {50 * 1024 * 1024LL, 40 * 1024 * 1024}, + {50 * 1024 * 1024LL, 40 * 1024 * 1024, 40 * 1024 * 1024, 40 * 1024 * 1024, + 40 * 1024 * 1024}, // Cache is default size, when default size is 10% to 80% of available // space. - {100 * 1024 * 1024LL, 80 * 1024 * 1024}, - {200 * 1024 * 1024LL, 80 * 1024 * 1024}, + {100 * 1024 * 1024LL, 80 * 1024 * 1024, 80 * 1024 * 1024, + 80 * 1024 * 1024, 80 * 1024 * 1024}, + {200 * 1024 * 1024LL, 80 * 1024 * 1024, 80 * 1024 * 1024, + 80 * 1024 * 1024, 80 * 1024 * 1024}, // Cache is 10% of available space if 2.5 * default size is more than 10% // of available space. - {1000 * 1024 * 1024LL, 100 * 1024 * 1024}, - {2000 * 1024 * 1024LL, 200 * 1024 * 1024}, + {1000 * 1024 * 1024LL, 100 * 1024 * 1024, 200 * 1024 * 1024, + 200 * 1024 * 1024, 200 * 1024 * 1024}, + {2000 * 1024 * 1024LL, 200 * 1024 * 1024, 400 * 1024 * 1024, + 400 * 1024 * 1024, 400 * 1024 * 1024}, // Cache is 2.5 * kDefaultCacheSize if 2.5 * kDefaultCacheSize uses from // 1% to 10% of available space. - {10000 * 1024 * 1024LL, 200 * 1024 * 1024}, + {10000 * 1024 * 1024LL, 200 * 1024 * 1024, 400 * 1024 * 1024, + 500 * 1024 * 1024, 600 * 1024 * 1024}, // Otherwise, cache is 1% of available space. - {20000 * 1024 * 1024LL, 200 * 1024 * 1024}, + {20000 * 1024 * 1024LL, 200 * 1024 * 1024, 400 * 1024 * 1024, + 500 * 1024 * 1024, 600 * 1024 * 1024}, // Until it runs into the cache size cap. - {32000 * 1024 * 1024LL, 320 * 1024 * 1024}, - {50000 * 1024 * 1024LL, 320 * 1024 * 1024}, + {32000 * 1024 * 1024LL, 320 * 1024 * 1024, 640 * 1024 * 1024, + 800 * 1024 * 1024, 960 * 1024 * 1024}, + {50000 * 1024 * 1024LL, 320 * 1024 * 1024, 640 * 1024 * 1024, + 800 * 1024 * 1024, 960 * 1024 * 1024}, }; for (const auto& test_case : kTestCases) { - EXPECT_EQ(test_case.expected, PreferredCacheSize(test_case.available)) + EXPECT_EQ(test_case.expected_without_trial, + PreferredCacheSize(test_case.available)) << test_case.available; } @@ -140,6 +157,61 @@ EXPECT_EQ(((320 * 1024 * 1024) / 2) * 3, PreferredCacheSize(50000 * 1024 * 1024LL, net::GENERATED_NATIVE_CODE_CACHE)); + + for (int cache_size_exeriment : {100, 200, 250, 300}) { + base::test::ScopedFeatureList scoped_feature_list; + std::map<std::string, std::string> field_trial_params; + field_trial_params["percent_relative_size"] = + base::NumberToString(cache_size_exeriment); + scoped_feature_list.InitAndEnableFeatureWithParameters( + disk_cache::kChangeDiskCacheSizeExperiment, field_trial_params); + + for (const auto& test_case : kTestCases) { + int expected = 0; + switch (cache_size_exeriment) { + case 100: + expected = test_case.expected_without_trial; + break; + case 200: + expected = test_case.expected_with_200_trial; + break; + case 250: + expected = test_case.expected_with_250_trial; + break; + case 300: + expected = test_case.expected_with_300_trial; + break; + } + + EXPECT_EQ(expected, PreferredCacheSize(test_case.available)); + + // For caches other than disk cache, the size is not scaled. + EXPECT_EQ(test_case.expected_without_trial, + PreferredCacheSize(test_case.available, + net::GENERATED_BYTE_CODE_CACHE)); + } + + // Check that the cache size cap is 50% higher for native code caches but is + // not scaled for the experiment. + EXPECT_EQ(((320 * 1024 * 1024) / 2) * 3, + PreferredCacheSize(50000 * 1024 * 1024LL, + net::GENERATED_NATIVE_CODE_CACHE)); + } + + // Check no "percent_relative_size" matches default behavior. + { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + disk_cache::kChangeDiskCacheSizeExperiment); + for (const auto& test_case : kTestCases) { + EXPECT_EQ(test_case.expected_without_trial, + PreferredCacheSize(test_case.available)); + } + // Check that the cache size cap is 50% higher for native code caches. + EXPECT_EQ(((320 * 1024 * 1024) / 2) * 3, + PreferredCacheSize(50000 * 1024 * 1024LL, + net::GENERATED_NATIVE_CODE_CACHE)); + } } } // namespace disk_cache
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index c6b3e77..8f284709 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -1499,6 +1499,8 @@ backend_factory_.reset(); // Reclaim memory. if (result == OK) { disk_cache_ = std::move(pending_op->backend); + UMA_HISTOGRAM_MEMORY_KB("HttpCache.MaxFileSizeOnInit", + disk_cache_->MaxFileSize() / 1024); } }
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 019a35c..aa5901f 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -1531,7 +1531,6 @@ { "name": "fedorapeople.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gamercredo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "garron.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gerardozamudio.mx", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gmcd.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hack.li", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hexony.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -2155,7 +2154,6 @@ { "name": "mh-bloemen.co.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mimovrste.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mittenhacks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mnemotiv.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "munuc.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mustika.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mvsecurity.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -3078,7 +3076,6 @@ { "name": "dogoodbehappyllc.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dreid.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-deca2.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "elitehosting.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "empowerdb.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "entrepreneur.or.id", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eol34.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4435,7 +4432,6 @@ { "name": "textualapp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "theater.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thehistory.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "thestagchorleywood.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thorbiswebsitedesign.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tlo.network", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "torprojects.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4457,7 +4453,6 @@ { "name": "unwiredbrain.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "uvarov.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "valentin-sundermann.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "veriny.tf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vincentcox.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vsund.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "walkeryoung.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4513,7 +4508,6 @@ { "name": "budgetalk.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "burningflipside.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "casperpanel.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "cfa.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "chic-leather.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "chijiokeindustries.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "chun.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4534,14 +4528,12 @@ { "name": "englishbulgaria.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eurostrategy.vn.ua", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eveseat.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "exekutori.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "familieholme.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fastcomcorp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "felisslovakia.sk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ff-bad-hoehenstadt.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fhcdn.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "filoo.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "flajshans.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "flat.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "florian-schlachter.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fortress.sk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4819,7 +4811,6 @@ { "name": "isaacman.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "isondo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jacobphono.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "jamesrains.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jcraft.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jennythebaker.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jonaskjodt.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4994,7 +4985,6 @@ { "name": "vapordepot.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "varghese.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vgatest.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "videnskabsklubben.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vikashkumar.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vimeo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "volcrado.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5040,7 +5030,6 @@ { "name": "alkami.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "alkamitech.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "angristan.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "annabellaw.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "approlys.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aquilaguild.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "arabdigitalexpression.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5619,7 +5608,6 @@ { "name": "ecogen.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ecogen.net.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eduif.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "einsatzstellenverwaltung.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "electricant.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "elektropost.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "element-43.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -7511,7 +7499,6 @@ { "name": "openvz.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "optumrxhealthstore.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "orcamoney.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "orionfcu.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "osmosis.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "oxynux.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pagewizz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -7555,7 +7542,6 @@ { "name": "renrenche.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "retrofitlab.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rheuma-online.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rhymix.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "riaucybersolution.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rk6.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "royzez.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8317,7 +8303,6 @@ { "name": "curacao-license.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cyberwire.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cybozu.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "cyclebeads.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cyfly.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cymtech.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cyph.audio", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8589,7 +8574,6 @@ { "name": "forbook.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "forex-dan.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fortesanshop.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "fortworth.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fotocerita.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fotopasja.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fotowettbewerb.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -9595,7 +9579,6 @@ { "name": "saunasandstuff.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "savingsstoreonline.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schooltrends.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "schoolze.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schreinerei-jahreis.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schritt4fit.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schroepfglas-versand.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11604,7 +11587,6 @@ { "name": "medicoresponde.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "meganreel.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "meme.institute", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "metricaid.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "microco.sm", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mightydicks.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mightydicks.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -13087,7 +13069,6 @@ { "name": "saturn.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sauvagebridge.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "savannahtasteexperience.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "savvysuit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sb.im", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schawe.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schd.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -13228,7 +13209,6 @@ { "name": "sys.tf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sysert.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "t-complex.space", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tailify.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "taiwantour.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "talentos.pt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "taler.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -13360,7 +13340,6 @@ { "name": "verein-kiekin.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "verfassungsklage.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "verifyos.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "vertner.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "veterinaire-cazeres-foucault.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "veto.fish", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vetofish.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -14726,7 +14705,6 @@ { "name": "scriptjunkie.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "s.how", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rokudenashi.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sainth.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rowlog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schadegarant.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "securetheorem.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16171,7 +16149,6 @@ { "name": "smeetsengraas.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sportsmanadvisor.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sinfulforums.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "split.is", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sevsey.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "simnovo.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "skyasker.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16265,7 +16242,6 @@ { "name": "timewasters.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "studentrightsadvocate.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "triadwars.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "uhm.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thewebsitemarketingagency.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ticktock.today", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tinyssh.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16887,7 +16863,6 @@ { "name": "cybertorsk.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "das-sommercamp.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cyber-konzept.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "dansk-skole.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cuppycakes.fi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "de-rwa.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "derpumpkinfuhrer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16950,7 +16925,6 @@ { "name": "deurenfabriek.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dogmap.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ditrutoancau.vn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "dognlife.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "digitalrights.fund", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "distrilogservices.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dress-cons.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16963,7 +16937,6 @@ { "name": "deuxsol.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "diare-na-miru.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "deuxvia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "darbtech.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dokelio-idf.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "doked.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dopply.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -17096,7 +17069,6 @@ { "name": "fix-the-timeline.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fix-the-timeline.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fixthetimeline.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "everything.place", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fbijobs.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "europapier.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "easyocm.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -17385,7 +17357,6 @@ { "name": "ithakama.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ipv4.gr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "infinity-lifestyle.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ibizatopcharter.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "huroji.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ipfp.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "invisionita.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18483,7 +18454,6 @@ { "name": "winsufi.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webstationservice.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "willstamper.name", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "welsh.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vodpay.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wahlman.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vivocloud.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18786,7 +18756,6 @@ { "name": "backterris.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "awan.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "amlvfs.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "artstopinc.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "azamra.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ayahuascaadvisor.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "asseenfromthesidecar.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18832,7 +18801,6 @@ { "name": "bendigoland.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "agridir.site", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "asepms.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ac-epmservices.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bbwteens.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "begabungsfoerderung.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "betseybuckheit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19102,7 +19070,6 @@ { "name": "criminal-attorney.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "defendinnovation.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "danielmoch.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "dataprotectionadvisors.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dcrdev.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dachdecker-ranzenberger.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "curio-shiki.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19626,7 +19593,6 @@ { "name": "insping.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "harbourweb.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "imagine-programming.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "imefuniversitario.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "inschrijfformulier.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "incontrixsingle.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "imed.com.pt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19925,7 +19891,6 @@ { "name": "marcosteixeira.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lewisllewellyn.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "manueldopheide.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "maryjruggles.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "main-street-seo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "macht-elektro.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "matlss.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20975,7 +20940,6 @@ { "name": "yd.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xvt-blog.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webdesignplay.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "zohar.shop", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zamis.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "yomepre.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "woi.vision", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -21329,7 +21293,6 @@ { "name": "feastr.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "feedstringer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "felixkauer.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ferdies.co.za", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ffprofile.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "figura.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "film-tutorial.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22201,7 +22164,6 @@ { "name": "aloalabs.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "alpenjuice.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "alphabrock.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "alstroemeria.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "altamarea.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "altbinaries.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "altercpa.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22306,7 +22268,6 @@ { "name": "austinmobilemechanics.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "authinfo-bestellen.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "author24.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "autoecolebudget.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "averen.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "avonlearningcampus.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "avtoforex.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22454,7 +22415,6 @@ { "name": "bookwitty.social", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "booox.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bootikexpress.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "bopera.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "borahan.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "borg.cloud", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "born-to-learn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22483,7 +22443,6 @@ { "name": "brentnewbury.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "brgins.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "brianroadifer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "brickyardbuffalo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "brisbanelogistics.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "britishbeef.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "britishmeat.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22904,7 +22863,6 @@ { "name": "dunashoes.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dunmanelectric.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "duskopy.top", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "dvx.cloud", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dwworld.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dxm.no-ip.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dycem-ns.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22917,7 +22875,6 @@ { "name": "dyz.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dzomo.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-migration.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "e-newshub.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-tune-mt.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-vau.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-wishlist.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -23470,7 +23427,6 @@ { "name": "immortal.run", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "impulse-clan.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "impulsionsa.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "inares.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "incowrimo.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "indarceky.sk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "index-games.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -23828,7 +23784,6 @@ { "name": "lszj.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ltls.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ltu.social", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "lubbockyounglawyers.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lubomirkazakov.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lucasgymnastics.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lucy.science", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -23989,7 +23944,6 @@ { "name": "mi-beratung.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mianfei-vpn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "miaowo.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "micasamgmt.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "michu.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "microsoftaffiliates.azurewebsites.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "midnight-visions.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24421,7 +24375,6 @@ { "name": "pouets.ovh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pourmesloisirs.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "power-flowengineer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "power-l.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pozyczka-bez-zaswiadczen.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "preexport.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "prefix.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24460,7 +24413,6 @@ { "name": "pschierl.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pseta.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "psicoexpansao.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "psicosalud.online", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "psm.org.ph", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "psono.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "psychintervention.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24880,7 +24832,6 @@ { "name": "spinspin.wtf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "spoketwist.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "spokonline.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sportxt.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sprk.fitness", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sputnik1net.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "srv.so", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24934,7 +24885,6 @@ { "name": "support4server.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "supportericking.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "surasak.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "susc.org.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sushikatze.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "suspension-shop.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "svc-sitec.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24951,7 +24901,6 @@ { "name": "system12.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "szyndler.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tagesmutter-in-bilm.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tahosalodge.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "taishon.nagoya", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "taiyouko-hatuden.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "takemoto-ped.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -25581,7 +25530,6 @@ { "name": "aholic.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "abbas.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "africanexponent.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "algebraaec.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "abobuch.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "allsearch.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aip-marine.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -25739,7 +25687,6 @@ { "name": "austromorph.space", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aveapps.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "avedesk.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ateliernihongo.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bangdream.ga", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "autostop-occasions.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bakongcondo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26352,7 +26299,6 @@ { "name": "elsvanderlugt.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "elpay.kz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "erikheemskerk.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "environmentkirklees.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "drivingtestpro.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dubrovnik-dental.clinic", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "essaypro.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26689,7 +26635,6 @@ { "name": "henneke.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "growingmetrics.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "henhenlu.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "harveymilton.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "healththoroughfare.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "guelo.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hanakaraku.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26840,7 +26785,6 @@ { "name": "ichasco.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "islief.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ipal.tel", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "interboursegeneva.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "intimici.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "intermax.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jackyliao123.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27094,7 +27038,6 @@ { "name": "leavesofchangeweekly.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jwolt-lx.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "libdeer.so", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "laurent-e-levy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lbgconsultores.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lescomptoirsdepierrot.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kominki-sauny.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27664,7 +27607,6 @@ { "name": "projectunity.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "phcimages.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pornohub.su", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "pmconference.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "proovn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "project.supply", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "princessbackpack.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27999,7 +27941,6 @@ { "name": "silvergoldbull.co.tz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "scistarter.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "silvergoldbull.cm", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "snap.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "securoswiss.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "silvergoldbull.ws", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "snerith.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28068,7 +28009,6 @@ { "name": "socializam.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "steamtrades.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stitthappens.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sospromotions.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sprachfreudehoch3.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stevedesmond.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stlucasmuseum.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28215,7 +28155,6 @@ { "name": "theory-test-online.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thesecurityteam.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thepartner.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "thecuppacakery.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "the-webmaster.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sundanceusa.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thecsw.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28431,7 +28370,6 @@ { "name": "warp-radio.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vivo.sx", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "viking-style.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "wavefloatrooms.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "veganosonline.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vroedvrouwella.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "voterstartingpoint.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28681,7 +28619,6 @@ { "name": "zonemaster.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zilsen.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zopy.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "zurickrelogios.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zilon.com.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zentience.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xn--dckya4a0bya6x.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28847,7 +28784,6 @@ { "name": "apparels24.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bbka.org.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "atorcidabrasileira.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "angelinahair.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "berduri.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "belpbleibtbelp.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "beetgroup.id", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -29150,7 +29086,6 @@ { "name": "dosipe.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eaimty.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "divertiagua.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "dfrance.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "devkid.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dzsula.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "discountmetaux.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -29643,7 +29578,6 @@ { "name": "lockyourcomputer.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "linux-vme.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "linkage.ph", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "logimagine.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kswcosmetics.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "loqyu.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "leclaire.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30245,9 +30179,7 @@ { "name": "sim4seed.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sexshopfacil.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "smartvideo.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "snake.dog", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "skysuite.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "showdepiscinas.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "smartshoppers.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "socal-babes.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sneed.company", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30884,7 +30816,6 @@ { "name": "aquarium-supplement.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "arcenergy.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "arian.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "artsinthevalley.net.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "atlantahairsurgeon.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "atwonline.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "auntie-eileens.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -31110,7 +31041,6 @@ { "name": "subwayz.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sussexwebdesigns.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "swissid.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "talltreeskv.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tdrcartuchos.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "teknemodus.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tempdomain.ml", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -31420,7 +31350,6 @@ { "name": "klustermedia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kneblinghausen.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "knightsweep.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "koddsson.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "komintek.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kotori.love", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kplnet.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -31628,7 +31557,6 @@ { "name": "tfx.pt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tfxstartup.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tfxstartup.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tgmkanis.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thebasebk.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thegym.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thehivedesign.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32677,7 +32605,6 @@ { "name": "macaw.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mach1club.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "magasindejouets.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "magentapinkinteriors.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mahansexcavating.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "maik-mahlow.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mailjet.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32721,7 +32648,6 @@ { "name": "mehmetakif.edu.tr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mehr-schulferien.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "meierhofer.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "melakaltenegger.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "melaniebernhardt.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "melbourneapartments.website", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "melina-schefczyk.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32847,7 +32773,6 @@ { "name": "omnisiens.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "on-te.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "on-tech.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "onestepfootcare.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "onlinebillingform.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "onlinecasino.vlaanderen", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "onlineth.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -33091,7 +33016,6 @@ { "name": "sieulog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "significados.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "siikarantacamping.fi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "silviamacallister.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "simpleinout.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "simplewire.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "singerwang.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34053,7 +33977,6 @@ { "name": "affordablebouncycastle.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "afi-business-consulting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aflowershop.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "agileecommerce.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "agrikulturchic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "agrilinks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aid-web.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -34537,7 +34460,6 @@ { "name": "ekaigotenshoku.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elderoost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "electronicafacil.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "elitebouncingfun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elliesbouncers.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ellisamusements.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ellisleisure.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -35175,7 +35097,6 @@ { "name": "sandhaufen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sandmanintel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sanepsychologen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "saudavel.com.vc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "savethedogfishfoundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scallywagsbouncycastles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scamblockplus.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -35304,7 +35225,6 @@ { "name": "thewebsitedoctors.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thexfactorgames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thinkingplanet.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thosci.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thxandbye.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ticketsvergleichen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tiggeriffic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -35481,7 +35401,6 @@ { "name": "fun99.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ggma.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hacksoc.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "howtogosolar.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "improvingwp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "innovamag.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jogi-server.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -36172,7 +36091,6 @@ { "name": "aciety.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "acousti-tech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "across.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "actc81.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "advento.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aerisnetwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aerobotz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -36586,7 +36504,6 @@ { "name": "steuerseminare-graf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stonewuu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sulian.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sunboxstore.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "supermil.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sve-hosting.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "systemli.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -36736,7 +36653,6 @@ { "name": "balconsverdun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bankofrealty.review", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "baustils.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bcradio.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bennygommers.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bgr34.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bilsho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37086,7 +37002,6 @@ { "name": "sana-store.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sandyrobsonhypnotherapy.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sanilodge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sbsnursery.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sci-internet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scp500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "searchgov.gov.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37110,7 +37025,6 @@ { "name": "ssuitesoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stackhub.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "standardequipment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "stanthonymaryclaret.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stevenz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stimmgabel.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stuarts.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37844,7 +37758,6 @@ { "name": "gorognyelv.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gotrail.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "grahamcluley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gram.tips", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "grandcafetwist.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gratiswifivoorjegasten.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "greatagain.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39633,7 +39546,6 @@ { "name": "walkingrehabilitation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "water-addict.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "watoo.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "webharvest.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webqualitat.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webworkshop.ltd", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wechatify.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39749,7 +39661,6 @@ { "name": "alexanderneng.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alparque.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amirmahdy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "amleeds.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "andreagobetti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "andycraftz.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ange-de-bonheur444.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40413,7 +40324,6 @@ { "name": "webcreation.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wedotrains.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wegethitched.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "wellmarts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wemovemountains.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "west-trans.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "westcanal.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40719,7 +40629,6 @@ { "name": "fnbnokomis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "followthedog.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "foundchurch.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "frankinteriordesign.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "freitasul.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "freitasul.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "frequentflyerapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40900,7 +40809,6 @@ { "name": "myphotoshopbrushes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "myproxy.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mytfg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "naomiheji.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "narenderchopra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nationalhomequotes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nationwiderealtyinvestors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41837,7 +41745,6 @@ { "name": "somosnoticia.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "spanda.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "staklim-malang.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "stefanorossi.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "storytea.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stuartmorris.id.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stuartmorris.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42108,7 +42015,6 @@ { "name": "dumont.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "duonganhtuan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dwbtoftshit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dwellstudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dybuster.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dynamicdesignuk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "e-bikesdirect.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42154,7 +42060,6 @@ { "name": "fly-en-drive.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flydrivesicilie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flyswoop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "folwark.krakow.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "folwarkwiazy.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "forum-heg.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fotoflits.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42169,7 +42074,6 @@ { "name": "furrytech.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "furtherfood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gailfellowsphotography.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gansleit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gaphag.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "garforthgolfclub.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "garten-diy.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42618,7 +42522,6 @@ { "name": "abe-medical.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abraxan.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abristolgeek.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "absolutehaitian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "accelerator.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "acem.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "addnine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42958,7 +42861,6 @@ { "name": "kine-duthil.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "koi-lexikon.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "koirala.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "koirala.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kokoiroworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kolbeinsson.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kolonie-am-stadtpark.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -45897,7 +45799,6 @@ { "name": "physiotherapie-seiwald.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pikimusic.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pildat.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pineapplesapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pinner.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pizzalongaway.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "planet-laas.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -46714,7 +46615,6 @@ { "name": "papiermakerijdehoop.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "papiermeteenverhaal.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pawelurbanek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "paytonmoledor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "peda.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "perala.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "perthhillsarmadale.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -47099,7 +46999,6 @@ { "name": "hanschventures.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hansen-kronshagen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hearty.ooo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "henchman.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hikarukujo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hilde.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hildegardis-schule.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -47148,7 +47047,6 @@ { "name": "locksmiththewoodlands.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "logoesun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "louerunhacker.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "luxurytimepieces.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lwhate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "m-chemical.com.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "m-warrior.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -47244,7 +47142,6 @@ { "name": "serveradium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sesam-biotech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sintaxis.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sisver.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skills2serve.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skrimix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skytec.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -47921,7 +47818,6 @@ { "name": "sandtonvipcompanions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sasioglu.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schemingmind.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "schwalliers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "se.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sealaw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sekoya.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48238,7 +48134,6 @@ { "name": "golighthouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gratisgamecards.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "guidebook.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hamcocc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "happndin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "havetherelationshipyouwant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "herbhuang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50510,7 +50405,6 @@ { "name": "premiumcredit.am", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "primoloyalty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "proact-it.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "procreditbank-kos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "programsareproofs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "project86fashion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "prolinos.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -51750,7 +51644,6 @@ { "name": "bonawehouse.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bongo.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bonux.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "boogaerdtmakelaars.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "botezdepoveste.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "botsindiscord.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bridgedirectoutreach.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54275,7 +54168,6 @@ { "name": "stb.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stbartholomewmanchester.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stbl.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "stbridgeteastfalls.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stcatharine-stmargaret.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stceciliakearny.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stelfox.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54913,7 +54805,6 @@ { "name": "ecosystemmanager.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ecuinformacion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "edeka-jbl-treueaktion.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "eden-eu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "edgedynasty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "edgefantasy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "edit.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -55485,7 +55376,6 @@ { "name": "ostgotamusiken.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "outplnr.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "overceny.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "owensordinarymd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "packagist.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pagalworld.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "paintball-ljubljana.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -56297,7 +56187,6 @@ { "name": "psychotechnique.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "psychotechniquetest.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "qkzy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "qlcvea.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "qpcna.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quadra.srl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "readyrowan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59693,7 +59582,6 @@ { "name": "firstsecurity.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "foroaranda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "foxbnc.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "foyer-laique-segre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "frietzombie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "funkfernbedienung-industrie.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "funknotaus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59726,7 +59614,6 @@ { "name": "joelving.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jogjacar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jungidee.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "junta.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "juyunce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kappharn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "karenwillisholmes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -60732,7 +60619,6 @@ { "name": "beeswarmrehoming.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bernar.do", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bernyweb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "besuccessful.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bi1gif.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bierwebshop.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bionima.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61079,7 +60965,6 @@ { "name": "vextraz.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vinosalmundo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vivemedialab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "voceempaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wage-feeg.gc.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wallis-inside.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "waterproofingahmedabad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61243,7 +61128,6 @@ { "name": "gelpinhos.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "georgeblack.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "giardiniere.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gloucestershiregospelpartnership.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "golkala.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "grabadolasermonterrey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "greenponik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61525,8 +61409,6 @@ { "name": "daniele.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "davidbrookes.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ddsmatchsouthwest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "deautomaat.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "deconsolas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "deltaservers.blog.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "devinite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "die-besten-bewertungen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61537,7 +61419,6 @@ { "name": "dirtytiles.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dnsrate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dsh.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dsimons.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dvlot.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ehorizon.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "embsaypreschool.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -62063,7 +61944,6 @@ { "name": "sbivc.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scouting-wageningen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scungioborst.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "securitydriver.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "senjukannonreiki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "serrature.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shuomingshu88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -64075,13 +63955,8 @@ { "name": "2692646200.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2941798824.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "30375500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "30375511.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "30375522.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "30375533.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "30375544.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "30375555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "30375566.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "30375577.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "30375588.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "30375599.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3054056550.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -64094,33 +63969,19 @@ { "name": "380201314.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3802024.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3802025.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222111.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222222.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222333.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222444.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380222999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3802288.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "3803300.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3804488.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3805201314.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3805355.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3805500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3805511abc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "3806600.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3806677.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3806789.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3807344.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3807711.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "3807722.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3807733.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3807755.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3808822.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "3808833.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3808844.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3808855.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3808866.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -64299,7 +64160,6 @@ { "name": "buckscountyobgyn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "buziaczki.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "caipao123.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "camdenboneandjoint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "campingshop.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "canavillage.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "candinya.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -65506,7 +65366,6 @@ { "name": "whatismyipv6.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whotracks.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wiocha.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "worthygo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ww5197.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ww9297.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ww9397.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -65712,7 +65571,6 @@ { "name": "buscasimple.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "caiben.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "californiawomensmedicalclinic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "campgesher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "canopytax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "capeannpediatrics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carolinapainandspine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -66353,10 +66211,7 @@ { "name": "uze-mobility.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uze-mobility.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uze-mobility.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "uze-mobility.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "uze-mobility.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uze-store.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "uze.mobi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uzemobility.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uzemobility.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uzemobility.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -66846,7 +66701,6 @@ { "name": "investigazione.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ips-consult.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iryogakkai.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ithelfer.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itsok.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ivoid.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "j-ph.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -66961,7 +66815,6 @@ { "name": "p1979.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "p6957.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "panevo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "partyhelfer.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pchancs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pe-bank.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pis.eu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -67795,7 +67648,6 @@ { "name": "k8082.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k8102.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k8106.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k81111.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k8125.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k816.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k816.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68349,7 +68201,6 @@ { "name": "universovalve.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "upmon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uze-mobility.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "uze-mobility.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uzemobility.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "valuecashhomes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "valuecashoffers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68826,7 +68677,6 @@ { "name": "comparemymobile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "confrerie-rp.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "connectium.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "copan.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cosentus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "crossnet.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cumnock.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68920,7 +68770,6 @@ { "name": "httpstest.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "httpswatch.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "httpswatch.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "humdingersnj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hwsw.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ibestproduct.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iccorporateinteriors.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70269,7 +70118,6 @@ { "name": "zl0606.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zl6767.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zl8824.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "00004048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "000a1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "000a2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "000a3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70282,7 +70130,6 @@ { "name": "000x2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "000x3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "00b58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "01234048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "012345678365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0123456789365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "018663.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70298,29 +70145,9 @@ { "name": "050a6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "065l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0681a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0681h.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681j.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0681k.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0681n.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681o.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681q.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681y.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0681z.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "068663.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0737399.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "078663.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70332,7 +70159,6 @@ { "name": "1190america.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "11b58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "1220323.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "12344048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "12345678365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "123456789365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "123seo.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70390,25 +70216,7 @@ { "name": "24848zz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "248663.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "25may.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878dd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878gg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878hh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878ii.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "27878jj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878ll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878nn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878oo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878pp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878qq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878rr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878ss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878tt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878vv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878ww.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878xx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878yy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "27878zz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "284365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2kvn.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2lovebirdsblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70503,15 +70311,7 @@ { "name": "365y99.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "365zg.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "380111000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380111111.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380111222.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380111333.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380111444.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380111555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380111666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "380111777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "380111888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "3809955.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3837b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3837c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3837d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70576,48 +70376,9 @@ { "name": "4025367.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "4025368.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "4025369.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "40481234.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "40482345.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "40484567.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "40485678.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "40486789.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048aaa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048ccc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048ddd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048eee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048fff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048ggg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048hhh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048iii.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048jjj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "4048kkk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "4048l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048lll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048mmm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048ooo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048ppp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048q.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048qqq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048r.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048rrr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048sss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048ttt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "4048v.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048vvv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048www.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048xxx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048y.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048yyy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048z.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048zzz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "408663.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "40n13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "416365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70628,7 +70389,6 @@ { "name": "444b58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "44b58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "451365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "45674048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "458663.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "476773.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "486773.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70648,12 +70408,10 @@ { "name": "51365dd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "51365ee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "52002c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "55554048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "555b58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "5566bet.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "55b58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "55n13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "56784048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "59759vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "59759z.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "5981844.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70766,7 +70524,6 @@ { "name": "666222bet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "666333bet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "666555bet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "66664048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "666777bet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "666888bet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "666999bet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70785,21 +70542,18 @@ { "name": "677384.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "678365cc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "678678365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "67894048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "70n13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "733575.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "74365365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "755243.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "755a.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "769k.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "77774048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "7788bet.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "77b58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "78365aa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "7888813.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "7888815.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "7888821.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "78904048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "80651a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "80n13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "811121.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70826,7 +70580,6 @@ { "name": "866394.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "88740n.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "888789j.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "88884048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "88n13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "8me.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "906vv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70839,7 +70592,6 @@ { "name": "97737.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "97738.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "97739.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "99994048.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "999b58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "99n13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "a30365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -75317,7 +75069,6 @@ { "name": "beticalia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bhat.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bibliology.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bigbendcoffeeroasters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "biggerpicture.agency", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bodegasvirei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brandfolder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -75631,7 +75382,6 @@ { "name": "thefuelcardpeople.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theoosmetalart.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theoutsiders.stream", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thriveafterabuse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "time.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tokitover.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tommyemo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -76159,7 +75909,6 @@ { "name": "finestrina.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fins.money", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fivestartrader.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "foodphotographyblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "forsi.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "frauen-etappenrennen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "g818city.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -76571,7 +76320,6 @@ { "name": "helkyn.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "helkyn.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "helkyn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hella-secure.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "herd-kaufen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "highclasseducation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "holacannx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77784,7 +77532,6 @@ { "name": "west-nerica.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whistleblowing.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wildrough.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "wohnbegleitung.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "writemyestimate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wsave.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wuz.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77995,7 +77742,6 @@ { "name": "i36594.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "icharme.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "id3global.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "idoo24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "impakho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imposingoods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imydl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78165,7 +77911,6 @@ { "name": "razalabs.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rc-respect.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "redper.serveminecraft.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "regateoapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "reinhart-auto.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "resolvergroup.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rfid-schutz.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78330,7 +78075,6 @@ { "name": "34365t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "36525.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "396228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "4048.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "44168365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "44365t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "444321365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78386,7 +78130,6 @@ { "name": "666321365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "666365t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "678365t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "7652.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "77168365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "777365t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "789365t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79904,7 +79647,6 @@ { "name": "swapfin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "swmlink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "systemdynamics.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "szkolajazdykaleta.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "t36533.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "taffe-elec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "taxisaeropuertomadrid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -80850,11 +80592,6 @@ { "name": "it-zt.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itsallsotireso.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ivanderevianko.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "j70101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "j70102.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "j70103.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "j70104.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "j70105.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "j7051.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "j7052.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "j7053.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81742,7 +81479,6 @@ { "name": "5icsb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9118.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9jabase.com.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "a-tes-cotes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abdelaliezzyn.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abdelaliezzyn.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "acronis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81851,7 +81587,6 @@ { "name": "cpls.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cry-sys.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cswebi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cumagini.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cyberdyne.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "d3a.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dabai.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83858,7 +83593,6 @@ { "name": "stijndv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stiliankasimov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stilingavonia.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sto500.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stoildaaliyski.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "storey-lines.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stpatsschool.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84512,7 +84246,6 @@ { "name": "tornadotwistar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "traditionalturk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trainoclock.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "transvolando.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "treezone.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trelloparea.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trenorario.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84632,7 +84365,6 @@ { "name": "advokat-vvp.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ae86zx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ahlstrom-filters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "alibamu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alphabet-z.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amanduscommunication.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ambra.net.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -85213,7 +84945,6 @@ { "name": "abellis-formation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abstechs.ae", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aclandia.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "adelina.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adi.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adi.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adinternational.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86049,7 +85780,6 @@ { "name": "theantisocialengineer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thebroadcastknowledge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thedanceacademybuckscounty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thedigitaleconomist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theflightsdesk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thejunkfiles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thestudioslucan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86105,7 +85835,6 @@ { "name": "vcanederland.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vdo-webshop.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vedatkarabacak.av.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "veiergangvermut.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "veryhome.com.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "veryssl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vezirecenzii.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86143,7 +85872,6 @@ { "name": "welfareness.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "welp-mail.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "westcoastmotors.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "westpointrealtors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wg-smue.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wheelsmaestro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whereapp.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86795,7 +86523,6 @@ { "name": "mojekonsultacje.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "monsterx.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "moviro.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mrjones.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mycompanysite.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nanxin.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nayefalebrahim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87011,7 +86738,6 @@ { "name": "alaturkaonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "albionfaeries.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alchemyvfx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "alibamu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alwa.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "am-globalgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ameeradubai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88028,7 +87754,6 @@ { "name": "usawireguard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uzay.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vanuithartenziel.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vg-store.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vizedia.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vleo.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "volcano-ug.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88077,7 +87802,6 @@ { "name": "yt892.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yt962.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yt972.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "zenown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zidanpainting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zumtaedanceschool.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zupit.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88567,7 +88291,6 @@ { "name": "hillingshaeuser.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hinderlider.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hinota.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hiphop2gif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hjallboscoutkar.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hjdiaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hjosh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88645,7 +88368,6 @@ { "name": "jewelryweluv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jg078.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jmussman.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "johnbeil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "johnopdenakker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jollyjoker.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jonathonkimmel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88934,7 +88656,6 @@ { "name": "priceofdollar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "prior.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "prismapixel.studio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "proactivediscovery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "promo-mobilhonda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "prostoporno.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "proximasrl.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89260,7 +88981,6 @@ { "name": "wiwi.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wolfshoehle.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "woodenwindowco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "workoptions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "worldfoodfestival.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "worldhairtrends.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wowede.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89863,7 +89583,6 @@ { "name": "ligadelconsorcista.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lina-stores.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lingroove.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "linkie.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "linuq.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "livingmachines.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "liznewton.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -104591,7 +104310,6 @@ { "name": "brajenovic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bran.cool", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "braxtonehle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "brooklynreclaimed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "businessguide.co.ke", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bytetime.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "c-netsys.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106518,7 +106236,6 @@ { "name": "milwaukee-webdesigner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "minipigscare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mirador.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mitzycoach.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mode-tabita.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "moe.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mojama3dz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106807,7 +106524,6 @@ { "name": "bomull.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brandon14.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bravoasociados.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "burz.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "burz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bwmcnc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "c1cdn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107682,7 +107398,6 @@ { "name": "mamapatrzy.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marinelife.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "markocloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "marturet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mascarillas.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "matega.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mclanedirect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108036,7 +107751,6 @@ { "name": "disenoyarquitectura.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "displayrd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "djmcadam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "djmoremusic.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dogwoodceramics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dominicself.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dominicself.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109474,7 +109188,6 @@ { "name": "cardschat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carevo.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carsonkoziol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cbcf.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cbd-oil.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ccaguavivadonaciones.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cctf-m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109718,7 +109431,6 @@ { "name": "minetrack.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "modulkuhni.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "monidenum.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "muellercustombuild.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "museodefutbol.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "museumofautism.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "musicbow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -110722,7 +110434,6 @@ { "name": "j-harrison.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jepa.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jesusdenazaret.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jhandke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jngle.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "joostmaglev.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "joshimedical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -112098,7 +111809,6 @@ { "name": "sendai-works.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sfltrends.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shadowsproject.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "share-links.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sheptytsky.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shinobayderm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shireyishunjian.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -112239,7 +111949,6 @@ { "name": "akshit.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aktivterapi.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "albertohurtado.fyi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "alfarisnet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "allline.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "allsarms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alphaconvites.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -114205,7 +113914,6 @@ { "name": "repat.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "risalatconsultants.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rodsct.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "romao.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rpschultz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rujbin.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rwalch.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -115347,7 +115055,6 @@ { "name": "hakuna.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "haluan.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "happiestoutdoors.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "happycoders.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "happycolors.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "harakahdaily.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hardinal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -115934,7 +115641,6 @@ { "name": "ubuntu-tr.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ufone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ufuq.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "umniah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unblockit.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "understrap.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uniritter.edu.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -116087,7 +115793,6 @@ { "name": "binabangsaschool.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "biologichemp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bioselect.com.cy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "biuaxia.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blastoise186.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blau-weiss-stolberg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "boostbazar.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -116729,7 +116434,6 @@ { "name": "mcsmart.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mds.cool", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mediaweb.com.ve", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "melikecapkin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mendosuits.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "michaelwmckinney.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "minimal-website.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -117621,7 +117325,6 @@ { "name": "lab-advancedservicesportal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "labadusa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lastrik.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "layarsosial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "letzi-immobilien.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "libget.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lifebun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -119558,7 +119261,6 @@ { "name": "shinyoko-saisyuusyou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shirosaki-hana.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shivering-isles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "shopcon.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shoppingplaza.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shunliandongli.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sid-giessen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -121111,7 +120813,6 @@ { "name": "bijlokesite.gent", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "biomassinfo.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "biotal.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bitcoinyab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blackfridaynew.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blits.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bluesheep.cool", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -121163,7 +120864,6 @@ { "name": "clinica.zapto.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cloudfree.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cloudfudge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "coach.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "codecrew.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "colorpalette.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "comfy.gay", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -121358,7 +121058,6 @@ { "name": "lightfestivalghent.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lightfestivalghent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lisbon-pre-1755-earthquake.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "livelinen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "livingthegreenlife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "loser.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lucasrl.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -121409,7 +121108,6 @@ { "name": "megavasoc.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mein-neuer-garten.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meldsluikstort.gent", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mermaidboattrips.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meshekard.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "metavr.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mevrouwtjepeper.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -121692,7 +121390,6 @@ { "name": "stlouisfence.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stockt-shirtdesigns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stomproced.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "stpetersresidence.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "strangerthanusual.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "straniero.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "strattonhats.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -122070,7 +121767,6 @@ { "name": "cantical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "capehipandknee.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "capitalgrio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "captaincoder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carespanclinic.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carolcoleventures.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "casadomus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -122510,7 +122206,6 @@ { "name": "lesley.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lgscripts.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lick.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lifehouseliving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lights0123.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "line-magazine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lingeries.boutique", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -123211,6 +122906,4368 @@ { "name": "zqwqz.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zsdublovice.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zukunft-mobilitaet.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "011101.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "0906-clan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "0culus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "10000spoons.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1100110.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "12socialsmansa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "14e.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1800shutters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "183cm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1989studio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1breadcrumb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1breadcrumb.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1up.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2018-frisuren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "24onlain.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2driver-ok.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3dflat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3dreal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3techjournal.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4305design.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4am.click", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4ree.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "52weekspodcast.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "701squad.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "808cleanups.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "848sf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "a-pradana.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "a7techs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aanhuisgebakken.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aarklendoia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aautoline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ab-pflege.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abc-people.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abcsystem.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abibliasagrada.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "about-jewelry.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutgrills.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutrom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutshakil.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutwealthcreation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abroferlendo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "absat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "absolutezero.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "absolutweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abusamraphotography.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abyzebyzek.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "academiacivilbalonmano.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "academiaeureka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acapetahua.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acceleratedreading.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accelerator.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accessiware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accessories-for-women.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accioninmobiliaria.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accordproject.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accustomedicals.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acebovirtual.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acefishing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acftienda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "achill.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acronaline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "actimap.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "activohotels.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acutane.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adamlevine.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adamraoof.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "addbonus.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "addmefast.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adelonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ademaulana.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adextremadurafs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adi.company", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adiesyndrome.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adminova.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adorewe.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adrenalinhunters.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adrian2023.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adrianpole.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "advertising-design.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aeroflot.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aerospacearchives.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afg-team.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afgraphic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afiador.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afrodita.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afroditafirm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afxsoft.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agasport.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agenciaempleo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agencxy.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agility-westvlaanderen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agnesmatilda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agnosia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agoradanza.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agralines.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agricultural-technology.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agrish.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agrodoki.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agron.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aguaviva.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agujetas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agustinperalt.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aibolit-apteka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aibolitik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aidablanco.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aimlessempire.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "air-rishon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airborne-clan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airfoto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airi.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airjordanpascher.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airpark-roissy.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airport-car-rental.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airsoftpinoso.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airzone.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aisthesthai.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ajaxforever.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ajforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "akachanwebsite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "akdenizim.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aketzasantacoloma.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "akf-plastics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "akiranet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aksaramedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alankardresswalla.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alansilson.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albagold.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albalew.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albaniachat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albarugby.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albertgibb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albinvega.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alcapalis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alcar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alcaralifusi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alchemisten.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alcionesakugawa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alcoholicbeverages.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alcoholismtreatment.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aldealices.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alegromania.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alejandromunoz.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alekseevski.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexanderg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexgonzalez-online.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexispoficial.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alextweewielers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alfabank-info.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alfonso-baya.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "algerie-music.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "algorista.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aliasinfoforums.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alicemag.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aljullusims.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "all-for-u.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "all4web.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allarticles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allbridges.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allegorymetal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allenacampbell.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allergento.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allergictoidiots.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allevamentoticinella.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allforhon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allhallows.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allmagic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allrepair.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alltherapies.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allthestuff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allthewaynorth.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allvideofoot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "almarail.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aloe-vera-info.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alquila-tu-casa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alquran-online.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alrobotics.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alsaagency.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altacomunicazione.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alternativagospel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alternative-e-energy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altovoltaggio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altralamezia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alukard.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alvarovega.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alxclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alzon.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "am-sonnenblick.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "am-sonnengarten.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amasing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amazonemotions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ambigramasdecarmela.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amdukis-bordercollies.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "americafc.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "americangods.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amigodeltoro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amigosdelvalenciadeastorga.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aminfarhoodi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amortyzator.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amorymerced.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amplifier-technics.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amputatedgenitals.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amstelradio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "analogical.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anamterminal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anarchyweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anarshist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anatomized.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ancentury.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andaluciaboard.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andcable.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andr-mobile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andreapalermo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "android-it.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andycatteceur.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andythomasonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anetteolzon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "angelarellano.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "angeltorri.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "angermanalvorna.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "angrybear.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aniblizzard.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anime-dragoon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "animeronews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ankaradaozelders.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "annalisefashion.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "annulleret.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anpigabon.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anradienstverlening.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antikvar-i-ya.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antishell.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antivirusnet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anton-media.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antoshka-net.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ants-carte-grise.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anubislinux.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anvilmetal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anvilsales.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anyshapemusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anyuta-mebel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aodnovel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aosclan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apertura.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aperturescience.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apertvre.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aplteam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apocalipsisdot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apopov.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apotom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "app-online.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "app.do", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "app.ps", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "appliances-for-home.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apresski-pictures.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aprilagentur.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apstats.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apsua.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aptekas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aqua-fm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aquabotanic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aquadarts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ar-oma.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ar-vernet.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arabicclass.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arabmusic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "araluenvalleyhotel.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aranym.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "architectsecurity.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arcoiriscastellon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arenadagon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "argentumonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arkhamasylum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arnottindustries.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arny.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arquipielago.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arrowduty.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arsenideas.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arshia.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "art-khotyn.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artadagroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artcommunity.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artdecoration.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artelignum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artemida-dot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arteproducciones.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arteshesorkh.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artetculture.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artextasia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "articlesplanet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artificiala.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artspark.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artvaastu.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artvinhaberleri.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asancharge.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asankomara.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asiacommerce.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aslamazyan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asonaderi2002.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asperox.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asriyatno.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "assana.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "assedo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "assessorindie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "astrologiatarocchi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "astrologic.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "astrostart.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "astucedirecte.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atakac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "athenainvestmentsystems.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "athenainvsys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "athenaspark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atmos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atnteam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "audioboomers.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "audiomir.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "audiotrace.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "audiovisualmurciano.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "auditingfirm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "augustanews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "auscube.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "austriahikingtours.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autenticismo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "auto-parts-store.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autoaircon.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autodocument.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "automir.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "automosanto.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autoparts-for-foreigncars.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autosneed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autosprint.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "auxilium-informatique.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avacatossiu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avalancha.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avaland.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avalonaardoom.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avanguardia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avaralar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aviaphoto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avinguard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avrilshine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avto-bazar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avtochip.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "awh.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "axavalon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ayon-games.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "azula.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b-utstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "babacuhocica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "babo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baby-tester.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bac-fiches.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "backwardsalphabet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "badassfantastico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "badmintonoverdag.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "badpreachers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baenoticias.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baircentral.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bakuze.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "balcony.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ballonnenopdakpannen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bamoza.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bandirmaevdenevenakliyat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bandures.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bandwagon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "barataeletrica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "barcoder.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bariatricsurgerynewjersey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "barrikade.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "barruntos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baseballpitchingmachine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bashkiria.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bashkiria.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "basiclimits.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "basicwallpapers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bastardator.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "battlefield1942.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "battletech.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "batucadastore.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "batukhan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bayscollisionrepairs.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bdfriends.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bdsmdating.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beachsoccer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beatfreaks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beatsdope.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beauty-blog.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beautyisfine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beckdesign.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beckylicious.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bedofcorpses.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beefclan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beerarchy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beergifts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beersheba.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "behemoth.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beinsports.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "belgianwesthoekclassic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bellafashion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bellesetrebelles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "belowzero.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "belrosstrakh.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benadesign.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bendminding.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bengalcat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bengkelkeramik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benjonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bentpunk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benzblog.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bepositive.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bepzi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beresbalazs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bermellar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "berthaphil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bessels.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "best-cat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "best-chiter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestanswer.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestdslrcameras.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestgriefbooks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "besthairsale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "besthomescents.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "besties4life.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestreleases.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "besttipsntricks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betatester.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betemyja.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betonsport.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beverley.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beyond360view.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beyond3dview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beyond3dviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bgmall.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bgtraffic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bibi-xxx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bicignet.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bidgreat.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bienvenue.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biflosgknm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "big-papa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigeaglesacademy.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigfreebielist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigpage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigrender.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bijzonderekiekjes.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bikesandbits.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biketrainer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bikini-shop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bikinibich.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bikinis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "billets-avion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "billybob.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biohazardonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biolegsanonims.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biotec.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "birmans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bistro-dengi.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitkub-app.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitkub-invest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitwok.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bizzybee.buzz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bjordanov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bl-builder.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "black-air-rpg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blackboxcity.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blackdot.casa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blackeaglenet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blackfirecrew.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blacklodge.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blacksport.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blaizer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blankstore.com.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blazingsuns.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bleaklyrics.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blinniza.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blitzcraft.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blitzlotto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blood-kirsche.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bloodandbones.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bloodybiz-news.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blue-python.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluecat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluecherry.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluesbarn.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluesystem.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blumenversand.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bobbyfischer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bodymod.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bojan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bologoe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bolosbatiente.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bomberosceuta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bonbonshop.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bonebreakers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bongoland.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bonitamacas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bonukset.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bookmark.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bootswinter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bosquedelasimagenes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bountyhuntermetaldetector.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bouwbedrijfdevor.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "boxeomexicano.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "boxing-kangaroo.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bozenadusseau.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bplan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brandoncricket.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brands-clothings.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brandsclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "branefive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "braniebananie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brasilweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "braslet-bianshi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bravebiz-news.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "breakeven.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "breakfree.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "breathingsound.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "breathlesssheranda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brechtheldens.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brentalbright.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brest-biz-belarus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brest-brest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brest24.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bribriescolawfirm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bricks-clicks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bridal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "briefbiz-news.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brigadasazules.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brightbiz-news.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brightonfc.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brightzoneofficecleaning.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brilliant-minds.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brinokidzonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "britneymanias.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "broadbiz-news.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "broadwayfamilydentalpc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brokenbiz-news.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brokentoaster.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bronx-ny-dentist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brooklynabortionclinic.nyc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brooklyngynplace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "browntiger.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bruceleeitems.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brunamarquezine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brunocesarlima.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bubblelist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buckthorn.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bufo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buick1958.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buildconcierge.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bulldogkennel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bullfitta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bunker307.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "burdurhaber.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bureauscript.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "burgoslacrosse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "burmania.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "burning-wheels.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buscaebooks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buscatodo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "businesslabs.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "busstation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "butik-mechty.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buy-lingerie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bypassgfw.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bytovetextilie.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ca-canovelles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caboverde.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cacoriccionline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cadonet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cafeamazon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cagivaclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caise.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cajadelparque.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "calconcontractors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "callfordataspeakers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "calwildgarden.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cameraman.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camilamoreno.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caminoneocatecumenal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camionerosdecoslada.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camisantiago.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camplaza.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "campushelloworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "campwaltblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camrosewebservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canadacommunity.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canadianmilitaryspouse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canarypower.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cancertherapy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "candados.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "candas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canetelareal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cantarefacile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cantarella.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "capitalscum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caps.equipment", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caps.solutions", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caps.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "capsuladigital.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "captainscarlet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "captainsunshine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "car-alarm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "car-market.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "car-touch.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caravansciences.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caravelairclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cardpaymentoptions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carkeysystem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carl-blum-haus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carlosguadian.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carmela.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carnica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carnivalcostumes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carpentrybyallen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carpio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carpticon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carrion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carroattrezzi.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carryvanbruggen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carsworld.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartomancieperso.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartoservice.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartridgesave.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartunings.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casa-indigo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casa-prince.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casadasmolas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casadedios.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casafina.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casalopez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casandraemge.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casanuova.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casapedra.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casatendeiro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casca.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cashyourcar.sydney", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casinoonlineprova.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cassini.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "castagnola.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "castorio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catalog-clothing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catalog-lingerie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catalog-lingeries.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catalogcomputerhardware.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catalonia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cathrine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catpic.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catstv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catterydelmoria.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cavediving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cavemax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ccrun.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cedric-garcia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "celebrityfakes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "celestia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cellulare.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "celmetro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "celtacad.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cemetary.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cennetfm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cennetforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "centralcityjuniorkindergarten.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "centralcoasthomeloans.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "centralhq.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "centurymedicaldental.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cepsychologie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cernybureau.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "certainbiz-news.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "certificateofpurchasing.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cetelon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chaacker.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chaghi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chalet-maubuisson.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chaqueteros.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charlesdouglastec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charley.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charliez0.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charliez0.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charliez0.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charnego.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charqawi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chat-cam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheatmasters.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheazey.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheazey.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheazey.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chechencity.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheiloplasty.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chenfengmedical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheng.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cherylbelber.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chesapeakebank.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chetori.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chiamatehot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chickteam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chielonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "child-theater-bs.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "childcaremanagementcompany.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "childrensrecipes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chillipadi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chimcanhcut.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chinawatchinstitute.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chiro-merksplas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chiroherne.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chiromeisjes-boxberg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chiropraktik-wildner.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chizouworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chjeco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chollospain.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chosenos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chrisi-si.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christengroei.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christiangaro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christianleedunn.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christianmoore.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christmasrecipe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christophe-dubois.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chriswarbo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chronicles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chubr.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chuckval.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "churchforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "churchofchrist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "churchssja.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chuskocity.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cicavkleci.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cigarette-electronique.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cilt.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cinemaperto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cinematic.asia", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cineterror.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cinexilio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cinicsystems.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cinquecentoclubholland.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "circleofleastconfusion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cirocunato.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cisincometax.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "citans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "citations.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cityfacialplastics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cityhide.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ciulea.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cj8.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ckcg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ckdemo.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clairevoyance.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clamatohalloffame.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clanlegends.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clantemplates.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clanto.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "claresderibota.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "class-zone.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "claytonjunior.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clean-water-and-sanitation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clementsfamily.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cleverinsert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "click-cat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clickinfo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clickpool-server.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clickpress.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clinlife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clodoteam.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clonyitaly.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "closernow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "closets-cheap.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clothes-for-school.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clothing-2010.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clothingjeans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cloudicles.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clowd.haus", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clubtecknocore.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clubvttlesloupsdemaixe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cmlcpa.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cms-mania.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coag.gov.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coastalphysie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coats-and-jackets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cobbcountygeorgia.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cockmonkey.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cocktails-club.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cocservice.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cofradiaqueimada.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coin-group.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coincalc.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "colarose.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "collectivedg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "colloquio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coloradoer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "colossalit.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "colourmeren.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "columbiaboatalarms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comfuzztible.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "commfortchat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "communication-services.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "communitydirectory.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comoyoko.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "companyaneksta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "compustuff.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "computer-worlds.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "computerforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "computertech-ut.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comunistas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "concept5.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "concreterepairconcreteleveling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conexstudios.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "confio.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "confiscation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "congelado.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "congresistas-ap.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "connective.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conoha.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conspectstudios.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "constructionstudent.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "consulting-brokerage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "consultinghousenet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "contactsolo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "contagiousaf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "contralaespeculacioninmobiliaria.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "controlyourwifi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "contuestilo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conviction.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cookiehulp.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cooks.house", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coolwaterevergreendrilling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "copenhagenleadtech.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "copewithdata.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "copperexports.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coqiptv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corbium.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corbusier.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cordenka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corduroyproducts-velvetjackets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coreless-initiative.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coremicro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corexpert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corky.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corner-cabinets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corona-less.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coronastationphotography.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "correspondent.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corsi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cortonaeranieri.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corvetto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "costa-ballena.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "costum-for-men.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cougarlyon.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coursingweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cousins.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "covar.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coventry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coverful.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "covid19details.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cozy.town", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cpafirmnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cpfs-group.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cqswxx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crabtreestore.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "craiggettydecorativepainting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cratedb-dev.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cratedb.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cratedb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crates-io.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crazycube.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crazymonkey.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crazypotato.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crearesiteweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creartcol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creatieverd.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creation-photos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creativedesign.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crepusculofansmexico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cresoweb.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "criativedesign.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cricketnmore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crimefire.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "criminalminds.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crimsondragoncosplay.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "criptex.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crisisdelos40.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crismar-flora.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crisssmanmix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cristiengoller.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cristina.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cristnasar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cromwell-intl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crookedcru.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crotchrockets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryps.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crypticstench.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptoafternoon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptoanarchist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptonaire.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptonetlife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crystalcube.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "csnet.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ctt.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cuartob.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cues.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cuitrau.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "culturalmaninhos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cumbiaperuana.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "currencyfreaks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cursoandroid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cursos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "curtisplumstone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "customssupport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cxbmystore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cxologic.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cxologic.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyberbotx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyberplus.net.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cybertronics.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyclamen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cycleshop.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyclingbiker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cynop.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "d-systems.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "d1k1dblh0pghv8.cloudfront.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "d2woj1dt0tk6sn.cloudfront.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dadcentral.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daily-puzzle.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dailydosehealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daim-avtoelektrika.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dal-loop.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dallasretiredff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daltonlabs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "damarsarkilar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "damnation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "damuhan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dan-maskiner.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dance-school.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dancefm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielacocco.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielaferpe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danieleoneta.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielsinsuranceinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danniellealbrechtdesigns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danny.fm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dannytemming.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dantesinferno.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danwaibel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dark-legion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dark-programs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "darkcure.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "darkfirestudios.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "darkmanthra.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "darknessinme.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "darksecret.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "das-quiz-plugin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dastannevis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "data-mail.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "datazoo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "datingyourmate.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "datosfreak.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "datutoday.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "davefuller.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daynia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dazzlestart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dbase.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dc-design.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dderyce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ddlcmods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deadhead.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deadpvp.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deafsound.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dealsbythebay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dealstreet.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dealwithstatistics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deathwarrior.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "debeer.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "decorator.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "decsys.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deepsky.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "defenseweapon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "degravel.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deimist.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dekoration.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "delennerd.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "delta-games.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deltacountymi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "delzottolink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "demes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "demonmassacre.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "demontage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "denhartogracing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dennisswiers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dennistyfus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dentistinbrooklyn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "denunzieren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deonlineassistente.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "depapboeren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "depilestil.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "derinsular.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desconfiats.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desertfury.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desertlinealuminium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desertlinegroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "design-total.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "designeline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "designschmiede-oberlausitz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "designsite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desingslash.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desivideos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desonnemannen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desperatesailors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deswaffelaars.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devilbyte.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devilrecords.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devopsbookmarks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devpage.lv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devr.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dewerveling.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dextra.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dfmvf.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dfwmv.vote", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dg-pic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dialupnerdstech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dianakaarina.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diaryspace.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diccionariomexico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dictatronics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dida.xin", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diegoforlan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diegosalgado.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diengiolachoa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digibean.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digiland.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digiloop.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitaliandm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalnomadsunderground.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalsphere.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dik-manusch.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dikkevettescania.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diligenciasprime.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dimitris.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dinda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dinnerclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dinposition.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dippydyes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "directory-sunglasses.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "directoryworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disbug.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "discountpark.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "discrede.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "discshop.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disctranulis.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disengaged.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disenialia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dishwashermagic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disinfectingassociation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disinfectingassociation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disinfectingdoctor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "distilleren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "district09.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "district09.gent", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "divarjonob.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diversity-otherwise.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "divfinsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "divinitas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "divorcelawyer365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dixieweld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diyeat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diyeventhire.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dj-ac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dj-iliri.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dj-morfu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dj62.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djaad.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djakuza.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djalberto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djang.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djazair.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djbell.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djboomarang.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djddt.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djefsane.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djembeforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djfelix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djfilms.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djgarcia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djhypnoticstate.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djjonimix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djkhalid.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djkonor.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djlifemusic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djlmk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djlogic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djluca.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djmetrix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djmilad.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djmullet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djnasvatbuzlin.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djosu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djpiere.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djrider.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djrizwan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djsearch.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djshox.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djskippy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djtavo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dknoops.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dlp-demo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dlyabega.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dmesure.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dmliving.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dmoutlet.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dngrexplorer.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "docbrown.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "docpc86.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doctoriko.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doctormartinclavo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dodard.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dodi-alhelo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doejedansvereniging.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dogcam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dogfights.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dogma2000.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dogmagic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dogtowneastpowell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dokonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dokterkelaminjakarta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dokument.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doldersumenzoon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dollhouseaustralia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dolliesauce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dom-byt.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dom-desertov.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dom-riviere.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dominicanisimo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dominiopruebados.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "domitori.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dommod.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donpietraos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dontkillspike.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doomsdaymag.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doordash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doors-and-windows.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doottrucks.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dorisdeluxe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dorpsparade.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dorsaycreative.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dotfile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doublebangmusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doublewood.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "douglascuddletoy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dowhatyoucannow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "downloadasik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doxtex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doxycycline-online.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dplpmtud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dr-diffusion.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dragdroplearning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dragon-ballz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dragonshare.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dragonsorcerers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dreadlocks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dreampointech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dreamsubmitting.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dressabelle.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dressesbal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dressestore.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "driveyouradblockcounterup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drivinginstruction.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drivio.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drivio.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drlevi.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drlevi.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drmonicatadros.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dropeverythingrecords.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dropshipp.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dropshippers.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drugtestingcourses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drum-majo-ijsselstrand.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drumnbass.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dsn-it.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dubl.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duckman.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duckonthepond.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duckstad.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duellin.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duesseldorf.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dukeofmetal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dumspiro.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dunescorporation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duodeno.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duohao.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duramaximportaciones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duranceofhate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "durand.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duredo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duskraven.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dustshop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dutchcariblaw.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duzavo.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dvclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dwaallicht.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dweilorkest-frederikshaven.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dwt-inc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dylan-park.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dylansevier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dynabob.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-bags.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-boss.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-buro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-copys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-fitnes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-games-board.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-hair.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-havenotime.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-interactivenet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-interview.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-jackets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-jewelrys.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-knitwear.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-lamp.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-loshadka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-massage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-medicines.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-nail.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-otdyx.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-placement.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-repairs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-rest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-sauna.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-slots.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-sneakers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-styling.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-tables.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-tablets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-transformer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-trucking.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-underwear.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-x-p-l-o-r-a-d-o-r-e-s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e2electric.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e6web.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eapcounselling.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "earlyvoting.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eastbourne-eip.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eastcoastexports.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eastportcorp.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "easy-affiliations.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "easybot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "easycrochet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "easyonlinetest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "easytestonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "easytrackghana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eatinglinks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eaugalliediscountpharmacy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eautocollision.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eautolease.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ebooksgratis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ebookweb.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecarscash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecoc2021.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecohaus-wongwaen-lumlukka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecosistema.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecowoman-armenian.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecowoman-turkey.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eddysystem.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edelveiys.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edenfactory.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edicionescrimentales.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edirnehaber.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edwardbrowninvestment.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edwinroelvink.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eerstemaanlanding.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "efficientsolutions.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "efleetcare.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eforw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "efs-auto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "efutbol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "egabroaventuras.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "egittophilia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "egoroskope.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "egoscolumn.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "egregius.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ehlersdanlos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ehtgov.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ehtpd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eigenetiket.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eightvirtues.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "einfach-fitz.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "einsteins.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ekonomska.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ekwgroup.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ekwilliamsaccountants.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elastiekschieten.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elbrus.ooo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elbvision.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elderscrolls.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electricannihilation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electricfireplaces.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electrico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electrodomesticos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electromotor.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electronmag.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elegancecement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elegro.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elektrolety.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elektrolety.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elektromont.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elements-space-time.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elementsoftware.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elexxos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elfranco.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eliminations.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elinformatico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elisabethborgermans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eliskamyskova.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elite-forums.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elite-units.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eliteco.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elitehouse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elitelounge.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eliterequestboard.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elliboettcher.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elloadingjr.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elmeson.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elmundoconpenelope.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elnegocioperfecto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elo-forum.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elperiodicodeycodendaute.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elprofeshows.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elreportero.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eltormo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elverdaderoamor.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elvikom.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elvikom.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elvis-presley.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "email24.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emavending.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emdyn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emdynint.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emeraldheights.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emergency-broadcast-system.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emersonreview.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emina-arapovic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emmagullstrand.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emotionalonlinestorytelling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emotionsgroup.kz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "empathyband.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "empatos.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "empire-group.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "empiredenham.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emplealis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emporioarchitect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "empreex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emunahstudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emystars.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "en-wp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "en-wp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "encode.agency", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "endbegins.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "endgame-economics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "energetiquetraditionnellechinoise.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "energiebesparingsexpert.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "energygroup.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eng3corp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enganchesevilla.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enroo-tech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enshin-karate.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ensilencio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "envaldemoro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enviarcurriculumvitae.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enviyatar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "envydesigns.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "envysmile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "envywe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eod.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eoskoch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epic.gl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epicauth.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eposzilos.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eprosto.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "equipedefrente.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "equipment-pool.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erasmusantoine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ericktello.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erozine.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eruzione.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erwannlaflute.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erwerbslosenforum.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erwinonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "escg.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "escordilla.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "escritoresdelcomahue.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eslamahmed.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esnekkaucuk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esocite.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esotericcosmos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "espace-orenda.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "espacejabugo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "espejo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "espeleogel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "essenttamarketplace-essenttamarketplaceqa.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "estreetshuffle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "estremeconseguenze.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "estruendo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "estudios-biblicos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ethereal-skies.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etl-it.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etrades.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eugenioperez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eurasierwelpen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "euro-issues.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europack.kiev.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europatour2005.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europeonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europesearbeiders.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europetourism.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europoint.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evanescenceturkey.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evangelionmagi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evendesign.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evenfall.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eventjams.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eventusgc.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evergreenilder.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evermade.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "everwinter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "everycorneroftheworld.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "everycorneroftheworld.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "everycorneroftheworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "everystudent.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evilduck.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evopack.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eworldmedia.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "examlab.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "examroo.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exarcheia.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "excelglobalpartners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exclusivemarket.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "excomm.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exdev.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exitoseguro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exitreality.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "experpento.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "expertmarktrg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "explore-malaysia.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "expouniverse.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "expressinfo.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "expressinfo.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exprimo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exquisito.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "extendet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "extraefficiency.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "extraefficient.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eyelash.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eyemagic.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eyesurgery.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eyfari.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezcourseonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezifund.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezmoddingz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezradulaney.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezytrade.africa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f1grandprix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f1sport.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f4bkv.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fa-fa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faberoclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fabrilec.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faburocks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "facchino.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "facialcare.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "facialplasticsurgeryofaustin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "facilit-info.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "facts-about-bees.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fademusic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fadusongs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fae.watch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fair-ai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fairfieldschool.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fakemoney.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fallonarrocho.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fallriverbiblechapel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fanclubmariaciobanu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fangbing.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fanschic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faraloda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faresgame.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "farian.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "farmer-miniaturen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "farol.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fasea.gov.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fashion-buttons.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fashioncatalogues.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fashionmovie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fastfox.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fastvisit.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "favoritestudent.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fdereplace.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feathersbtq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feedbackproduction.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feelya.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "felitecn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "felixharo.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "felixsanchez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "female-costumes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fencekirkwood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fengying.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fenix-site.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fennet.rentals", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fenus.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ferienwohnung-becks.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "festivitas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ff5g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fianna.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fidonet.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fierce-escarpment-59441.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "figuras.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fihrest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fikavirtual.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filecatchers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filipi.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmcorner.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmedonstage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmero.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmisfun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmisfun.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmnetz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmsidan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmtheaternieuwegein.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fina-foxy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finalfate.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finalonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finance-consulting.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "financeinterface.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "financial-law.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finanssaati.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finansy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fincitegroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "findmytricks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finnishclothing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finom.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "firatofm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fireeye.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "firefish.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fireurboss.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "firewallremoval.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fireware.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "firexp.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "firmament.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "firstechpayments.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fisaplay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fisarmonica.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fishergo.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fishfish.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fishingworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fishoftheday.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fisiolunges.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fitplus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fivepedia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flacon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flamencoshoes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flattie.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flavinha.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fleetpal.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flirtbox.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "floart.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "floridaimigracao.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flowercare.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flowerdelivery.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flowstars.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flutterappdev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flyinglions.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flythecopter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fmlife.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foamfortress.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fof-clan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "folianti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "folktalerecords.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fonbet-zerkalo.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fondation-machpal.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foodcraft.ae", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fooddeliverypartners.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fooddeliverypartners.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foodseurope.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foolproofcomics.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "footdoctorpodiatristnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forcemat.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fordeetv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foreignpharmacydirectory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forensischepsychiatrie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forexclubteam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "formand.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "formar-contract.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foroenguera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forosdelmisterio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forti1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortifydiy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortipartner.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortipartner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortipartner.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortipartner.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortipartner.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortipartner.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortipartner.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortipartner.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortunabuilders.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortuneinvestments.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forum-expert.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forumistudentore.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forumpenaguru.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forumvardbyggnad.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forwardfever.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fotografianowoczesna.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fotografontes.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foundationassure.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frageboegen-martini-klinik.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fragmentus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frames-hair-design.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "francescosiciliano.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frankieylosmatadores.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frankland.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frankydo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "franzen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fraterbolivia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freakyhappenings.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fredjanssen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "free-cms.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "free-webtv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freeagent.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freedatingonline.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freedomtwp-pc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freefonts.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freesmile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freesoul-deactivate-plugins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freestylemartialarts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freetimefun.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freizeitpark.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frettennet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freudedurchmachen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fridaybridge.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fried.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "friends-online.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "friendsofmagnacarta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "friendsonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frightmare.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frisuren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fritzbox-forum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frontigate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fruityloop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fuddittu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fuegosalsapower.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fujikochan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "funboat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "funhotdate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "funkyflo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "funloaded.org.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "funphone.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "funplaza.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fur-shop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "furkankose.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "furnitureproduction.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fursandfur.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "futureplanet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fuzzbucket.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fzfeletronicos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gabysoft.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gadingpromosindo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gafan.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gaijin.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "galina.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gallifreyan-koala.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gallolineabagno.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamalawadforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "game-dominion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gameonespirit.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamepower.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamerstudiozinc.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamesgate.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gameshopsrbija.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamespark.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamespider.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gameview.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gameworldcdr.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamezon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamingtoday.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gangbangs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gangstaflow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gardarika.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "garotos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "garrulousgrimoire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gastrolab.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gattomatto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gattschan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gayubo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gc-hartberg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gconcept.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gebrvansanten.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geeksquadforums.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geldoderleben.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gelmostop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gemini.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "generateurdesmiley.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "generatormusic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentgreenkey.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlecollies.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geolex.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "georgeclooney.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geowest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geowithmaps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gesentorno.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getdishnow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getfreeelectricity.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getlibrary.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getlostforever.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getnew.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gettext.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ghentcityofmusic.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ghostbustersuk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ghosts-to-you.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gibbon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gideonbot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "giftsholidays.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gig40.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gigatags.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gilion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gilpincountydronepilot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gimpware.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ginn.press", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gintonic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "giovinco.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "giuliawylde.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "givemebeer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gladiators-clan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "glaswolsite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gleam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "glgclan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "global-electronic-music.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "globalcancer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "globalobuv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "globalopsgame.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "globe-brasil.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gmcpe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gml4d2.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gnrinfo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "go350.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "going-dutch.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "golden-sea.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goldstein.rs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "golf-supplies.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gonebald.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goodi.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "googleadvies.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gopet.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gorbatschow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goroskopnew.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gosarhiv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gosia-banaszkiewicz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gothicmarketing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gpsnavigator.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "graceq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "graffitiwall.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grafos.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "graftonglobe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grand-house.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grandcountydronepilot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grantsolutions.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "graphviewer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gratishandy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gratisparati.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gravedigger.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gravirovshik.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greatepier.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greatmazes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greenroom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greenyway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greghouse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greystonesmovement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greywalker.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grinpis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "groep20.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "groningerkustvaart.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "growingsearch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grupodepasajeros.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grupoellatu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gruposanjose.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gruppakolibri.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grurez.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gsm-info.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gtestepourvous.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gtrwebdesign.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gtsoftware.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guardando.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guarderiajackson.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guardiapretoriana.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guerrasgalacticas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guesthouse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guiasdemexico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guinguetteclovis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guitards.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guitarraclasica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gumbles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gunzreplays.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guolaoban.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gustavapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gvp.co.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gyannews.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gzonemu.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "habbolibres.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "habibhidayat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hacifadilogullari.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hackclubmauritius.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hackeado.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hackops.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hadelandgjestegard.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hadouken.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "haigle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hair-dressing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hairstyles-salon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "haititransfert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hakrietdekker.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "halligan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hallofoddities.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hallways.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "halotours.rs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "halsokost4life.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hamburgerland.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hammed.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hammeracademy.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hammerofdamnation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hamsternetwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hamstersenanos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hamsterworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "handrollschile.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "handstandstudio.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "handy-page.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hannaljungberg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "happy-herd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "happy-wans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "happyhealthytechie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hard-drive-recovery-blog.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hardtec.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hardtimeszine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "harery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "haroldkip.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "harrychristensen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "harrysdiveshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hartsfieldrock.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hartvannike.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "haru-restaurant.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hassclan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hastingssecondarycollege.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hastmassage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "havenseniorinvestments.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hazan.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hazara-online.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hctegelhandel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "head-hunters.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heading2australia.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthekids.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthyaging-digital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthyhabitswellness.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthyliving-healthnetwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthyprinciples.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthyrun.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heatherleysephotography.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heber.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hedman.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heimansschildersbedrijf.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hekimim.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helagotaland.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helali.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helder.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helenapaparizouspainfanclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helenevanwunnik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hellblast.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hellhavens.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helloteen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hellpc.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hellsoldiers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helpcalculator.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helpcomp.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helprb.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hemaroids.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hemdian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "henrieta-nagyova.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "henryclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herbiez.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herbreathonglass.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hereticmaniacs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hereticofficial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hereticpreist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herewomentell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heritagereformed.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hermanoscarrera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hermetiaprotein.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hermetien.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herritage.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hetdebat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heybritney.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "highspenfc.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "highway11north.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "highway54.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "higueras.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hiper-humor.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hiphopfashion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hirsch-lawyer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hirschl.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hispasat.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "historiasyrelatos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hitmaker.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hjelmqvist-it.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hntuin.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hobokenrecords.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hockeypartner.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hogerduinen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "holidaytable.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hollidays.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "holod-servis777.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "holycrosscatholics.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "home-portal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "home-style.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homeimprovement.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homemadetips.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homemediadb.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homeplace.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homero.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homesforaustralia.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homnest.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homyneeds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "honeycomb.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "honnedechuju.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hoogstraatseschaakclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hoogveen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hooliganka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hornblower.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "horoscopimages.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "horozo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "horsebreeding.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "horsehead.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hostfact.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hot-models.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hot101fm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hotelfloresta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hottoys.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "house-cleaning-howtos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "household-appliances.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "houstonhomerevival.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "howlinhawk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "howtobehealthy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "howtohomepage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "howudoin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hpneo-conseil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hr-clan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hristijanspirovski.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hsrm.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "html-css.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "http3-hosting.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hubdesmille.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hubloy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "huesitos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humdruma-recordingz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humorcheck.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hundur.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hungryas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hupsa-kindermode.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "huron.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hutson-foods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hxr404.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hydrochlorothiazide.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hydrogenplatform.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hydroid.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hynerd.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hyperblast-universe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hypercdn.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hyperhidrose.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hypershell.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hypnose-mieux-etre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hysquad.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i-like-hits.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i-motor.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i-panic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i-so.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i24.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iabot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "icentury.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iconecoiffure.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iczelion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idee-geschenk.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ideorealm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idonthaveawebsite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idwebtools.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iforced.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iglesiabelen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iglesiadesalvacion.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iglesiapentecostal.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igraonicalara.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iisuss.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iknowd.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ikwileendomein.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ileonidze.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ilneminis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ilona-france.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ilouis.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ilovefanyi.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ilovefun.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ilquintoseitu.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ilusionistas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "image4arab.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imageproductions.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "images99.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imageworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "immersionclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "immovisual.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imperialteam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "impf.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "impfung.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "impfung.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imrbq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "incrediblez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "independentadvicefinancial.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "independentfinancial.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "independentmoneyadvice.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "independenza.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indevelopment.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indiaexamresult.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indianapolisrestorations.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indianstorestuttgart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indianwarriors.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indigestiblesuppuration.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indo4life.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indopress.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indyroom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infectedvoice.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infidia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infinita.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infinityfaces.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infinitysearch.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infirmiers-montpellier.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "info-kiwi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "info-reason.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infocanicatti.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "informasi-teknologi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "informaticmousset.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "informationdoor.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "informelles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infrastat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ingresomedicina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inmemorium.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "innio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inoruhana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insanedevs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inserta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insideevs.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insideprisonbreak.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insidevice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inspirationalstories.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insurancebonzer.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insuranceclassic.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insurrectosdelbosque.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insytesecurity.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inta-aivn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "integrativewellnessny.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "integritymedicalwaste.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intelalumni.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intellio.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "interiorcolors.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intermediapub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "internetauction.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "internetline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "internetoskol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intertrans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intestclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "invariant.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "invariant.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "investasipasti.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "invokingspirits.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "involve.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ionline.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iperon.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iperon.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "irando.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "irangeodesy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iraq4u.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "irdll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "irlprable.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ironcross.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isa4310.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isex-anal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "islamicacademy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "islamicsolution.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "istorija-balkana.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "it82.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "italentado.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itfall.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itleaked.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itlogic.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itnrd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itrew.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itsmohitchahal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itsnotnot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itxcjm.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ivan-tadej.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ivankuchin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ivanzorin.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ivjose.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iwatchla.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "izmir-organizasyon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jabberdog.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jabberster.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jacket-coat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jackets-coats.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jackets-for-men.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jackgreiner.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jackiecunliffe.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jackstone.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jadox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jambihackerlink.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jamesl.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jamesnowlin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "janetandjohns.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "janservfl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "janujani.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jasawebbisnis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jasik.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "javafiles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "javsod.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jb-pixel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jdelgado.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeanniegraefe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeans-stores.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeansbutik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeansstyle.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jedilukmas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jencshiny-org.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jerome-r.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jerridoswell.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jerrybustillo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jesperandersson.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jetixclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeugdclubjia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeugdwmo.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jewelry-directories.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jewishinseattle.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jhonesmarcos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jimwoodrealty.help", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jmbproject.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jmsmarcelo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jmsole.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joansoy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobrus.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobs-it.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jofel-kinderkleding.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johnblotsky.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johninwood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johnmillerdesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johnnydoe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jokersro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joksara.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joky.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jonahtheprophet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jonathantaylorthomas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jos-verstappen-fan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "josemortellaro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "josephziegler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joshgroban.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "journaliste.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jouwbuis.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joydivision.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jrock.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jt-evolution.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jtbservice.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "julenetxaniz.eus", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jurquestion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "just6f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "justfoodfordogs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kabal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kadett-c-club-limburg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kadhal-kirukkan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kadolis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaffeklubben.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kagutech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaiseraerospace.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaladarb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaliforniya.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kalinka-shop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kalmar.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaltoft.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kamandula.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kamareddine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kampffische.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kanatsuki.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kandelaberi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kangoeroeteam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kanitha.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kapitany.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kapiteintje.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kapulakennel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karabukhaber.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karatepunkslaroca.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karel-dingeldey.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karel-it.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kargosuben.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karmelava.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karnage.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karpets.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karpo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kasaysayan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kasper-team.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "katabra.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "katalog-parfyum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "katapult.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kathrynbernardo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kavalasite.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kavithai.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kavkaz-info.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kawabeest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kayakcastro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kayakpolouniversidades.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaysvillechurch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kbkstudio.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kbz.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kcsprayfoam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keekmix.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keepwatchprayer.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keesmartens.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kein-vergessen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kelantan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kelax.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kelder.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kelinda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kelvinchung.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kendle.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kenzelmann.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kettmail.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kezmanweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kfbl.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kga-rathaustreptow.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "khankandi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kibizoid.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kidswithguns.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kierweb.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kievlove.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "killborn.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "killharmonic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kimdotcom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinder-garten.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinesiologie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinksecrets.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinomaniac.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kirie-photos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kirstygreenwoodartist.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kite-surfen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kiteboard-selbstbau.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kits-graphiques-shop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kknapredak-rubin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klassenlos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klassiekballet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klea.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kleen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klenc.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kleverltd.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kliklinks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klj-beveren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klj-walshoutem.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kmsk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "knarkkorven.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "knitted-hats.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "knize.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "knobboutheftrucks.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "know.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kocheshkov.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kochura.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kodineuerleben.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koffiekoeken.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kokoroheart.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kokteili.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kolaci.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kolaczek.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kom.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "komp-plus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kompaniya-vasya.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "komputer-net.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "komun.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "konfliktklaerer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "konijnen-knaagdieren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koningslust.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "konjunktion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "konservy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kontabilitet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "konyahaber.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koolkool.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koomaldreaming.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kooratalk.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kopb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koreanure.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kostyumi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kotatgent.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koyaanisqatsi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kprf-school74.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kramersworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "krasivye-foto.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kredit24.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kreidlernet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kristina-lari.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kroliczki.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kroll.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kronosproject.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "krozilla.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kruemels-kleine-kinderwuensche.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "krystalrsimpson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kserownia.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ksoftware.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ktstreams.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kubrick.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kulinarika.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kunden-webseite.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kurdigrafya.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kuritsa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kustarnik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kutaisi.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kv-genebos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kvarta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kvdekolk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "l-poya.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "la-verite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laborriquita.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "labroma.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lacalderera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lacallas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lacarniceria.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lacazadora.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ladies-shoes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ladiescode.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ladisko.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ladrones.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lady-blog.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ladytron.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lag-fan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lagavach.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lagirafe.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lalagunachalate.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lamaline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lamalleauxsaveurs-aubigny.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lamanufacturedebaches.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lamisionband.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lanchong.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "landslide.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lankarkivet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laolaweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lappersfort.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laromlab.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "larosadelosvientos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laserena.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lasourisglobe-trotteuse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laspeligrosas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laspeludas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lastsunset.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "latka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "latrynchera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lawebnobasta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lawlessitalian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lawsoner.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lazysoftware.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lbt-russia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "le-forum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leandri-campana-avocat.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leathergoods.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lebesis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lecannabis.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leconnecteur-biarritz.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lecul.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leech.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leetpat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "legal-aid.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "legalisierung.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "legend-of-pirates.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leladesign.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lelocaldrive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lemmy.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lenergietoutcompris.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lenkeran.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lenqiue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lenseshop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leo-music.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leonardlorenz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leongalin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leonidas-dovido.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leps.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "les-formations.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lesconcours.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lesspass.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leuvensefilmclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "level5-drywall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leverj.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leviathanfan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leweslivingstreets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lg-obchod.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lg-store.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lg.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgobchod.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgshop.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgstore.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgworld.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "liberte-toujours.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "libertyxpress.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "licx.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "life-is-riddle.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifeinhellfansite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifesaver.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifesaverhindi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifesettlements.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "likefast.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lilidarcek.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lilie.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lilypadwikisecret.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lindependant.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linkagemag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linknaarlinux.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linksbridge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linkview.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linux-share.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lipetsk-centralniy.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lipovka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lipturess.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lisamaffia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "litecloud.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "litemere.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "literie06.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "litespeed-webserver.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "litespeedwebserver.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "litespeedwebserver.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "littlehide.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livepl.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livinglink.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lj-creation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "llamerapido.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loa.land", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lobocapoeira.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "location-groix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "location-vacances-croatie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lockless.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lode.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lodni.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lodosswar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loftymedia.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lofw.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "logal.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "logart.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "logevou-immobilier.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lojahaus.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lolcats.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lolmania.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lomaster.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "londontrivia.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loneronin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "long08.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "longtermrentalsportugal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lonleymoon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lonlomba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "looker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lopendvuurtje.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loratadine10mg.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lord-design.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lord-of-forex.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lorqui.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "losgringos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "losinterrogantes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "losjuegosdemesa.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lost-bit.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lottothaipro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lotuselise.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lov4affiliate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lovelyflavor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loveplanets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "low-battery.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lowercostcalls.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lowerthetone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lpfan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lphispano.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lscache.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lscache.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lu-rp.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luanxt.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luc-nutrition.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luchalibre.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lucillewillemsen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lucky-bul.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lugobama.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luiza.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lukasldc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lukekuza.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luker.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lukersstorage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lukerstorage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lukertech.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lukka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lule-kendo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luls.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lumberjackman.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luminaire-mobilier-design.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luna-corazon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luska.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lutesite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lutonsky-vizovice.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lutricia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luxden.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luxurygifts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lw1.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lwnlh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lyfstylorganix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lynxbroker.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lynxbroker.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lyuks-parfyum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "m-ch.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "m42-gmbh.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maahchepen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maailm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maaldrift.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "macapflag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "macehead.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "machineaecrire.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "madcs.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "madinina.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "madlandezboard.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "madprod.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "madtown.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mafia-web.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mafiamohaa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magdalenatransa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magicvaporizers.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magnetto.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magnewspress.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magniezetassocies.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mahabharat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mahayana.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maidenworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mail-ink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mailway.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mair.best", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maisondureau.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "make.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "makfra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "makkiyaz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maksimmrvica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malabarismo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maliciousdeath.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malimusavirler.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malsoftware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mamijaclean.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mammaklader.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mamodsteam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manboy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mandzak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manegehenriet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mangeur-de-cigogne.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manhattandermatologistsnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manhattangastroenterology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manhattanprimarycaredoctorsnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manikinuk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manolitodarts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maplewood.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maquinasquepiensan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marabumadrid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marasma.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcelino.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcopierrard.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcusporter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marhobateren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maria-blanco.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mariecurie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marina-group.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mariogb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marketbasket.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marketerprofesional.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "markhoodphoto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "markusribs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marlenefavela.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marmaladetoast.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marmo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marocweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marokkaansearganolie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marquisepools.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marsilioblack.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martialartsbrownsplains.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martijnschreuders.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martin-burger.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martindano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martinhal.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martinhalresidences.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martinverkerkonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marw.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marymaloney.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "masdzub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mask-skin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "masmusica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "massage-technique.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "masterquest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maswali.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matgauthanky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matheball.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mathebau.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mathewlane.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matinataskincare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matov.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matrixfm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matthewimaniphotography.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mattnetwork83.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mauhalito.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mauletsmallorca.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maumovie.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mauricechavez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mauriziomoretti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mausmani.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maven.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mavon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maxgamez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maxico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maxihide.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mcagon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mcculloughsgolf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mcg4loans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mckenna.academy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mckeownshvac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mcsidan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mebelconcept.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mediaareplural.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mediacenter.dynv6.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mediacluster.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mediafresco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medianbases.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medical-safety-system.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medicalonliner.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medicals-i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medicinalflora.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medicompany.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medscope.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meetjeslandsetriathlon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meetpoint.education", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "megateam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mehdavia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mekajen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mekanagadde.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "melica.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "melissalb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "melodycenter.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "menglong.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mengqingzhong.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mengqingzhong.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mengqingzhong.com.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "menlosecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mens-watch.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mensajitos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "menspeak.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mentesinquietas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mergellina.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "merkchest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "merke.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "merlin.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mes-vacances.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "messifan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meteohuertamur.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "methusalem.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "metro-vet.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "metrocraft2033.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "metropolis5000.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mettle.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meulenerkes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mh2.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "miamifl.casa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "miamifl.homes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "micase.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michael-r.dynv6.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaelgroves.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaelgwynn.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaelhayes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaeljohnsrestaurant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaelvician.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michey.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michig.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mickel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "micredito-ok.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "microcert.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "middlesexwoodpigeonclub.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "midtnorskvask.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mig5.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mijnwefact.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikaila.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikhailkolesnikov.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mildridesua.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "military-equipment.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "miljotankar.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "millenniumfalcon.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mindandfull.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minddistortion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mindvsmind.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minecraftonlinesfull.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mineralky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minintendo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ministory.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minna.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minuto30.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mir-koji.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mir-torgovli.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mir.do", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mir24.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mirinfonews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mirvent.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "missakari.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "missilovely.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "misterkeltic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mistressofbeads.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mjstudios.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mladenovac.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mlmjunction.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mlum.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mmmonk.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mmscy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mnbg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mnkt.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobi-katalog.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobilegoldcoastelectrical.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moca-kinder.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mocking.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "modernagritec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mohaabobclan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mohamedsherif.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mojome.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mon-lab-digital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monakinolandscape.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monarchisc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monconcoursdgfip.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monfilm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monicanaranjo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monjob.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monnaiecourante.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monocl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monokli.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monsterminus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "montarosa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monzaradio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moonzerotwo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moppenfactory.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mordovia.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mordovia.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mordovia.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mostmost.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mosurist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "motofoto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "motolife.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "motor-cycles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "motoridiricerca.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moushed.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mozgovoy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mpornoindir.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrautomazioni.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrfinka.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrshahin.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mselectronique.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "msgmon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "msl.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "msm-data.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mssm-portal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mudramagik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mudrc.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mugrabyhostel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mundodosagapornis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mural.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "murksbreider.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musicupdate.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musicvietnam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muzi-tips.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muzicari.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mwine.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mwork.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mwteh.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mxii.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "my-health-homes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "my-town.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myathena.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myauto.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mycdn.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mychunky.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myenemy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myfamilyancestry.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mykonos-island.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myles.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mynoveltyshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mypivcard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mysports.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nabitrix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nabosoft.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nagelideeen.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nagoya.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nandemo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naples.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naquebec.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nash-megagid.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nasospromsnab.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nates.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nationx.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natunion.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natur-plus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naturalbladdercontrol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nauz-art.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "navalkejigo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naveengranites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "navegarea.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "navkor.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nawaf-blog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncommenuptial.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncs-cleaning.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nebuchadnezzar.codes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nedvrf.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "negrete.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neoblog.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neodaedalus.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neoni.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nepalese.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neptun-rio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neptuna.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neropiceno.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nes-watch.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ness.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netbeacon.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netbeyond.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netcenteret.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netculturejokes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netdude.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netwiseprofits.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neuropsychologisthouston.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "never-more.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "new-medic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "new-mvp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "new-standart.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newbrest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newbuilding.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newcars.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newdenversurvivors.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newhamyoungbloods.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newhope.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newjerseyvideography.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newmusic.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "news-big.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "news-club.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "news.mc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newscheck.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newsgrowing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newsletters.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newsxp.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newwind.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newyorkcardiac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nextsound.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neyjens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nezis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nezkakukec.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ngatikuri.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nicava.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nice-germany.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nicekicks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "niels-modeltog.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nighthawkstrategies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nijzoon.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nikahsekeri.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "niko-mapping-studio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nilsanenglish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nimbl.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nintendocollectionsystem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nitroxpowerpc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nndfn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "no-andishan.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noaccess.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noctisphoto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noideas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noisyfox.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noobsunited.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noodles.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noripon.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "normandy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "norrishome.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nostaljicicekcilik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notbot.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notime.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notizie.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notresiteduvercors.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nourishbyfrida.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nova-host.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "novarock.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "novosad-kom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nowbb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nowtime.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "npcradio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nrealsport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nsdcprayerforce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ntgltema.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nu-spine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nubilum.noip.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nudaveritas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nuevacombarbala.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nuke-masters.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nunsarean.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nycdentalimplantscenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nystrom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oakbarnwellness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oberg.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "obet901vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "obgynecologistnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "obgynqueensnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "obi-betriebsrat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "objectif-vancouver-2010.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oblik.pp.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oblik.press", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "observednews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "obsuzhday.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "occultumproductions.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ochki-linzi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odezdaotto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odiall.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odiall.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odlicomul.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odonoghue.kiwi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odyssee-animation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ofaqim.city", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ohmydish.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ohype.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oikontroloi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oknavdom-rf.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "old-wheelers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oldcars.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oldcitysmokehouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oldenzaal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oldskoolreviews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oldvaliken.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "olivier-giroud.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "olivierdurand.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "omegalan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "omerta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "omnel.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "on-tv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ondoorgrond.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onebreadcrumb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onebreadcrumb.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oneirosociety.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onetakeonehit.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onevpn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlanka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "online-car-show.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "online-clothing-store.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "online-mobile-phone-shop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "online-shop-equipment.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "online-store-phones.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlinebookmarks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlinecosmeticsstore.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlinedoctors24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlinegallery.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlinesports.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlinewallpapers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlineworkshops.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "opalhunter.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "openvision.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "optim-ease.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "optimize-jpeg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orchidhouse.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ordenmutantes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orderpizza.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orehoreh.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "organization-of-holidays.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "osbeck.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "osmaniyehaber.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "otdelka76.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "otdih-krim.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "otimismoemrede.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "otptikforum.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oumrace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oumsnatch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ouronyx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "outbound.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ovalle.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ovallevirtual.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oversimplifiedeconomics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "overthegate.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ovkerk-avezaath.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "owningless.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ownwolke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oximoron.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ozone-medical.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "p4030.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paceinvestmentclub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pachalingo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pacobarbera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "padderne.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paddestoelen-encyclopedie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paff.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paganistisch-forum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paidtohavesex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "painclinic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "painfreenyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "painmanagementnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "palaceitalia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "palmoilpledge.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "palmosradio.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "palucms.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pan-portugal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "panheelstraat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "panicrev.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "panoramaresidence-moesern.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pantera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pantypit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paolomargari.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paperpress.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pappacoda.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paradigmas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paradiserydes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paradisim.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parapenteciconia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paras.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parattusdecora.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parentpayments.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paritexpressions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parizhanka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parkngo.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "party-produkte.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "partyclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "partydesign.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "partyphoto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "passiveseinkommen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patanegra-jambon.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patanegra-prosciutto.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patanegra-schinken.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patanegra-schinken.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patricefyffe.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patrickdankers.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patrickpeeters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paulibean.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pawelurbanski.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pawson.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paycardtech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paystarkagency.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pbern.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pcbarchitect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pckartel.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pcmasters.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pcstoronto.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pds.uy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peaksports.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peanutpay.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pediatricdentistrycenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pedrazanoticias.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pefile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peklostroj.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pelmeniuralskie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peluqueriacanina.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "penguinshome.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peninsulaadvancedurology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pennywise.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "penyavictorhernani.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perberestja.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perdterm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perfectsize.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perfectsoft.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "performancerunningsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "periodista.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "periony.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perseo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "personaljourneys.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perthunicyclists.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pesandansampai.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peterackermans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "petertrevor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "petite-annonce.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "petr22shcool.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pfsquad.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pfsquad.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phantomlord.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pharma24.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phildevient.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "philiplowran.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "philipprouhet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "philographie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phonet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phonetrace.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phonosynthese.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "photoclothing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "photolakeview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phototechnique.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phpdevlabs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pianostemmer.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "piata-imobiliara.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "picobellos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "picstar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "picturoftheday.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "piepschuimlogo.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pikkuegypti.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pilotproject.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pimoid.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pinale.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pinchoparados.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pineko.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pinkitalia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "piplwize.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "piraten-recording.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "piter178.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pitman.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pizza-house.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pizza-odessa.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pizzaplus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planetamusik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planetaprogramas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planetmetroidprime.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planetofsound.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planetonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plasapulsa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plastex.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plasticobiodegradable.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "playabalares.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "playdlawosp.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "playtheme.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ple-conseil.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plumbingshop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pluricosmetica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pocketbookdot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "podari-radost.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "podarkiboss.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "podarochek.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "podarochkki.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "podatrans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "poesiafm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "poetasmenores.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pogljad-brest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pokerventure.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "polisport.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "polliga.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ponyhof-muensterland.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "popflow.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "popl.uz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "porkpiesonline.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pornfriends.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "porno.watch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "portativ-mobi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "poskok.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "postlogistic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "postroim.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "posturographie.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "posturography.courses", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "posturography.education", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "potwin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powerhockey.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powersergsis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pozega.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ppweb.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pr-project.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pra.rip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "praha.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "praiagrande.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "praktikum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prankawards.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prcarrier.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prdashboard.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "precisiondentalnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "premier-podiatry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "premierpups.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "premierrisksolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "premium-job.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prepscouts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "preserving.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pressnewscafe.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pricelesspics.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "priestess.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prima-assol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "primerdeal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "princesspawg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prismosystems.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "privacycloud.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "privacysavvy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proceed.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "procountorsolo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "producemybook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "products-for-health.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proextenderindia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proformi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prognozis.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "programnews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "programvaruexperten.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "progressivestreetdance.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "project-forum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "projecthopeless.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "projekt-wild.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prosyscom.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "protok.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prsg.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ps8318.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "psi-tv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "psyart.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "psychosis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pteroforge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "publik.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "puccaso.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pumarin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "purenhd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "purplehotel.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "purples.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pvdplanet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pywikibot.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qingan.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qto.com.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qto.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qto.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qto.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qto.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qto.support", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quadratimkreis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quakeworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qualebroker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qualityoflife.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quantalytics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quassowski.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quaternion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quattro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "queenkedi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quehay.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quepourlesjuristes.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quic-hosting.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quickrate.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quickudpinternetconnections.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quietlife.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quietplace.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quizzard.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qurium.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rabenkralle.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rabotayte.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rabotenkadot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radio-angelos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radio-delmare.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radio-mouse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radio404.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radio99.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiobandung.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiocrash.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radioculture.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiodance.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiodxguatemala.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiogaga.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radioheikrekel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radioilusiones.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiomagicafm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radioricardo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radios-associatives.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiotelephoni.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiotv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raheel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raiderhacks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rainbowmath.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rakom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rakovec.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ramonasbeauty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ramt.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ran-sama.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "randolphcareertech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rankgrowup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rankingide.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raoliveoil.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rascvet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rautarutto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ravagers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ravages.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ravenstonejeweler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rawforce.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rayhanshop.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raynbo.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "razajewellers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rdmc.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rdmc.support", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reachley.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reactor-family.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "real360show.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reallivingcc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rebalancenyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "receitas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "recomendador.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "red-dragon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redbarnwoodwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redcat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redemption.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redes-neuronales.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reds-dev.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "regospel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "regulative.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reikimaster.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reinodemurcia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reishihealthcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reklamirui.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "relatosypoesias.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "releases.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "relentlessroofing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remateszarate.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remcuavilla.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reminded.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remontdot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remontfirm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remora.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remorse.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "renderworld.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "renet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "repairdriveshafts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "repairingmobile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "replicacoin.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reptieleninfo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "residencesatthebluffs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "resident-evil.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "respiradores.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "respire-yoga.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rest-in-moscow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "restauratorin-maubach-dresden.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "restorationphotos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "resurspartner.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rethymnorooms.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "retrojugo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reunion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "revellio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "revoluciondelacuchara-fusa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rhforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ribes.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "richardbulley.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "richardhouts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "richardsdebt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "richwayfun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ricksdailytips.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rindlerwahn.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riseshost.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rivennero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riveraurology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riverschool.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rivolta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rmb.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rmol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rmsk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rmvalues.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "robbiebird.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "robbielowe.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "robertobilic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "robindeheer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roboform.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "robuststory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rocketeer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rojiblancos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rollingshuttle.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rolzzandik.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "romeoijulio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ronaldleite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rongreenbaum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "room45.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rootsmusicmanagement.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roozaneh.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rosetwig.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rosetwig.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rovatronic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rovezzano.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rowra.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "royalcrowns.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "royalteam.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rozprodat.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rpgfactory.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rubic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rudibora.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rudovasky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rugadgets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rugged-cctv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rumble.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "runet.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "russcole.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "russia-furniture.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "russian-fur.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rustamkhanko.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rutavietnam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rvvc.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rygy.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "s402.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sabachat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sabrinamiskiewicz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sabrinarus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sairlerimiz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sakuraakino.cyou", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salamanders.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salento-nostro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saleproductsoffer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salestaxspecialists.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salibandy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salon-svadbi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salutes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samarth.edu.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samentest.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samenuitsamenthuis.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samepage.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samir-software.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samuelbeckett.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samueletoo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samuelkyalo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sandokan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sandras-hobbystueble.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sandwichclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sandwoman.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sangoandmiroku.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sanmarcovecchio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "santong.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "santoscarmelitas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sanukarlos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sapienz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sarafanchiki.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saranamayyappa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "satanindito.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "satellite-equipment.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "satellite-shop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "satellite-top.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "satermadan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saturdayenterprises.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "savage-harmony.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sbmlogistik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sbmt.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sbodewissel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sc2pte.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scanpassword.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scansearchtravel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scaricamusica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scarsviewchrysler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scatteredcode.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schauraum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schenkel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schenkelimoveis.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schirmer.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schlitzbergers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schmitzvertalingen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schonversichert.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schoolbytes.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schoolbytes.education", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schreilechner.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schulden.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sciencenews.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sciences-world.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scientificallytalking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scootertechnofrance.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scorpions.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scottyspot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scourgesofcarpathia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scriptsrus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scstg.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sdfamilycare.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seanchristian.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seaspiration.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "secong.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "secretdeals.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sectrans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "securot.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seeinred.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seguridadyredes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sehat-solusi-makmur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seilgold.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "selfdevelopment.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "selftech.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "semira.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "senseiclassroom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sentinelpeakmedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seomaxion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seoulartcollective.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "serenata.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "serveru.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "service-centre.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "serviceflow.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "servicemaxgreencleaning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "servingroddick.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "servingupsouthern.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sevacy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sevasmos.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seveiller-simplement.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seven-seas.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seven.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "severing.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sevillanazarena.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sexandthecitty.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sexpdf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sexruby.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shabashka.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shacall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shadowfox.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shadownet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shadowstalkers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shakesprimer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shanli.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "share4brain.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sharelinks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shaumine.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shd.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shenannigans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sheweek.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shihabuddin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shineleds.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shiptek.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shitdick.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shlyapa-com.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shlyhi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shmulvad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shochikubai.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shoestorebiz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shoestorenet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shontakleinpeter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shop-cosmetics.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shop-lingerie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopcom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopcosmetic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopcrocs.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopee6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopunderwear.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shorinkarate.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "showno.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shrines.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shrovetide.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sht-vr-player.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shufflecube.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shufflemix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shunter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shunzi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "siberianhuskytraining.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sifecs.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sight-restoration.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sigi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sigmaomeganu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "silasborowy.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "silentdream.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "silentsky.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "silindir-taslama.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "silvianavarro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simex.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simonoener.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simply-pattinson.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simplyjet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simscale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simulise.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sin4psi77.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sineafoods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "singingblackbird.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sinistragiovanile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sinsalida.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sipo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sirpsycho.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sistonenfranco.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "site-development.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "site-oflcial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "siteheft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "siteru.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sithr.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sjoelsport.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skaitliukas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skamper.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skateparkmontbriz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skaterangels.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skatesliide.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skeppsbrons.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sketchok.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skidka.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skillablers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skillatwill.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skk-krovlya.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skrivebeskyttet.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skvelecesko.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skyrieptravel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skytickets.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skywindowsnj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slamdunkdedication.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sledgeroofing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slew.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slimetutorial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sloboda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slotjava.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slow-coaching.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slowinski.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slrie.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smalandscountryclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smalltunepress.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smallville25.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smartb2balgeria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smarteco.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smarthome365.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smialnumenor.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smicenter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smith-tech.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smsstock.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sngukrainatv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "snowhana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "socatel.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "social-line.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "social-work.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "socialdemo.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "socials.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "socialwave.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sociedadcivil.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sociedadecologica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sodiummedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sofa-bed.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soft-search-system.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "softconcept.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "softview.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "software-voor-projecten.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "softwareclub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sokosport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sol-negro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soldaten-genealogie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soloingenieria.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sololabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solviejo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "somerm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "somewherein.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "somnusoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "somosweb.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sophias-haarmanufaktur.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sopronforras.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sos-zimmerpflanzen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sosedisetka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sosmicro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sotin-hr.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sotocine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sotolar.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soulinbusiness.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soundinthesignals.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sowtarabiya.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soytusitio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spa-center.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spaceon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spamedica.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sparkplug.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sparta-upice.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spasem-park.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spatter.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spb.ooo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "specialtechnique.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "speckrot.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "speed-bonus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "speed-strike.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spendo.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spermosens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spettacolocame.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spithoven.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "splintercake.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spolshy.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sport-news.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportsdeck.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportspainmanagementnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportygirlsjewels.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sprashivalka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spreadthejam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sprillerer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spruces.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "squaredseven.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "squealing-filth.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "srv11.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssd.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sshwiki.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sskb-ey.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "st-andrews.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stainless-steel-cookware.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stalker-source.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stalphonsusks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stamforddentalarts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "starlinks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "startpoint.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stasia.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "staytokei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stdavidparish.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stefania.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stefaniharvilla.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stelletjeafgebeuktemongolen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stemcellstherapynyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stensund.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stenvallmcclain.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stestena.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sthetix.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stichtingvlinders.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stickstone.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stiehler-leipzig.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stil.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stilnaya-odezhda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "storedaway.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stormrider.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stpatrick.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stradsolutions.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strahovanienet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strangelittlecovers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strass-sur-mesure.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stratlibs.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stratocumulus.legal", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strawberrydreadlocks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "streamgoalandres.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "streetforceteam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "streetmaderecordz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strengthnutrition.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stricken.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stupendo.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuyvesantoutdoor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sublimm.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "subpage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suburbanprojects.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suburbanweldingandsteel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "succorfish.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sugarcube.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sumitchahal.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sunshinerequest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "super-baik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "superfaktura.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "superfly.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "superlight.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "superlog.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "supplycore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "supremaquimica.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "surf1969.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "surialternat.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "surpriz-net.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "surrealismocantabria.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sustained.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sutinenmatthews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "svobodny.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "svoi-ugolok.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swapbox.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swarmdrone.services", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swjz.art", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swtrayssq.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "syc-rotterdam.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "symphonise.consulting", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "syo-ryuga.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sysoon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sysoon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sysoons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "szelagnes.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "t-shirty.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tabernaalibaba.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tabordaadvogados.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tagboards.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tahaonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taiga-aikidojo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "takhfifeirani.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taki.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taki.to", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "takzetak.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "talkbasket.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "talkingbittersweet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tallac.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tallercs.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tamilentertainment.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tampereenliberaalit.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tandartsvanos.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tanjaradovic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tanks.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tantrabali.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tapcloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "targetlonglife.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tasswoq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tatjana-young.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tavelbutiken.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taxi-doudoune.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tbi.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teahawaii.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "team-17.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teamdarko.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teamliquidstarleague.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teampoison.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teamredfox.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tech-doc.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tech-ideas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techangel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techcompany.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techisfake.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techitsol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "technohram.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "technoids.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "technomagia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tecke.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tecnewsnow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tedder.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teenwolfturkey.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teiseken.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teknoharekat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teknow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teksol-boat.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "telepedia.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "televisionesendirecto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "telka-online.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "templeandalucia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tempsoundsolutions.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tendure.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tenniscritic.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tennisnyi-stol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "termi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "termopares.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "terrab.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "terrarium.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "territoriya.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "test-na-beremennost.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "testingtask.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tetovaweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "texascharterbuscompany.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "texnoguru.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "texnotroniks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thai-massage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thai-ridgeback.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thaigirls.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thassos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "the-dream.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "the-farm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "the-morpheus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "the-muddy-trophy-team.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "the-storm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "the-world.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theanswerexperts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theatresocietyguts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thebathroomexchange.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thebitchneyfiles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thebrewingtonfamily.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thebucklandreligion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thebutterflyencounters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thecalmnessofblankspace.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thecarphunter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thecelticfiles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thechicanos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thechoice.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thecustomerinstitute.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thedeathofannakarina.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thedrawbacks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theelephant.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theenchantedannex.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thegadget.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thegentleman.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thegrandtour.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thegrotto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thehowlinwolfcafe.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thehumorist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thelastvikings.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thelibertinephilosophy.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thelostfreighter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "themagician.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "themaster.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thementornetwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "themusicthatnobodylikes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "then.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thenappylaundry.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thenaturalpath.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theocrazzolara.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thepixel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thepulpit.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thereptiles.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theroadrunners.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theserpent.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thesipher.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thesomepeople.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theta.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theunconventionalconventionists.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thevelvetlove.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thevoice4you.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thewebhut.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thewomenschoice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thilko.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thisisart.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thisuniverse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thoreau.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "three-wheels.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "threeringdev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "threerivers.edu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thweis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tielsebakkers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tierrahost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tiffanitooley.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tiflonet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tifokaos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tigerads.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "timeharmony.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "timweb.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tipnews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tirebichon.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "titanicauto.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tlicycling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tnved2013-narod.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toki-doki.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toledo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tolkienmusic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tom-hanks.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toman-vzv.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tomoko-clinic.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tonysantos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tookhan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toolboxsoftware.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "top-info.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "top-kuwait.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "top-schools.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "top-zentr.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topbrasilnews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topicpoint.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topicpulse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topmoods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topnaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topofertas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topographic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topspace.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topteen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topviet.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "torgopt.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "torrededonmiguel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toshik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tossitaway.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "totemgames.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toughcodes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tourguideagent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toutankamon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "touwhalster.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "towers-kolomna.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "townifi.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "townofbridgewater.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trabajouniversitario.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tradersrank.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trafficgenerator.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trafficsale.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trainingsalicante.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trakteren.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "traktor-troubadour.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trans-aliyans.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "translatorall.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trappersoutfitters.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trashcraft.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trastornoevitacion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "traumschwingen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "travellets.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "travelongravel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "travin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "treasureislandbeads.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trends2day.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tribalzone.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tribunalinternacional.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tricksforgreeks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trik-komputer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trinary.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trinhtrongson.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trinityny.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "triplepointliquidity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tripomanija.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "triptnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trophcomplewin.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tropiweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trubmet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trugears.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trulock.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trustvox.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "truthlost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trychameleon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trypathnow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tryptamine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tscripts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tsentrobuv.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tshirtgenerator.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ttsuaevisas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ttt-networks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tubus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tulocura.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tunisiangamers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tunningcars.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turanga.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turfirm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turkana.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turksite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turksiteleri.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turobot.casa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tutorsheetstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tuttonotizie.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tweekshow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "twigandolive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "twolinesmedia.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "txtentertainment.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tyinnovations.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tylerdurden.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tylerharcourt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tyuning-avto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ua-autonews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uba-tra.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ufa-soft.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ufologiahistorica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ugameclub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ukfoodbox.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uloztoasdilej.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultimategaming.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultras-venlo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultrasvargon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultreya.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "umwelt-galerie.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "umweltgalerie.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unanaciounaseleccio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unautreregard.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uncadeaupour.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uncuteyes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "under-wears.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "undergroundmusic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "underwaterasia.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "underwood.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "underworlds.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "underwriting.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "une-femme-dhonneur.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unfathomable.blue", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unicycle.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unionmagdalena.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uniresbajdas.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unitedlisbon.school", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unitedstables.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "univ-segou.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "universalcircus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "universalcredit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "universityofedinburgh.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "universus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unixer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unknownmasses.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unknownnet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unko.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unlimiteddsl.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unlimitedheatingcooling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unobet-partners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "untvweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "upfurniture.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uportal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "upr.llc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uptech.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uqschool.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urbanarcana.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urfreecon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urke.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urkonsultant.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urlgoo.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urlkurzco.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uruslugi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "usenet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ushi808.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "usyfawovad.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uzone.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "v-horus.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "v-phoenix.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vackor.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vagasdeempregos.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "valdelcubo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "valentinvesa.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "valerian.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "valerieadolff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vander-vegt.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vaneyckwashere.gent", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vanna-mechti.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vanquish.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vanveenendaaladvies.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vanzoestheftrucks.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "varney.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vasya-com.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vasya-odyag.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veessen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vektor.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "velocitygames.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veluwerally2002.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "venali.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vendela.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "venera-magik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "venga.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verbio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vercopy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verepeliculashd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verkossa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verlete.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veros-volejbal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vertikal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verwer-infra.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veselka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vesinhcongnghiepttchome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vestibulartechnologies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vesuvio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vet-dogs.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veterinarylabsupply.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vgopilot.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vias-ferratas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vicentaburon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vicentico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vicescorts.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "victorianosaez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vidapositiva.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vigridpartiet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viktoria-goo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "villaditirano.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "villisek.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "villitalia.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vimium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vincentsimon.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vinceracing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viniciuscosta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vinsonfinancials.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vintagetoydepot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viralinsurance.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "virtualbruges.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "virtualmachine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "virtualprom.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "visconapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vitalheatingsolutions.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vitalshop.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viterboonair.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vitromex.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vitta.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vitto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vivamortgage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vivekanandaspokenenglish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vivian.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vivide.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vkwebsite.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vlaamsegemeenschap.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vlaamsetollers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vlance.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vodadombay.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vodavoda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "voetbalforum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "volleypatos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "voltcloud.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "voprosownet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vous-les-jeunnes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vozdux.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vpnaustralianow.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vpnclient.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vr-tops.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vreeken-selfstorage.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vstrikovaci-lisy.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vsz.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vuonthotuanh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vyroba.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vzemiseo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "w-oasis.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "w8wat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waagen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waffarcash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wahminda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wakecountynorthcarolina.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wakeofthepredator.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waldenwritingcenter.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waldo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waldparkerwoelfe.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "walkfordogs2017.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "walkingranada.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wallada.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wallbanksweb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wangzuan168.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wannaknow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wapflash.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wappie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waptransfer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ward2u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wardemons.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wardogz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "warlords.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "warrantycontracts.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "washup.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wassenaar.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "watch-host.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "watchersrealm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waterpolosantona.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "watersky.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "watestsite.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "watismijnbandenspanning.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "watobi.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waycoolmail.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wayfair.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wayfair.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wayfair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wayfair.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wayneo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wbbwbwebweb.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wc3modding.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wd-api.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wd-img.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wd-ljt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "web76.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webannonces.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webapplay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webbolivia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webcase.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webcollector.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webcontrol.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webenglish.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webfeifei.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webfun.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webhostingshop.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webika.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webimagina.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webinformer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webkorobka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weblagalera.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webnancy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webofthingsmarwane.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webpakken.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webpiar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webportail.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webranko.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webrepresalia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "websitesdemos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "websitesseller.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "websitesthatwork.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webtostore.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webuniverse.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webverdienst.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wedding-e-dress.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wedding-ua.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weightlosseasy.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weldersnet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "welovemugs.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wendycityblossoms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wernicke-it.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "westerdraai.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "westlander-nostalgie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "westline.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whatabout.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whatevername.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whatsapp.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whatsmysuggestion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wheelyking.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whitdoit.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whitekings.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whoiswho.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wholesalediamonds.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wholevood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wholevood.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wickedsick.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wielrennen-in-zeeland.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wifinube.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wigos.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wiikipedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wijewick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikepedia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wiki-pedia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wiki.voyage", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikibook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikijunior.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.community", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.jp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimedia.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimediacommons.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimediacommons.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikimediafoundation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikinews.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikipedia.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikipedia.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikipedia.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikipedia.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikipedia.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikipediafoundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikispecies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikispecies.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikispecies.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikiversity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikiversity.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikivoyage.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikivoyage.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wiktionary.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wiktionary.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wildfilm.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wildwoodrockers.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "willusherwood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wiltrovira.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "winampnederlands.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "winario.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "winrss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wiretransaction.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wise.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wisekidscollect.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wm-referrals.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wodax.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wooby.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "woodconditioningonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "woodtrust.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "woothelpdesk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wordpressbot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wordsearchwhiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "workaholics.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "workat.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "workermess.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "workreview10.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worksheets-to-print.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldconsultingchile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldfootball.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldnewsphoto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldranking.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldtourismgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wormhole.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worthwritingfor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wotcheats.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wowcinema.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wownskportal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wowonini.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wowqueboda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wpthemecloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "writersblock.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "writesafer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wrnck.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wroclawguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wsa.org.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wtfindonesia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wwa-clan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wxservices.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xakep-slon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xenforo.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xenocide.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xerowaste.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ximeshosted.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xitin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--41a.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--bersetzungen-beglaubigt-bpc.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--dfirtrning-i6a.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--fakovcov-gza74b.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--fakovec-k6a.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--j1agcso.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--sb-lka.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xobotun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xportxpert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xrak.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xserownia.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xsolla.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xsosa.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "y-nas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ya-hudeyu.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yacostasolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yandong.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yasmingarcia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yephy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yhn.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yogaangels.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yoneda-paint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yonkersdentalspa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "youarethelight.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "youservice.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "youthclothing.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "youtuberus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yukimiu.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zac.cy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zaci.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zack.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zagadki-cosmosa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zakaria.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zakazat-dizayn-interyera.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zakladki.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zamarax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zarabotki-v-internete.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zdorov-blog.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zeihetecumre.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zeihetecumre.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zendarhunters.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zenitkft.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zer0dayhacks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zerotwo.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zhanxiangyang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zima-lito.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "znakomstvatochka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zukonar.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, // END OF 1-YEAR BULK HSTS ENTRIES // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/net/http2/platform/impl/http2_flag_utils_impl.h b/net/http2/platform/impl/http2_flag_utils_impl.h deleted file mode 100644 index 73b8718..0000000 --- a/net/http2/platform/impl/http2_flag_utils_impl.h +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_HTTP2_PLATFORM_IMPL_HTTP2_FLAG_UTILS_IMPL_H_ -#define NET_HTTP2_PLATFORM_IMPL_HTTP2_FLAG_UTILS_IMPL_H_ - -#include "base/logging.h" - -#define HTTP2_RELOADABLE_FLAG_COUNT_IMPL(flag) \ - DVLOG(1) << "FLAG_" #flag ": " << FLAGS_##flag - -#endif // NET_HTTP2_PLATFORM_IMPL_HTTP2_FLAG_UTILS_IMPL_H_
diff --git a/net/http2/platform/impl/http2_flags_impl.cc b/net/http2/platform/impl/http2_flags_impl.cc deleted file mode 100644 index f102736..0000000 --- a/net/http2/platform/impl/http2_flags_impl.cc +++ /dev/null
@@ -1,9 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http2/platform/impl/http2_flags_impl.h" - -bool FLAGS_http2_varint_decode_64_bits = true; - -bool FLAGS_http2_skip_querying_entry_buffer_error = true;
diff --git a/net/http2/platform/impl/http2_flags_impl.h b/net/http2/platform/impl/http2_flags_impl.h deleted file mode 100644 index 3d2f153..0000000 --- a/net/http2/platform/impl/http2_flags_impl.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_HTTP2_PLATFORM_IMPL_HTTP2_FLAGS_IMPL_H_ -#define NET_HTTP2_PLATFORM_IMPL_HTTP2_FLAGS_IMPL_H_ - -#include "net/third_party/quiche/src/common/platform/api/quiche_export.h" - -QUICHE_EXPORT_PRIVATE extern bool FLAGS_http2_varint_decode_64_bits; -QUICHE_EXPORT_PRIVATE extern bool FLAGS_http2_skip_querying_entry_buffer_error; - -namespace http2 { - -inline bool GetHttp2FlagImpl(bool flag) { - return flag; -} - -inline void SetHttp2FlagImpl(bool* f, bool v) { - *f = v; -} - -#define HTTP2_RELOADABLE_FLAG(flag) FLAGS_##flag - -#define GetHttp2ReloadableFlagImpl(flag) \ - GetHttp2FlagImpl(HTTP2_RELOADABLE_FLAG(flag)) -#define SetHttp2ReloadableFlagImpl(flag, value) \ - SetHttp2FlagImpl(&HTTP2_RELOADABLE_FLAG(flag), value) - -#define HTTP2_CODE_COUNT_N_IMPL(flag, instance, total) \ - do { \ - } while (0) - -} // namespace http2 - -#endif // NET_HTTP2_PLATFORM_IMPL_HTTP2_FLAGS_IMPL_H_
diff --git a/net/quic/platform/impl/quic_flag_utils_impl.h b/net/quic/platform/impl/quic_flag_utils_impl.h index 974893bc..717cc0e 100644 --- a/net/quic/platform/impl/quic_flag_utils_impl.h +++ b/net/quic/platform/impl/quic_flag_utils_impl.h
@@ -5,24 +5,4 @@ #ifndef NET_QUIC_PLATFORM_IMPL_QUIC_FLAG_UTILS_IMPL_H_ #define NET_QUIC_PLATFORM_IMPL_QUIC_FLAG_UTILS_IMPL_H_ -#include "base/logging.h" -#include "net/quic/platform/impl/quic_flags_impl.h" - -#define QUIC_RELOADABLE_FLAG_COUNT_IMPL(flag) \ - DVLOG(3) << "FLAG_" #flag ": " << FLAGS_quic_reloadable_flag_##flag -#define QUIC_RELOADABLE_FLAG_COUNT_N_IMPL(flag, instance, total) \ - QUIC_RELOADABLE_FLAG_COUNT_IMPL(flag) - -#define QUIC_RESTART_FLAG_COUNT_IMPL(flag) \ - DVLOG(3) << "FLAG_" #flag ": " << FLAGS_quic_restart_flag_##flag -#define QUIC_RESTART_FLAG_COUNT_N_IMPL(flag, instance, total) \ - QUIC_RESTART_FLAG_COUNT_IMPL(flag) - -#define QUIC_CODE_COUNT_IMPL(name) \ - do { \ - } while (0) -#define QUIC_CODE_COUNT_N_IMPL(name, instance, total) \ - do { \ - } while (0) - #endif // NET_QUIC_PLATFORM_IMPL_QUIC_FLAG_UTILS_IMPL_H_
diff --git a/net/quic/platform/impl/quic_flags_impl.cc b/net/quic/platform/impl/quic_flags_impl.cc index c92a7156..a9d98b0 100644 --- a/net/quic/platform/impl/quic_flags_impl.cc +++ b/net/quic/platform/impl/quic_flags_impl.cc
@@ -21,10 +21,6 @@ #include "build/build_config.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" -#define QUIC_FLAG(flag, value) bool flag = value; -#include "net/third_party/quiche/src/quic/core/quic_flags_list.h" -#undef QUIC_FLAG - #define DEFINE_QUIC_PROTOCOL_FLAG_SINGLE_VALUE(type, flag, value, doc) \ type FLAGS_##flag = value;
diff --git a/net/quic/platform/impl/quic_flags_impl.h b/net/quic/platform/impl/quic_flags_impl.h index c1a2eee..f2193ca 100644 --- a/net/quic/platform/impl/quic_flags_impl.h +++ b/net/quic/platform/impl/quic_flags_impl.h
@@ -13,13 +13,10 @@ #include "base/export_template.h" #include "base/optional.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_flags.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" -#define QUIC_FLAG(flag, value) QUIC_EXPORT_PRIVATE extern bool flag; -#include "net/third_party/quiche/src/quic/core/quic_flags_list.h" -#undef QUIC_FLAG - #define QUIC_PROTOCOL_FLAG(type, flag, ...) \ QUIC_EXPORT_PRIVATE extern type FLAGS_##flag; #include "net/third_party/quiche/src/quic/core/quic_protocol_flags_list.h" @@ -31,29 +28,6 @@ class NoDestructor; } // namespace base -// API compatibility with new-style flags. - -inline bool GetQuicFlagImpl(bool flag) { - return flag; -} -inline int32_t GetQuicFlagImpl(int32_t flag) { - return flag; -} -inline int64_t GetQuicFlagImpl(int64_t flag) { - return flag; -} -inline uint64_t GetQuicFlagImpl(uint64_t flag) { - return flag; -} -inline double GetQuicFlagImpl(double flag) { - return flag; -} -inline std::string GetQuicFlagImpl(const std::string& flag) { - return flag; -} - -#define SetQuicFlagImpl(flag, value) ((flag) = (value)) - // Sets the flag named |flag_name| to the value of |value| after converting // it from a string to the appropriate type. If |value| is invalid or out of // range, the flag will be unchanged. @@ -191,18 +165,5 @@ QUIC_EXPORT_PRIVATE void QuicPrintCommandLineFlagHelpImpl(const char* usage); -// ------------------------------------------------------------------------ -// QUIC feature flags implementation. -// ------------------------------------------------------------------------ -#define RELOADABLE_FLAG(flag) FLAGS_quic_reloadable_flag_##flag -#define RESTART_FLAG(flag) FLAGS_quic_restart_flag_##flag - -#define GetQuicReloadableFlagImpl(flag) GetQuicFlag(RELOADABLE_FLAG(flag)) -#define SetQuicReloadableFlagImpl(flag, value) \ - SetQuicFlag(RELOADABLE_FLAG(flag), value) -#define GetQuicRestartFlagImpl(flag) GetQuicFlag(RESTART_FLAG(flag)) -#define SetQuicRestartFlagImpl(flag, value) \ - SetQuicFlag(RESTART_FLAG(flag), value) - } // namespace quic #endif // NET_QUIC_PLATFORM_IMPL_QUIC_FLAGS_IMPL_H_
diff --git a/net/quiche/common/platform/impl/quiche_flag_utils_impl.h b/net/quiche/common/platform/impl/quiche_flag_utils_impl.h new file mode 100644 index 0000000..9631f17 --- /dev/null +++ b/net/quiche/common/platform/impl/quiche_flag_utils_impl.h
@@ -0,0 +1,26 @@ +// 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 NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_FLAG_UTILS_IMPL_H_ +#define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_FLAG_UTILS_IMPL_H_ + +#include "base/logging.h" + +#define QUICHE_RELOADABLE_FLAG_COUNT_IMPL(flag) \ + DVLOG(3) << "FLAG_" #flag ": reloadable" +#define QUICHE_RELOADABLE_FLAG_COUNT_N_IMPL(flag, instance, total) \ + DVLOG(3) << "FLAG_" #flag ": reloadable, instance: " << instance \ + << " total: " << total + +#define QUICHE_RESTART_FLAG_COUNT_IMPL(flag) \ + DVLOG(3) << "FLAG_" #flag ": resart" +#define QUICHE_RESTART_FLAG_COUNT_N_IMPL(flag, instance, total) \ + DVLOG(3) << "FLAG_" #flag ": restart, instance: " << instance \ + << " total: " << total + +#define QUICHE_CODE_COUNT_IMPL(flag) DVLOG(3) << "FLAG_" #flag +#define QUICHE_CODE_COUNT_N_IMPL(flag, instance, total) \ + DVLOG(3) << "FLAG_" #flag + +#endif // NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_FLAG_UTILS_IMPL_H_
diff --git a/net/quiche/common/platform/impl/quiche_flags_impl.cc b/net/quiche/common/platform/impl/quiche_flags_impl.cc new file mode 100644 index 0000000..033769b --- /dev/null +++ b/net/quiche/common/platform/impl/quiche_flags_impl.cc
@@ -0,0 +1,9 @@ +// 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 "net/quiche/common/platform/impl/quiche_flags_impl.h" + +#define QUIC_FLAG(flag, value) bool flag = value; +#include "net/third_party/quiche/src/quic/core/quic_flags_list.h" +#undef QUIC_FLAG
diff --git a/net/quiche/common/platform/impl/quiche_flags_impl.h b/net/quiche/common/platform/impl/quiche_flags_impl.h new file mode 100644 index 0000000..dff0754a8 --- /dev/null +++ b/net/quiche/common/platform/impl/quiche_flags_impl.h
@@ -0,0 +1,56 @@ +// 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 NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_FLAGS_IMPL_H_ +#define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_FLAGS_IMPL_H_ + +#include <cstdint> +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "net/third_party/quiche/src/common/platform/api/quiche_export.h" + +#define QUIC_FLAG(flag, value) QUICHE_EXPORT_PRIVATE extern bool flag; +#include "net/third_party/quiche/src/quic/core/quic_flags_list.h" +#undef QUIC_FLAG + +inline bool GetQuicheFlagImpl(bool flag) { + return flag; +} +inline int32_t GetQuicheFlagImpl(int32_t flag) { + return flag; +} +inline int64_t GetQuicheFlagImpl(int64_t flag) { + return flag; +} +inline uint64_t GetQuicheFlagImpl(uint64_t flag) { + return flag; +} +inline double GetQuicheFlagImpl(double flag) { + return flag; +} +inline std::string GetQuicheFlagImpl(const std::string& flag) { + return flag; +} + +#define SetQuicheFlagImpl(flag, value) ((flag) = (value)) + +// ------------------------------------------------------------------------ +// QUIC feature flags implementation. +// ------------------------------------------------------------------------ + +#define RELOADABLE_FLAG(flag) FLAGS_quic_reloadable_flag_##flag +#define RESTART_FLAG(flag) FLAGS_quic_restart_flag_##flag + +#define GetQuicheReloadableFlagImpl(module, flag) \ + GetQuicheFlag(RELOADABLE_FLAG(flag)) +#define SetQuicheReloadableFlagImpl(module, flag, value) \ + SetQuicheFlag(RELOADABLE_FLAG(flag), value) +#define GetQuicheRestartFlagImpl(module, flag) GetQuicheFlag(RESTART_FLAG(flag)) +#define SetQuicheRestartFlagImpl(module, flag, value) \ + SetQuicheFlag(RESTART_FLAG(flag), value) + +#endif // NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_FLAGS_IMPL_H_
diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h index 910f8122..10de291 100644 --- a/net/spdy/buffered_spdy_framer.h +++ b/net/spdy/buffered_spdy_framer.h
@@ -192,6 +192,8 @@ spdy::SpdyStreamId parent_stream_id, int weight, bool exclusive) override {} + void OnPriorityUpdate(spdy::SpdyStreamId prioritized_stream_id, + absl::string_view priority_field_value) override {} bool OnUnknownFrame(spdy::SpdyStreamId stream_id, uint8_t frame_type) override;
diff --git a/net/spdy/platform/impl/spdy_flags_impl.h b/net/spdy/platform/impl/spdy_flags_impl.h deleted file mode 100644 index 88641073..0000000 --- a/net/spdy/platform/impl/spdy_flags_impl.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_ -#define NET_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_ - -#include "net/base/net_export.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" - -#define GetSpdyReloadableFlagImpl GetQuicReloadableFlagImpl - -#define SPDY_CODE_COUNT_IMPL(name) \ - do { \ - } while (0) - -#define GetSpdyRestartFlagImpl GetQuicRestartFlagImpl - -#define SPDY_CODE_COUNT_N_IMPL(name, instance, total) \ - do { \ - } while (0) - -#endif // NET_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_
diff --git a/net/third_party/quiche/BUILD.gn b/net/third_party/quiche/BUILD.gn index 15d38ad..797deb8 100644 --- a/net/third_party/quiche/BUILD.gn +++ b/net/third_party/quiche/BUILD.gn
@@ -25,6 +25,8 @@ if (!is_nacl) { sources += [ "src/common/platform/api/quiche_export.h", + "src/common/platform/api/quiche_flag_utils.h", + "src/common/platform/api/quiche_flags.h", "src/common/platform/api/quiche_logging.h", "src/common/platform/api/quiche_str_cat.h", "src/common/platform/api/quiche_string_piece.h",
diff --git a/services/device/hid/hid_connection_impl_unittest.cc b/services/device/hid/hid_connection_impl_unittest.cc index edd52b1..d50561e 100644 --- a/services/device/hid/hid_connection_impl_unittest.cc +++ b/services/device/hid/hid_connection_impl_unittest.cc
@@ -175,13 +175,18 @@ } scoped_refptr<HidDeviceInfo> CreateTestDevice() { + HidDeviceInfo::PlatformDeviceIdMap platform_device_id_map; + platform_device_id_map.emplace_back(base::flat_set<uint8_t>{0}, + kTestDeviceId); + std::vector<mojom::HidCollectionInfoPtr> collections; auto hid_collection_info = mojom::HidCollectionInfo::New(); hid_collection_info->usage = mojom::HidUsageAndPage::New(0, 0); hid_collection_info->report_ids.push_back(kTestReportId); + collections.push_back(std::move(hid_collection_info)); return base::MakeRefCounted<HidDeviceInfo>( - kTestDeviceId, "1", 0x1234, 0xabcd, "product name", "serial number", - mojom::HidBusType::kHIDBusTypeUSB, std::move(hid_collection_info), - kMaxReportSizeBytes, kMaxReportSizeBytes, 0); + std::move(platform_device_id_map), "1", 0x1234, 0xabcd, "product name", + "serial number", mojom::HidBusType::kHIDBusTypeUSB, + std::move(collections), kMaxReportSizeBytes, kMaxReportSizeBytes, 0); } std::vector<uint8_t> CreateTestReportBuffer(uint8_t report_id, size_t size) {
diff --git a/services/device/hid/hid_connection_win.cc b/services/device/hid/hid_connection_win.cc index 98f7fbe..e0efa2a 100644 --- a/services/device/hid/hid_connection_win.cc +++ b/services/device/hid/hid_connection_win.cc
@@ -29,6 +29,21 @@ namespace device { +namespace { + +bool IsValidHandle(HANDLE handle) { + return handle != nullptr && handle != INVALID_HANDLE_VALUE; +} + +} // namespace + +HidConnectionWin::HidDeviceEntry::HidDeviceEntry( + base::flat_set<uint8_t> report_ids, + base::win::ScopedHandle file_handle) + : report_ids(std::move(report_ids)), file_handle(std::move(file_handle)) {} + +HidConnectionWin::HidDeviceEntry::~HidDeviceEntry() = default; + class PendingHidTransfer : public base::win::ObjectWatcher::Delegate { public: typedef base::OnceCallback<void(PendingHidTransfer*, bool)> Callback; @@ -77,7 +92,7 @@ } else if (GetLastError() == ERROR_IO_PENDING) { watcher_.StartWatchingOnce(event_.Get(), this); } else { - HID_PLOG(EVENT) << "HID transfer failed"; + HID_PLOG(DEBUG) << "HID transfer failed"; std::move(callback_).Run(this, false); } } @@ -89,28 +104,33 @@ // static scoped_refptr<HidConnection> HidConnectionWin::Create( scoped_refptr<HidDeviceInfo> device_info, - base::win::ScopedHandle file, + std::vector<std::unique_ptr<HidDeviceEntry>> file_handles, bool allow_protected_reports) { - scoped_refptr<HidConnectionWin> connection(new HidConnectionWin( - std::move(device_info), std::move(file), allow_protected_reports)); - connection->ReadNextInputReport(); + scoped_refptr<HidConnectionWin> connection( + new HidConnectionWin(std::move(device_info), std::move(file_handles), + allow_protected_reports)); + connection->SetUpInitialReads(); return std::move(connection); } -HidConnectionWin::HidConnectionWin(scoped_refptr<HidDeviceInfo> device_info, - base::win::ScopedHandle file, - bool allow_protected_reports) +HidConnectionWin::HidConnectionWin( + scoped_refptr<HidDeviceInfo> device_info, + std::vector<std::unique_ptr<HidDeviceEntry>> file_handles, + bool allow_protected_reports) : HidConnection(std::move(device_info), allow_protected_reports), - file_(std::move(file)) {} + file_handles_(std::move(file_handles)) {} HidConnectionWin::~HidConnectionWin() { - DCHECK(!file_.IsValid()); + DCHECK(file_handles_.empty()); DCHECK(transfers_.empty()); } void HidConnectionWin::PlatformClose() { - CancelIo(file_.Get()); - file_.Close(); + for (auto& entry : file_handles_) { + CancelIo(entry->file_handle.Get()); + entry->file_handle.Close(); + } + file_handles_.clear(); transfers_.clear(); } @@ -124,11 +144,18 @@ DCHECK(buffer->size() <= expected_size); buffer->data().resize(expected_size); + uint8_t report_id = buffer->data()[0]; + HANDLE file_handle = GetHandleForReportId(report_id); + if (!IsValidHandle(file_handle)) { + HID_LOG(DEBUG) << "HID write failed due to invalid handle."; + std::move(callback).Run(false); + } + transfers_.push_back(std::make_unique<PendingHidTransfer>( buffer, base::BindOnce(&HidConnectionWin::OnWriteComplete, this, - std::move(callback)))); + file_handle, std::move(callback)))); transfers_.back()->TakeResultFromWindowsAPI(WriteFile( - file_.Get(), buffer->front(), static_cast<DWORD>(buffer->size()), NULL, + file_handle, buffer->front(), static_cast<DWORD>(buffer->size()), NULL, transfers_.back()->GetOverlapped())); } @@ -139,11 +166,17 @@ device_info()->max_feature_report_size() + 1); buffer->data()[0] = report_id; + HANDLE file_handle = GetHandleForReportId(report_id); + if (!IsValidHandle(file_handle)) { + HID_LOG(DEBUG) << "HID read failed due to invalid handle."; + std::move(callback).Run(false, nullptr, 0); + } + transfers_.push_back(std::make_unique<PendingHidTransfer>( buffer, base::BindOnce(&HidConnectionWin::OnReadFeatureComplete, this, - buffer, std::move(callback)))); + file_handle, buffer, std::move(callback)))); transfers_.back()->TakeResultFromWindowsAPI( - DeviceIoControl(file_.Get(), IOCTL_HID_GET_FEATURE, NULL, 0, + DeviceIoControl(file_handle, IOCTL_HID_GET_FEATURE, NULL, 0, buffer->front(), static_cast<DWORD>(buffer->size()), NULL, transfers_.back()->GetOverlapped())); } @@ -151,54 +184,65 @@ void HidConnectionWin::PlatformSendFeatureReport( scoped_refptr<base::RefCountedBytes> buffer, WriteCallback callback) { + uint8_t report_id = buffer->data()[0]; + HANDLE file_handle = GetHandleForReportId(report_id); + if (!IsValidHandle(file_handle)) { + HID_LOG(DEBUG) << "HID write failed due to invalid handle."; + std::move(callback).Run(false); + return; + } + // The Windows API always wants either a report ID (if supported) or // zero at the front of every output report. transfers_.push_back(std::make_unique<PendingHidTransfer>( buffer, base::BindOnce(&HidConnectionWin::OnWriteComplete, this, - std::move(callback)))); + file_handle, std::move(callback)))); transfers_.back()->TakeResultFromWindowsAPI( - DeviceIoControl(file_.Get(), IOCTL_HID_SET_FEATURE, buffer->front(), + DeviceIoControl(file_handle, IOCTL_HID_SET_FEATURE, buffer->front(), static_cast<DWORD>(buffer->size()), NULL, 0, NULL, transfers_.back()->GetOverlapped())); } -void HidConnectionWin::ReadNextInputReport() { +void HidConnectionWin::SetUpInitialReads() { + for (const auto& entry : file_handles_) + ReadNextInputReportOnHandle(entry->file_handle.Get()); +} + +void HidConnectionWin::ReadNextInputReportOnHandle(HANDLE file_handle) { // Windows will always include the report ID (including zero if report IDs // are not in use) in the buffer. auto buffer = base::MakeRefCounted<base::RefCountedBytes>( device_info()->max_input_report_size() + 1); transfers_.push_back(std::make_unique<PendingHidTransfer>( - buffer, - base::BindOnce(&HidConnectionWin::OnReadInputReport, this, buffer))); + buffer, base::BindOnce(&HidConnectionWin::OnReadInputReport, this, + file_handle, buffer))); transfers_.back()->TakeResultFromWindowsAPI( - ReadFile(file_.Get(), buffer->front(), static_cast<DWORD>(buffer->size()), + ReadFile(file_handle, buffer->front(), static_cast<DWORD>(buffer->size()), NULL, transfers_.back()->GetOverlapped())); } void HidConnectionWin::OnReadInputReport( + HANDLE file_handle, scoped_refptr<base::RefCountedBytes> buffer, PendingHidTransfer* transfer_raw, bool signaled) { - if (!file_.IsValid()) - return; - std::unique_ptr<PendingHidTransfer> transfer = UnlinkTransfer(transfer_raw); DWORD bytes_transferred; - if (!signaled || !GetOverlappedResult(file_.Get(), transfer->GetOverlapped(), + if (!signaled || !GetOverlappedResult(file_handle, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { - HID_PLOG(EVENT) << "HID read failed"; + HID_PLOG(DEBUG) << "HID read failed"; return; } if (bytes_transferred < 1) { - HID_LOG(EVENT) << "HID read too short."; + HID_LOG(DEBUG) << "HID read too short."; return; } uint8_t report_id = buffer->data()[0]; if (IsReportIdProtected(report_id, HidReportType::kInput)) { - ReadNextInputReport(); + ReadNextInputReportOnHandle(file_handle); return; } @@ -207,46 +251,38 @@ scoped_refptr<HidConnection> self(this); ProcessInputReport(buffer, bytes_transferred); - ReadNextInputReport(); + ReadNextInputReportOnHandle(file_handle); } void HidConnectionWin::OnReadFeatureComplete( + HANDLE file_handle, scoped_refptr<base::RefCountedBytes> buffer, ReadCallback callback, PendingHidTransfer* transfer_raw, bool signaled) { - if (!file_.IsValid()) { - std::move(callback).Run(false, nullptr, 0); - return; - } - std::unique_ptr<PendingHidTransfer> transfer = UnlinkTransfer(transfer_raw); DWORD bytes_transferred; - if (signaled && GetOverlappedResult(file_.Get(), transfer->GetOverlapped(), + if (signaled && GetOverlappedResult(file_handle, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { DCHECK_LE(bytes_transferred, buffer->size()); std::move(callback).Run(true, buffer, bytes_transferred); } else { - HID_PLOG(EVENT) << "HID read failed"; + HID_PLOG(DEBUG) << "HID read failed"; std::move(callback).Run(false, nullptr, 0); } } -void HidConnectionWin::OnWriteComplete(WriteCallback callback, +void HidConnectionWin::OnWriteComplete(HANDLE file_handle, + WriteCallback callback, PendingHidTransfer* transfer_raw, bool signaled) { - if (!file_.IsValid()) { - std::move(callback).Run(false); - return; - } - std::unique_ptr<PendingHidTransfer> transfer = UnlinkTransfer(transfer_raw); DWORD bytes_transferred; - if (signaled && GetOverlappedResult(file_.Get(), transfer->GetOverlapped(), + if (signaled && GetOverlappedResult(file_handle, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { std::move(callback).Run(true); } else { - HID_PLOG(EVENT) << "HID write failed"; + HID_PLOG(DEBUG) << "HID write failed"; std::move(callback).Run(false); } } @@ -264,4 +300,12 @@ return saved_transfer; } +HANDLE HidConnectionWin::GetHandleForReportId(uint8_t report_id) const { + for (const auto& entry : file_handles_) { + if (base::Contains(entry->report_ids, report_id)) + return entry->file_handle.Get(); + } + return nullptr; +} + } // namespace device
diff --git a/services/device/hid/hid_connection_win.h b/services/device/hid/hid_connection_win.h index e068cac..6fdb9e5e 100644 --- a/services/device/hid/hid_connection_win.h +++ b/services/device/hid/hid_connection_win.h
@@ -11,6 +11,7 @@ #include <list> +#include "base/containers/flat_set.h" #include "base/macros.h" #include "base/win/scoped_handle.h" #include "services/device/hid/hid_connection.h" @@ -21,9 +22,25 @@ class HidConnectionWin : public HidConnection { public: + // On Windows, a single HID interface may be represented by multiple file + // handles where each file handle represents one top-level HID collection. + // Maintain a mapping of report IDs to open file handles so that the correct + // handle is used for each report supported by the device. + struct HidDeviceEntry { + HidDeviceEntry(base::flat_set<uint8_t> report_ids, + base::win::ScopedHandle file_handle); + ~HidDeviceEntry(); + + // Reports with these IDs will be routed to |file_handle|. + base::flat_set<uint8_t> report_ids; + + // An open file handle representing a HID top-level collection. + base::win::ScopedHandle file_handle; + }; + static scoped_refptr<HidConnection> Create( scoped_refptr<HidDeviceInfo> device_info, - base::win::ScopedHandle file, + std::vector<std::unique_ptr<HidDeviceEntry>> file_handles, bool allow_protected_reports); private: @@ -31,7 +48,7 @@ friend class PendingHidTransfer; HidConnectionWin(scoped_refptr<HidDeviceInfo> device_info, - base::win::ScopedHandle file, + std::vector<std::unique_ptr<HidDeviceEntry>> file_handles, bool allow_protected_reports); ~HidConnectionWin() override; @@ -44,22 +61,31 @@ void PlatformSendFeatureReport(scoped_refptr<base::RefCountedBytes> buffer, WriteCallback callback) override; - void ReadNextInputReport(); - void OnReadInputReport(scoped_refptr<base::RefCountedBytes> buffer, + // Start listening for input reports from all devices in |file_handles_|. + void SetUpInitialReads(); + + // Listen for the next input report from |file_handle|. + void ReadNextInputReportOnHandle(HANDLE file_handle); + + void OnReadInputReport(HANDLE file_handle, + scoped_refptr<base::RefCountedBytes> buffer, PendingHidTransfer* transfer, bool signaled); - void OnReadFeatureComplete(scoped_refptr<base::RefCountedBytes> buffer, + void OnReadFeatureComplete(HANDLE file_handle, + scoped_refptr<base::RefCountedBytes> buffer, ReadCallback callback, PendingHidTransfer* transfer, bool signaled); - void OnWriteComplete(WriteCallback callback, + void OnWriteComplete(HANDLE file_handle, + WriteCallback callback, PendingHidTransfer* transfer, bool signaled); std::unique_ptr<PendingHidTransfer> UnlinkTransfer( PendingHidTransfer* transfer); + HANDLE GetHandleForReportId(uint8_t report_id) const; - base::win::ScopedHandle file_; + std::vector<std::unique_ptr<HidDeviceEntry>> file_handles_; std::list<std::unique_ptr<PendingHidTransfer>> transfers_;
diff --git a/services/device/hid/hid_device_info.cc b/services/device/hid/hid_device_info.cc index 93cf696..1b88096 100644 --- a/services/device/hid/hid_device_info.cc +++ b/services/device/hid/hid_device_info.cc
@@ -11,7 +11,22 @@ namespace device { -HidDeviceInfo::HidDeviceInfo(const HidPlatformDeviceId& platform_device_id, +HidDeviceInfo::PlatformDeviceIdEntry::PlatformDeviceIdEntry( + base::flat_set<uint8_t> report_ids, + HidPlatformDeviceId platform_device_id) + : report_ids(std::move(report_ids)), + platform_device_id(platform_device_id) {} + +HidDeviceInfo::PlatformDeviceIdEntry::PlatformDeviceIdEntry( + const PlatformDeviceIdEntry& entry) = default; + +HidDeviceInfo::PlatformDeviceIdEntry& +HidDeviceInfo::PlatformDeviceIdEntry::operator=( + const PlatformDeviceIdEntry& entry) = default; + +HidDeviceInfo::PlatformDeviceIdEntry::~PlatformDeviceIdEntry() = default; + +HidDeviceInfo::HidDeviceInfo(HidPlatformDeviceId platform_device_id, const std::string& physical_device_id, uint16_t vendor_id, uint16_t product_id, @@ -19,8 +34,7 @@ const std::string& serial_number, mojom::HidBusType bus_type, const std::vector<uint8_t> report_descriptor, - std::string device_node) - : platform_device_id_(platform_device_id) { + std::string device_node) { std::vector<mojom::HidCollectionInfoPtr> collections; bool has_report_id; size_t max_input_report_size; @@ -39,6 +53,17 @@ auto protected_feature_report_ids = HidBlocklist::Get().GetProtectedReportIds( HidBlocklist::kReportTypeFeature, vendor_id, product_id, collections); + std::vector<uint8_t> report_ids; + if (has_report_id) { + for (const auto& collection : collections) { + report_ids.insert(report_ids.end(), collection->report_ids.begin(), + collection->report_ids.end()); + } + } else { + report_ids.push_back(0); + } + platform_device_id_map_.emplace_back(report_ids, platform_device_id); + device_ = mojom::HidDeviceInfo::New( base::GenerateGUID(), physical_device_id, vendor_id, product_id, product_name, serial_number, bus_type, report_descriptor, @@ -48,21 +73,26 @@ protected_feature_report_ids); } -HidDeviceInfo::HidDeviceInfo(const HidPlatformDeviceId& platform_device_id, - const std::string& physical_device_id, - uint16_t vendor_id, - uint16_t product_id, - const std::string& product_name, - const std::string& serial_number, - mojom::HidBusType bus_type, - mojom::HidCollectionInfoPtr collection, - size_t max_input_report_size, - size_t max_output_report_size, - size_t max_feature_report_size) - : platform_device_id_(platform_device_id) { - std::vector<mojom::HidCollectionInfoPtr> collections; - bool has_report_id = !collection->report_ids.empty(); - collections.push_back(std::move(collection)); +HidDeviceInfo::HidDeviceInfo( + PlatformDeviceIdMap platform_device_id_map, + const std::string& physical_device_id, + uint16_t vendor_id, + uint16_t product_id, + const std::string& product_name, + const std::string& serial_number, + mojom::HidBusType bus_type, + std::vector<mojom::HidCollectionInfoPtr> collections, + size_t max_input_report_size, + size_t max_output_report_size, + size_t max_feature_report_size) + : platform_device_id_map_(std::move(platform_device_id_map)) { + bool has_report_id = false; + for (const auto& collection : collections) { + if (!collection->report_ids.empty()) { + has_report_id = true; + break; + } + } auto protected_input_report_ids = HidBlocklist::Get().GetProtectedReportIds( HidBlocklist::kReportTypeInput, vendor_id, product_id, collections);
diff --git a/services/device/hid/hid_device_info.h b/services/device/hid/hid_device_info.h index 0c84e73..e5ae5a0 100644 --- a/services/device/hid/hid_device_info.h +++ b/services/device/hid/hid_device_info.h
@@ -11,6 +11,7 @@ #include <string> #include <vector> +#include "base/containers/flat_set.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/strings/string16.h" @@ -29,7 +30,21 @@ class HidDeviceInfo : public base::RefCountedThreadSafe<HidDeviceInfo> { public: - HidDeviceInfo(const HidPlatformDeviceId& platform_device_id, + // PlatformDeviceIdMap defines a mapping from report IDs to the + // HidPlatformDeviceId responsible for handling those reports. + struct PlatformDeviceIdEntry { + PlatformDeviceIdEntry(base::flat_set<uint8_t> report_ids, + HidPlatformDeviceId platform_device_id); + PlatformDeviceIdEntry(const PlatformDeviceIdEntry& entry); + PlatformDeviceIdEntry& operator=(const PlatformDeviceIdEntry& entry); + ~PlatformDeviceIdEntry(); + + base::flat_set<uint8_t> report_ids; + HidPlatformDeviceId platform_device_id; + }; + using PlatformDeviceIdMap = std::vector<PlatformDeviceIdEntry>; + + HidDeviceInfo(HidPlatformDeviceId platform_device_id, const std::string& physical_device_id, uint16_t vendor_id, uint16_t product_id, @@ -39,14 +54,14 @@ const std::vector<uint8_t> report_descriptor, std::string device_node = ""); - HidDeviceInfo(const HidPlatformDeviceId& platform_device_id, + HidDeviceInfo(PlatformDeviceIdMap platform_device_id_map, const std::string& physical_device_id, uint16_t vendor_id, uint16_t product_id, const std::string& product_name, const std::string& serial_number, mojom::HidBusType bus_type, - mojom::HidCollectionInfoPtr collection, + std::vector<mojom::HidCollectionInfoPtr> collections, size_t max_input_report_size, size_t max_output_report_size, size_t max_feature_report_size); @@ -55,8 +70,8 @@ // Device identification. const std::string& device_guid() const { return device_->guid; } - const HidPlatformDeviceId& platform_device_id() const { - return platform_device_id_; + const PlatformDeviceIdMap& platform_device_id_map() const { + return platform_device_id_map_; } const std::string& physical_device_id() const { return device_->physical_device_id; @@ -94,7 +109,7 @@ private: friend class base::RefCountedThreadSafe<HidDeviceInfo>; - HidPlatformDeviceId platform_device_id_; + PlatformDeviceIdMap platform_device_id_map_; mojom::HidDeviceInfoPtr device_; DISALLOW_COPY_AND_ASSIGN(HidDeviceInfo);
diff --git a/services/device/hid/hid_manager_unittest.cc b/services/device/hid/hid_manager_unittest.cc index ad3a5728..f946bb6b 100644 --- a/services/device/hid/hid_manager_unittest.cc +++ b/services/device/hid/hid_manager_unittest.cc
@@ -163,12 +163,17 @@ scoped_refptr<HidDeviceInfo> AddTestDeviceWithTopLevelCollection() { // Construct a HidDeviceInfo with a top-level collection. The collection has // a usage ID from the FIDO usage page. + HidDeviceInfo::PlatformDeviceIdMap platform_device_id_map; + platform_device_id_map.emplace_back(base::flat_set<uint8_t>{0}, + kTestDeviceIds[2]); + std::vector<mojom::HidCollectionInfoPtr> collections; auto collection_info = mojom::HidCollectionInfo::New(); collection_info->usage = mojom::HidUsageAndPage::New(1, 0xf1d0); + collections.push_back(std::move(collection_info)); auto device_info = base::MakeRefCounted<HidDeviceInfo>( - kTestDeviceIds[2], "physical id 2", /*vendor_id=*/0, /*product_id=*/0, - "Hid Service Unit Test", "HidDevice-2", - mojom::HidBusType::kHIDBusTypeUSB, std::move(collection_info), + std::move(platform_device_id_map), "physical id 2", /*vendor_id=*/0, + /*product_id=*/0, "Hid Service Unit Test", "HidDevice-2", + mojom::HidBusType::kHIDBusTypeUSB, std::move(collections), /*max_input_report_size=*/64, /*max_output_report_size=*/64, /*max_feature_report_size=*/64); mock_hid_service_->AddDevice(device_info);
diff --git a/services/device/hid/hid_service.cc b/services/device/hid/hid_service.cc index 09a7fd2..4ec2d7b31 100644 --- a/services/device/hid/hid_service.cc +++ b/services/device/hid/hid_service.cc
@@ -4,6 +4,8 @@ #include "services/device/hid/hid_service.h" +#include <sstream> + #include "base/at_exit.h" #include "base/bind.h" #include "base/containers/contains.h" @@ -24,6 +26,26 @@ namespace device { +namespace { + +// Formats the platform device IDs in |platform_device_id_map| into a +// comma-separated list for logging. The report IDs are not logged. +std::string PlatformDeviceIdsToString( + const HidDeviceInfo::PlatformDeviceIdMap& platform_device_id_map) { + std::ostringstream buf("'"); + bool first = true; + for (const auto& entry : platform_device_id_map) { + if (!first) + buf << "', '"; + first = false; + buf << entry.platform_device_id; + } + buf << "'"; + return buf.str(); +} + +} // namespace + void HidService::Observer::OnDeviceAdded(mojom::HidDeviceInfoPtr device_info) {} void HidService::Observer::OnDeviceRemoved( @@ -74,9 +96,12 @@ void HidService::AddDevice(scoped_refptr<HidDeviceInfo> device_info) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::string device_guid = - FindDeviceIdByPlatformDeviceId(device_info->platform_device_id()); - if (device_guid.empty()) { + base::Optional<std::string> found_guid = base::nullopt; + for (const auto& entry : device_info->platform_device_id_map()) { + if ((found_guid = FindDeviceGuidInDeviceMap(entry.platform_device_id))) + break; + } + if (!found_guid) { devices_[device_info->device_guid()] = device_info; HID_LOG(USER) << "HID device " @@ -84,8 +109,10 @@ << ": vendorId=" << device_info->vendor_id() << ", productId=" << device_info->product_id() << ", name='" << device_info->product_name() << "', serial='" - << device_info->serial_number() << "', deviceId='" - << device_info->platform_device_id() << "'"; + << device_info->serial_number() << "', deviceIds=[" + << PlatformDeviceIdsToString( + device_info->platform_device_id_map()) + << "]"; if (enumeration_ready_) { for (auto& observer : observer_list_) @@ -97,18 +124,18 @@ void HidService::RemoveDevice(const HidPlatformDeviceId& platform_device_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::string device_guid = FindDeviceIdByPlatformDeviceId(platform_device_id); - if (!device_guid.empty()) { + auto found_guid = FindDeviceGuidInDeviceMap(platform_device_id); + if (found_guid) { HID_LOG(USER) << "HID device removed: deviceId='" << platform_device_id << "'"; - DCHECK(base::Contains(devices_, device_guid)); + DCHECK(base::Contains(devices_, *found_guid)); - scoped_refptr<HidDeviceInfo> device_info = devices_[device_guid]; + scoped_refptr<HidDeviceInfo> device_info = devices_[*found_guid]; if (enumeration_ready_) { for (auto& observer : observer_list_) observer.OnDeviceRemoved(device_info->device()->Clone()); } - devices_.erase(device_guid); + devices_.erase(*found_guid); } } @@ -135,14 +162,17 @@ } } -std::string HidService::FindDeviceIdByPlatformDeviceId( +base::Optional<std::string> HidService::FindDeviceGuidInDeviceMap( const HidPlatformDeviceId& platform_device_id) { - for (const auto& map_entry : devices_) { - if (map_entry.second->platform_device_id() == platform_device_id) { - return map_entry.first; + for (const auto& device_entry : devices_) { + const auto& platform_device_map = + device_entry.second->platform_device_id_map(); + for (const auto& platform_device_entry : platform_device_map) { + if (platform_device_entry.platform_device_id == platform_device_id) + return device_entry.first; } } - return std::string(); + return base::nullopt; } } // namespace device
diff --git a/services/device/hid/hid_service.h b/services/device/hid/hid_service.h index a6c4790b..725573de 100644 --- a/services/device/hid/hid_service.h +++ b/services/device/hid/hid_service.h
@@ -89,7 +89,7 @@ private: void RunPendingEnumerations(); - std::string FindDeviceIdByPlatformDeviceId( + base::Optional<std::string> FindDeviceGuidInDeviceMap( const HidPlatformDeviceId& platform_device_id); DeviceMap devices_;
diff --git a/services/device/hid/hid_service_linux.cc b/services/device/hid/hid_service_linux.cc index de3637e3f..b3942252 100644 --- a/services/device/hid/hid_service_linux.cc +++ b/services/device/hid/hid_service_linux.cc
@@ -446,7 +446,7 @@ DCHECK(params->fd.is_valid()); if (!base::SetNonBlocking(params->fd.get())) { - HID_PLOG(ERROR) << "Failed to set the non-blocking flag on the device fd"; + HID_PLOG(DEBUG) << "Failed to set the non-blocking flag on the device fd"; std::move(params->callback).Run(nullptr); return; }
diff --git a/services/device/hid/hid_service_mac.cc b/services/device/hid/hid_service_mac.cc index 72ba607..65443746 100644 --- a/services/device/hid/hid_service_mac.cc +++ b/services/device/hid/hid_service_mac.cc
@@ -105,7 +105,7 @@ IOServiceMatching(kIOHIDDeviceKey), FirstMatchCallback, this, devices_added_iterator_.InitializeInto()); if (result != kIOReturnSuccess) { - HID_LOG(ERROR) << "Failed to listen for device arrival: " + HID_LOG(DEBUG) << "Failed to listen for device arrival: " << HexErrorCode(result); return; } @@ -118,7 +118,7 @@ IOServiceMatching(kIOHIDDeviceKey), TerminatedCallback, this, devices_removed_iterator_.InitializeInto()); if (result != kIOReturnSuccess) { - HID_LOG(ERROR) << "Failed to listen for device removal: " + HID_LOG(DEBUG) << "Failed to listen for device removal: " << HexErrorCode(result); return; } @@ -157,11 +157,14 @@ // static base::ScopedCFTypeRef<IOHIDDeviceRef> HidServiceMac::OpenOnBlockingThread( scoped_refptr<HidDeviceInfo> device_info) { + DCHECK_EQ(device_info->platform_device_id_map().size(), 1u); + const auto& platform_device_id = + device_info->platform_device_id_map().front().platform_device_id; base::ScopedCFTypeRef<CFDictionaryRef> matching_dict( - IORegistryEntryIDMatching(device_info->platform_device_id())); + IORegistryEntryIDMatching(platform_device_id)); if (!matching_dict.get()) { - HID_LOG(EVENT) << "Failed to create matching dictionary for ID: " - << device_info->platform_device_id(); + HID_LOG(DEBUG) << "Failed to create matching dictionary for ID: " + << platform_device_id; return base::ScopedCFTypeRef<IOHIDDeviceRef>(); } @@ -170,21 +173,20 @@ base::mac::ScopedIOObject<io_service_t> service(IOServiceGetMatchingService( kIOMasterPortDefault, matching_dict.release())); if (!service.get()) { - HID_LOG(EVENT) << "IOService not found for ID: " - << device_info->platform_device_id(); + HID_LOG(DEBUG) << "IOService not found for ID: " << platform_device_id; return base::ScopedCFTypeRef<IOHIDDeviceRef>(); } base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device( IOHIDDeviceCreate(kCFAllocatorDefault, service)); if (!hid_device) { - HID_LOG(EVENT) << "Unable to create IOHIDDevice object."; + HID_LOG(DEBUG) << "Unable to create IOHIDDevice object."; return base::ScopedCFTypeRef<IOHIDDeviceRef>(); } IOReturn result = IOHIDDeviceOpen(hid_device, kIOHIDOptionsTypeNone); if (result != kIOReturnSuccess) { - HID_LOG(EVENT) << "Failed to open device: " << HexErrorCode(result); + HID_LOG(DEBUG) << "Failed to open device: " << HexErrorCode(result); return base::ScopedCFTypeRef<IOHIDDeviceRef>(); }
diff --git a/services/device/hid/hid_service_win.cc b/services/device/hid/hid_service_win.cc index 34a2000..e6180f2 100644 --- a/services/device/hid/hid_service_win.cc +++ b/services/device/hid/hid_service_win.cc
@@ -25,7 +25,9 @@ #include "base/location.h" #include "base/memory/free_deleter.h" #include "base/sequenced_task_runner.h" +#include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/task/thread_pool.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -67,23 +69,72 @@ item->is_buffered_bytes = bit_field & kBitFieldFlagBufferedBytes; } -// Looks up the value of a GUID-type device property specified by |property| for -// the device described by |device_info_data|. On success, returns true and sets -// |property_buffer| to the property value. Returns false if the property is not -// present or has a different type. -bool GetDeviceGuidProperty(HDEVINFO device_info_set, - SP_DEVINFO_DATA& device_info_data, - const DEVPROPKEY& property, - GUID* property_buffer) { +// Looks up the value of a string list device property specified by +// |property_key| for the device described by |device_info_data|. On success, +// returns the property value as a string vector. Returns base::nullopt if the +// property is not present or has a different type. +base::Optional<std::vector<std::wstring>> GetDeviceStringListProperty( + HDEVINFO device_info_set, + SP_DEVINFO_DATA& device_info_data, + const DEVPROPKEY& property_key) { DEVPROPTYPE property_type; - if (!SetupDiGetDeviceProperty( - device_info_set, &device_info_data, &property, &property_type, - reinterpret_cast<PBYTE>(property_buffer), sizeof(*property_buffer), - /*RequiredSize=*/nullptr, /*Flags=*/0) || - property_type != DEVPROP_TYPE_GUID) { - return false; + DWORD required_size; + if (SetupDiGetDeviceProperty(device_info_set, &device_info_data, + &property_key, &property_type, + /*PropertyBuffer=*/nullptr, + /*PropertyBufferSize=*/0, &required_size, + /*Flags=*/0)) { + HID_LOG(DEBUG) << "SetupDiGetDeviceProperty unexpectedly succeeded."; + return base::nullopt; } - return true; + + DWORD last_error = GetLastError(); + if (last_error == ERROR_NOT_FOUND) + return base::nullopt; + + if (last_error != ERROR_INSUFFICIENT_BUFFER) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed"; + return base::nullopt; + } + + if (property_type != DEVPROP_TYPE_STRING_LIST) + return base::nullopt; + + base::string16 buffer16; + if (!SetupDiGetDeviceProperty( + device_info_set, &device_info_data, &property_key, &property_type, + reinterpret_cast<PBYTE>(base::WriteInto(&buffer16, required_size)), + required_size, /*RequiredSize=*/nullptr, /*Flags=*/0)) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed"; + return base::nullopt; + } + + return base::SplitString(buffer16, base::WStringPiece(L"\0", 1), + base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); +} + +// Looks up the value of a GUID-type device property specified by |property| for +// the device described by |device_info_data|. On success, returns the property +// value as a string. Returns base::nullopt if the property is not present or +// has a different type. +base::Optional<std::string> GetDeviceGuidProperty( + HDEVINFO device_info_set, + SP_DEVINFO_DATA& device_info_data, + const DEVPROPKEY& property_key) { + DEVPROPTYPE property_type; + GUID property_buffer; + if (!SetupDiGetDeviceProperty( + device_info_set, &device_info_data, &property_key, &property_type, + reinterpret_cast<PBYTE>(&property_buffer), sizeof(property_buffer), + /*RequiredSize=*/nullptr, /*Flags=*/0)) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed"; + return base::nullopt; + } + + if (property_type != DEVPROP_TYPE_GUID) + return base::nullopt; + + return base::SysWideToUTF8(base::win::WStringFromGUID(property_buffer)); } // Looks up information about the device described by |device_interface_data| @@ -103,8 +154,13 @@ /*DeviceInterfaceDetailData=*/nullptr, /*DeviceInterfaceDetailSize=*/0, &required_size, - /*DeviceInfoData=*/nullptr) || - GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + /*DeviceInfoData=*/nullptr)) { + HID_LOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail unexpectedly succeeded."; + return false; + } + + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed"; return false; } @@ -119,6 +175,7 @@ device_interface_detail_data.get(), required_size, /*RequiredSize=*/nullptr, device_info_data)) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed"; return false; } @@ -130,22 +187,83 @@ return true; } +// Returns a device path for the HID device described by |instance_id|, or +// base::nullopt if an error occurred. +base::Optional<std::wstring> GetDevicePathFromInstanceId( + const std::wstring& instance_id) { + base::win::ScopedDevInfo device_info_set(SetupDiGetClassDevs( + &GUID_DEVINTERFACE_HID, instance_id.c_str(), + /*hwndParent=*/0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); + if (!device_info_set.is_valid()) { + HID_PLOG(DEBUG) << "SetupDiGetClassDevsA failed"; + return base::nullopt; + } + + // Assume there is at most one matching device. + SP_DEVICE_INTERFACE_DATA device_interface_data; + device_interface_data.cbSize = sizeof(device_interface_data); + if (!SetupDiEnumDeviceInterfaces(device_info_set.get(), + /*DeviceInfoData=*/nullptr, + &GUID_DEVINTERFACE_HID, + /*MemberIndex=*/0, &device_interface_data)) { + HID_PLOG(DEBUG) << "SetupDiEnumDeviceInterfaces failed"; + return base::nullopt; + } + + // Determine the required size of the detail struct. + DWORD required_size = 0; + if (SetupDiGetDeviceInterfaceDetail( + device_info_set.get(), &device_interface_data, + /*DeviceInterfaceDetailData=*/nullptr, + /*DeviceInterfaceDetailDataSize=*/0, &required_size, + /*DeviceInfoData=*/nullptr)) { + HID_LOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail unexpectedly succeeded."; + return base::nullopt; + } + + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed"; + return base::nullopt; + } + + std::unique_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA, base::FreeDeleter> + device_interface_detail_data( + static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(malloc(required_size))); + device_interface_detail_data->cbSize = sizeof(*device_interface_detail_data); + + // Get the detailed data for this device. + if (!SetupDiGetDeviceInterfaceDetail( + device_info_set.get(), &device_interface_data, + device_interface_detail_data.get(), required_size, + /*RequiredSize=*/nullptr, + /*DeviceInfoData=*/nullptr)) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed"; + return base::nullopt; + } + + DCHECK(base::IsStringASCII(device_interface_detail_data->DevicePath)); + return base::ToLowerASCII(device_interface_detail_data->DevicePath); +} + // Returns a device info set containing only the device described by // |device_path|, or an invalid ScopedDevInfo if there was an error while // creating the device set. The device info is returned in |device_info_data|. -base::win::ScopedDevInfo GetDeviceInfoFromPath( +base::win::ScopedDevInfo GetDeviceInfoSetFromDevicePath( const std::wstring& device_path, SP_DEVINFO_DATA* device_info_data) { base::win::ScopedDevInfo device_info_set(SetupDiGetClassDevs( &GUID_DEVINTERFACE_HID, /*Enumerator=*/nullptr, /*hwndParent=*/0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); - if (!device_info_set.is_valid()) + if (!device_info_set.is_valid()) { + HID_PLOG(DEBUG) << "SetupDiGetClassDevs failed"; return base::win::ScopedDevInfo(); + } SP_DEVICE_INTERFACE_DATA device_interface_data; device_interface_data.cbSize = sizeof(device_interface_data); if (!SetupDiOpenDeviceInterface(device_info_set.get(), device_path.c_str(), /*OpenFlags=*/0, &device_interface_data)) { + HID_PLOG(DEBUG) << "SetupDiOpenDeviceInterface failed"; return base::win::ScopedDevInfo(); } @@ -157,6 +275,83 @@ return device_info_set; } +// Looks up the device instance ID for the device described by +// |device_info_data|. On success, returns the property value as a string +// vector. Returns base::nullopt if the property is not present or has a +// different type. +base::Optional<std::wstring> GetDeviceInstanceId( + HDEVINFO device_info_set, + SP_DEVINFO_DATA& device_info_data) { + DEVPROPTYPE property_type; + DWORD required_size; + if (SetupDiGetDeviceProperty(device_info_set, &device_info_data, + &DEVPKEY_Device_InstanceId, &property_type, + /*PropertyBuffer=*/nullptr, + /*PropertyBufferSize=*/0, &required_size, + /*Flags=*/0)) { + HID_LOG(DEBUG) << "SetupDiGetDeviceProperty unexpectedly succeeded."; + return base::nullopt; + } + + DWORD last_error = GetLastError(); + if (last_error == ERROR_NOT_FOUND) + return base::nullopt; + + if (last_error != ERROR_INSUFFICIENT_BUFFER) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed"; + return base::nullopt; + } + + if (property_type != DEVPROP_TYPE_STRING) + return base::nullopt; + + std::wstring instance_id; + if (!SetupDiGetDeviceProperty( + device_info_set, &device_info_data, &DEVPKEY_Device_InstanceId, + &property_type, + reinterpret_cast<PBYTE>(base::WriteInto(&instance_id, required_size)), + required_size, /*RequiredSize=*/nullptr, /*Flags=*/0)) { + HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed"; + return base::nullopt; + } + + // Canonicalize the instance ID. + DCHECK(base::IsStringASCII(instance_id)); + instance_id = base::ToLowerASCII(instance_id); + // Removing trailing NUL bytes. + return std::wstring(base::TrimString( + instance_id, base::WStringPiece(L"\0", 1), base::TRIM_TRAILING)); +} + +// Returns a vector of instance IDs for all siblings of the device described by +// |device_interface_data| in |device_info_set|. Returns an empty vector if the +// instance IDs could not be retrieved. +std::vector<std::wstring> GetSiblingInstanceIds( + HDEVINFO device_info_set, + SP_DEVICE_INTERFACE_DATA& device_interface_data) { + // Get device info for |device_interface_data|. + SP_DEVINFO_DATA device_info_data = {0}; + device_info_data.cbSize = sizeof(device_info_data); + std::wstring device_path; + if (!GetDeviceInfoAndPathFromInterface(device_info_set, device_interface_data, + &device_info_data, &device_path)) { + return {}; + } + + // Get the sibling instance IDs. + auto instance_ids = GetDeviceStringListProperty( + device_info_set, device_info_data, DEVPKEY_Device_Siblings); + if (!instance_ids) + return {}; + + // Canonicalize the instance IDs. + for (auto& instance_id : *instance_ids) { + DCHECK(base::IsStringASCII(instance_id)); + instance_id = base::ToLowerASCII(instance_id); + } + return *instance_ids; +} + mojom::HidReportItemPtr CreateHidReportItem( const HidServiceWin::PreparsedData::ReportItem& item) { auto hid_report_item = mojom::HidReportItem::New(); @@ -364,19 +559,32 @@ } scoped_refptr<HidDeviceInfo> device_info = map_entry->second; - base::win::ScopedHandle file(OpenDevice(device_info->platform_device_id())); - if (!file.IsValid()) { - HID_PLOG(EVENT) << "Failed to open device"; + const auto& platform_device_id_map = device_info->platform_device_id_map(); + std::vector<std::unique_ptr<HidConnectionWin::HidDeviceEntry>> file_handles; + for (const auto& entry : platform_device_id_map) { + base::win::ScopedHandle file_handle(OpenDevice(entry.platform_device_id)); + if (!file_handle.IsValid()) { + HID_PLOG(DEBUG) << "Failed to open device with deviceId='" + << entry.platform_device_id << "'"; + continue; + } + + file_handles.push_back(std::make_unique<HidConnectionWin::HidDeviceEntry>( + entry.report_ids, std::move(file_handle))); + } + + if (file_handles.empty()) { + // Report failure if none of the file handles could be opened. task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(callback), nullptr)); return; } task_runner_->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - HidConnectionWin::Create(device_info, std::move(file), - allow_protected_reports))); + FROM_HERE, base::BindOnce(std::move(callback), + HidConnectionWin::Create( + device_info, std::move(file_handles), + allow_protected_reports))); } base::WeakPtr<HidService> HidServiceWin::GetWeakPtr() { @@ -387,37 +595,61 @@ void HidServiceWin::EnumerateBlocking( base::WeakPtr<HidServiceWin> service, scoped_refptr<base::SequencedTaskRunner> task_runner) { - base::win::ScopedDevInfo dev_info(SetupDiGetClassDevs( + base::win::ScopedDevInfo device_info_set(SetupDiGetClassDevs( &GUID_DEVINTERFACE_HID, /*Enumerator=*/nullptr, /*hwndParent=*/nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); - if (dev_info.is_valid()) { + // Remember the instance IDs of devices that have already been enumerated. + base::flat_set<std::wstring> seen_instance_ids; + + if (device_info_set.is_valid()) { SP_DEVICE_INTERFACE_DATA device_interface_data = {0}; device_interface_data.cbSize = sizeof(device_interface_data); for (int device_index = 0; SetupDiEnumDeviceInterfaces( - dev_info.get(), /*DeviceInfoData=*/nullptr, &GUID_DEVINTERFACE_HID, - device_index, &device_interface_data); + device_info_set.get(), /*DeviceInfoData=*/nullptr, + &GUID_DEVINTERFACE_HID, device_index, &device_interface_data); ++device_index) { - SP_DEVINFO_DATA dev_info_data = {0}; - dev_info_data.cbSize = sizeof(dev_info_data); + SP_DEVINFO_DATA device_info_data = {0}; + device_info_data.cbSize = sizeof(device_info_data); std::wstring device_path; - if (!GetDeviceInfoAndPathFromInterface(dev_info.get(), + if (!GetDeviceInfoAndPathFromInterface(device_info_set.get(), device_interface_data, - &dev_info_data, &device_path)) { + &device_info_data, &device_path)) { continue; } + // Get the instance ID. Skip this device if it was already enumerated as a + // sibling of another device. + auto instance_id = + GetDeviceInstanceId(device_info_set.get(), device_info_data); + if (!instance_id || base::Contains(seen_instance_ids, *instance_id)) + continue; + seen_instance_ids.insert(*instance_id); + // Get the container ID for the physical device. - GUID container_id; - if (!GetDeviceGuidProperty(dev_info.get(), dev_info_data, - DEVPKEY_Device_ContainerId, &container_id)) { + auto physical_device_id = GetDeviceGuidProperty( + device_info_set.get(), device_info_data, DEVPKEY_Device_ContainerId); + if (!physical_device_id) continue; - } - std::string physical_device_id = - base::WideToUTF8(base::win::WStringFromGUID(container_id)); - AddDeviceBlocking(service, task_runner, device_path, physical_device_id); + // Get the instance IDs for any siblings of the added device. Siblings of + // a HID device node represent other top-level collections generated from + // the same HID interface. + auto sibling_instance_ids = + GetSiblingInstanceIds(device_info_set.get(), device_interface_data); + + // Get the device path for each sibling from its instance ID. + std::vector<std::wstring> device_paths = {device_path}; + for (auto sibling_instance_id : sibling_instance_ids) { + seen_instance_ids.insert(sibling_instance_id); + auto sibling_path = GetDevicePathFromInstanceId(sibling_instance_id); + if (sibling_path) + device_paths.push_back(std::move(*sibling_path)); + } + + AddDeviceBlocking(service, task_runner, device_paths, + *physical_device_id); } } @@ -430,51 +662,84 @@ void HidServiceWin::AddDeviceBlocking( base::WeakPtr<HidServiceWin> service, scoped_refptr<base::SequencedTaskRunner> task_runner, - const std::wstring& device_path, + const std::vector<std::wstring>& device_paths, const std::string& physical_device_id) { - base::win::ScopedHandle device_handle(OpenDevice(device_path)); - if (!device_handle.IsValid()) { - return; - } - - HIDD_ATTRIBUTES attrib = {0}; - attrib.Size = sizeof(attrib); - if (!HidD_GetAttributes(device_handle.Get(), &attrib)) { - HID_LOG(EVENT) << "Failed to get device attributes."; - return; - } - - auto preparsed_data = HidPreparsedData::Create(device_handle.Get()); - if (!preparsed_data) - return; - - // 1023 characters plus NULL terminator is more than enough for a USB string - // descriptor which is limited to 126 characters. - base::char16 buffer[1024]; + // On Windows, HID interfaces with multiple top-level collections are split + // into separate device nodes. Merge these top-level collections into a single + // HidDeviceInfo object. + uint16_t vendor_id = 0; + uint16_t product_id = 0; std::string product_name; - if (HidD_GetProductString(device_handle.Get(), &buffer[0], sizeof(buffer))) { - // NULL termination guaranteed by the API. - product_name = base::UTF16ToUTF8(buffer); - } std::string serial_number; - if (HidD_GetSerialNumberString(device_handle.Get(), &buffer[0], - sizeof(buffer))) { - // NULL termination guaranteed by the API. - serial_number = base::UTF16ToUTF8(buffer); + HidDeviceInfo::PlatformDeviceIdMap platform_device_id_map; + std::vector<mojom::HidCollectionInfoPtr> collections; + uint16_t max_input_report_size = 0; + uint16_t max_output_report_size = 0; + uint16_t max_feature_report_size = 0; + for (const auto& device_path : device_paths) { + base::win::ScopedHandle device_handle(OpenDevice(device_path)); + if (!device_handle.IsValid()) + continue; + + auto preparsed_data = HidPreparsedData::Create(device_handle.Get()); + if (!preparsed_data) + continue; + + // USB-level device properties should not differ for device nodes that are + // part of the same physical device. Only read these properties once. + if (collections.empty()) { + HIDD_ATTRIBUTES attrib = {0}; + attrib.Size = sizeof(attrib); + if (!HidD_GetAttributes(device_handle.Get(), &attrib)) { + HID_LOG(DEBUG) << "Failed to get device attributes."; + continue; + } + vendor_id = attrib.VendorID; + product_id = attrib.ProductID; + + // 1023 characters plus NULL terminator is more than enough for a USB + // string descriptor which is limited to 126 characters. + base::char16 buffer[1024]; + if (HidD_GetProductString(device_handle.Get(), &buffer[0], + sizeof(buffer))) { + // NULL termination guaranteed by the API. + product_name = base::UTF16ToUTF8(buffer); + } + if (HidD_GetSerialNumberString(device_handle.Get(), &buffer[0], + sizeof(buffer))) { + // NULL termination guaranteed by the API. + serial_number = base::UTF16ToUTF8(buffer); + } + } + + // Create a HidCollectionInfo for |device_path| and update the relevant + // HidDeviceInfo properties. + auto collection = preparsed_data->CreateHidCollectionInfo(); + platform_device_id_map.emplace_back(collection->report_ids, device_path); + collections.push_back(std::move(collection)); + max_input_report_size = std::max( + max_input_report_size, preparsed_data->GetReportByteLength(HidP_Input)); + max_output_report_size = + std::max(max_output_report_size, + preparsed_data->GetReportByteLength(HidP_Output)); + max_feature_report_size = + std::max(max_feature_report_size, + preparsed_data->GetReportByteLength(HidP_Feature)); } + // Only add the device if we were able to create a HidCollectionInfo for at + // least one of the paths in |device_paths|. + if (collections.empty()) + return; + // This populates the HidDeviceInfo instance without a raw report descriptor. - // The descriptor is unavailable on Windows because HID devices are exposed to - // user-space as individual top-level collections. - scoped_refptr<HidDeviceInfo> device_info( - new HidDeviceInfo(device_path, physical_device_id, attrib.VendorID, - attrib.ProductID, product_name, serial_number, - // TODO(crbug.com/443335): Detect Bluetooth. - mojom::HidBusType::kHIDBusTypeUSB, - preparsed_data->CreateHidCollectionInfo(), - preparsed_data->GetReportByteLength(HidP_Input), - preparsed_data->GetReportByteLength(HidP_Output), - preparsed_data->GetReportByteLength(HidP_Feature))); + // The descriptor is unavailable on Windows. + scoped_refptr<HidDeviceInfo> device_info(new HidDeviceInfo( + std::move(platform_device_id_map), physical_device_id, vendor_id, + product_id, product_name, serial_number, + // TODO(crbug.com/443335): Detect Bluetooth. + mojom::HidBusType::kHIDBusTypeUSB, std::move(collections), + max_input_report_size, max_output_report_size, max_feature_report_size)); task_runner->PostTask(FROM_HERE, base::BindOnce(&HidServiceWin::AddDevice, service, device_info)); @@ -484,22 +749,50 @@ const std::wstring& device_path) { SP_DEVINFO_DATA device_info_data = {0}; device_info_data.cbSize = sizeof(device_info_data); - auto device_info_set = GetDeviceInfoFromPath(device_path, &device_info_data); + auto device_info_set = + GetDeviceInfoSetFromDevicePath(device_path, &device_info_data); if (!device_info_set.is_valid()) return; - GUID container_id; - if (!GetDeviceGuidProperty(device_info_set.get(), device_info_data, - DEVPKEY_Device_ContainerId, &container_id)) { + // Assume there is at most one matching device. + SP_DEVICE_INTERFACE_DATA device_interface_data; + device_interface_data.cbSize = sizeof(device_interface_data); + if (!SetupDiEnumDeviceInterfaces(device_info_set.get(), &device_info_data, + &GUID_DEVINTERFACE_HID, + /*MemberIndex=*/0, &device_interface_data)) { + HID_PLOG(DEBUG) << "SetupDiEnumDeviceInterfaces failed"; return; } - std::string physical_device_id = - base::WideToUTF8(base::win::WStringFromGUID(container_id)); + + // Get the container ID for the physical device. + auto physical_device_id = GetDeviceGuidProperty( + device_info_set.get(), device_info_data, DEVPKEY_Device_ContainerId); + if (!physical_device_id) + return; + + // Get the instance IDs for any siblings of the added device. Siblings of a + // HID device node represent other top-level collections generated from the + // same HID interface. + // + // It is expected that OnDeviceAdded will be called again for each of the + // siblings, causing some of the work here to be duplicated. We assume that + // all sibling devices have been added to the device registry by the time + // OnDeviceAdded is called. + auto sibling_instance_ids = + GetSiblingInstanceIds(device_info_set.get(), device_interface_data); + + // Get the device path for each sibling from its instance ID. + std::vector<std::wstring> device_paths = {device_path}; + for (auto sibling_instance_id : sibling_instance_ids) { + auto sibling_path = GetDevicePathFromInstanceId(sibling_instance_id); + if (sibling_path) + device_paths.push_back(std::move(*sibling_path)); + } blocking_task_runner_->PostTask( FROM_HERE, base::BindOnce(&HidServiceWin::AddDeviceBlocking, weak_factory_.GetWeakPtr(), task_runner_, - device_path, physical_device_id)); + std::move(device_paths), *physical_device_id)); } void HidServiceWin::OnDeviceRemoved(const GUID& class_guid,
diff --git a/services/device/hid/hid_service_win.h b/services/device/hid/hid_service_win.h index 2ff89c33..958b3ef5 100644 --- a/services/device/hid/hid_service_win.h +++ b/services/device/hid/hid_service_win.h
@@ -141,7 +141,7 @@ static void AddDeviceBlocking( base::WeakPtr<HidServiceWin> service, scoped_refptr<base::SequencedTaskRunner> task_runner, - const std::wstring& device_path, + const std::vector<std::wstring>& device_paths, const std::string& physical_device_id); // DeviceMonitorWin::Observer implementation:
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index 240e0fe..fb79ebe 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -72,6 +72,7 @@ #include "net/cookies/cookie_options.h" #include "net/cookies/cookie_store.h" #include "net/cookies/cookie_util.h" +#include "net/disk_cache/cache_util.h" #include "net/disk_cache/disk_cache.h" #include "net/dns/context_host_resolver.h" #include "net/dns/dns_test_util.h" @@ -902,6 +903,66 @@ GetBackendType(backend)); } +class DiskCacheSizeTest : public NetworkContextTest { + public: + DiskCacheSizeTest() = default; + ~DiskCacheSizeTest() override = default; + + int64_t VerifyDiskCacheSize(int scale = 100) { + base::test::ScopedFeatureList scoped_feature_list; + if (scale != 100) { + std::map<std::string, std::string> field_trial_params; + field_trial_params["percent_relative_size"] = base::NumberToString(scale); + scoped_feature_list.InitAndEnableFeatureWithParameters( + disk_cache::kChangeDiskCacheSizeExperiment, field_trial_params); + } + + base::HistogramTester histogram_tester; + + mojom::NetworkContextParamsPtr context_params = CreateContextParams(); + context_params->http_cache_enabled = true; + + base::ScopedTempDir temp_dir; + EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); + context_params->http_cache_path = temp_dir.GetPath(); + + std::unique_ptr<NetworkContext> network_context = + CreateContextWithParams(std::move(context_params)); + + net::HttpCache* cache = network_context->url_request_context() + ->http_transaction_factory() + ->GetCache(); + EXPECT_TRUE(cache); + + disk_cache::Backend* backend = nullptr; + net::TestCompletionCallback callback; + int rv = cache->GetBackend(&backend, callback.callback()); + EXPECT_EQ(net::OK, callback.GetResult(rv)); + EXPECT_TRUE(backend); + + EXPECT_EQ(net::DISK_CACHE, backend->GetCacheType()); + + int64_t max_file_size = backend->MaxFileSize(); + histogram_tester.ExpectTotalCount("HttpCache.MaxFileSizeOnInit", 1); + histogram_tester.ExpectUniqueSample("HttpCache.MaxFileSizeOnInit", + max_file_size / 1024, 1); + + return max_file_size; + } +}; + +TEST_F(DiskCacheSizeTest, DiskCacheSize) { + int64_t max_file_size = VerifyDiskCacheSize(); + + // Scale to 200%. The size should be twice of |max_file_size| but + // since max size is capped on 20% of available size, checking for the size to + // be between max_file_size and max_file_size*2. + int64_t max_file_size_scaled = VerifyDiskCacheSize(200); + + EXPECT_GE(max_file_size_scaled, max_file_size); + EXPECT_LE(max_file_size_scaled, 2 * max_file_size); +} + // This makes sure that network_session_configurator::ChooseCacheType is // connected to NetworkContext. TEST_F(NetworkContextTest, SimpleCache) {
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 35dcc6d..8f27290 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -240,11 +240,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.133" + "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.134" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.133", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.134", "resultdb": { "enable": true }, @@ -254,7 +254,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.133" + "revision": "version:87.0.4280.134" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -394,11 +394,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.133" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.134" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.133", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.134", "resultdb": { "enable": true }, @@ -408,7 +408,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.133" + "revision": "version:87.0.4280.134" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -769,11 +769,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.133" + "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.134" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.133", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.134", "resultdb": { "enable": true }, @@ -783,7 +783,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.133" + "revision": "version:87.0.4280.134" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -923,11 +923,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.133" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.134" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.133", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.134", "resultdb": { "enable": true }, @@ -937,7 +937,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.133" + "revision": "version:87.0.4280.134" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1298,11 +1298,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.133" + "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.134" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.133", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.134", "resultdb": { "enable": true }, @@ -1312,7 +1312,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.133" + "revision": "version:87.0.4280.134" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1452,11 +1452,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.133" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.134" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.133", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.134", "resultdb": { "enable": true }, @@ -1466,7 +1466,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.133" + "revision": "version:87.0.4280.134" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1827,11 +1827,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.133" + "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.134" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.133", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.134", "resultdb": { "enable": true }, @@ -1841,7 +1841,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.133" + "revision": "version:87.0.4280.134" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1981,11 +1981,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.133" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.134" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.133", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.134", "resultdb": { "enable": true }, @@ -1995,7 +1995,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.133" + "revision": "version:87.0.4280.134" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json index 3d42643c..525e897 100644 --- a/testing/buildbot/chromium.clang.json +++ b/testing/buildbot/chromium.clang.json
@@ -24344,22 +24344,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -26832,22 +26816,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [],
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 031acf6..837cd8e 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -1698,27 +1698,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Mac-11.0|Mac-10.16" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -43947,27 +43926,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -46053,28 +46011,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "isolate_profile_data": true, - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "isolate_profile_data": true, "merge": { @@ -50033,29 +49969,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "cpu": "arm64", - "os": "Mac-11.0", - "pool": "chromium.tests.mac-arm64" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -53518,29 +53431,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-11.0|Mac-10.16" - } - ], - "expiration": 21600, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [],
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 8d92d59..db84dd7 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -7725,28 +7725,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "isolate_profile_data": true, - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "isolate_profile_data": true, "merge": { @@ -9714,27 +9692,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -11787,29 +11744,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "isolate_profile_data": true, - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04", - "pool": "chromium.tests.robocrop" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "isolate_profile_data": true, "merge": { @@ -14070,27 +14004,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-14.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [],
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index 24b3eb91..a354e568 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -1570,28 +1570,6 @@ "test_id_prefix": "ninja://components:components_perftests/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "none", - "os": "Mac-10.11" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -3344,28 +3322,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12.6" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -5263,29 +5219,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "isolate_profile_data": true, - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "none", - "os": "Mac-10.13.6" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "isolate_profile_data": true, "merge": { @@ -7028,28 +6961,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "none", - "os": "Mac-10.13.6" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -8817,28 +8728,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "none", - "os": "Mac-10.14.6" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -10560,27 +10449,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Mac-10.15" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [],
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index 7ab6a452..a13f76d 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -1331,22 +1331,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -3742,29 +3726,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "isolate_profile_data": true, - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "cpu": "x86-64", - "os": "Windows-10-18363" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "isolate_profile_data": true, "merge": { @@ -5901,28 +5862,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "cpu": "x86-64", - "os": "Windows-10-18363" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -7513,22 +7452,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [], @@ -9031,22 +8954,6 @@ "test_id_prefix": "ninja://content/shell:content_shell_crash_test/" }, { - "isolate_name": "extension_docserver_python_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "extension_docserver_python_unittests", - "resultdb": { - "enable": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/" - }, - { "isolate_name": "flatbuffers_unittests", "merge": { "args": [],
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index e4ae25a6..6f7da4b 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -837,14 +837,6 @@ "label": "//extensions:extensions_browsertests", "type": "windowed_test_launcher", }, - "extension_docserver_python_unittests": { - "args": [ - "../../chrome/common/extensions/docs/server2/run_all_unittests.py", - ], - "label": "//chrome/common/extensions/docs/server2:extension_docserver_python_unittests", - "script": "//testing/scripts/run_isolated_script_test.py", - "type": "script", - }, "extensions_unittests": { "label": "//extensions:extensions_unittests", "type": "windowed_test_launcher",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 12d4bbb4..19a2500 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -1241,11 +1241,6 @@ 'result_format': 'single' } }, - 'extension_docserver_python_unittests': { - 'resultdb': { - 'enable': True, - }, - }, 'flatbuffers_unittests': { 'resultdb': { 'enable': True,
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 2849831a..7e3896e 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -342,13 +342,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--impl-version=87', ], - 'identifier': 'Implementation Tests For 87.0.4280.133', + 'identifier': 'Implementation Tests For 87.0.4280.134', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M87', - 'revision': 'version:87.0.4280.133', + 'revision': 'version:87.0.4280.134', } ], }, @@ -411,13 +411,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--client-version=87', ], - 'identifier': 'Client Tests For 87.0.4280.133', + 'identifier': 'Client Tests For 87.0.4280.134', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M87', - 'revision': 'version:87.0.4280.133', + 'revision': 'version:87.0.4280.134', } ], },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 4a181b0..3f216d8 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -407,6 +407,53 @@ ] } ], + "AndroidInProductHelpToolbarButtons": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "NewTabPageButtonIphConfig", + "params": { + "availability": ">=1", + "cohortFeatureName": "ToolbarIphAndroidCohort2", + "event_trigger": "name:ntp_iph_triggered;comparator:==0;window:90;storage:90", + "event_used": "name:homepage_button_clicked;comparator:==0;window:14;storage:90", + "session_rate": "<1" + }, + "enable_features": [ + "IPH_NewTabPageHomeButton", + "ToolbarIphAndroid", + "ToolbarIphAndroidCohort2" + ] + } + ] + } + ], + "AndroidInProductHelpToolbarButtons_TabSwitcher": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "TabSwitcherButtonIphConfig", + "params": { + "availability": ">=1", + "cohortFeatureName": "ToolbarIphAndroidCohort1", + "event_trigger": "name:tab_switcher_iph_triggered;comparator:==0;window:90;storage:90", + "event_used": "name:tab_switcher_button_clicked;comparator:==0;window:14;storage:90", + "session_rate": "<1" + }, + "enable_features": [ + "IPH_TabSwitcherButton", + "ToolbarIphAndroidCohort1" + ] + } + ] + } + ], "AndroidInlineUpdateFlowStudy": [ { "platforms": [
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium index 3ac5920e..68a64fde 100644 --- a/third_party/abseil-cpp/README.chromium +++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@ License: Apache 2.0 License File: LICENSE Version: 0 -Revision: 8a9ef3c5da2a9064dda0ac3c61b43b87c12c50b8 +Revision: e7ca23acac146b10edc4f752edd0bd28b0f14ea3 Security Critical: yes Description:
diff --git a/third_party/abseil-cpp/README.md b/third_party/abseil-cpp/README.md index f180234..76f1d1e1 100644 --- a/third_party/abseil-cpp/README.md +++ b/third_party/abseil-cpp/README.md
@@ -9,7 +9,9 @@ - [About Abseil](#about) - [Quickstart](#quickstart) - [Building Abseil](#build) +- [Support](#support) - [Codemap](#codemap) +- [Releases](#releases) - [License](#license) - [Links](#links) @@ -42,14 +44,22 @@ <a name="build"></a> ## Building Abseil -[Bazel](https://bazel.build) is the official build system for Abseil, -which is supported on most major platforms (Linux, Windows, macOS, for example) -and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for -more information on building Abseil using the Bazel build system. +[Bazel](https://bazel.build) and [CMake](https://cmake.org/) are the official +build systems for Abseil. -<a name="cmake"></a> -If you require CMake support, please check the -[CMake build instructions](CMake/README.md). +See the [quickstart](https://abseil.io/docs/cpp/quickstart) for more information +on building Abseil using the Bazel build system. + +If you require CMake support, please check the [CMake build +instructions](CMake/README.md) and [CMake +Quickstart](https://abseil.io/docs/cpp/quickstart-cmake). + +## Support + +Abseil is officially supported on many platforms. See the [Abseil +platform support +guide](https://abseil.io/docs/cpp/platforms/platforms) for details on +supported operating systems, compilers, CPUs, etc. ## Codemap @@ -100,6 +110,15 @@ * [`utility`](absl/utility/) <br /> The `utility` library contains utility and helper code. +## Releases + +Abseil recommends users "live-at-head" (update to the latest commit from the +master branch as often as possible). However, we realize this philosophy doesn't +work for every project, so we also provide [Long Term Support +Releases](https://github.com/abseil/abseil-cpp/releases) to which we backport +fixes for severe bugs. See our [release +management](https://abseil.io/about/releases) document for more details. + ## License The Abseil C++ library is licensed under the terms of the Apache
diff --git a/third_party/abseil-cpp/absl/base/internal/raw_logging.cc b/third_party/abseil-cpp/absl/base/internal/raw_logging.cc index ae8754c..074e026a 100644 --- a/third_party/abseil-cpp/absl/base/internal/raw_logging.cc +++ b/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
@@ -67,28 +67,32 @@ #undef ABSL_HAVE_RAW_IO #endif -// TODO(gfalcon): We want raw-logging to work on as many platforms as possible. -// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a -// selected set of platforms for which we expect not to be able to raw log. +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace raw_logging_internal { +namespace { -ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook< - absl::raw_logging_internal::LogPrefixHook> - log_prefix_hook; -ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook< - absl::raw_logging_internal::AbortHook> - abort_hook; +// TODO(gfalcon): We want raw-logging to work on as many platforms as possible. +// Explicitly `#error` out when not `ABSL_LOW_LEVEL_WRITE_SUPPORTED`, except for +// a selected set of platforms for which we expect not to be able to raw log. + +ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES + absl::base_internal::AtomicHook<LogPrefixHook> + log_prefix_hook; +ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES + absl::base_internal::AtomicHook<AbortHook> + abort_hook; #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED -static const char kTruncated[] = " ... (message truncated)\n"; +constexpr char kTruncated[] = " ... (message truncated)\n"; // sprintf the format to the buffer, adjusting *buf and *size to reflect the // consumed bytes, and return whether the message fit without truncation. If // truncation occurred, if possible leave room in the buffer for the message // kTruncated[]. -inline static bool VADoRawLog(char** buf, int* size, const char* format, - va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0); -inline static bool VADoRawLog(char** buf, int* size, - const char* format, va_list ap) { +bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) + ABSL_PRINTF_ATTRIBUTE(3, 0); +bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) { int n = vsnprintf(*buf, *size, format, ap); bool result = true; if (n < 0 || n > *size) { @@ -96,7 +100,7 @@ if (static_cast<size_t>(*size) > sizeof(kTruncated)) { n = *size - sizeof(kTruncated); // room for truncation message } else { - n = 0; // no room for truncation message + n = 0; // no room for truncation message } } *size -= n; @@ -105,9 +109,7 @@ } #endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED -static constexpr int kLogBufSize = 3000; - -namespace { +constexpr int kLogBufSize = 3000; // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths // that invoke malloc() and getenv() that might acquire some locks. @@ -166,7 +168,7 @@ } else { DoRawLog(&buf, &size, "%s", kTruncated); } - absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer)); + SafeWriteToStderr(buffer, strlen(buffer)); } #else static_cast<void>(format); @@ -181,11 +183,18 @@ } } +// Non-formatting version of RawLog(). +// +// TODO(gfalcon): When string_view no longer depends on base, change this +// interface to take its message as a string_view instead. +void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line, + const std::string& message) { + RawLog(severity, file, line, "%.*s", static_cast<int>(message.size()), + message.data()); +} + } // namespace -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace raw_logging_internal { void SafeWriteToStderr(const char *s, size_t len) { #if defined(ABSL_HAVE_SYSCALL_WRITE) syscall(SYS_write, STDERR_FILENO, s, len); @@ -201,8 +210,6 @@ } void RawLog(absl::LogSeverity severity, const char* file, int line, - const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); -void RawLog(absl::LogSeverity severity, const char* file, int line, const char* format, ...) { va_list ap; va_start(ap, format); @@ -210,15 +217,6 @@ va_end(ap); } -// Non-formatting version of RawLog(). -// -// TODO(gfalcon): When string_view no longer depends on base, change this -// interface to take its message as a string_view instead. -static void DefaultInternalLog(absl::LogSeverity severity, const char* file, - int line, const std::string& message) { - RawLog(severity, file, line, "%s", message.c_str()); -} - bool RawLoggingFullySupported() { #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED return true; @@ -231,6 +229,10 @@ absl::base_internal::AtomicHook<InternalLogFunction> internal_log_function(DefaultInternalLog); +void RegisterLogPrefixHook(LogPrefixHook func) { log_prefix_hook.Store(func); } + +void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); } + void RegisterInternalLogFunction(InternalLogFunction func) { internal_log_function.Store(func); }
diff --git a/third_party/abseil-cpp/absl/base/internal/raw_logging.h b/third_party/abseil-cpp/absl/base/internal/raw_logging.h index 20f4291b..2bf7aab 100644 --- a/third_party/abseil-cpp/absl/base/internal/raw_logging.h +++ b/third_party/abseil-cpp/absl/base/internal/raw_logging.h
@@ -178,6 +178,14 @@ InternalLogFunction> internal_log_function; +// Registers hooks of the above types. Only a single hook of each type may be +// registered. It is an error to call these functions multiple times with +// different input arguments. +// +// These functions are safe to call at any point during initialization; they do +// not block or malloc, and are async-signal safe. +void RegisterLogPrefixHook(LogPrefixHook func); +void RegisterAbortHook(AbortHook func); void RegisterInternalLogFunction(InternalLogFunction func); } // namespace raw_logging_internal
diff --git a/third_party/abseil-cpp/absl/container/btree_test.cc b/third_party/abseil-cpp/absl/container/btree_test.cc index a933386a..367d75be7 100644 --- a/third_party/abseil-cpp/absl/container/btree_test.cc +++ b/third_party/abseil-cpp/absl/container/btree_test.cc
@@ -2038,6 +2038,30 @@ EXPECT_EQ(res, ++other.begin()); } +TEST(Btree, ExtractMultiMapEquivalentKeys) { + // Note: using string keys means a three-way comparator. + absl::btree_multimap<std::string, int> map; + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < 100; ++j) { + map.insert({absl::StrCat(i), j}); + } + } + + for (int i = 0; i < 100; ++i) { + const std::string key = absl::StrCat(i); + auto node_handle = map.extract(key); + EXPECT_EQ(node_handle.key(), key); + EXPECT_EQ(node_handle.mapped(), 0) << i; + } + + for (int i = 0; i < 100; ++i) { + const std::string key = absl::StrCat(i); + auto node_handle = map.extract(key); + EXPECT_EQ(node_handle.key(), key); + EXPECT_EQ(node_handle.mapped(), 1) << i; + } +} + // For multisets, insert with hint also affects correctness because we need to // insert immediately before the hint if possible. struct InsertMultiHintData { @@ -2726,7 +2750,6 @@ TYPED_TEST(BtreeMultiKeyTest, EqualRange) { absl::btree_set<MultiKey, TypeParam> set; - for (int i = 0; i < 100; ++i) { for (int j = 0; j < 100; ++j) { set.insert({i, j}); @@ -2736,11 +2759,32 @@ for (int i = 0; i < 100; ++i) { auto equal_range = set.equal_range(i); EXPECT_EQ(equal_range.first->i1, i); - EXPECT_EQ(equal_range.first->i2, 0); + EXPECT_EQ(equal_range.first->i2, 0) << i; EXPECT_EQ(std::distance(equal_range.first, equal_range.second), 100) << i; } } +TYPED_TEST(BtreeMultiKeyTest, Extract) { + absl::btree_set<MultiKey, TypeParam> set; + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < 100; ++j) { + set.insert({i, j}); + } + } + + for (int i = 0; i < 100; ++i) { + auto node_handle = set.extract(i); + EXPECT_EQ(node_handle.value().i1, i); + EXPECT_EQ(node_handle.value().i2, 0) << i; + } + + for (int i = 0; i < 100; ++i) { + auto node_handle = set.extract(i); + EXPECT_EQ(node_handle.value().i1, i); + EXPECT_EQ(node_handle.value().i2, 1) << i; + } +} + TYPED_TEST(BtreeMultiKeyTest, Erase) { absl::btree_set<MultiKey, TypeParam> set = { {1, 1}, {2, 1}, {2, 2}, {3, 1}};
diff --git a/third_party/abseil-cpp/absl/container/internal/btree.h b/third_party/abseil-cpp/absl/container/internal/btree.h index d863cb30..6f5f01b8 100644 --- a/third_party/abseil-cpp/absl/container/internal/btree.h +++ b/third_party/abseil-cpp/absl/container/internal/btree.h
@@ -1211,7 +1211,7 @@ return const_reverse_iterator(begin()); } - // Finds the first element whose key is not less than key. + // Finds the first element whose key is not less than `key`. template <typename K> iterator lower_bound(const K &key) { return internal_end(internal_lower_bound(key).value); @@ -1221,7 +1221,12 @@ return internal_end(internal_lower_bound(key).value); } - // Finds the first element whose key is greater than key. + // Finds the first element whose key is not less than `key` and also returns + // whether that element is equal to `key`. + template <typename K> + std::pair<iterator, bool> lower_bound_equal(const K &key) const; + + // Finds the first element whose key is greater than `key`. template <typename K> iterator upper_bound(const K &key) { return internal_end(internal_upper_bound(key)); @@ -1303,8 +1308,8 @@ // to the element after the last erased element. std::pair<size_type, iterator> erase_range(iterator begin, iterator end); - // Finds the iterator corresponding to a key or returns end() if the key is - // not present. + // Finds an element with key equivalent to `key` or returns `end()` if `key` + // is not present. template <typename K> iterator find(const K &key) { return internal_end(internal_find(key)); @@ -1905,12 +1910,23 @@ template <typename P> template <typename K> -auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> { +auto btree<P>::lower_bound_equal(const K &key) const + -> std::pair<iterator, bool> { const SearchResult<iterator, is_key_compare_to::value> res = internal_lower_bound(key); - const iterator lower = internal_end(res.value); - if (res.HasMatch() ? !res.IsEq() - : lower == end() || compare_keys(key, lower.key())) { + const iterator lower = iterator(internal_end(res.value)); + const bool equal = res.HasMatch() + ? res.IsEq() + : lower != end() && !compare_keys(key, lower.key()); + return {lower, equal}; +} + +template <typename P> +template <typename K> +auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> { + const std::pair<iterator, bool> lower_and_equal = lower_bound_equal(key); + const iterator lower = lower_and_equal.first; + if (!lower_and_equal.second) { return {lower, lower}; } @@ -2510,14 +2526,17 @@ template <typename K> auto btree<P>::internal_lower_bound(const K &key) const -> SearchResult<iterator, is_key_compare_to::value> { + if (!params_type::template can_have_multiple_equivalent_keys<K>()) { + SearchResult<iterator, is_key_compare_to::value> ret = internal_locate(key); + ret.value = internal_last(ret.value); + return ret; + } iterator iter(const_cast<node_type *>(root())); SearchResult<int, is_key_compare_to::value> res; bool seen_eq = false; for (;;) { res = iter.node->lower_bound(key, key_comp()); iter.position = res.value; - // TODO(ezb): we should be able to terminate early on IsEq() if there can't - // be multiple equivalent keys in container for this lookup type. if (iter.node->leaf()) { break; }
diff --git a/third_party/abseil-cpp/absl/container/internal/btree_container.h b/third_party/abseil-cpp/absl/container/internal/btree_container.h index 887eda4..03be708e 100644 --- a/third_party/abseil-cpp/absl/container/internal/btree_container.h +++ b/third_party/abseil-cpp/absl/container/internal/btree_container.h
@@ -338,13 +338,12 @@ } // Node extraction routines. - // TODO(ezb): when the comparator is heterogeneous and has different - // equivalence classes for different lookup types, we should extract the first - // equivalent value if there are multiple. template <typename K = key_type> node_type extract(const key_arg<K> &key) { - auto it = this->find(key); - return it == this->end() ? node_type() : extract(it); + const std::pair<iterator, bool> lower_and_equal = + this->tree_.lower_bound_equal(key); + return lower_and_equal.second ? extract(lower_and_equal.first) + : node_type(); } using super_type::extract; @@ -621,12 +620,12 @@ } // Node extraction routines. - // TODO(ezb): we are supposed to extract the first equivalent key if there are - // multiple, but this isn't guaranteed to extract the first one. template <typename K = key_type> node_type extract(const key_arg<K> &key) { - auto it = this->find(key); - return it == this->end() ? node_type() : extract(it); + const std::pair<iterator, bool> lower_and_equal = + this->tree_.lower_bound_equal(key); + return lower_and_equal.second ? extract(lower_and_equal.first) + : node_type(); } using super_type::extract;
diff --git a/third_party/abseil-cpp/absl/debugging/leak_check.h b/third_party/abseil-cpp/absl/debugging/leak_check.h index 7a5a22d..b66a81c 100644 --- a/third_party/abseil-cpp/absl/debugging/leak_check.h +++ b/third_party/abseil-cpp/absl/debugging/leak_check.h
@@ -62,7 +62,8 @@ // // If the passed `ptr` does not point to an actively allocated object at the // time `IgnoreLeak()` is called, the call is a no-op; if it is actively -// allocated, the object must not get deallocated later. +// allocated, leak sanitizer will assume this object is referenced even if +// there is no actual reference in user memory. // template <typename T> T* IgnoreLeak(T* ptr) {
diff --git a/third_party/abseil-cpp/absl/numeric/internal/bits.h b/third_party/abseil-cpp/absl/numeric/internal/bits.h index 50828156..af45700 100644 --- a/third_party/abseil-cpp/absl/numeric/internal/bits.h +++ b/third_party/abseil-cpp/absl/numeric/internal/bits.h
@@ -23,12 +23,6 @@ // windows intrinsic functions. #if defined(_MSC_VER) && !defined(__clang__) #include <intrin.h> -#if defined(_M_X64) -#pragma intrinsic(_BitScanReverse64) -#pragma intrinsic(_BitScanForward64) -#endif -#pragma intrinsic(_BitScanReverse) -#pragma intrinsic(_BitScanForward) #endif #include "absl/base/attributes.h" @@ -185,7 +179,8 @@ // Handle 0 as a special case because __builtin_clzll(0) is undefined. return x == 0 ? 64 : __builtin_clzll(x); -#elif defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64) +#elif defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_X64) || defined(_M_ARM64)) // MSVC does not have __buitin_clzll. Use _BitScanReverse64. unsigned long result = 0; // NOLINT(runtime/int) if (_BitScanReverse64(&result, x)) { @@ -271,7 +266,8 @@ static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) "__builtin_ctzll does not take 64-bit arg"); return __builtin_ctzll(x); -#elif defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64) +#elif defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_X64) || defined(_M_ARM64)) unsigned long result = 0; // NOLINT(runtime/int) _BitScanForward64(&result, x); return result;
diff --git a/third_party/abseil-cpp/absl/strings/string_view_test.cc b/third_party/abseil-cpp/absl/strings/string_view_test.cc index dcebb15..643af8f 100644 --- a/third_party/abseil-cpp/absl/strings/string_view_test.cc +++ b/third_party/abseil-cpp/absl/strings/string_view_test.cc
@@ -915,9 +915,9 @@ EXPECT_EQ(abc.at(1), 'b'); EXPECT_EQ(abc.at(2), 'c'); #ifdef ABSL_HAVE_EXCEPTIONS - EXPECT_THROW(abc.at(3), std::out_of_range); + EXPECT_THROW((void)abc.at(3), std::out_of_range); #else - ABSL_EXPECT_DEATH_IF_SUPPORTED(abc.at(3), "absl::string_view::at"); + ABSL_EXPECT_DEATH_IF_SUPPORTED((void)abc.at(3), "absl::string_view::at"); #endif }
diff --git a/third_party/abseil-cpp/symbols_arm64_dbg.def b/third_party/abseil-cpp/symbols_arm64_dbg.def index 5a85fef1..df0b9fe5 100644 --- a/third_party/abseil-cpp/symbols_arm64_dbg.def +++ b/third_party/abseil-cpp/symbols_arm64_dbg.def
@@ -1557,12 +1557,14 @@ ?DoLoad@?$AtomicHook@P6A_NPEBXPEADH@Z@base_internal@absl@@AEBAP6A_NPEBXPEADH@ZXZ ?DoLoad@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@AEBAP6A_NW4LogSeverity@3@PEBDHPEAPEADPEAH@ZXZ ?DoStore@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@AEBVCord@2@@Z@base_internal@absl@@AEAA_NP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@AEBVCord@3@@Z@Z + ?DoStore@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@AEAA_NP6AXPEBDH000@Z@Z ?DoStore@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@AEAA_NP6AXPEBDPEBX@Z@Z ?DoStore@?$AtomicHook@P6AXPEBDPEBX_J@Z@base_internal@absl@@AEAA_NP6AXPEBDPEBX_J@Z@Z ?DoStore@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@AEAA_NP6AXPEBX_J@Z@Z ?DoStore@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@AEAA_NP6AXW4LogSeverity@3@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z ?DoStore@?$AtomicHook@P6AX_J@Z@base_internal@absl@@AEAA_NP6AX_J@Z@Z ?DoStore@?$AtomicHook@P6A_NPEBXPEADH@Z@base_internal@absl@@AEAA_NP6A_NPEBXPEADH@Z@Z + ?DoStore@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@AEAA_NP6A_NW4LogSeverity@3@PEBDHPEAPEADPEAH@Z@Z ?DummyFunction@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@AEBVCord@2@@Z@base_internal@absl@@CA?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@AEBVCord@3@@Z ?DummyFunction@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@CAXPEBDH000@Z ?DummyFunction@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@CAXPEBDPEBX@Z @@ -2002,8 +2004,10 @@ ?Ref@CordRep@cord_internal@absl@@SAPEAU123@PEAU123@@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QEAAPEAUHashtablezInfo@23@XZ + ?RegisterAbortHook@raw_logging_internal@absl@@YAXP6AXPEBDH000@Z@Z ?RegisterCondVarTracer@absl@@YAXP6AXPEBDPEBX@Z@Z ?RegisterInternalLogFunction@raw_logging_internal@absl@@YAXP6AXW4LogSeverity@2@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z + ?RegisterLogPrefixHook@raw_logging_internal@absl@@YAXP6A_NW4LogSeverity@2@PEBDHPEAPEADPEAH@Z@Z ?RegisterMutexProfiler@absl@@YAXP6AX_J@Z@Z ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z @@ -2090,12 +2094,14 @@ ?StatusCodeToString@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@W4StatusCode@1@@Z ?Store64@little_endian@absl@@YAXPEAX_K@Z ?Store@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@AEBVCord@2@@Z@base_internal@absl@@QEAAXP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@AEBVCord@3@@Z@Z + ?Store@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@QEAAXP6AXPEBDH000@Z@Z ?Store@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEAAXP6AXPEBDPEBX@Z@Z ?Store@?$AtomicHook@P6AXPEBDPEBX_J@Z@base_internal@absl@@QEAAXP6AXPEBDPEBX_J@Z@Z ?Store@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@QEAAXP6AXPEBX_J@Z@Z ?Store@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@QEAAXP6AXW4LogSeverity@3@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z ?Store@?$AtomicHook@P6AX_J@Z@base_internal@absl@@QEAAXP6AX_J@Z@Z ?Store@?$AtomicHook@P6A_NPEBXPEADH@Z@base_internal@absl@@QEAAXP6A_NPEBXPEADH@Z@Z + ?Store@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@QEAAXP6A_NW4LogSeverity@3@PEBDHPEAPEADPEAH@Z@Z ?StrAppend@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@AEBVAlphaNum@1@111@Z ?StrAppend@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@AEBVAlphaNum@1@11@Z ?StrAppend@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@AEBVAlphaNum@1@1@Z
diff --git a/third_party/abseil-cpp/symbols_arm64_rel.def b/third_party/abseil-cpp/symbols_arm64_rel.def index 1c5eec8..6160b72c 100644 --- a/third_party/abseil-cpp/symbols_arm64_rel.def +++ b/third_party/abseil-cpp/symbols_arm64_rel.def
@@ -289,6 +289,7 @@ ?DummyFunction@?$AtomicHook@P6AXPEBDPEBX_J@Z@base_internal@absl@@CAXPEBDPEBX_J@Z ?DummyFunction@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@CAXPEBX_J@Z ?DummyFunction@?$AtomicHook@P6AX_J@Z@base_internal@absl@@CAX_J@Z + ?DummyFunction@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@CA_NW4LogSeverity@3@PEBDHPEAPEADPEAH@Z ?DumpPCAndFrameSizesAndStackTrace@debugging_internal@absl@@YAXPEAXQEBQEAXQEAHHH_NP6AXPEBD0@Z0@Z ?DurationFromTimespec@absl@@YA?AVDuration@1@Utimespec@@@Z ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z @@ -539,8 +540,10 @@ ?RecordInsertSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@_K1@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QEAAPEAUHashtablezInfo@23@XZ + ?RegisterAbortHook@raw_logging_internal@absl@@YAXP6AXPEBDH000@Z@Z ?RegisterCondVarTracer@absl@@YAXP6AXPEBDPEBX@Z@Z ?RegisterInternalLogFunction@raw_logging_internal@absl@@YAXP6AXW4LogSeverity@2@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z + ?RegisterLogPrefixHook@raw_logging_internal@absl@@YAXP6A_NW4LogSeverity@2@PEBDHPEAPEADPEAH@Z@Z ?RegisterMutexProfiler@absl@@YAXP6AX_J@Z@Z ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z
diff --git a/third_party/abseil-cpp/symbols_x64_dbg.def b/third_party/abseil-cpp/symbols_x64_dbg.def index 9e8220e..4f45507 100644 --- a/third_party/abseil-cpp/symbols_x64_dbg.def +++ b/third_party/abseil-cpp/symbols_x64_dbg.def
@@ -1558,12 +1558,14 @@ ?DoLoad@?$AtomicHook@P6A_NPEBXPEADH@Z@base_internal@absl@@AEBAP6A_NPEBXPEADH@ZXZ ?DoLoad@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@AEBAP6A_NW4LogSeverity@3@PEBDHPEAPEADPEAH@ZXZ ?DoStore@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@AEBVCord@2@@Z@base_internal@absl@@AEAA_NP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@AEBVCord@3@@Z@Z + ?DoStore@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@AEAA_NP6AXPEBDH000@Z@Z ?DoStore@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@AEAA_NP6AXPEBDPEBX@Z@Z ?DoStore@?$AtomicHook@P6AXPEBDPEBX_J@Z@base_internal@absl@@AEAA_NP6AXPEBDPEBX_J@Z@Z ?DoStore@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@AEAA_NP6AXPEBX_J@Z@Z ?DoStore@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@AEAA_NP6AXW4LogSeverity@3@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z ?DoStore@?$AtomicHook@P6AX_J@Z@base_internal@absl@@AEAA_NP6AX_J@Z@Z ?DoStore@?$AtomicHook@P6A_NPEBXPEADH@Z@base_internal@absl@@AEAA_NP6A_NPEBXPEADH@Z@Z + ?DoStore@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@AEAA_NP6A_NW4LogSeverity@3@PEBDHPEAPEADPEAH@Z@Z ?DummyFunction@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@AEBVCord@2@@Z@base_internal@absl@@CA?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@AEBVCord@3@@Z ?DummyFunction@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@CAXPEBDH000@Z ?DummyFunction@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@CAXPEBDPEBX@Z @@ -2002,8 +2004,10 @@ ?Ref@CordRep@cord_internal@absl@@SAPEAU123@PEAU123@@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QEAAPEAUHashtablezInfo@23@XZ + ?RegisterAbortHook@raw_logging_internal@absl@@YAXP6AXPEBDH000@Z@Z ?RegisterCondVarTracer@absl@@YAXP6AXPEBDPEBX@Z@Z ?RegisterInternalLogFunction@raw_logging_internal@absl@@YAXP6AXW4LogSeverity@2@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z + ?RegisterLogPrefixHook@raw_logging_internal@absl@@YAXP6A_NW4LogSeverity@2@PEBDHPEAPEADPEAH@Z@Z ?RegisterMutexProfiler@absl@@YAXP6AX_J@Z@Z ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z @@ -2089,12 +2093,14 @@ ?StartsWithIgnoreCase@absl@@YA_NVstring_view@1@0@Z ?StatusCodeToString@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@W4StatusCode@1@@Z ?Store@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@AEBVCord@2@@Z@base_internal@absl@@QEAAXP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@AEBVCord@3@@Z@Z + ?Store@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@QEAAXP6AXPEBDH000@Z@Z ?Store@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEAAXP6AXPEBDPEBX@Z@Z ?Store@?$AtomicHook@P6AXPEBDPEBX_J@Z@base_internal@absl@@QEAAXP6AXPEBDPEBX_J@Z@Z ?Store@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@QEAAXP6AXPEBX_J@Z@Z ?Store@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@QEAAXP6AXW4LogSeverity@3@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z ?Store@?$AtomicHook@P6AX_J@Z@base_internal@absl@@QEAAXP6AX_J@Z@Z ?Store@?$AtomicHook@P6A_NPEBXPEADH@Z@base_internal@absl@@QEAAXP6A_NPEBXPEADH@Z@Z + ?Store@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@QEAAXP6A_NW4LogSeverity@3@PEBDHPEAPEADPEAH@Z@Z ?StrAppend@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@AEBVAlphaNum@1@111@Z ?StrAppend@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@AEBVAlphaNum@1@11@Z ?StrAppend@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@AEBVAlphaNum@1@1@Z
diff --git a/third_party/abseil-cpp/symbols_x64_rel.def b/third_party/abseil-cpp/symbols_x64_rel.def index a45f133..a7bc2d0 100644 --- a/third_party/abseil-cpp/symbols_x64_rel.def +++ b/third_party/abseil-cpp/symbols_x64_rel.def
@@ -290,6 +290,7 @@ ?DummyFunction@?$AtomicHook@P6AXPEBDPEBX_J@Z@base_internal@absl@@CAXPEBDPEBX_J@Z ?DummyFunction@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@CAXPEBX_J@Z ?DummyFunction@?$AtomicHook@P6AX_J@Z@base_internal@absl@@CAX_J@Z + ?DummyFunction@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@CA_NW4LogSeverity@3@PEBDHPEAPEADPEAH@Z ?DumpPCAndFrameSizesAndStackTrace@debugging_internal@absl@@YAXPEAXQEBQEAXQEAHHH_NP6AXPEBD0@Z0@Z ?DurationFromTimespec@absl@@YA?AVDuration@1@Utimespec@@@Z ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z @@ -540,8 +541,10 @@ ?RecordInsertSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@_K1@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QEAAPEAUHashtablezInfo@23@XZ + ?RegisterAbortHook@raw_logging_internal@absl@@YAXP6AXPEBDH000@Z@Z ?RegisterCondVarTracer@absl@@YAXP6AXPEBDPEBX@Z@Z ?RegisterInternalLogFunction@raw_logging_internal@absl@@YAXP6AXW4LogSeverity@2@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z + ?RegisterLogPrefixHook@raw_logging_internal@absl@@YAXP6A_NW4LogSeverity@2@PEBDHPEAPEADPEAH@Z@Z ?RegisterMutexProfiler@absl@@YAXP6AX_J@Z@Z ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z
diff --git a/third_party/abseil-cpp/symbols_x64_rel_asan.def b/third_party/abseil-cpp/symbols_x64_rel_asan.def index 9531472..5db4edf 100644 --- a/third_party/abseil-cpp/symbols_x64_rel_asan.def +++ b/third_party/abseil-cpp/symbols_x64_rel_asan.def
@@ -308,6 +308,7 @@ ?DummyFunction@?$AtomicHook@P6AXPEBDPEBX_J@Z@base_internal@absl@@CAXPEBDPEBX_J@Z ?DummyFunction@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@CAXPEBX_J@Z ?DummyFunction@?$AtomicHook@P6AX_J@Z@base_internal@absl@@CAX_J@Z + ?DummyFunction@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@CA_NW4LogSeverity@3@PEBDHPEAPEADPEAH@Z ?DumpPCAndFrameSizesAndStackTrace@debugging_internal@absl@@YAXPEAXQEBQEAXQEAHHH_NP6AXPEBD0@Z0@Z ?DurationFromTimespec@absl@@YA?AVDuration@1@Utimespec@@@Z ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z @@ -558,8 +559,10 @@ ?RecordInsertSlow@container_internal@absl@@YAXPEAUHashtablezInfo@12@_K1@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QEAAPEAUHashtablezInfo@23@XZ + ?RegisterAbortHook@raw_logging_internal@absl@@YAXP6AXPEBDH000@Z@Z ?RegisterCondVarTracer@absl@@YAXP6AXPEBDPEBX@Z@Z ?RegisterInternalLogFunction@raw_logging_internal@absl@@YAXP6AXW4LogSeverity@2@PEBDHAEBV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z + ?RegisterLogPrefixHook@raw_logging_internal@absl@@YAXP6A_NW4LogSeverity@2@PEBDHPEAPEADPEAH@Z@Z ?RegisterMutexProfiler@absl@@YAXP6AX_J@Z@Z ?RegisterMutexTracer@absl@@YAXP6AXPEBDPEBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPEBX_J@Z@Z
diff --git a/third_party/abseil-cpp/symbols_x86_dbg.def b/third_party/abseil-cpp/symbols_x86_dbg.def index cc7b0f64..74d7457 100644 --- a/third_party/abseil-cpp/symbols_x86_dbg.def +++ b/third_party/abseil-cpp/symbols_x86_dbg.def
@@ -1555,12 +1555,14 @@ ?DoLoad@?$AtomicHook@P6A_NPBXPADH@Z@base_internal@absl@@ABEP6A_NPBXPADH@ZXZ ?DoLoad@?$AtomicHook@P6A_NW4LogSeverity@absl@@PBDHPAPADPAH@Z@base_internal@absl@@ABEP6A_NW4LogSeverity@3@PBDHPAPADPAH@ZXZ ?DoStore@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@ABVCord@2@@Z@base_internal@absl@@AAE_NP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@ABVCord@3@@Z@Z + ?DoStore@?$AtomicHook@P6AXPBDH000@Z@base_internal@absl@@AAE_NP6AXPBDH000@Z@Z ?DoStore@?$AtomicHook@P6AXPBDPBX@Z@base_internal@absl@@AAE_NP6AXPBDPBX@Z@Z ?DoStore@?$AtomicHook@P6AXPBDPBX_J@Z@base_internal@absl@@AAE_NP6AXPBDPBX_J@Z@Z ?DoStore@?$AtomicHook@P6AXPBX_J@Z@base_internal@absl@@AAE_NP6AXPBX_J@Z@Z ?DoStore@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@AAE_NP6AXW4LogSeverity@3@PBDHABV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z ?DoStore@?$AtomicHook@P6AX_J@Z@base_internal@absl@@AAE_NP6AX_J@Z@Z ?DoStore@?$AtomicHook@P6A_NPBXPADH@Z@base_internal@absl@@AAE_NP6A_NPBXPADH@Z@Z + ?DoStore@?$AtomicHook@P6A_NW4LogSeverity@absl@@PBDHPAPADPAH@Z@base_internal@absl@@AAE_NP6A_NW4LogSeverity@3@PBDHPAPADPAH@Z@Z ?DummyFunction@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@ABVCord@2@@Z@base_internal@absl@@CA?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@ABVCord@3@@Z ?DummyFunction@?$AtomicHook@P6AXPBDH000@Z@base_internal@absl@@CAXPBDH000@Z ?DummyFunction@?$AtomicHook@P6AXPBDPBX@Z@base_internal@absl@@CAXPBDPBX@Z @@ -1999,8 +2001,10 @@ ?Ref@CordRep@cord_internal@absl@@SAPAU123@PAU123@@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QAEPAUHashtablezInfo@23@XZ + ?RegisterAbortHook@raw_logging_internal@absl@@YAXP6AXPBDH000@Z@Z ?RegisterCondVarTracer@absl@@YAXP6AXPBDPBX@Z@Z ?RegisterInternalLogFunction@raw_logging_internal@absl@@YAXP6AXW4LogSeverity@2@PBDHABV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z + ?RegisterLogPrefixHook@raw_logging_internal@absl@@YAXP6A_NW4LogSeverity@2@PBDHPAPADPAH@Z@Z ?RegisterMutexProfiler@absl@@YAXP6AX_J@Z@Z ?RegisterMutexTracer@absl@@YAXP6AXPBDPBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPBX_J@Z@Z @@ -2086,12 +2090,14 @@ ?StartsWithIgnoreCase@absl@@YA_NVstring_view@1@0@Z ?StatusCodeToString@absl@@YA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@W4StatusCode@1@@Z ?Store@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@absl@@Vstring_view@2@ABVCord@2@@Z@base_internal@absl@@QAEXP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@3@Vstring_view@3@ABVCord@3@@Z@Z + ?Store@?$AtomicHook@P6AXPBDH000@Z@base_internal@absl@@QAEXP6AXPBDH000@Z@Z ?Store@?$AtomicHook@P6AXPBDPBX@Z@base_internal@absl@@QAEXP6AXPBDPBX@Z@Z ?Store@?$AtomicHook@P6AXPBDPBX_J@Z@base_internal@absl@@QAEXP6AXPBDPBX_J@Z@Z ?Store@?$AtomicHook@P6AXPBX_J@Z@base_internal@absl@@QAEXP6AXPBX_J@Z@Z ?Store@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@base_internal@absl@@QAEXP6AXW4LogSeverity@3@PBDHABV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z ?Store@?$AtomicHook@P6AX_J@Z@base_internal@absl@@QAEXP6AX_J@Z@Z ?Store@?$AtomicHook@P6A_NPBXPADH@Z@base_internal@absl@@QAEXP6A_NPBXPADH@Z@Z + ?Store@?$AtomicHook@P6A_NW4LogSeverity@absl@@PBDHPAPADPAH@Z@base_internal@absl@@QAEXP6A_NW4LogSeverity@3@PBDHPAPADPAH@Z@Z ?StrAppend@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@ABVAlphaNum@1@111@Z ?StrAppend@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@ABVAlphaNum@1@11@Z ?StrAppend@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@ABVAlphaNum@1@1@Z
diff --git a/third_party/abseil-cpp/symbols_x86_rel.def b/third_party/abseil-cpp/symbols_x86_rel.def index 1aa85941..5e4e37c 100644 --- a/third_party/abseil-cpp/symbols_x86_rel.def +++ b/third_party/abseil-cpp/symbols_x86_rel.def
@@ -287,6 +287,7 @@ ?DummyFunction@?$AtomicHook@P6AXPBDPBX_J@Z@base_internal@absl@@CAXPBDPBX_J@Z ?DummyFunction@?$AtomicHook@P6AXPBX_J@Z@base_internal@absl@@CAXPBX_J@Z ?DummyFunction@?$AtomicHook@P6AX_J@Z@base_internal@absl@@CAX_J@Z + ?DummyFunction@?$AtomicHook@P6A_NW4LogSeverity@absl@@PBDHPAPADPAH@Z@base_internal@absl@@CA_NW4LogSeverity@3@PBDHPAPADPAH@Z ?DumpPCAndFrameSizesAndStackTrace@debugging_internal@absl@@YAXPAXQBQAXQAHHH_NP6AXPBD0@Z0@Z ?DurationFromTimespec@absl@@YA?AVDuration@1@Utimespec@@@Z ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z @@ -536,8 +537,10 @@ ?RecordInsertSlow@container_internal@absl@@YAXPAUHashtablezInfo@12@II@Z ?Register@CycleClockSource@base_internal@absl@@CAXP6A_JXZ@Z ?Register@HashtablezSampler@container_internal@absl@@QAEPAUHashtablezInfo@23@XZ + ?RegisterAbortHook@raw_logging_internal@absl@@YAXP6AXPBDH000@Z@Z ?RegisterCondVarTracer@absl@@YAXP6AXPBDPBX@Z@Z ?RegisterInternalLogFunction@raw_logging_internal@absl@@YAXP6AXW4LogSeverity@2@PBDHABV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@@Z@Z + ?RegisterLogPrefixHook@raw_logging_internal@absl@@YAXP6A_NW4LogSeverity@2@PBDHPAPADPAH@Z@Z ?RegisterMutexProfiler@absl@@YAXP6AX_J@Z@Z ?RegisterMutexTracer@absl@@YAXP6AXPBDPBX_J@Z@Z ?RegisterSpinLockProfiler@base_internal@absl@@YAXP6AXPBX_J@Z@Z
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn index 82bd3a98..93dcde5 100644 --- a/third_party/android_deps/BUILD.gn +++ b/third_party/android_deps/BUILD.gn
@@ -438,7 +438,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. android_aar_prebuilt("androidx_legacy_legacy_support_core_utils_java") { - aar_path = "libs/androidx_legacy_legacy_support_core_utils/legacy-support-core-utils-1.0.0.aar" + aar_path = "libs/androidx_legacy_legacy_support_core_utils/legacy-support-core-utils-1.1.0-SNAPSHOT.aar" info_path = "libs/androidx_legacy_legacy_support_core_utils/androidx_legacy_legacy_support_core_utils.info" deps = [ ":androidx_annotation_annotation_java", @@ -487,6 +487,19 @@ } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. +android_aar_prebuilt("androidx_lifecycle_lifecycle_livedata_java") { + aar_path = + "libs/androidx_lifecycle_lifecycle_livedata/lifecycle-livedata-2.0.0.aar" + info_path = "libs/androidx_lifecycle_lifecycle_livedata/androidx_lifecycle_lifecycle_livedata.info" + deps = [ + ":androidx_arch_core_core_common_java", + ":androidx_arch_core_core_runtime_java", + ":androidx_lifecycle_lifecycle_livedata_core_java", + ] + resource_overlay = true +} + +# This is generated, do not edit. Update BuildConfigGenerator.groovy instead. android_aar_prebuilt("androidx_lifecycle_lifecycle_livedata_core_java") { aar_path = "libs/androidx_lifecycle_lifecycle_livedata_core/lifecycle-livedata-core-2.2.0.aar" info_path = "libs/androidx_lifecycle_lifecycle_livedata_core/androidx_lifecycle_lifecycle_livedata_core.info" @@ -1909,7 +1922,8 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. android_aar_prebuilt("androidx_documentfile_documentfile_java") { - aar_path = "libs/androidx_documentfile_documentfile/documentfile-1.0.0.aar" + aar_path = + "libs/androidx_documentfile_documentfile/documentfile-1.1.0-SNAPSHOT.aar" info_path = "libs/androidx_documentfile_documentfile/androidx_documentfile_documentfile.info" # To remove visibility constraint, add this dependency to @@ -1957,23 +1971,6 @@ } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. -android_aar_prebuilt("androidx_lifecycle_lifecycle_livedata_java") { - aar_path = - "libs/androidx_lifecycle_lifecycle_livedata/lifecycle-livedata-2.0.0.aar" - info_path = "libs/androidx_lifecycle_lifecycle_livedata/androidx_lifecycle_lifecycle_livedata.info" - - # To remove visibility constraint, add this dependency to - # //third_party/android_deps/build.gradle. - visibility = [ ":*" ] - deps = [ - ":androidx_arch_core_core_common_java", - ":androidx_arch_core_core_runtime_java", - ":androidx_lifecycle_lifecycle_livedata_core_java", - ] - resource_overlay = true -} - -# This is generated, do not edit. Update BuildConfigGenerator.groovy instead. android_aar_prebuilt("androidx_lifecycle_lifecycle_viewmodel_savedstate_java") { aar_path = "libs/androidx_lifecycle_lifecycle_viewmodel_savedstate/lifecycle-viewmodel-savedstate-2.2.0.aar" info_path = "libs/androidx_lifecycle_lifecycle_viewmodel_savedstate/androidx_lifecycle_lifecycle_viewmodel_savedstate.info" @@ -1992,7 +1989,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. android_aar_prebuilt("androidx_loader_loader_java") { - aar_path = "libs/androidx_loader_loader/loader-1.0.0.aar" + aar_path = "libs/androidx_loader_loader/loader-1.2.0-SNAPSHOT.aar" info_path = "libs/androidx_loader_loader/androidx_loader_loader.info" # To remove visibility constraint, add this dependency to @@ -2000,8 +1997,9 @@ visibility = [ ":*" ] deps = [ ":androidx_annotation_annotation_java", + ":androidx_collection_collection_java", ":androidx_core_core_java", - ":androidx_lifecycle_lifecycle_livedata_java", + ":androidx_lifecycle_lifecycle_livedata_core_java", ":androidx_lifecycle_lifecycle_viewmodel_java", ] resource_overlay = true @@ -2024,7 +2022,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. android_aar_prebuilt("androidx_print_print_java") { - aar_path = "libs/androidx_print_print/print-1.0.0.aar" + aar_path = "libs/androidx_print_print/print-1.1.0-SNAPSHOT.aar" info_path = "libs/androidx_print_print/androidx_print_print.info" # To remove visibility constraint, add this dependency to
diff --git a/third_party/android_deps/build.gradle b/third_party/android_deps/build.gradle index 50ecdbd6..5622cf2a 100644 --- a/third_party/android_deps/build.gradle +++ b/third_party/android_deps/build.gradle
@@ -47,6 +47,7 @@ compile "androidx.lifecycle:lifecycle-runtime:${androidXArchComponentsVersion}" compile "androidx.lifecycle:lifecycle-common:${androidXArchComponentsVersion}" compile "androidx.lifecycle:lifecycle-common-java8:${androidXArchComponentsVersion}" + compile "androidx.lifecycle:lifecycle-livedata:${androidXArchComponentsVersion}" compile "androidx.lifecycle:lifecycle-livedata-core:${androidXArchComponentsVersion}" compile "androidx.lifecycle:lifecycle-viewmodel:${androidXArchComponentsVersion}" @@ -88,7 +89,7 @@ // Those are for use by doubledown libraries. compile "androidx.arch.core:core-common:2.2.0-SNAPSHOT" compile "androidx.annotation:annotation-experimental:1.1.0-SNAPSHOT" - compile "androidx.legacy:legacy-support-core-utils:1.0.0" + compile "androidx.legacy:legacy-support-core-utils:1.1.0-SNAPSHOT" compile "androidx.lifecycle:lifecycle-runtime:${androidXSupportLibVersion}" compile "androidx.transition:transition:1.4.0-SNAPSHOT" compile "androidx.viewpager2:viewpager2:1.1.0-SNAPSHOT"
diff --git a/third_party/android_deps/libs/androidx_documentfile_documentfile/README.chromium b/third_party/android_deps/libs/androidx_documentfile_documentfile/README.chromium index a029f60..dd44ea7 100644 --- a/third_party/android_deps/libs/androidx_documentfile_documentfile/README.chromium +++ b/third_party/android_deps/libs/androidx_documentfile_documentfile/README.chromium
@@ -1,7 +1,7 @@ Name: Android Support Library Document File Short Name: documentfile -URL: http://developer.android.com/tools/extras/support-library.html -Version: 1.0.0 +URL: https://developer.android.com/jetpack/androidx/releases/documentfile#1.1.0-SNAPSHOT +Version: 1.1.0-SNAPSHOT License: Apache Version 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/android_deps/libs/androidx_documentfile_documentfile/cipd.yaml b/third_party/android_deps/libs/androidx_documentfile_documentfile/cipd.yaml index e9a3bd1..7dc20b2b 100644 --- a/third_party/android_deps/libs/androidx_documentfile_documentfile/cipd.yaml +++ b/third_party/android_deps/libs/androidx_documentfile_documentfile/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:1.0.0-cr0 +# cipd create --pkg-def cipd.yaml -tag version:1.1.0-SNAPSHOT-cr0 package: chromium/third_party/android_deps/libs/androidx_documentfile_documentfile description: "Android Support Library Document File" data: -- file: documentfile-1.0.0.aar +- file: documentfile-1.1.0-SNAPSHOT.aar
diff --git a/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils/README.chromium b/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils/README.chromium index 4b3cc9fc..2f36cf7 100644 --- a/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils/README.chromium +++ b/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils/README.chromium
@@ -1,7 +1,7 @@ Name: Android Support Library core utils Short Name: legacy-support-core-utils -URL: http://developer.android.com/tools/extras/support-library.html -Version: 1.0.0 +URL: https://developer.android.com/jetpack/androidx/releases/legacy#1.1.0-SNAPSHOT +Version: 1.1.0-SNAPSHOT License: Apache Version 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils/cipd.yaml b/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils/cipd.yaml index 2b29fe3..33dc438e 100644 --- a/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils/cipd.yaml +++ b/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:1.0.0-cr0 +# cipd create --pkg-def cipd.yaml -tag version:1.1.0-SNAPSHOT-cr0 package: chromium/third_party/android_deps/libs/androidx_legacy_legacy_support_core_utils description: "Android Support Library core utils" data: -- file: legacy-support-core-utils-1.0.0.aar +- file: legacy-support-core-utils-1.1.0-SNAPSHOT.aar
diff --git a/third_party/android_deps/libs/androidx_loader_loader/README.chromium b/third_party/android_deps/libs/androidx_loader_loader/README.chromium index 90418a8..471e5d7 100644 --- a/third_party/android_deps/libs/androidx_loader_loader/README.chromium +++ b/third_party/android_deps/libs/androidx_loader_loader/README.chromium
@@ -1,7 +1,7 @@ Name: Android Support Library loader Short Name: loader -URL: http://developer.android.com/tools/extras/support-library.html -Version: 1.0.0 +URL: https://developer.android.com/jetpack/androidx/releases/loader#1.2.0-SNAPSHOT +Version: 1.2.0-SNAPSHOT License: Apache Version 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/android_deps/libs/androidx_loader_loader/cipd.yaml b/third_party/android_deps/libs/androidx_loader_loader/cipd.yaml index 1924e17d..3bd5bd1 100644 --- a/third_party/android_deps/libs/androidx_loader_loader/cipd.yaml +++ b/third_party/android_deps/libs/androidx_loader_loader/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:1.0.0-cr0 +# cipd create --pkg-def cipd.yaml -tag version:1.2.0-SNAPSHOT-cr0 package: chromium/third_party/android_deps/libs/androidx_loader_loader description: "Android Support Library loader" data: -- file: loader-1.0.0.aar +- file: loader-1.2.0-SNAPSHOT.aar
diff --git a/third_party/android_deps/libs/androidx_print_print/README.chromium b/third_party/android_deps/libs/androidx_print_print/README.chromium index 9a0e00b..6064674 100644 --- a/third_party/android_deps/libs/androidx_print_print/README.chromium +++ b/third_party/android_deps/libs/androidx_print_print/README.chromium
@@ -1,7 +1,7 @@ Name: Android Support Library Print Short Name: print -URL: http://developer.android.com/tools/extras/support-library.html -Version: 1.0.0 +URL: https://developer.android.com/jetpack/androidx/releases/print#1.1.0-SNAPSHOT +Version: 1.1.0-SNAPSHOT License: Apache Version 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/android_deps/libs/androidx_print_print/cipd.yaml b/third_party/android_deps/libs/androidx_print_print/cipd.yaml index aea6747..b4090d4 100644 --- a/third_party/android_deps/libs/androidx_print_print/cipd.yaml +++ b/third_party/android_deps/libs/androidx_print_print/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:1.0.0-cr0 +# cipd create --pkg-def cipd.yaml -tag version:1.1.0-SNAPSHOT-cr0 package: chromium/third_party/android_deps/libs/androidx_print_print description: "Android Support Library Print" data: -- file: print-1.0.0.aar +- file: print-1.1.0-SNAPSHOT.aar
diff --git a/third_party/blink/common/page/drag_mojom_traits.cc b/third_party/blink/common/page/drag_mojom_traits.cc index a574de1..30b15b64 100644 --- a/third_party/blink/common/page/drag_mojom_traits.cc +++ b/third_party/blink/common/page/drag_mojom_traits.cc
@@ -4,8 +4,6 @@ #include "third_party/blink/public/common/page/drag_mojom_traits.h" -#include "base/notreached.h" - namespace { constexpr int allow_all = blink::kDragOperationCopy | @@ -16,49 +14,6 @@ namespace mojo { // static -blink::mojom::DragOperation -EnumTraits<blink::mojom::DragOperation, blink::DragOperation>::ToMojom( - blink::DragOperation op) { - switch (op) { - case blink::kDragOperationNone: - return blink::mojom::DragOperation::kNone; - case blink::kDragOperationCopy: - return blink::mojom::DragOperation::kCopy; - case blink::kDragOperationLink: - return blink::mojom::DragOperation::kLink; - case blink::kDragOperationMove: - return blink::mojom::DragOperation::kMove; - default: - // blink::kDragOperationEvery is not handled on purpose, as - // DragOperation should only represent a single operation. - NOTREACHED(); - return blink::mojom::DragOperation::kNone; - } -} - -// static -bool EnumTraits<blink::mojom::DragOperation, blink::DragOperation>::FromMojom( - blink::mojom::DragOperation op, - blink::DragOperation* out) { - switch (op) { - case blink::mojom::DragOperation::kNone: - *out = blink::kDragOperationNone; - return true; - case blink::mojom::DragOperation::kCopy: - *out = blink::kDragOperationCopy; - return true; - case blink::mojom::DragOperation::kLink: - *out = blink::kDragOperationLink; - return true; - case blink::mojom::DragOperation::kMove: - *out = blink::kDragOperationMove; - return true; - } - NOTREACHED(); - return false; -} - -// static bool StructTraits<blink::mojom::AllowedDragOperationsDataView, blink::DragOperationsMask>:: Read(blink::mojom::AllowedDragOperationsDataView data,
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index 92600b5..74932bf 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -440,6 +440,7 @@ "//third_party/blink/public/common", "//ui/accessibility:ax_base", "//ui/base/cursor:cursor_base", + "//ui/base/dragdrop/mojom:mojom_shared", "//ui/base/ime", "//ui/base/ime/mojom", "//ui/base/prediction:prediction",
diff --git a/third_party/blink/public/common/page/drag_mojom_traits.h b/third_party/blink/public/common/page/drag_mojom_traits.h index f9686db3..6d9dedde 100644 --- a/third_party/blink/public/common/page/drag_mojom_traits.h +++ b/third_party/blink/public/common/page/drag_mojom_traits.h
@@ -15,14 +15,6 @@ template <> struct BLINK_COMMON_EXPORT - EnumTraits<blink::mojom::DragOperation, blink::DragOperation> { - static blink::mojom::DragOperation ToMojom(blink::DragOperation op); - static bool FromMojom(blink::mojom::DragOperation op, - blink::DragOperation* out); -}; - -template <> -struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::AllowedDragOperationsDataView, blink::DragOperationsMask> { static bool allow_copy(const blink::DragOperationsMask& op_mask) {
diff --git a/third_party/blink/public/common/page/drag_operation.h b/third_party/blink/public/common/page/drag_operation.h index 6c7263faf..ce8b1f3 100644 --- a/third_party/blink/public/common/page/drag_operation.h +++ b/third_party/blink/public/common/page/drag_operation.h
@@ -35,13 +35,10 @@ namespace blink { -// "Verb" of a drag-and-drop operation as negotiated between the source and -// destination. +// Mask of the allowed of the allowed drag-and-drop operations. // These constants match their equivalents in NSDragOperation and // should not be renumbered. -// TODO(https://crbug.com/1093536): replace this enum with -// blink::mojom::DragOperation. -enum DragOperation { +enum DragOperationsMask { kDragOperationNone = 0, kDragOperationCopy = 1, kDragOperationLink = 2, @@ -49,10 +46,6 @@ kDragOperationEvery = UINT_MAX }; -// Alternate typedef to make it clear when this is being used as a mask -// with potentially multiple value bits set. -typedef DragOperation DragOperationsMask; - } // namespace blink #endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_PAGE_DRAG_OPERATION_H_
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index 9fb6d365..7ea2a72 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -289,11 +289,6 @@ { types = [ { - mojom = "blink.mojom.DragOperation" - cpp = "::blink::DragOperation" - copyable_pass_by_value = true - }, - { mojom = "blink.mojom.AllowedDragOperations" cpp = "::blink::DragOperationsMask" copyable_pass_by_value = true
diff --git a/third_party/blink/public/mojom/page/drag.mojom b/third_party/blink/public/mojom/page/drag.mojom index 700e24f..303c5e28 100644 --- a/third_party/blink/public/mojom/page/drag.mojom +++ b/third_party/blink/public/mojom/page/drag.mojom
@@ -13,15 +13,6 @@ import "url/mojom/url.mojom"; import "third_party/blink/public/mojom/file_system_access/native_file_system_drag_drop_token.mojom"; -// "Verb" of a drag-and-drop operation as negotiated between the source and -// destination. It's typemapped to blink::DragOperation. -enum DragOperation { - kNone, - kCopy, - kLink, - kMove, -}; - // This struct encodes what drag-and-drop operations are allowed. It's // typemapped to blink::DragOperationsMask. // TODO(https://crbug.com/1082291): Change this to a bitset if/when mojom
diff --git a/third_party/blink/public/mojom/page/widget.mojom b/third_party/blink/public/mojom/page/widget.mojom index a5731b65..aca77842 100644 --- a/third_party/blink/public/mojom/page/widget.mojom +++ b/third_party/blink/public/mojom/page/widget.mojom
@@ -21,6 +21,7 @@ import "third_party/blink/public/mojom/page/record_content_to_visible_time_request.mojom"; import "third_party/blink/public/mojom/widget/device_emulation_params.mojom"; import "third_party/blink/public/mojom/widget/visual_properties.mojom"; +import "ui/base/dragdrop/mojom/drag_drop_types.mojom"; import "ui/base/mojom/ui_base_types.mojom"; import "ui/base/ime/mojom/text_input_state.mojom"; import "ui/base/cursor/mojom/cursor.mojom"; @@ -51,7 +52,7 @@ gfx.mojom.PointF screen_point, AllowedDragOperations operations_allowed, uint32 key_modifiers) - => (DragOperation operation); + => (ui.mojom.DragOperation operation); // Notifies the Widget of a drag over operation. Once the renderer has // completed processing the event the callback is called with the type of @@ -61,7 +62,7 @@ gfx.mojom.PointF screen_point, AllowedDragOperations operations_allowed, uint32 key_modifiers) - => (DragOperation operation); + => (ui.mojom.DragOperation operation); // Notifies the Widget of a drag leave operation. DragTargetDragLeave(gfx.mojom.PointF point_in_viewport, @@ -76,7 +77,7 @@ // Notifies the Widget that a drag has terminated. DragSourceEndedAt(gfx.mojom.PointF point_in_viewport, gfx.mojom.PointF screen_point, - DragOperation drag_operation); + ui.mojom.DragOperation drag_operation); // Notifies the Widget that the system drag and drop operation has ended. DragSourceSystemDragEnded();
diff --git a/third_party/blink/public/web/DEPS b/third_party/blink/public/web/DEPS index 4be0558..3a5e523 100644 --- a/third_party/blink/public/web/DEPS +++ b/third_party/blink/public/web/DEPS
@@ -44,6 +44,7 @@ "+services/network/public/mojom/url_loader.mojom-shared.h", "+services/network/public/mojom/url_loader_factory.mojom-shared.h", "+services/service_manager/public", + "+ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h", "+ui/base/ime/ime_text_span.h", "+ui/events/types", "+ui/gfx/geometry",
diff --git a/third_party/blink/public/web/web_ax_object.h b/third_party/blink/public/web/web_ax_object.h index 402c393..f54825b 100644 --- a/third_party/blink/public/web/web_ax_object.h +++ b/third_party/blink/public/web/web_ax_object.h
@@ -232,10 +232,6 @@ int& focus_offset, ax::mojom::TextAffinity& focus_affinity) const; - // 1-based position in set & Size of set. - BLINK_EXPORT int PosInSet() const; - BLINK_EXPORT int SetSize() const; - // Live regions. BLINK_EXPORT bool IsInLiveRegion() const; BLINK_EXPORT bool LiveRegionAtomic() const;
diff --git a/third_party/blink/public/web/web_frame_widget.h b/third_party/blink/public/web/web_frame_widget.h index 21bfe5e..d94e58c 100644 --- a/third_party/blink/public/web/web_frame_widget.h +++ b/third_party/blink/public/web/web_frame_widget.h
@@ -43,6 +43,7 @@ #include "third_party/blink/public/platform/web_touch_action.h" #include "third_party/blink/public/web/web_swap_result.h" #include "third_party/blink/public/web/web_widget.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h" namespace blink { @@ -83,13 +84,13 @@ const gfx::PointF& screen_point, DragOperationsMask operations_allowed, uint32_t key_modifiers, - base::OnceCallback<void(blink::DragOperation)> callback) = 0; + base::OnceCallback<void(ui::mojom::DragOperation)> callback) = 0; virtual void DragTargetDragOver( const gfx::PointF& point_in_viewport, const gfx::PointF& screen_point, DragOperationsMask operations_allowed, uint32_t key_modifiers, - base::OnceCallback<void(blink::DragOperation)> callback) = 0; + base::OnceCallback<void(ui::mojom::DragOperation)> callback) = 0; virtual void DragTargetDragLeave(const gfx::PointF& point_in_viewport, const gfx::PointF& screen_point) = 0; virtual void DragTargetDrop(const WebDragData&, @@ -100,7 +101,7 @@ // Notifies the WebFrameWidget that a drag has terminated. virtual void DragSourceEndedAt(const gfx::PointF& point_in_viewport, const gfx::PointF& screen_point, - DragOperation) = 0; + ui::mojom::DragOperation) = 0; // Notifies the WebFrameWidget that the system drag and drop operation has // ended.
diff --git a/third_party/blink/public/web/web_plugin_container.h b/third_party/blink/public/web/web_plugin_container.h index ba7f201..ca3c8cd 100644 --- a/third_party/blink/public/web/web_plugin_container.h +++ b/third_party/blink/public/web/web_plugin_container.h
@@ -142,7 +142,7 @@ // Sets the layer representing the plugin for compositing. The // WebPluginContainer does *not* take ownership. - virtual void SetCcLayer(cc::Layer*, bool prevent_contents_opaque_changes) = 0; + virtual void SetCcLayer(cc::Layer*) = 0; virtual void RequestFullscreen() = 0; virtual bool IsFullscreenElement() const = 0;
diff --git a/third_party/blink/renderer/DEPS b/third_party/blink/renderer/DEPS index 9b681d5f..d113b8dd 100644 --- a/third_party/blink/renderer/DEPS +++ b/third_party/blink/renderer/DEPS
@@ -78,7 +78,7 @@ "+ui/base/cursor/mojom/cursor.mojom-blink.h", "+ui/base/cursor/mojom/cursor_type.mojom-blink.h", - "+ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h", + "+ui/base/dragdrop/mojom", "+ui/events/keycodes/dom", "+v8", ]
diff --git a/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc index ab2c20f..6aff54a 100644 --- a/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc +++ b/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
@@ -74,6 +74,7 @@ if ((next_status == Lifecycle::kV8MemoryIsForciblyPurged || next_status == Lifecycle::kGlobalObjectIsDetached) && !global_proxy_.IsEmpty()) { + v8::HandleScope handle_scope(GetIsolate()); global_proxy_.Get().SetWrapperClassId(0); V8DOMWrapper::ClearNativeInfo(GetIsolate(), global_proxy_.NewLocal(GetIsolate()));
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index 4ba8b44f..b9e8f4e2d73 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -261,6 +261,8 @@ "//third_party/blink/renderer/core/typed_arrays", "//third_party/blink/renderer/platform", "//ui/base/cursor:cursor_base", + "//ui/base/dragdrop/mojom:mojom_blink_headers", + "//ui/base/dragdrop/mojom:mojom_shared", "//url", "//v8", ] @@ -1621,6 +1623,7 @@ "//ui/accessibility:ax_base", "//ui/base/cursor:cursor_base", "//ui/base/cursor/mojom:cursor_type_blink", + "//ui/base/dragdrop/mojom:mojom_blink", ] data_deps = [ ":unit_tests_data" ]
diff --git a/third_party/blink/renderer/core/clipboard/data_transfer.cc b/third_party/blink/renderer/core/clipboard/data_transfer.cc index 8f1274e..1bc4141 100644 --- a/third_party/blink/renderer/core/clipboard/data_transfer.cc +++ b/third_party/blink/renderer/core/clipboard/data_transfer.cc
@@ -60,6 +60,7 @@ #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h" #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h" #include "third_party/skia/include/core/SkSurface.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h" namespace blink { @@ -159,7 +160,7 @@ }; base::Optional<DragOperationsMask> ConvertEffectAllowedToDragOperationsMask( - const String& op) { + const AtomicString& op) { // Values specified in // https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-effectallowed if (op == "uninitialized") @@ -189,7 +190,7 @@ return base::nullopt; } -String ConvertDragOperationsMaskToEffectAllowed(DragOperationsMask op) { +AtomicString ConvertDragOperationsMaskToEffectAllowed(DragOperationsMask op) { if (((op & kDragOperationMove) && (op & kDragOperationCopy) && (op & kDragOperationLink)) || (op == kDragOperationEvery)) @@ -245,7 +246,7 @@ DataTransfer::~DataTransfer() = default; -void DataTransfer::setDropEffect(const String& effect) { +void DataTransfer::setDropEffect(const AtomicString& effect) { if (!IsForDragAndDrop()) return; @@ -260,7 +261,7 @@ drop_effect_ = effect; } -void DataTransfer::setEffectAllowed(const String& effect) { +void DataTransfer::setEffectAllowed(const AtomicString& effect) { if (!IsForDragAndDrop()) return; @@ -568,22 +569,18 @@ return *op; } -DragOperation DataTransfer::DestinationOperation() const { +ui::mojom::blink::DragOperation DataTransfer::DestinationOperation() const { DCHECK(DropEffectIsInitialized()); base::Optional<DragOperationsMask> op = ConvertEffectAllowedToDragOperationsMask(drop_effect_); - DCHECK(op == kDragOperationCopy || op == kDragOperationNone || - op == kDragOperationLink || op == kDragOperationMove); - return static_cast<DragOperation>(*op); + return static_cast<ui::mojom::blink::DragOperation>(*op); } void DataTransfer::SetSourceOperation(DragOperationsMask op) { effect_allowed_ = ConvertDragOperationsMaskToEffectAllowed(op); } -void DataTransfer::SetDestinationOperation(DragOperation op) { - DCHECK(op == kDragOperationCopy || op == kDragOperationNone || - op == kDragOperationLink || op == kDragOperationMove); +void DataTransfer::SetDestinationOperation(ui::mojom::blink::DragOperation op) { drop_effect_ = ConvertDragOperationsMaskToEffectAllowed( static_cast<DragOperationsMask>(op)); }
diff --git a/third_party/blink/renderer/core/clipboard/data_transfer.h b/third_party/blink/renderer/core/clipboard/data_transfer.h index 043b4172..8884592 100644 --- a/third_party/blink/renderer/core/clipboard/data_transfer.h +++ b/third_party/blink/renderer/core/clipboard/data_transfer.h
@@ -34,6 +34,8 @@ #include "third_party/blink/renderer/platform/geometry/int_point.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink-forward.h" namespace blink { @@ -78,13 +80,13 @@ bool IsForCopyAndPaste() const { return transfer_type_ == kCopyAndPaste; } bool IsForDragAndDrop() const { return transfer_type_ == kDragAndDrop; } - String dropEffect() const { + AtomicString dropEffect() const { return DropEffectIsInitialized() ? drop_effect_ : "none"; } - void setDropEffect(const String&); + void setDropEffect(const AtomicString&); bool DropEffectIsInitialized() const { return !drop_effect_.IsNull(); } - String effectAllowed() const { return effect_allowed_; } - void setEffectAllowed(const String&); + AtomicString effectAllowed() const { return effect_allowed_; } + void setEffectAllowed(const AtomicString&); void clearData(const String& type = String()); String getData(const String& type) const; @@ -123,9 +125,9 @@ bool CanSetDragImage() const; DragOperationsMask SourceOperation() const; - DragOperation DestinationOperation() const; + ui::mojom::blink::DragOperation DestinationOperation() const; void SetSourceOperation(DragOperationsMask); - void SetDestinationOperation(DragOperation); + void SetDestinationOperation(ui::mojom::blink::DragOperation); DataTransferItemList* items(); @@ -165,8 +167,8 @@ // Instead of using this member directly, prefer to use the can*() methods // above. DataTransferAccessPolicy policy_; - String drop_effect_; - String effect_allowed_; + AtomicString drop_effect_; + AtomicString effect_allowed_; DataTransferType transfer_type_; Member<DataObject> data_object_;
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc index 52ca536..8d07634 100644 --- a/third_party/blink/renderer/core/css/style_engine.cc +++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -447,7 +447,7 @@ } } - if (style_needs_recalc) { + if (style_needs_recalc && text_track->Owner()) { // Use kSubtreeTreeStyleChange instead of RuleSet style invalidation // because it won't be expensive for tracks and we won't have dynamic // changes.
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc index 6be2044..d3512edd 100644 --- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc +++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -361,15 +361,10 @@ return frame->PageZoomFactor(); } -void WebPluginContainerImpl::SetCcLayer(cc::Layer* new_layer, - bool prevent_contents_opaque_changes) { - if (layer_ == new_layer && - prevent_contents_opaque_changes == prevent_contents_opaque_changes_) +void WebPluginContainerImpl::SetCcLayer(cc::Layer* new_layer) { + if (layer_ == new_layer) return; - layer_ = new_layer; - prevent_contents_opaque_changes_ = prevent_contents_opaque_changes; - if (element_) element_->SetNeedsCompositingUpdate(); } @@ -735,10 +730,6 @@ return layer_; } -bool WebPluginContainerImpl::PreventContentsOpaqueChangesToCcLayer() const { - return prevent_contents_opaque_changes_; -} - v8::Local<v8::Object> WebPluginContainerImpl::ScriptableObject( v8::Isolate* isolate) { // With Oilpan, on plugin element detach dispose() will be called to safely @@ -783,7 +774,6 @@ web_plugin_(web_plugin), layer_(nullptr), touch_event_request_type_(kTouchEventRequestTypeNone), - prevent_contents_opaque_changes_(false), wants_wheel_events_(false) {} WebPluginContainerImpl::~WebPluginContainerImpl() {
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h index fbc1467b..88f1f2e 100644 --- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h +++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
@@ -98,7 +98,6 @@ void Hide() override; cc::Layer* CcLayer() const; - bool PreventContentsOpaqueChangesToCcLayer() const; v8::Local<v8::Object> ScriptableObject(v8::Isolate*); bool SupportsKeyboardFocus() const; bool SupportsInputMethod() const; @@ -145,7 +144,7 @@ float DeviceScaleFactor() override; float PageScaleFactor() override; float PageZoomFactor() override; - void SetCcLayer(cc::Layer*, bool prevent_contents_opaque_changes) override; + void SetCcLayer(cc::Layer*) override; void RequestFullscreen() override; bool IsFullscreenElement() const override; void CancelFullscreen() override; @@ -238,7 +237,6 @@ WebPlugin* web_plugin_; cc::Layer* layer_; TouchEventRequestType touch_event_request_type_; - bool prevent_contents_opaque_changes_; bool wants_wheel_events_; };
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc index 44965521..bb5deae7 100644 --- a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc +++ b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
@@ -1435,12 +1435,12 @@ bool Initialize(WebPluginContainer* container) override { if (!FakeWebPlugin::Initialize(container)) return false; - container->SetCcLayer(layer_.get(), false); + container->SetCcLayer(layer_.get()); return true; } void Destroy() override { - Container()->SetCcLayer(nullptr, false); + Container()->SetCcLayer(nullptr); FakeWebPlugin::Destroy(); }
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc index 4693c0d..41443577 100644 --- a/third_party/blink/renderer/core/exported/web_view_test.cc +++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -152,6 +152,7 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "ui/base/cursor/cursor.h" #include "ui/base/cursor/mojom/cursor_type.mojom-blink.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h" #include "ui/base/mojom/ui_base_types.mojom-shared.h" #include "ui/events/keycodes/dom/dom_key.h" #include "v8/include/v8.h" @@ -2977,7 +2978,7 @@ // Simulate the end of a non-moving drag. const gfx::PointF dragend_point(250, 8); web_view->MainFrameViewWidget()->DragSourceEndedAt( - dragend_point, dragend_point, kDragOperationNone); + dragend_point, dragend_point, ui::mojom::blink::DragOperation::kNone); EXPECT_TRUE( web_view->GetPage()->GetContextMenuController().ContextMenuNodeForFrame( web_view->MainFrameImpl()->GetFrame())); @@ -3016,7 +3017,7 @@ // Simulate the end of a drag. const gfx::PointF dragend_point(270, 28); web_view->MainFrameViewWidget()->DragSourceEndedAt( - dragend_point, dragend_point, kDragOperationNone); + dragend_point, dragend_point, ui::mojom::blink::DragOperation::kNone); EXPECT_FALSE( web_view->GetPage()->GetContextMenuController().ContextMenuNodeForFrame( web_view->MainFrameImpl()->GetFrame()));
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc index d3cec2fc..0d5d1bf 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -143,25 +143,28 @@ // simplify this code. ScriptForbiddenScope forbid_scripts; - if (provisional_frame_) { - // This path should never be taken for a swap of any sort. - // 1. When swapping local->remote, that means the actual navigation is - // committing in a different process. Thus, there should be no - // provisional frame in this process, since there should only be one - // provisional frame for a FrameTreeNode at any given time. - // 2. When swapping remote->local, that means the actual navigation is - // committing in this frame tree. However, the committing frame should - // have unset itself as the provisional frame in `Swap()` already, so - // this should never be reached. - // 3. Similarly, when swapping local->local, the actual navigation is - // committing in this frame tree, and the same logic applies except for - // one edge case where RenderDocument is enabled and a JS unload handler - // removes its own frame, causing it to be detached during a swap. - DCHECK_EQ(FrameDetachType::kRemove, type); - provisional_frame_->Detach(type); + if (type == FrameDetachType::kRemove) { + if (provisional_frame_) { + provisional_frame_->Detach(FrameDetachType::kRemove); + } + SetOpener(nullptr); + // Clearing the window proxies can call back into `LocalFrameClient`, so + // this must be done before nulling out `client_` below. + GetWindowProxyManager()->ClearForClose(); + } else { + // In the case of a swap, detach is carefully coordinated with `Swap()`. + // Intentionally avoid clearing the opener with `SetOpener(nullptr)` here, + // since `Swap()` needs the original value to clone to the new frame. + DCHECK_EQ(FrameDetachType::kSwap, type); + + // Clearing the window proxies can call back into `LocalFrameClient`, so + // this must be done before nulling out `client_` below. + // `ClearForSwap()` preserves the v8::Objects that represent the global + // proxies; `Swap()` will later use `ReleaseGlobalProxies()` + + // `SetGlobalProxies()` to adopt the global proxies into the new frame. + GetWindowProxyManager()->ClearForSwap(); } - SetOpener(nullptr); // After this, we must no longer talk to the client since this clears // its owning reference back to our owning LocalFrame. client_->Detached(type); @@ -538,7 +541,7 @@ return parent; } -bool Frame::Swap(WebFrame* frame) { +bool Frame::Swap(WebFrame* new_web_frame) { using std::swap; // TODO(dcheng): This should not be reachable. Reaching this implies `Swap()` // is being called on an already-detached frame which should never happen... @@ -546,35 +549,16 @@ return false; // Important: do not cache frame tree pointers (e.g. `previous_sibling_`, // `next_sibling_`, `first_child_`, `last_child_`) here. It is possible for - // `DetachDocument()` to mutate the frame tree and cause cached values to - // become invalid. + // `Detach()` to mutate the frame tree and cause cached values to become + // invalid. FrameOwner* owner = owner_; FrameSwapScope frame_swap_scope(owner); Page* page = page_; AtomicString name = Tree().GetName(); - // Unload the current Document in this frame: this calls unload handlers, - // detaches child frames, etc. Since this runs script, make sure this frame - // wasn't detached before continuing with the swap. - if (!DetachDocument()) { - // If the Swap() fails, it should be because the frame has been detached - // already. Otherwise the caller will not detach the frame when we return - // false, and the browser and renderer will disagree about the destruction - // of |this|. - CHECK(IsDetached()); - return false; - } - - if (provisional_frame_) { - // `this` is about to be replaced, so if `provisional_frame_` is set, it - // should match `frame` which is being swapped in. - DCHECK_EQ(provisional_frame_, WebFrame::ToCoreFrame(*frame)); - provisional_frame_ = nullptr; - } - // TODO(dcheng): This probably isn't necessary if we fix the ordering of - // events in `Swap()`, e.g. `Detach()` should not happen before `new_frame` is - // swapped in. + // events in `Swap()`, e.g. `Detach()` should not happen before + // `new_web_frame` is swapped in. // If there is a local parent, it might incorrectly declare itself complete // during the detach phase of this swap. Suppress its completion until swap is // over, at which point its completion will be correctly dependent on its @@ -585,28 +569,38 @@ *parent_local_frame->GetDocument()) : nullptr; + // Unload the current Document in this frame: this calls unload handlers, + // detaches child frames, etc. Since this runs script, make sure this frame + // wasn't detached before continuing with the swap. + if (!Detach(FrameDetachType::kSwap)) { + // If the Swap() fails, it should be because the frame has been detached + // already. Otherwise the caller will not detach the frame when we return + // false, and the browser and renderer will disagree about the destruction + // of |this|. + CHECK(IsDetached()); + return false; + } + + // Otherwise, on a successful `Detach()` for swap, `this` is now detached--but + // crucially--still linked into the frame tree. + + if (provisional_frame_) { + // `this` is about to be replaced, so if `provisional_frame_` is set, it + // should match `frame` which is being swapped in. + DCHECK_EQ(provisional_frame_, WebFrame::ToCoreFrame(*new_web_frame)); + provisional_frame_ = nullptr; + } + v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); WindowProxyManager::GlobalProxyVector global_proxies; - GetWindowProxyManager()->ClearForSwap(); GetWindowProxyManager()->ReleaseGlobalProxies(global_proxies); - // This must be before Detach so DidChangeOpener is not called. - Frame* original_opener = opener_; - if (original_opener) - SetOpenerDoNotNotify(nullptr); - - // Although the Document in this frame is now unloaded, many resources - // associated with the frame itself have not yet been freed yet. Note that - // after `Detach()` returns, `this` is detached but *not* yet unlinked from - // the frame tree. - // TODO(dcheng): Merge this into the `DetachDocument()` step above. Executing - // parts of `Detach()` twice is confusing. - Detach(FrameDetachType::kSwap); - if (frame->IsWebRemoteFrame()) { - CHECK(!WebFrame::ToCoreFrame(*frame)); - To<WebRemoteFrameImpl>(frame)->InitializeCoreFrame( - *page, owner, WebFrame::FromCoreFrame(parent_), nullptr, - FrameInsertType::kInsertLater, name, &window_agent_factory()); + if (new_web_frame->IsWebRemoteFrame()) { + CHECK(!WebFrame::ToCoreFrame(*new_web_frame)); + To<WebRemoteFrameImpl>(new_web_frame) + ->InitializeCoreFrame(*page, owner, WebFrame::FromCoreFrame(parent_), + nullptr, FrameInsertType::kInsertLater, name, + &window_agent_factory()); // At this point, a `RemoteFrame` will have already updated // `Page::MainFrame()` or `FrameOwner::ContentFrame()` as appropriate, and // its `parent_` pointer is also populated. @@ -618,7 +612,7 @@ // TODO(dcheng): Make local and remote frame updates more uniform. } - Frame* new_frame = WebFrame::ToCoreFrame(*frame); + Frame* new_frame = WebFrame::ToCoreFrame(*new_web_frame); CHECK(new_frame); // At this point, `new_frame->parent_` is correctly set, but `new_frame`'s @@ -648,8 +642,9 @@ parent_ = nullptr; } - if (original_opener) { - new_frame->SetOpenerDoNotNotify(original_opener); + if (Frame* opener = opener_) { + SetOpenerDoNotNotify(nullptr); + new_frame->SetOpenerDoNotNotify(opener); } opened_frame_tracker_.TransferTo(new_frame);
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index 9016c40..cb4b823 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1068,14 +1068,8 @@ void LocalDOMWindow::blur() {} void LocalDOMWindow::print(ScriptState* script_state) { - // Don't print after detach begins, even if GetFrame() hasn't been nulled out - // yet. - // TODO(crbug.com/1063150): When a frame is being detached for a swap, the - // document has already been Shutdown() and is no longer in a consistent - // state, even though GetFrame() is not yet nulled out. This is an ordering - // violation, and checking whether we're in the middle of detach here is - // probably not the right long-term fix. - if (!GetFrame() || !GetFrame()->IsAttached()) + // Don't try to print if there's no frame attached anymore. + if (!GetFrame()) return; if (script_state &&
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index ef9f0b8..b11ef956 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -666,9 +666,6 @@ DCHECK(!view_->IsAttached()); Client()->WillBeDetached(); - // Notify WindowProxyManager that the frame is closing, since its cleanup ends - // up calling back to LocalFrameClient via WindowProxy. - GetWindowProxyManager()->ClearForClose(); // TODO(crbug.com/729196): Trace why LocalFrameView::DetachFromLayout crashes. CHECK(!view_->IsAttached());
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc index be9b962..8b435b7 100644 --- a/third_party/blink/renderer/core/frame/remote_frame.cc +++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -234,7 +234,6 @@ // the parent is a local frame. if (view_) view_->Dispose(); - GetWindowProxyManager()->ClearForClose(); SetView(nullptr); // ... the RemoteDOMWindow will need to be informed of detachment, // as otherwise it will keep a strong reference back to this RemoteFrame.
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 cc07678c..a1126d1 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
@@ -136,6 +136,8 @@ namespace { +using ::ui::mojom::blink::DragOperation; + const int kCaretPadding = 10; const float kIdealPaddingRatio = 0.3f; @@ -352,7 +354,7 @@ current_drag_data_ = DataObject::Create(web_drag_data); operations_allowed_ = operations_allowed; - blink::DragOperation operation = DragTargetDragEnterOrOver( + DragOperation operation = DragTargetDragEnterOrOver( point_in_viewport, screen_point, kDragEnter, key_modifiers); std::move(callback).Run(operation); } @@ -365,7 +367,7 @@ DragTargetDragOverCallback callback) { operations_allowed_ = operations_allowed; - blink::DragOperation operation = DragTargetDragEnterOrOver( + DragOperation operation = DragTargetDragEnterOrOver( point_in_viewport, screen_point, kDragOver, key_modifiers); std::move(callback).Run(operation); } @@ -394,7 +396,7 @@ // FIXME: why is the drag scroll timer not stopped here? - drag_operation_ = kDragOperationNone; + drag_operation_ = DragOperation::kNone; current_drag_data_ = nullptr; } @@ -412,9 +414,9 @@ // flight, or else delayed by javascript processing in this webview. If a // drop happens before our IPC reply has reached the browser process, then // the browser forwards the drop to this webview. So only allow a drop to - // proceed if our webview m_dragOperation state is not DragOperationNone. + // proceed if our webview drag_operation_ state is not DragOperation::kNone. - if (drag_operation_ == kDragOperationNone) { + if (drag_operation_ == DragOperation::kNone) { // IPC RACE CONDITION: do not allow this drop. DragTargetDragLeave(point_in_viewport, screen_point); return; @@ -429,7 +431,7 @@ GetPage()->GetDragController().PerformDrag(&drag_data, *local_root_->GetFrame()); } - drag_operation_ = kDragOperationNone; + drag_operation_ = DragOperation::kNone; current_drag_data_ = nullptr; } @@ -1065,7 +1067,7 @@ // check for |!m_currentDragData| should be removed. (crbug.com/671504) if (IgnoreInputEvents() || !current_drag_data_) { CancelDrag(); - return kDragOperationNone; + return DragOperation::kNone; } FloatPoint point_in_root_frame(ViewportToRootFrame(point_in_viewport)); @@ -1080,8 +1082,9 @@ // Mask the drag operation against the drag source's allowed // operations. - if (!(drag_operation & drag_data.DraggingSourceOperationMask())) - drag_operation = kDragOperationNone; + if (!(static_cast<int>(drag_operation) & + drag_data.DraggingSourceOperationMask())) + drag_operation = DragOperation::kNone; drag_operation_ = drag_operation; @@ -2128,6 +2131,10 @@ .WeightedScore(); if (layout_shift > 0.f) metrics->layout_shift = layout_shift; + + if (!metrics->HasValue()) + return nullptr; + return metrics; }
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 d8ee60cb..c1316d7 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
@@ -69,6 +69,7 @@ #include "third_party/blink/renderer/platform/widget/frame_widget.h" #include "third_party/blink/renderer/platform/widget/widget_base_client.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h" #include "ui/base/mojom/ui_base_types.mojom-shared.h" namespace gfx { @@ -377,7 +378,7 @@ mojom::blink::ViewportIntersectionStatePtr intersection_state) override; void DragSourceEndedAt(const gfx::PointF& point_in_viewport, const gfx::PointF& screen_point, - DragOperation) override; + ui::mojom::blink::DragOperation) override; // Sets the display mode, which comes from the top-level browsing context and // is applied to all widgets. @@ -776,10 +777,11 @@ // Consolidate some common code between starting a drag over a target and // updating a drag over a target. If we're starting a drag, |isEntering| // should be true. - DragOperation DragTargetDragEnterOrOver(const gfx::PointF& point_in_viewport, - const gfx::PointF& screen_point, - DragAction, - uint32_t key_modifiers); + ui::mojom::blink::DragOperation DragTargetDragEnterOrOver( + const gfx::PointF& point_in_viewport, + const gfx::PointF& screen_point, + DragAction, + uint32_t key_modifiers); // Helper function to call VisualViewport::viewportToRootFrame(). gfx::PointF ViewportToRootFrame(const gfx::PointF& point_in_viewport) const; @@ -852,7 +854,8 @@ // The current drag operation as negotiated by the source and destination. // When not equal to DragOperationNone, the drag data can be dropped onto the // current drop target in this WebView (the drop target can accept the drop). - DragOperation drag_operation_ = kDragOperationNone; + ui::mojom::blink::DragOperation drag_operation_ = + ui::mojom::blink::DragOperation::kNone; // This field stores drag/drop related info for the event that is currently // being handled. If the current event results in starting a drag/drop
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc index 9299015..9f34353 100644 --- a/third_party/blink/renderer/core/input/event_handler.cc +++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -116,6 +116,7 @@ #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/cursor/mojom/cursor_type.mojom-blink.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h" namespace blink { @@ -2304,8 +2305,9 @@ event, mouse_event_manager_->MousePressNode()); } -void EventHandler::DragSourceEndedAt(const WebMouseEvent& event, - DragOperation operation) { +void EventHandler::DragSourceEndedAt( + const WebMouseEvent& event, + ui::mojom::blink::DragOperation operation) { // Asides from routing the event to the correct frame, the hit test is also an // opportunity for Layer to update the :hover and :active pseudoclasses. HitTestRequest request(HitTestRequest::kRelease |
diff --git a/third_party/blink/renderer/core/input/event_handler.h b/third_party/blink/renderer/core/input/event_handler.h index cc38da9..1e4d85f 100644 --- a/third_party/blink/renderer/core/input/event_handler.h +++ b/third_party/blink/renderer/core/input/event_handler.h
@@ -30,7 +30,6 @@ #include "base/optional.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/common/input/web_menu_source_type.h" -#include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h" #include "third_party/blink/public/platform/web_input_event_result.h" #include "third_party/blink/renderer/core/core_export.h" @@ -53,6 +52,7 @@ #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_traits.h" #include "ui/base/cursor/cursor.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink-forward.h" namespace blink { @@ -238,7 +238,7 @@ TextEventInputType = kTextEventInputKeyboard); void DefaultTextInputEventHandler(TextEvent*); - void DragSourceEndedAt(const WebMouseEvent&, DragOperation); + void DragSourceEndedAt(const WebMouseEvent&, ui::mojom::blink::DragOperation); void CapsLockStateMayHaveChanged(); // Only called by FrameSelection
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc index 5181904..7c3c4c0 100644 --- a/third_party/blink/renderer/core/input/event_handler_test.cc +++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -52,6 +52,7 @@ #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "ui/base/cursor/cursor.h" #include "ui/base/cursor/mojom/cursor_type.mojom-blink.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/dom_key.h" @@ -1006,7 +1007,7 @@ WebInputEvent::kNoModifiers, base::TimeTicks::Now()); mouse_up_event.SetFrameScale(1); GetDocument().GetFrame()->GetEventHandler().DragSourceEndedAt( - mouse_up_event, kDragOperationNone); + mouse_up_event, ui::mojom::blink::DragOperation::kNone); // This test passes if it doesn't crash. }
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.cc b/third_party/blink/renderer/core/input/mouse_event_manager.cc index 7321141..3856924 100644 --- a/third_party/blink/renderer/core/input/mouse_event_manager.cc +++ b/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -46,6 +46,7 @@ #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/svg/svg_document_extensions.h" #include "third_party/blink/renderer/platform/geometry/float_quad.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h" namespace blink { @@ -1092,8 +1093,9 @@ } } -void MouseEventManager::DragSourceEndedAt(const WebMouseEvent& event, - DragOperation operation) { +void MouseEventManager::DragSourceEndedAt( + const WebMouseEvent& event, + ui::mojom::blink::DragOperation operation) { if (GetDragState().drag_src_) { GetDragState().drag_data_transfer_->SetDestinationOperation(operation); // The return value is ignored because dragend is not cancelable.
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.h b/third_party/blink/renderer/core/input/mouse_event_manager.h index 4a7004ad..9f75785a 100644 --- a/third_party/blink/renderer/core/input/mouse_event_manager.h +++ b/third_party/blink/renderer/core/input/mouse_event_manager.h
@@ -6,15 +6,14 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_MOUSE_EVENT_MANAGER_H_ #include "third_party/blink/public/common/input/web_mouse_event.h" -#include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/public/platform/web_input_event_result.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/synchronous_mutation_observer.h" #include "third_party/blink/renderer/core/input/boundary_event_dispatcher.h" -// #include "third_party/blink/renderer/core/page/drag_actions.h" #include "third_party/blink/renderer/core/page/event_with_hit_test_results.h" #include "third_party/blink/renderer/platform/timer.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink-forward.h" namespace blink { @@ -109,7 +108,7 @@ // drag heuristics. void ClearDragHeuristicState(); - void DragSourceEndedAt(const WebMouseEvent&, DragOperation); + void DragSourceEndedAt(const WebMouseEvent&, ui::mojom::blink::DragOperation); void UpdateSelectionForMouseDrag();
diff --git a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc index 1d61e2d..c5d49cd 100644 --- a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
@@ -48,8 +48,9 @@ navigator_platform_override_(&agent_state_, /*default_value=*/WTF::String()), user_agent_override_(&agent_state_, /*default_value=*/WTF::String()), - serialized_ua_metadata_override_(&agent_state_, - /*default_value=*/WTF::String()), + serialized_ua_metadata_override_( + &agent_state_, + /*default_value=*/std::vector<uint8_t>()), accept_language_override_(&agent_state_, /*default_value=*/WTF::String()), locale_override_(&agent_state_, /*default_value=*/WTF::String()), @@ -74,14 +75,15 @@ // Since serialized_ua_metadata_override_ can't directly be converted back // to appropriate protocol message, we initially pass null and decode it // directly. - WTF::String save_serialized_ua_metadata_override = + std::vector<uint8_t> save_serialized_ua_metadata_override = serialized_ua_metadata_override_.Get(); setUserAgentOverride( user_agent_override_.Get(), accept_language_override_.Get(), navigator_platform_override_.Get(), protocol::Maybe<protocol::Emulation::UserAgentMetadata>()); - ua_metadata_override_ = blink::UserAgentMetadata::Demarshal( - save_serialized_ua_metadata_override.Latin1()); + ua_metadata_override_ = blink::UserAgentMetadata::Demarshal(std::string( + reinterpret_cast<char*>(save_serialized_ua_metadata_override.data()), + save_serialized_ua_metadata_override.size())); serialized_ua_metadata_override_.Set(save_serialized_ua_metadata_override); if (!locale_override_.Get().IsEmpty()) @@ -589,7 +591,7 @@ if (ua_metadata_override.isJust()) { if (user_agent.IsEmpty()) { ua_metadata_override_ = base::nullopt; - serialized_ua_metadata_override_.Set(WTF::String()); + serialized_ua_metadata_override_.Set(std::vector<uint8_t>()); return Response::InvalidParams( "Can't specify UserAgentMetadata but no UA string"); } @@ -619,8 +621,10 @@ std::string marshalled = blink::UserAgentMetadata::Marshal(ua_metadata_override_) .value_or(std::string()); - serialized_ua_metadata_override_.Set( - WTF::String(marshalled.data(), marshalled.size())); + std::vector<uint8_t> marshalled_as_bytes; + marshalled_as_bytes.insert(marshalled_as_bytes.end(), marshalled.begin(), + marshalled.end()); + serialized_ua_metadata_override_.Set(std::move(marshalled_as_bytes)); return Response::Success(); }
diff --git a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h index 55d45934..0c18731e 100644 --- a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h +++ b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h
@@ -145,7 +145,7 @@ InspectorAgentState::String emulated_vision_deficiency_; InspectorAgentState::String navigator_platform_override_; InspectorAgentState::String user_agent_override_; - InspectorAgentState::String serialized_ua_metadata_override_; + InspectorAgentState::Bytes serialized_ua_metadata_override_; base::Optional<blink::UserAgentMetadata> ua_metadata_override_; InspectorAgentState::String accept_language_override_; InspectorAgentState::String locale_override_;
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/third_party/blink/renderer/core/layout/layout_embedded_content.cc index 48baf99..11bdc58 100644 --- a/third_party/blink/renderer/core/layout/layout_embedded_content.cc +++ b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -142,11 +142,15 @@ return kForcedPaintLayer; } -bool LayoutEmbeddedContent::ContentDocumentIsCompositing() const { +bool LayoutEmbeddedContent::ContentDocumentContainsGraphicsLayer() const { NOT_DESTROYED(); + // This method must use the same logic as GraphicsLayerTreeBuilder: if + // an iframe is throttled, we look for the existence of a root graphics layer, + // even if the compositing state information is stale. if (PaintLayerCompositor* inner_compositor = PaintLayerCompositor::FrameContentsCompositor(*this)) { - return inner_compositor->StaleInCompositingMode(); + DisableCompositingQueryAsserts compositing_disabler; + return inner_compositor->RootGraphicsLayer(); } return false; }
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.h b/third_party/blink/renderer/core/layout/layout_embedded_content.h index ee3c732..b39d9738 100644 --- a/third_party/blink/renderer/core/layout/layout_embedded_content.h +++ b/third_party/blink/renderer/core/layout/layout_embedded_content.h
@@ -44,7 +44,7 @@ explicit LayoutEmbeddedContent(HTMLFrameOwnerElement*); ~LayoutEmbeddedContent() override; - bool ContentDocumentIsCompositing() const; + bool ContentDocumentContainsGraphicsLayer() const; bool NodeAtPoint(HitTestResult&, const HitTestLocation&,
diff --git a/third_party/blink/renderer/core/page/drag_controller.cc b/third_party/blink/renderer/core/page/drag_controller.cc index cbeac8f..d4f1325 100644 --- a/third_party/blink/renderer/core/page/drag_controller.cc +++ b/third_party/blink/renderer/core/page/drag_controller.cc
@@ -92,6 +92,7 @@ #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/shared_buffer.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h" #if defined(OS_WIN) #include <windows.h> @@ -99,6 +100,8 @@ namespace blink { +using ui::mojom::blink::DragOperation; + static const int kMaxOriginalImageArea = 1500 * 1500; static const int kLinkDragBorderInset = 2; static const float kDragImageAlpha = 0.75f; @@ -284,7 +287,7 @@ return; } - if (OperationForLoad(drag_data, local_root) != kDragOperationNone) { + if (OperationForLoad(drag_data, local_root) != DragOperation::kNone) { if (page_->GetSettings().GetNavigateOnDragDrop()) { ResourceRequest resource_request(drag_data->AsURL()); resource_request.SetHasUserGesture(LocalFrame::HasTransientUserActivation( @@ -346,7 +349,7 @@ : static_cast<DragDestinationAction>(kDragDestinationActionDHTML | kDragDestinationActionEdit); - DragOperation drag_operation = kDragOperationNone; + DragOperation drag_operation = DragOperation::kNone; document_is_handling_drag_ = TryDocumentDrag( drag_data, drag_destination_action_, drag_operation, local_root); if (!document_is_handling_drag_ && @@ -445,8 +448,8 @@ LocalFrame* inner_frame = element->GetDocument().GetFrame(); drag_operation = DragIsMove(inner_frame->Selection(), drag_data) - ? kDragOperationMove - : kDragOperationCopy; + ? DragOperation::kMove + : DragOperation::kCopy; if (file_input_element_under_mouse_) { bool can_receive_dropped_files = false; if (!file_input_element_under_mouse_->IsDisabledFormControl()) { @@ -455,7 +458,7 @@ : drag_data->NumberOfFiles() == 1; } if (!can_receive_dropped_files) - drag_operation = kDragOperationNone; + drag_operation = DragOperation::kNone; file_input_element_under_mouse_->SetCanReceiveDroppedFiles( can_receive_dropped_files); } @@ -480,7 +483,7 @@ if (doc && (did_initiate_drag_ || IsA<PluginDocument>(doc) || HasEditableStyle(*doc))) - return kDragOperationNone; + return DragOperation::kNone; return GetDragOperation(drag_data); } @@ -758,17 +761,17 @@ // This is designed to match IE's operation fallback for the case where // the page calls preventDefault() in a drag event but doesn't set dropEffect. if (src_op_mask == kDragOperationEvery) - return kDragOperationCopy; + return DragOperation::kCopy; if (src_op_mask == kDragOperationNone) - return kDragOperationNone; + return DragOperation::kNone; if (src_op_mask & kDragOperationMove) - return kDragOperationMove; + return DragOperation::kMove; if (src_op_mask & kDragOperationCopy) - return kDragOperationCopy; + return DragOperation::kCopy; if (src_op_mask & kDragOperationLink) - return kDragOperationLink; + return DragOperation::kLink; - return kDragOperationNone; + return DragOperation::kNone; } bool DragController::TryDHTMLDrag(DragData* drag_data, @@ -797,9 +800,9 @@ operation = DefaultOperationForDrag(src_op_mask); } else { operation = data_transfer->DestinationOperation(); - if (!(src_op_mask & operation)) { + if (!(src_op_mask & static_cast<int>(operation))) { // The element picked an operation which is not supported by the source. - operation = kDragOperationNone; + operation = DragOperation::kNone; } } @@ -1340,13 +1343,13 @@ } DragOperation DragController::GetDragOperation(DragData* drag_data) { - // FIXME: To match the MacOS behaviour we should return DragOperationNone + // FIXME: To match the MacOS behaviour we should return DragOperation::kNone // if we are a modal window, we are the drag source, or the window is an // attached sheet If this can be determined from within WebCore // operationForDrag can be pulled into WebCore itself DCHECK(drag_data); - return drag_data->ContainsURL() && !did_initiate_drag_ ? kDragOperationCopy - : kDragOperationNone; + return drag_data->ContainsURL() && !did_initiate_drag_ ? DragOperation::kCopy + : DragOperation::kNone; } bool DragController::IsCopyKeyDown(DragData* drag_data) {
diff --git a/third_party/blink/renderer/core/page/drag_controller.h b/third_party/blink/renderer/core/page/drag_controller.h index 82a38635..498edf2 100644 --- a/third_party/blink/renderer/core/page/drag_controller.h +++ b/third_party/blink/renderer/core/page/drag_controller.h
@@ -27,7 +27,6 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_DRAG_CONTROLLER_H_ #include "base/macros.h" -#include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/events/event_target.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" @@ -36,6 +35,7 @@ #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/forward.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink-forward.h" namespace blink { @@ -58,7 +58,8 @@ public: explicit DragController(Page*); - DragOperation DragEnteredOrUpdated(DragData*, LocalFrame& local_root); + ui::mojom::blink::DragOperation DragEnteredOrUpdated(DragData*, + LocalFrame& local_root); void DragExited(DragData*, LocalFrame& local_root); void PerformDrag(DragData*, LocalFrame& local_root); @@ -98,13 +99,16 @@ DispatchEventResult DispatchTextInputEventFor(LocalFrame*, DragData*); bool CanProcessDrag(DragData*, LocalFrame& local_root); bool ConcludeEditDrag(DragData*); - DragOperation OperationForLoad(DragData*, LocalFrame& local_root); + ui::mojom::blink::DragOperation OperationForLoad(DragData*, + LocalFrame& local_root); bool TryDocumentDrag(DragData*, DragDestinationAction, - DragOperation&, + ui::mojom::blink::DragOperation&, LocalFrame& local_root); - bool TryDHTMLDrag(DragData*, DragOperation&, LocalFrame& local_root); - DragOperation GetDragOperation(DragData*); + bool TryDHTMLDrag(DragData*, + ui::mojom::blink::DragOperation&, + LocalFrame& local_root); + ui::mojom::blink::DragOperation GetDragOperation(DragData*); // Clear the selection from the document this drag is exiting. void ClearDragCaret(); bool DragIsMove(FrameSelection&, DragData*);
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc index 4a28986..8467e86 100644 --- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc +++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -405,8 +405,7 @@ if (layout_object.IsLayoutEmbeddedContent()) { if (WebPluginContainerImpl* plugin = GetPluginContainer(layout_object)) { - graphics_layer_->SetContentsToCcLayer( - plugin->CcLayer(), plugin->PreventContentsOpaqueChangesToCcLayer()); + graphics_layer_->SetContentsToCcLayer(plugin->CcLayer(), true); } else if (auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(layout_object.GetNode())) { if (auto* remote = DynamicTo<RemoteFrame>(frame_owner->ContentFrame())) {
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc b/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc index 9cfe34d..bbc95189 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
@@ -395,7 +395,7 @@ // squash layers painted after the iframe with layers painted before it. if (layer->GetLayoutObject().IsLayoutEmbeddedContent() && To<LayoutEmbeddedContent>(layer->GetLayoutObject()) - .ContentDocumentIsCompositing()) { + .ContentDocumentContainsGraphicsLayer()) { squashing_state.have_assigned_backings_to_entire_squashing_layer_subtree = false; }
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc index 17482ee..a9e25c3 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -378,7 +378,7 @@ bool contains_composited_layer = (layer->GetLayoutObject().IsLayoutEmbeddedContent() && To<LayoutEmbeddedContent>(layer->GetLayoutObject()) - .ContentDocumentIsCompositing()); + .ContentDocumentContainsGraphicsLayer()); bool will_be_composited_or_squashed = can_be_composited && RequiresCompositingOrSquashing(reasons_to_composite);
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc index 241260bc..4014ebf 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
@@ -5,9 +5,12 @@ #include "third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/core/layout/layout_embedded_content.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" +#include "third_party/blink/renderer/core/testing/sim/sim_request.h" +#include "third_party/blink/renderer/core/testing/sim/sim_test.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" @@ -222,4 +225,88 @@ GetPaintLayerByElementId("3d-descendant")->GetCompositingReasons()); } +class CompositingRequirementsUpdaterSimTest : public SimTest { + protected: + void SetUp() override { + SimTest::SetUp(); + WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600)); + } +}; + +TEST_F(CompositingRequirementsUpdaterSimTest, + StaleCompositingStateInThrottledFrame) { + SimRequest top_resource("https://example.com/top.html", "text/html"); + SimRequest middle_resource("https://cross-origin.com/middle.html", + "text/html"); + SimRequest bottom_resource("https://cross-origin.com/bottom.html", + "text/html"); + + LoadURL("https://example.com/top.html"); + top_resource.Complete(R"HTML( + <div id='spacer'></div> + <iframe id='middle' src='https://cross-origin.com/middle.html'></iframe> + )HTML"); + middle_resource.Complete(R"HTML( + <iframe id='bottom' src='bottom.html'></iframe> + )HTML"); + bottom_resource.Complete(R"HTML( + <div id='composited' style='will-change:transform'>Hello, world!</div> + )HTML"); + + LocalFrame& middle_frame = + *To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild()); + LocalFrame& bottom_frame = *To<LocalFrame>(middle_frame.Tree().FirstChild()); + middle_frame.View()->BeginLifecycleUpdates(); + bottom_frame.View()->BeginLifecycleUpdates(); + GetDocument().View()->UpdateAllLifecyclePhasesForTest(); + ASSERT_FALSE(bottom_frame.View()->ShouldThrottleRenderingForTest()); + LayoutEmbeddedContent* bottom_owner = bottom_frame.OwnerLayoutObject(); + EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer()); + EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant()); + + // Move iframe offscreen to throttle it. Compositing status shouldn't change. + Element* spacer = GetDocument().getElementById("spacer"); + spacer->setAttribute(html_names::kStyleAttr, "height:2000px"); + GetDocument().View()->UpdateAllLifecyclePhasesForTest(); + ASSERT_TRUE(middle_frame.View()->ShouldThrottleRenderingForTest()); + ASSERT_TRUE(bottom_frame.View()->ShouldThrottleRenderingForTest()); + EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer()); + EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant()); + + // Remove direct compositing reason from iframe content, but add + // position:relative so it still has a PaintLayer and won't force a + // compositing update. + Element* composited = + bottom_frame.GetDocument()->getElementById("composited"); + composited->setAttribute(html_names::kStyleAttr, "position:relative"); + + // Force a lifecycle update up to pre-paint clean; compositing inputs will be + // updated, but not compositing assignments. This imitates what would happen + // if a new IntersectionObservation is created inside a throttled frame. This + // should not affect final compositing state. + GetDocument().View()->ForceUpdateViewportIntersections(); + EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer()); + EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant()); + + // Force a full, throttled lifecycle update. Compositing state in the bottom + // frame will remain stale; compositing state in the middle frame will be + // based on the stale state of the iframe. + GetDocument().View()->UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE( + middle_frame.ContentLayoutObject()->Layer()->GetCompositingReasons() | + CompositingReason::kRoot); + EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer()); + EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant()); + + // Move the iframe back on screen and run two lifecycle updates to unthrottle + // it and update compositing. + spacer->setAttribute(html_names::kStyleAttr, ""); + GetDocument().View()->UpdateAllLifecyclePhasesForTest(); + ASSERT_FALSE(middle_frame.View()->ShouldThrottleRenderingForTest()); + ASSERT_FALSE(bottom_frame.View()->ShouldThrottleRenderingForTest()); + GetDocument().View()->UpdateAllLifecyclePhasesForTest(); + EXPECT_FALSE(bottom_owner->ContentDocumentContainsGraphicsLayer()); + EXPECT_FALSE(bottom_owner->Layer()->HasCompositingDescendant()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc index edb39bf..eb412c6 100644 --- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc +++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -221,6 +221,12 @@ target_state, compositing_reasons_stats); if (child_compositor->root_layer_attachment_dirty_) SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree); +#if DCHECK_IS_ON() + // Even if the child frame is throttled, this should be consistent. + DisableCompositingQueryAsserts query_assert_disabler; + DCHECK_EQ(child_compositor->InCompositingMode(), + (bool)child_compositor->RootGraphicsLayer()); +#endif } }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index d78a842..4db3271 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -853,6 +853,23 @@ dom_node_id); } + // Heading level. + if (ui::IsHeading(RoleValue()) && HeadingLevel()) { + node_data->AddIntAttribute( + ax::mojom::blink::IntAttribute::kHierarchicalLevel, HeadingLevel()); + } + + AXObject* parent = ParentObject(); + if (Language().length()) { + // TODO(chrishall): should we still trim redundant languages off here? + if (!parent || parent->Language() != Language()) { + TruncateAndAddStringAttribute( + node_data, ax::mojom::blink::StringAttribute::kLanguage, + Language().Utf8()); + } + } + + SerializeListAttributes(node_data); SerializeTableAttributes(node_data); } @@ -1119,6 +1136,18 @@ } } +void AXObject::SerializeListAttributes(ui::AXNodeData* node_data) { + if (SetSize()) { + node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kSetSize, + SetSize()); + } + + if (PosInSet()) { + node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kPosInSet, + PosInSet()); + } +} + void AXObject::TruncateAndAddStringAttribute( ui::AXNodeData* dst, ax::mojom::blink::StringAttribute attribute,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h index 1c90c32c..685fa3d 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -1315,6 +1315,7 @@ void SerializeStyleAttributes(ui::AXNodeData* node_data); void SerializeSparseAttributes(ui::AXNodeData* node_data); void SerializeTableAttributes(ui::AXNodeData* node_data); + void SerializeListAttributes(ui::AXNodeData* node_data); private: void UpdateDistributionForFlatTreeTraversal() const;
diff --git a/third_party/blink/renderer/modules/csspaint/README.md b/third_party/blink/renderer/modules/csspaint/README.md index 2b70c76..26a07ad 100644 --- a/third_party/blink/renderer/modules/csspaint/README.md +++ b/third_party/blink/renderer/modules/csspaint/README.md
@@ -50,16 +50,84 @@ executes the V8 paint callback synchronously. A PaintRecord is produced and passed to the compositor thread to raster. +When animation is involved, the main thread animation system updates the value +of the animated properties, which are used by the `PaintWorklet::Paint`. + ### Off main thread workflow -During the main thread paint, a -[PaintWorkletInput](../../core/css/cssom/paint_worklet_input.h) is created and -passed to the compositor. The PaintWorkletInput contains all necessary -information for the compositor to run the V8 paint callback. The compositor -thread asynchronously dispatches the V8 paint callback to a Worklet thread. -The V8 paint callback is then executed on the Worklet thread and a PaintRecord is -given back to the compositor thread. The compositor thread then rasters the -PaintRecord. +Let's see how it works without animations. + +1. During the main thread paint, a + [PaintWorkletDeferredImage](../../core/css/cssom/paint_worklet_deferred_image.h) + is created. This is an image without any color information, it is a + placeholder to the Blink paint system. The creation of its actual content + is deferred to CC raster time. It holds input arguments which is + encapsulated in [CSSPaintWorkletInput](../../core/css/cssom/css_paint_worklet_input.h). + The input arguments contain necessary information for the CC raster phase. + +1. During commit, the `PaintWorkletInput` is passed to CC. Specifically, the + `PictureLayerImpl` owns `PaintWorkletRecordMap`, which is a map from + `PaintWorkletInput` to `std::pair<PaintImage::Id, PaintRecord>`. The + `PaintImage::Id` is used for efficient invalidation. The `PaintRecord` is + the actual content of the `PaintWorkletDeferredImage`, which will be + generated at CC raster time. Initially the `PaintRecord` is `nullptr` which + indicates that it needs to be produced. + +1. After commit, we need to update the pending tree. This happens in + `LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation`. + There are two steps involved. + + 1. The first step is to gather all dirty paint worklets that need to be + updated, which happens in `LayerTreeHostImpl::GatherDirtyPaintWorklets`. It + basically goes through each `PictureLayerImpl` whose + `PaintWorkletRecrodMap` isn't empty, and if there is a `PaintWorkletInput` + with its associated `PaintRecord` being nullptr, then this worklet needs to + be updated. + + 1. Once we have gathered all the dirty paint worklets, the next step is to + produce the `PaintRecord` which is the actual contents. The compositor + thread asynchronously dispatches the paint jobs that produce the + `PaintRecord` to a worklet thread. Each paint job is basically a V8 paint + callback, the paint callback is executed on the worklet thread and the + `PaintRecord` is given back to the compositor thread such that it can be + rastered. Given that the V8 paint callback contains user defined javascript + code and can take arbitrary amount of time, the paint job doesn't block the + tree activation. In other word, the pending tree can be activated even if + the paint jobs are not finished, it will just use the `PaintRecord` that + was produced in the previous frame. + +Now let's see how it works with animation. Here is an +[example](https://jsbin.com/muwiyux/9/edit?html,css,output) that animates a +custom property '--foo' with paint worklet. Traditionally +[custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) +cannot be animated on the compositor thread. With off main thread paint worklet +design, we can animate the custom properties off the main thread and use them in +paint worklet. Note that currently our implementation supports custom property +animations only, not native properties. We do intend to extend to support +native properties in the future. + +1. When resolving style, `CompositorKeyframeValue` will be created through + `CompositorKeyframeValueFactory::Create` function. This basically tells the + main thread animation system to not animate the custom properties, and + instead creating a compositor animation for each custom property. + +1. After Blink paint, a compositor animation will be created through the + `CreateCompositorAnimation` function. The compositor animation is passed to + CC via commit process. + +1. CC ticks the compositor animation, which updates the value for the custom + property. Currently we only support custom properties that represents number + or color. This is handled by + `AnimatedPaintWorkletTracker::OnCustomPropertyMutated`. The + `AnimatedPaintWorkletTracker` class handles custom properties animated by + paint worklet. + +1. By combining custom property name with `ElementId`, we create + `PaintWorkletInput::PropertyKey` which can be used to identify a + `PaintWorkletInput`. Then we can use the `PaintWorkletInput` to find its + associated `PaintRecord` in the `PictureLayerImpl`'s `PaintWorkletRecordMap`, + invalidate it and update its content when we update the pending tree via + `LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation`. ## Implementation @@ -116,4 +184,3 @@ Tests live [here](../../../web_tests/http/tests/csspaint/) and [here](../../../web_tests/external/wpt/css/css-paint-api/). -
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc index 0cd8f335..817bcd7 100644 --- a/third_party/blink/renderer/modules/exported/web_ax_object.cc +++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -392,20 +392,6 @@ return private_->IsEditable(); } -int WebAXObject::PosInSet() const { - if (IsDetached()) - return 0; - - return private_->PosInSet(); -} - -int WebAXObject::SetSize() const { - if (IsDetached()) - return 0; - - return private_->SetSize(); -} - bool WebAXObject::IsInLiveRegion() const { if (IsDetached()) return false;
diff --git a/third_party/blink/renderer/modules/launch/launch_params.h b/third_party/blink/renderer/modules/launch/launch_params.h index e3b60d5..4e773c8 100644 --- a/third_party/blink/renderer/modules/launch/launch_params.h +++ b/third_party/blink/renderer/modules/launch/launch_params.h
@@ -18,7 +18,7 @@ DEFINE_WRAPPERTYPEINFO(); public: - LaunchParams(HeapVector<Member<NativeFileSystemHandle>> files); + explicit LaunchParams(HeapVector<Member<NativeFileSystemHandle>> files); ~LaunchParams() override; // LaunchParams IDL interface.
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc index 3ee29cf..b88f8e9 100644 --- a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc +++ b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
@@ -912,12 +912,19 @@ TEST_F(SecurityOriginTest, NonStandardSchemeWithAndroidWebViewHack) { url::ScopedSchemeRegistryForTests scoped_registry; url::EnableNonStandardSchemesForAndroidWebView(); + + // Regression test for https://crbug.com/896059. scoped_refptr<const SecurityOrigin> origin = SecurityOrigin::CreateFromString("cow://"); EXPECT_FALSE(origin->IsOpaque()); EXPECT_EQ("cow", origin->Protocol()); EXPECT_EQ("", origin->Host()); EXPECT_EQ(0, origin->Port()); + + // about:blank translates into an opaque origin, even in presence of + // EnableNonStandardSchemesForAndroidWebView. + origin = SecurityOrigin::CreateFromString("about:blank"); + EXPECT_TRUE(origin->IsOpaque()); } TEST_F(SecurityOriginTest, OpaqueIsolatedCopy) {
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 1e87662..0336acc7 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
@@ -360,10 +360,12 @@ cmd.HasSwitch(cc::switches::kHighlightNonLCDTextLayers); settings.initial_debug_state.show_web_vital_metrics = base::FeatureList::IsEnabled( - ::features::kHudDisplayForPerformanceMetrics); + ::features::kHudDisplayForPerformanceMetrics) && + !for_child_local_root_frame; settings.initial_debug_state.show_smoothness_metrics = base::FeatureList::IsEnabled( - ::features::kHudDisplayForPerformanceMetrics); + ::features::kHudDisplayForPerformanceMetrics) && + !for_child_local_root_frame; settings.initial_debug_state.SetRecordRenderingStats( cmd.HasSwitch(cc::switches::kEnableGpuBenchmarking));
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index 493e8a2..636a4a2d 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -492,6 +492,7 @@ # Accessibility helper functions - mostly used in Blink for # serialization. 'ui::IsDialog', + 'ui::IsHeading', 'ui::IsContainerWithSelectableChildren', 'ui::IsTableLike', 'ui::IsTableRow',
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 0ddd900..4f18e993 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -4355,6 +4355,9 @@ crbug.com/1074441 external/wpt/cookies/samesite/iframe.https.html [ Skip ] crbug.com/1074441 virtual/legacy-samesite/external/wpt/cookies/samesite/iframe-reload.https.html?legacy-samesite [ Skip ] crbug.com/1074441 virtual/legacy-samesite/external/wpt/cookies/samesite/iframe.https.html?legacy-samesite [ Skip ] +# Flaky Windows-only content_shell crash +crbug.com/1162205 [ Win ] virtual/schemeful-same-site/external/wpt/cookies/attributes/path-redirect.html [ Crash Pass ] +crbug.com/1162205 [ Win ] external/wpt/cookies/attributes/path-redirect.html [ Crash Pass ] # The virtual tests run with Schemeful Same-Site disabled. These should fail to ensure the disabled feature code paths work. crbug.com/1127348 virtual/schemeful-same-site/external/wpt/cookies/schemeful-same-site/schemeful-websockets.sub.tentative.html [ Failure ] @@ -4572,6 +4575,9 @@ # Sheriff 2018-08-01 crbug.com/869773 http/tests/misc/window-dot-stop.html [ Pass Failure ] +crbug.com/1162393 [ Fuchsia ] paint/invalidation/selection/selected-replaced.html [ Failure Pass ] +crbug.com/1162393 [ Fuchsia ] tables/mozilla/bugs/bug1188.html [ Failure Pass ] + crbug.com/873873 external/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html [ Timeout Pass ] crbug.com/873873 external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ] @@ -5895,6 +5901,7 @@ # DevTools roll crbug.com/1144171 http/tests/devtools/report-API-errors.js [ Skip ] +crbug.com/1028078 http/tests/devtools/throttling/mobile-throttling.js [ Skip ] # Sheriff 2020-12-07 crbug.com/1156175 external/wpt/requestidlecallback/callback-iframe.html [ Pass Timeout ] @@ -5917,6 +5924,7 @@ # Wpt importer sheriff 2020-12-23 crbug.com/626703 external/wpt/cookies/samesite/multiple-samesite-attributes.https.html?legacy-samesite [ Failure ] crbug.com/626703 virtual/legacy-samesite/external/wpt/cookies/samesite/multiple-samesite-attributes.https.html [ Failure ] +crbug.com/1161590 external/wpt/html/semantics/forms/textfieldselection/select-event.html [ Failure Timeout ] # Sheriff 2020-12-14 crbug.com/1046784 http/tests/devtools/console/console-context-selector.js [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/textfieldselection/select-event-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/forms/textfieldselection/select-event-expected.txt deleted file mode 100644 index 11a2360a9..0000000 --- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/textfieldselection/select-event-expected.txt +++ /dev/null
@@ -1,274 +0,0 @@ -This is a testharness.js-based test. -Found 270 tests; 255 PASS, 15 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS textarea: select() -PASS textarea: select() a second time (must not fire select) -PASS textarea: select() disconnected node -PASS textarea: select() event queue -FAIL textarea: select() twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: selectionStart -PASS textarea: selectionStart a second time (must not fire select) -PASS textarea: selectionStart disconnected node -PASS textarea: selectionStart event queue -FAIL textarea: selectionStart twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: selectionEnd -PASS textarea: selectionEnd a second time (must not fire select) -PASS textarea: selectionEnd disconnected node -PASS textarea: selectionEnd event queue -FAIL textarea: selectionEnd twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: selectionDirection -PASS textarea: selectionDirection a second time (must not fire select) -PASS textarea: selectionDirection disconnected node -PASS textarea: selectionDirection event queue -FAIL textarea: selectionDirection twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: setSelectionRange() -PASS textarea: setSelectionRange() a second time (must not fire select) -PASS textarea: setSelectionRange() disconnected node -PASS textarea: setSelectionRange() event queue -FAIL textarea: setSelectionRange() twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: setRangeText() -PASS textarea: setRangeText() a second time (must not fire select) -PASS textarea: setRangeText() disconnected node -PASS textarea: setRangeText() event queue -FAIL textarea: setRangeText() twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 15 -PASS textarea: selectionStart out of range -PASS textarea: selectionStart out of range a second time (must not fire select) -FAIL textarea: selectionStart out of range disconnected node step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: selectionStart out of range event queue step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: selectionStart out of range twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: selectionEnd out of range -PASS textarea: selectionEnd out of range a second time (must not fire select) -FAIL textarea: selectionEnd out of range disconnected node step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: selectionEnd out of range event queue step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: selectionEnd out of range twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: setSelectionRange out of range -PASS textarea: setSelectionRange out of range a second time (must not fire select) -FAIL textarea: setSelectionRange out of range disconnected node step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: setSelectionRange out of range event queue step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: setSelectionRange out of range twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS input type text: select() -PASS input type text: select() a second time (must not fire select) -PASS input type text: select() disconnected node -PASS input type text: select() event queue -PASS input type text: select() twice in disconnected node (must fire select only once) -PASS input type text: selectionStart -PASS input type text: selectionStart a second time (must not fire select) -PASS input type text: selectionStart disconnected node -PASS input type text: selectionStart event queue -PASS input type text: selectionStart twice in disconnected node (must fire select only once) -PASS input type text: selectionEnd -PASS input type text: selectionEnd a second time (must not fire select) -PASS input type text: selectionEnd disconnected node -PASS input type text: selectionEnd event queue -PASS input type text: selectionEnd twice in disconnected node (must fire select only once) -PASS input type text: selectionDirection -PASS input type text: selectionDirection a second time (must not fire select) -PASS input type text: selectionDirection disconnected node -PASS input type text: selectionDirection event queue -PASS input type text: selectionDirection twice in disconnected node (must fire select only once) -PASS input type text: setSelectionRange() -PASS input type text: setSelectionRange() a second time (must not fire select) -PASS input type text: setSelectionRange() disconnected node -PASS input type text: setSelectionRange() event queue -PASS input type text: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type text: setRangeText() -PASS input type text: setRangeText() a second time (must not fire select) -PASS input type text: setRangeText() disconnected node -PASS input type text: setRangeText() event queue -PASS input type text: setRangeText() twice in disconnected node (must fire select only once) -PASS input type text: selectionStart out of range -PASS input type text: selectionStart out of range a second time (must not fire select) -PASS input type text: selectionStart out of range disconnected node -PASS input type text: selectionStart out of range event queue -PASS input type text: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type text: selectionEnd out of range -PASS input type text: selectionEnd out of range a second time (must not fire select) -PASS input type text: selectionEnd out of range disconnected node -PASS input type text: selectionEnd out of range event queue -PASS input type text: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type text: setSelectionRange out of range -PASS input type text: setSelectionRange out of range a second time (must not fire select) -PASS input type text: setSelectionRange out of range disconnected node -PASS input type text: setSelectionRange out of range event queue -PASS input type text: setSelectionRange out of range twice in disconnected node (must fire select only once) -PASS input type search: select() -PASS input type search: select() a second time (must not fire select) -PASS input type search: select() disconnected node -PASS input type search: select() event queue -PASS input type search: select() twice in disconnected node (must fire select only once) -PASS input type search: selectionStart -PASS input type search: selectionStart a second time (must not fire select) -PASS input type search: selectionStart disconnected node -PASS input type search: selectionStart event queue -PASS input type search: selectionStart twice in disconnected node (must fire select only once) -PASS input type search: selectionEnd -PASS input type search: selectionEnd a second time (must not fire select) -PASS input type search: selectionEnd disconnected node -PASS input type search: selectionEnd event queue -PASS input type search: selectionEnd twice in disconnected node (must fire select only once) -PASS input type search: selectionDirection -PASS input type search: selectionDirection a second time (must not fire select) -PASS input type search: selectionDirection disconnected node -PASS input type search: selectionDirection event queue -PASS input type search: selectionDirection twice in disconnected node (must fire select only once) -PASS input type search: setSelectionRange() -PASS input type search: setSelectionRange() a second time (must not fire select) -PASS input type search: setSelectionRange() disconnected node -PASS input type search: setSelectionRange() event queue -PASS input type search: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type search: setRangeText() -PASS input type search: setRangeText() a second time (must not fire select) -PASS input type search: setRangeText() disconnected node -PASS input type search: setRangeText() event queue -PASS input type search: setRangeText() twice in disconnected node (must fire select only once) -PASS input type search: selectionStart out of range -PASS input type search: selectionStart out of range a second time (must not fire select) -PASS input type search: selectionStart out of range disconnected node -PASS input type search: selectionStart out of range event queue -PASS input type search: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type search: selectionEnd out of range -PASS input type search: selectionEnd out of range a second time (must not fire select) -PASS input type search: selectionEnd out of range disconnected node -PASS input type search: selectionEnd out of range event queue -PASS input type search: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type search: setSelectionRange out of range -PASS input type search: setSelectionRange out of range a second time (must not fire select) -PASS input type search: setSelectionRange out of range disconnected node -PASS input type search: setSelectionRange out of range event queue -PASS input type search: setSelectionRange out of range twice in disconnected node (must fire select only once) -PASS input type tel: select() -PASS input type tel: select() a second time (must not fire select) -PASS input type tel: select() disconnected node -PASS input type tel: select() event queue -PASS input type tel: select() twice in disconnected node (must fire select only once) -PASS input type tel: selectionStart -PASS input type tel: selectionStart a second time (must not fire select) -PASS input type tel: selectionStart disconnected node -PASS input type tel: selectionStart event queue -PASS input type tel: selectionStart twice in disconnected node (must fire select only once) -PASS input type tel: selectionEnd -PASS input type tel: selectionEnd a second time (must not fire select) -PASS input type tel: selectionEnd disconnected node -PASS input type tel: selectionEnd event queue -PASS input type tel: selectionEnd twice in disconnected node (must fire select only once) -PASS input type tel: selectionDirection -PASS input type tel: selectionDirection a second time (must not fire select) -PASS input type tel: selectionDirection disconnected node -PASS input type tel: selectionDirection event queue -PASS input type tel: selectionDirection twice in disconnected node (must fire select only once) -PASS input type tel: setSelectionRange() -PASS input type tel: setSelectionRange() a second time (must not fire select) -PASS input type tel: setSelectionRange() disconnected node -PASS input type tel: setSelectionRange() event queue -PASS input type tel: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type tel: setRangeText() -PASS input type tel: setRangeText() a second time (must not fire select) -PASS input type tel: setRangeText() disconnected node -PASS input type tel: setRangeText() event queue -PASS input type tel: setRangeText() twice in disconnected node (must fire select only once) -PASS input type tel: selectionStart out of range -PASS input type tel: selectionStart out of range a second time (must not fire select) -PASS input type tel: selectionStart out of range disconnected node -PASS input type tel: selectionStart out of range event queue -PASS input type tel: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type tel: selectionEnd out of range -PASS input type tel: selectionEnd out of range a second time (must not fire select) -PASS input type tel: selectionEnd out of range disconnected node -PASS input type tel: selectionEnd out of range event queue -PASS input type tel: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type tel: setSelectionRange out of range -PASS input type tel: setSelectionRange out of range a second time (must not fire select) -PASS input type tel: setSelectionRange out of range disconnected node -PASS input type tel: setSelectionRange out of range event queue -PASS input type tel: setSelectionRange out of range twice in disconnected node (must fire select only once) -PASS input type url: select() -PASS input type url: select() a second time (must not fire select) -PASS input type url: select() disconnected node -PASS input type url: select() event queue -PASS input type url: select() twice in disconnected node (must fire select only once) -PASS input type url: selectionStart -PASS input type url: selectionStart a second time (must not fire select) -PASS input type url: selectionStart disconnected node -PASS input type url: selectionStart event queue -PASS input type url: selectionStart twice in disconnected node (must fire select only once) -PASS input type url: selectionEnd -PASS input type url: selectionEnd a second time (must not fire select) -PASS input type url: selectionEnd disconnected node -PASS input type url: selectionEnd event queue -PASS input type url: selectionEnd twice in disconnected node (must fire select only once) -PASS input type url: selectionDirection -PASS input type url: selectionDirection a second time (must not fire select) -PASS input type url: selectionDirection disconnected node -PASS input type url: selectionDirection event queue -PASS input type url: selectionDirection twice in disconnected node (must fire select only once) -PASS input type url: setSelectionRange() -PASS input type url: setSelectionRange() a second time (must not fire select) -PASS input type url: setSelectionRange() disconnected node -PASS input type url: setSelectionRange() event queue -PASS input type url: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type url: setRangeText() -PASS input type url: setRangeText() a second time (must not fire select) -PASS input type url: setRangeText() disconnected node -PASS input type url: setRangeText() event queue -PASS input type url: setRangeText() twice in disconnected node (must fire select only once) -PASS input type url: selectionStart out of range -PASS input type url: selectionStart out of range a second time (must not fire select) -PASS input type url: selectionStart out of range disconnected node -PASS input type url: selectionStart out of range event queue -PASS input type url: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type url: selectionEnd out of range -PASS input type url: selectionEnd out of range a second time (must not fire select) -PASS input type url: selectionEnd out of range disconnected node -PASS input type url: selectionEnd out of range event queue -PASS input type url: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type url: setSelectionRange out of range -PASS input type url: setSelectionRange out of range a second time (must not fire select) -PASS input type url: setSelectionRange out of range disconnected node -PASS input type url: setSelectionRange out of range event queue -PASS input type url: setSelectionRange out of range twice in disconnected node (must fire select only once) -PASS input type password: select() -PASS input type password: select() a second time (must not fire select) -PASS input type password: select() disconnected node -PASS input type password: select() event queue -PASS input type password: select() twice in disconnected node (must fire select only once) -PASS input type password: selectionStart -PASS input type password: selectionStart a second time (must not fire select) -PASS input type password: selectionStart disconnected node -PASS input type password: selectionStart event queue -PASS input type password: selectionStart twice in disconnected node (must fire select only once) -PASS input type password: selectionEnd -PASS input type password: selectionEnd a second time (must not fire select) -PASS input type password: selectionEnd disconnected node -PASS input type password: selectionEnd event queue -PASS input type password: selectionEnd twice in disconnected node (must fire select only once) -PASS input type password: selectionDirection -PASS input type password: selectionDirection a second time (must not fire select) -PASS input type password: selectionDirection disconnected node -PASS input type password: selectionDirection event queue -PASS input type password: selectionDirection twice in disconnected node (must fire select only once) -PASS input type password: setSelectionRange() -PASS input type password: setSelectionRange() a second time (must not fire select) -PASS input type password: setSelectionRange() disconnected node -PASS input type password: setSelectionRange() event queue -PASS input type password: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type password: setRangeText() -PASS input type password: setRangeText() a second time (must not fire select) -PASS input type password: setRangeText() disconnected node -PASS input type password: setRangeText() event queue -PASS input type password: setRangeText() twice in disconnected node (must fire select only once) -PASS input type password: selectionStart out of range -PASS input type password: selectionStart out of range a second time (must not fire select) -PASS input type password: selectionStart out of range disconnected node -PASS input type password: selectionStart out of range event queue -PASS input type password: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type password: selectionEnd out of range -PASS input type password: selectionEnd out of range a second time (must not fire select) -PASS input type password: selectionEnd out of range disconnected node -PASS input type password: selectionEnd out of range event queue -PASS input type password: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type password: setSelectionRange out of range -PASS input type password: setSelectionRange out of range a second time (must not fire select) -PASS input type password: setSelectionRange out of range disconnected node -PASS input type password: setSelectionRange out of range event queue -PASS input type password: setSelectionRange out of range twice in disconnected node (must fire select only once) -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/semantics/forms/textfieldselection/select-event-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/semantics/forms/textfieldselection/select-event-expected.txt deleted file mode 100644 index 60e2cc21..0000000 --- a/third_party/blink/web_tests/platform/mac/external/wpt/html/semantics/forms/textfieldselection/select-event-expected.txt +++ /dev/null
@@ -1,274 +0,0 @@ -This is a testharness.js-based test. -Found 270 tests; 249 PASS, 21 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS textarea: select() -PASS textarea: select() a second time (must not fire select) -PASS textarea: select() disconnected node -PASS textarea: select() event queue -FAIL textarea: select() twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: selectionStart -PASS textarea: selectionStart a second time (must not fire select) -PASS textarea: selectionStart disconnected node -PASS textarea: selectionStart event queue -FAIL textarea: selectionStart twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: selectionEnd -PASS textarea: selectionEnd a second time (must not fire select) -PASS textarea: selectionEnd disconnected node -PASS textarea: selectionEnd event queue -FAIL textarea: selectionEnd twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: selectionDirection -FAIL textarea: selectionDirection a second time (must not fire select) assert_unreached: the select event must not fire the second time Reached unreachable code -PASS textarea: selectionDirection disconnected node -PASS textarea: selectionDirection event queue -FAIL textarea: selectionDirection twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: setSelectionRange() -PASS textarea: setSelectionRange() a second time (must not fire select) -PASS textarea: setSelectionRange() disconnected node -PASS textarea: setSelectionRange() event queue -FAIL textarea: setSelectionRange() twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: setRangeText() -PASS textarea: setRangeText() a second time (must not fire select) -PASS textarea: setRangeText() disconnected node -PASS textarea: setRangeText() event queue -FAIL textarea: setRangeText() twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 15 -PASS textarea: selectionStart out of range -PASS textarea: selectionStart out of range a second time (must not fire select) -FAIL textarea: selectionStart out of range disconnected node step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: selectionStart out of range event queue step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: selectionStart out of range twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: selectionEnd out of range -PASS textarea: selectionEnd out of range a second time (must not fire select) -FAIL textarea: selectionEnd out of range disconnected node step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: selectionEnd out of range event queue step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: selectionEnd out of range twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS textarea: setSelectionRange out of range -PASS textarea: setSelectionRange out of range a second time (must not fire select) -FAIL textarea: setSelectionRange out of range disconnected node step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: setSelectionRange out of range event queue step_wait_func: event didn't fire Timed out waiting on condition -FAIL textarea: setSelectionRange out of range twice in disconnected node (must fire select only once) assert_equals: expected 0 but got 6 -PASS input type text: select() -PASS input type text: select() a second time (must not fire select) -PASS input type text: select() disconnected node -PASS input type text: select() event queue -PASS input type text: select() twice in disconnected node (must fire select only once) -PASS input type text: selectionStart -PASS input type text: selectionStart a second time (must not fire select) -PASS input type text: selectionStart disconnected node -PASS input type text: selectionStart event queue -PASS input type text: selectionStart twice in disconnected node (must fire select only once) -PASS input type text: selectionEnd -PASS input type text: selectionEnd a second time (must not fire select) -PASS input type text: selectionEnd disconnected node -PASS input type text: selectionEnd event queue -PASS input type text: selectionEnd twice in disconnected node (must fire select only once) -PASS input type text: selectionDirection -FAIL input type text: selectionDirection a second time (must not fire select) assert_unreached: the select event must not fire the second time Reached unreachable code -PASS input type text: selectionDirection disconnected node -PASS input type text: selectionDirection event queue -PASS input type text: selectionDirection twice in disconnected node (must fire select only once) -PASS input type text: setSelectionRange() -PASS input type text: setSelectionRange() a second time (must not fire select) -PASS input type text: setSelectionRange() disconnected node -PASS input type text: setSelectionRange() event queue -PASS input type text: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type text: setRangeText() -PASS input type text: setRangeText() a second time (must not fire select) -PASS input type text: setRangeText() disconnected node -PASS input type text: setRangeText() event queue -PASS input type text: setRangeText() twice in disconnected node (must fire select only once) -PASS input type text: selectionStart out of range -PASS input type text: selectionStart out of range a second time (must not fire select) -PASS input type text: selectionStart out of range disconnected node -PASS input type text: selectionStart out of range event queue -PASS input type text: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type text: selectionEnd out of range -PASS input type text: selectionEnd out of range a second time (must not fire select) -PASS input type text: selectionEnd out of range disconnected node -PASS input type text: selectionEnd out of range event queue -PASS input type text: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type text: setSelectionRange out of range -PASS input type text: setSelectionRange out of range a second time (must not fire select) -PASS input type text: setSelectionRange out of range disconnected node -PASS input type text: setSelectionRange out of range event queue -PASS input type text: setSelectionRange out of range twice in disconnected node (must fire select only once) -PASS input type search: select() -PASS input type search: select() a second time (must not fire select) -PASS input type search: select() disconnected node -PASS input type search: select() event queue -PASS input type search: select() twice in disconnected node (must fire select only once) -PASS input type search: selectionStart -PASS input type search: selectionStart a second time (must not fire select) -PASS input type search: selectionStart disconnected node -PASS input type search: selectionStart event queue -PASS input type search: selectionStart twice in disconnected node (must fire select only once) -PASS input type search: selectionEnd -PASS input type search: selectionEnd a second time (must not fire select) -PASS input type search: selectionEnd disconnected node -PASS input type search: selectionEnd event queue -PASS input type search: selectionEnd twice in disconnected node (must fire select only once) -PASS input type search: selectionDirection -FAIL input type search: selectionDirection a second time (must not fire select) assert_unreached: the select event must not fire the second time Reached unreachable code -PASS input type search: selectionDirection disconnected node -PASS input type search: selectionDirection event queue -PASS input type search: selectionDirection twice in disconnected node (must fire select only once) -PASS input type search: setSelectionRange() -PASS input type search: setSelectionRange() a second time (must not fire select) -PASS input type search: setSelectionRange() disconnected node -PASS input type search: setSelectionRange() event queue -PASS input type search: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type search: setRangeText() -PASS input type search: setRangeText() a second time (must not fire select) -PASS input type search: setRangeText() disconnected node -PASS input type search: setRangeText() event queue -PASS input type search: setRangeText() twice in disconnected node (must fire select only once) -PASS input type search: selectionStart out of range -PASS input type search: selectionStart out of range a second time (must not fire select) -PASS input type search: selectionStart out of range disconnected node -PASS input type search: selectionStart out of range event queue -PASS input type search: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type search: selectionEnd out of range -PASS input type search: selectionEnd out of range a second time (must not fire select) -PASS input type search: selectionEnd out of range disconnected node -PASS input type search: selectionEnd out of range event queue -PASS input type search: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type search: setSelectionRange out of range -PASS input type search: setSelectionRange out of range a second time (must not fire select) -PASS input type search: setSelectionRange out of range disconnected node -PASS input type search: setSelectionRange out of range event queue -PASS input type search: setSelectionRange out of range twice in disconnected node (must fire select only once) -PASS input type tel: select() -PASS input type tel: select() a second time (must not fire select) -PASS input type tel: select() disconnected node -PASS input type tel: select() event queue -PASS input type tel: select() twice in disconnected node (must fire select only once) -PASS input type tel: selectionStart -PASS input type tel: selectionStart a second time (must not fire select) -PASS input type tel: selectionStart disconnected node -PASS input type tel: selectionStart event queue -PASS input type tel: selectionStart twice in disconnected node (must fire select only once) -PASS input type tel: selectionEnd -PASS input type tel: selectionEnd a second time (must not fire select) -PASS input type tel: selectionEnd disconnected node -PASS input type tel: selectionEnd event queue -PASS input type tel: selectionEnd twice in disconnected node (must fire select only once) -PASS input type tel: selectionDirection -FAIL input type tel: selectionDirection a second time (must not fire select) assert_unreached: the select event must not fire the second time Reached unreachable code -PASS input type tel: selectionDirection disconnected node -PASS input type tel: selectionDirection event queue -PASS input type tel: selectionDirection twice in disconnected node (must fire select only once) -PASS input type tel: setSelectionRange() -PASS input type tel: setSelectionRange() a second time (must not fire select) -PASS input type tel: setSelectionRange() disconnected node -PASS input type tel: setSelectionRange() event queue -PASS input type tel: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type tel: setRangeText() -PASS input type tel: setRangeText() a second time (must not fire select) -PASS input type tel: setRangeText() disconnected node -PASS input type tel: setRangeText() event queue -PASS input type tel: setRangeText() twice in disconnected node (must fire select only once) -PASS input type tel: selectionStart out of range -PASS input type tel: selectionStart out of range a second time (must not fire select) -PASS input type tel: selectionStart out of range disconnected node -PASS input type tel: selectionStart out of range event queue -PASS input type tel: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type tel: selectionEnd out of range -PASS input type tel: selectionEnd out of range a second time (must not fire select) -PASS input type tel: selectionEnd out of range disconnected node -PASS input type tel: selectionEnd out of range event queue -PASS input type tel: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type tel: setSelectionRange out of range -PASS input type tel: setSelectionRange out of range a second time (must not fire select) -PASS input type tel: setSelectionRange out of range disconnected node -PASS input type tel: setSelectionRange out of range event queue -PASS input type tel: setSelectionRange out of range twice in disconnected node (must fire select only once) -PASS input type url: select() -PASS input type url: select() a second time (must not fire select) -PASS input type url: select() disconnected node -PASS input type url: select() event queue -PASS input type url: select() twice in disconnected node (must fire select only once) -PASS input type url: selectionStart -PASS input type url: selectionStart a second time (must not fire select) -PASS input type url: selectionStart disconnected node -PASS input type url: selectionStart event queue -PASS input type url: selectionStart twice in disconnected node (must fire select only once) -PASS input type url: selectionEnd -PASS input type url: selectionEnd a second time (must not fire select) -PASS input type url: selectionEnd disconnected node -PASS input type url: selectionEnd event queue -PASS input type url: selectionEnd twice in disconnected node (must fire select only once) -PASS input type url: selectionDirection -FAIL input type url: selectionDirection a second time (must not fire select) assert_unreached: the select event must not fire the second time Reached unreachable code -PASS input type url: selectionDirection disconnected node -PASS input type url: selectionDirection event queue -PASS input type url: selectionDirection twice in disconnected node (must fire select only once) -PASS input type url: setSelectionRange() -PASS input type url: setSelectionRange() a second time (must not fire select) -PASS input type url: setSelectionRange() disconnected node -PASS input type url: setSelectionRange() event queue -PASS input type url: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type url: setRangeText() -PASS input type url: setRangeText() a second time (must not fire select) -PASS input type url: setRangeText() disconnected node -PASS input type url: setRangeText() event queue -PASS input type url: setRangeText() twice in disconnected node (must fire select only once) -PASS input type url: selectionStart out of range -PASS input type url: selectionStart out of range a second time (must not fire select) -PASS input type url: selectionStart out of range disconnected node -PASS input type url: selectionStart out of range event queue -PASS input type url: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type url: selectionEnd out of range -PASS input type url: selectionEnd out of range a second time (must not fire select) -PASS input type url: selectionEnd out of range disconnected node -PASS input type url: selectionEnd out of range event queue -PASS input type url: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type url: setSelectionRange out of range -PASS input type url: setSelectionRange out of range a second time (must not fire select) -PASS input type url: setSelectionRange out of range disconnected node -PASS input type url: setSelectionRange out of range event queue -PASS input type url: setSelectionRange out of range twice in disconnected node (must fire select only once) -PASS input type password: select() -PASS input type password: select() a second time (must not fire select) -PASS input type password: select() disconnected node -PASS input type password: select() event queue -PASS input type password: select() twice in disconnected node (must fire select only once) -PASS input type password: selectionStart -PASS input type password: selectionStart a second time (must not fire select) -PASS input type password: selectionStart disconnected node -PASS input type password: selectionStart event queue -PASS input type password: selectionStart twice in disconnected node (must fire select only once) -PASS input type password: selectionEnd -PASS input type password: selectionEnd a second time (must not fire select) -PASS input type password: selectionEnd disconnected node -PASS input type password: selectionEnd event queue -PASS input type password: selectionEnd twice in disconnected node (must fire select only once) -PASS input type password: selectionDirection -FAIL input type password: selectionDirection a second time (must not fire select) assert_unreached: the select event must not fire the second time Reached unreachable code -PASS input type password: selectionDirection disconnected node -PASS input type password: selectionDirection event queue -PASS input type password: selectionDirection twice in disconnected node (must fire select only once) -PASS input type password: setSelectionRange() -PASS input type password: setSelectionRange() a second time (must not fire select) -PASS input type password: setSelectionRange() disconnected node -PASS input type password: setSelectionRange() event queue -PASS input type password: setSelectionRange() twice in disconnected node (must fire select only once) -PASS input type password: setRangeText() -PASS input type password: setRangeText() a second time (must not fire select) -PASS input type password: setRangeText() disconnected node -PASS input type password: setRangeText() event queue -PASS input type password: setRangeText() twice in disconnected node (must fire select only once) -PASS input type password: selectionStart out of range -PASS input type password: selectionStart out of range a second time (must not fire select) -PASS input type password: selectionStart out of range disconnected node -PASS input type password: selectionStart out of range event queue -PASS input type password: selectionStart out of range twice in disconnected node (must fire select only once) -PASS input type password: selectionEnd out of range -PASS input type password: selectionEnd out of range a second time (must not fire select) -PASS input type password: selectionEnd out of range disconnected node -PASS input type password: selectionEnd out of range event queue -PASS input type password: selectionEnd out of range twice in disconnected node (must fire select only once) -PASS input type password: setSelectionRange out of range -PASS input type password: setSelectionRange out of range a second time (must not fire select) -PASS input type password: setSelectionRange out of range disconnected node -PASS input type password: setSelectionRange out of range event queue -PASS input type password: setSelectionRange out of range twice in disconnected node (must fire select only once) -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/wpt_internal/hid/hidDevice_collections-manual.https.html b/third_party/blink/web_tests/wpt_internal/hid/hidDevice_collections-manual.https.html index c87b151..a86d437 100644 --- a/third_party/blink/web_tests/wpt_internal/hid/hidDevice_collections-manual.https.html +++ b/third_party/blink/web_tests/wpt_internal/hid/hidDevice_collections-manual.https.html
@@ -62,15 +62,21 @@ 'Incorrect bit width for usage 0x' + hex32(usage) + '.'); }; + // Returns the first top-level collection in |device.collections| with a + // usage matching |usagePage| and |usage|, or undefined if no matching + // collection was found. + const getCollectionByUsage = (device, usagePage, usage) => { + return device.collections.find(c => { + return c.usagePage == usagePage && c.usage == usage;}); + } + // Returns the first device in |devices| with a top-level collection // matching |usagePage| and |usage|, or undefined if no matching device // was found. const getDeviceByCollectionUsage = (devices, usagePage, usage) => { return devices.find(d => { - return d.collections.find(c => { - return c.usagePage == usagePage && c.usage == usage; - }) !== undefined; - }); + return getCollectionByUsage(d, usagePage, usage); + }) !== undefined; } // Returns the first report in |devices| with matching |reportType| and @@ -103,6 +109,12 @@ }; const checkReportMapDualshock4 = devices => { + // Expect one device with one top-level collection. + assert_equals(devices.length, 1, 'device count'); + assert_equals(devices[0].collections.length, 1, 'collection count'); + const collection = getCollectionByUsage(devices[0], 0x0001, 0x0005); + assert_not_equals(collection, undefined, 'game pad collection'); + // Input report const input01 = getReport(devices, 'input', 0x01); assert_not_equals(input01, undefined, 'input report 0x01'); @@ -282,6 +294,12 @@ }; checkReportMapDualSense = devices => { + // Expect one device with one top-level collection. + assert_equals(devices.length, 1, 'device count'); + assert_equals(devices[0].collections.length, 1, 'collection count'); + const collection = getCollectionByUsage(devices[0], 0x0001, 0x0005); + assert_not_equals(collection, undefined, 'game pad collection'); + // Input report const input01 = getReport(devices, 'input', 0x01); assert_not_equals(input01, undefined, 'input report 0x01'); @@ -380,6 +398,12 @@ }; checkReportMapSwitchPro = devices => { + // Expect one device with one top-level collection. + assert_equals(devices.length, 1, 'device count'); + assert_equals(devices[0].collections.length, 1, 'collection count'); + const collection = getCollectionByUsage(devices[0], 0x0001, 0x0004); + assert_not_equals(collection, undefined, 'joystick collection'); + // Input reports const input30 = getReport(devices, 'input', 0x30); assert_not_equals(input30, undefined, 'input report 0x30'); @@ -437,12 +461,19 @@ // Speech Mike exposes five HID interfaces, two of which are blocked by // WebHID. None of the interfaces use report IDs. Distinguish the // interfaces by their top-level collection usage information. + assert_equals(devices.length, 3, 'device count'); const device0 = getDeviceByCollectionUsage(devices, 0xffa0, 0x0001); assert_not_equals(device0, undefined, 'vendor device'); + assert_equals(device0.collections.length, 1, + 'vendor device collection count'); const device1 = getDeviceByCollectionUsage(devices, 0x000c, 0x0001); assert_not_equals(device1, undefined, 'consumer device'); + assert_equals(device1.collections.length, 1, + 'consumer device collection count'); const device2 = getDeviceByCollectionUsage(devices, 0x0001, 0x0004); assert_not_equals(device2, undefined, 'joystick device'); + assert_equals(device2.collections.length, 1, + 'joystick device collection count'); // These devices should be blocked by WebHID. const device3 = getDeviceByCollectionUsage(devices, 0x0001, 0x0002); @@ -492,6 +523,16 @@ }; checkReportMapEvolveLink = devices => { + // Expect one device with three top-level collections. + assert_equals(devices.length, 1, 'device count'); + assert_equals(devices[0].collections.length, 3, 'collection count'); + const collection0 = getCollectionByUsage(devices[0], 0x000b, 0x0005); + assert_not_equals(collection0, undefined, 'headset collection'); + const collection1 = getCollectionByUsage(devices[0], 0xff00, 0x0005); + assert_not_equals(collection1, undefined, 'vendor collection'); + const collection2 = getCollectionByUsage(devices[0], 0x000c, 0x0001); + assert_not_equals(collection2, undefined, 'consumer collection'); + // Input reports const input01 = getReport(devices, 'input', 0x01); assert_not_equals(input01, undefined, 'input report 0x01'); @@ -609,6 +650,12 @@ }; checkReportMapStadiaController = devices => { + // Expect one device with one top-level collection. + assert_equals(devices.length, 1, 'device count'); + assert_equals(devices[0].collections.length, 1, 'collection count'); + const collection = getCollectionByUsage(devices[0], 0x0001, 0x0005); + assert_not_equals(collection, undefined, 'game pad collection'); + // Input report 0x03 const input03 = getReport(devices, 'input', 0x03); assert_not_equals(input03, undefined, 'input report 0x03');
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium index b752693..8506a8b3 100644 --- a/third_party/freetype/README.chromium +++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@ Name: FreeType URL: http://www.freetype.org/ -Version: VER-2-10-4-54-g768022b98 -Revision: 768022b98e45d343b540f83816fb65f549eac041 +Version: VER-2-10-4-95 +Revision: c6ff2556c8e6f3bb8370cf3f6113bf73a6d5d9a3 CPEPrefix: cpe:/a:freetype:freetype:2.10.4 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses"
diff --git a/third_party/freetype/include/freetype-custom/freetype/config/ftmodule.h b/third_party/freetype/include/freetype-custom/freetype/config/ftmodule.h index 7d1271f..f2f4446 100644 --- a/third_party/freetype/include/freetype-custom/freetype/config/ftmodule.h +++ b/third_party/freetype/include/freetype-custom/freetype/config/ftmodule.h
@@ -36,4 +36,6 @@ FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_sdf_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_bitmap_sdf_renderer_class ) */
diff --git a/third_party/freetype/roll-freetype.sh b/third_party/freetype/roll-freetype.sh index 19160677..2032d7a 100755 --- a/third_party/freetype/roll-freetype.sh +++ b/third_party/freetype/roll-freetype.sh
@@ -8,15 +8,16 @@ addtrybots() { STEP="add trybots" && - OLD_MSG=$(git show -s --format=%B HEAD) && - git commit --amend -m"$OLD_MSG" -m"Cq-Include-Trybots: luci.chromium.try:linux_chromium_msan_rel_ng" + (git show -s --format=%B HEAD \ + | git interpret-trailers --trailer "Cq-Include-Trybots:luci.chromium.try:linux_chromium_msan_rel_ng" \ + | git commit --amend -F -) } addotherprojectbugs() { STEP="add pdfium bug" && - OLD_MSG=$(git show -s --format=%B HEAD) && - git commit --amend -m"$OLD_MSG" -m" -PDFium-Issue: pdfium:" + (git show -s --format=%B HEAD \ + | git interpret-trailers --trailer "PDFium-Issue:pdfium:" \ + | git commit --amend -F -) } updatereadme() {
diff --git a/third_party/sqlite/README.chromium b/third_party/sqlite/README.chromium index cfc1abbf0..4ae58cf 100644 --- a/third_party/sqlite/README.chromium +++ b/third_party/sqlite/README.chromium
@@ -1,7 +1,7 @@ Name: sqlite URL: https://sqlite.org/ -Version: 3.33.0 -CPEPrefix: cpe:/a:sqlite:sqlite:3.33.0 +Version: 3.34.0 +CPEPrefix: cpe:/a:sqlite:sqlite:3.34.0 Included In Release: Yes Security Critical: Yes License: Public domain
diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py index 43274dd..8238fed 100644 --- a/tools/binary_size/libsupersize/console.py +++ b/tools/binary_size/libsupersize/console.py
@@ -340,6 +340,19 @@ tool_prefix = path_util.ToolPrefixFinder( output_directory=output_directory_finder.Finalized(), linker_name='ld').Finalized() + else: + # Output directory is not set, so we cannot load tool_prefix from + # build_vars.json, nor resolve the output directory-relative path stored + # size_info.metadata. + is_android = next( + filter(None, (m.get(models.METADATA_APK_FILENAME) + for m in size_info.metadata)), None) + arch = next( + filter(None, (m.get(models.METADATA_ELF_ARCHITECTURE) + for m in size_info.metadata)), None) + # Hardcode path for arm32. + if is_android and arch == 'arm': + tool_prefix = path_util.ANDROID_ARM_NDK_TOOL_PREFIX args = [ path_util.GetObjDumpPath(tool_prefix),
diff --git a/tools/binary_size/libsupersize/path_util.py b/tools/binary_size/libsupersize/path_util.py index df1edd1..e8e5e2f 100644 --- a/tools/binary_size/libsupersize/path_util.py +++ b/tools/binary_size/libsupersize/path_util.py
@@ -23,6 +23,11 @@ _SAMPLE_TOOL_SUFFIX = 'readelf' +ANDROID_ARM_NDK_TOOL_PREFIX = os.path.join(TOOLS_SRC_ROOT, 'third_party', + 'android_ndk', 'toolchains', 'llvm', + 'prebuilt', 'linux-x86_64', 'bin', + 'arm-linux-androideabi-') + class _PathFinder(object): def __init__(self, name, value):
diff --git a/tools/cfi/ignores.txt b/tools/cfi/ignores.txt index 14ece19..767d99fa 100644 --- a/tools/cfi/ignores.txt +++ b/tools/cfi/ignores.txt
@@ -170,6 +170,7 @@ # Calls to vulkan function pointers from shared library. src:*third_party/vulkan_memory_allocator/src/vk_mem_alloc.h src:*third_party/angle/third_party/vulkan-loader/src/loader* +src:*third_party/vulkan-deps/vulkan-loader/src/loader* src:*components/os_crypt/*
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index a8a3d29..e241a20 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -14251,6 +14251,11 @@ <int value="3" label="User disabled"/> </enum> +<enum name="CrosCdmType"> + <int value="0" label="Chrome CDM"/> + <int value="1" label="Platform CDM"/> +</enum> + <enum name="CrosComponentManagerError"> <int value="0" label="NONE"/> <int value="1" label="UNKNOWN_COMPONENT"/> @@ -46624,6 +46629,7 @@ <int value="4" label="Preloaded password sites list"/> <int value="5" label="Field trial logged-in site"/> <int value="6" label="Password manager saved site"/> + <int value="7" label="OAuth popup based first time login flow"/> </enum> <enum name="LoginFailureReason">
diff --git a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml index 94e15ab..0126d1b1 100644 --- a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
@@ -426,7 +426,7 @@ </histogram> <histogram name="Accessibility.CrosVirtualKeyboard" enum="BooleanEnabled" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>dmazzoni@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>chrome-a11y-core@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/apps/histograms.xml b/tools/metrics/histograms/histograms_xml/apps/histograms.xml index 129a432a..c330fc9 100644 --- a/tools/metrics/histograms/histograms_xml/apps/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
@@ -333,7 +333,7 @@ </histogram> <histogram name="Apps.AppList.OmniboxProvider.ZeroStateLatency" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>jennyz@chromium.org</owner> <owner>newcomer@chromium.org</owner> <summary> @@ -744,7 +744,7 @@ </histogram> <histogram name="Apps.AppListFolder.ShowHide.AnimationSmoothness" units="%" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>wutao@chromium.org</owner> <summary> Relative smoothness of animations of showing and hiding app list folder. @@ -871,7 +871,7 @@ </histogram> <histogram name="Apps.AppListPlayStoreQueryState" - enum="AppListPlayStoreQueryState" expires_after="2021-04-25"> + enum="AppListPlayStoreQueryState" expires_after="2021-06-27"> <owner>hejq@chromium.org</owner> <summary>The state of a Play Store app search request.</summary> </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/arc/histograms.xml b/tools/metrics/histograms/histograms_xml/arc/histograms.xml index 0547bd3..59ab879c 100644 --- a/tools/metrics/histograms/histograms_xml/arc/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/arc/histograms.xml
@@ -457,7 +457,7 @@ </histogram> <histogram name="Arc.EngagementTime.Foreground" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>maajid@google.com</owner> <owner>shaochuan@google.com</owner> <owner>shihuis@google.com</owner> @@ -694,7 +694,7 @@ </histogram> <histogram name="Arc.OptInSilentAuthCode" enum="ArcOptInSilentAuthCode" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>elijahtaylor@google.com</owner> <summary> Arc Silent Auth Code status. This status is set during the ARC OptIn flow. @@ -762,7 +762,7 @@ </histogram> <histogram name="Arc.PlayStoreSearch.QueryTime" units="ms" - expires_after="2021-04-04"> + expires_after="2021-06-27"> <owner>hejq@chromium.org</owner> <summary> Time between sending an Play Store app discovery request and the storing
diff --git a/tools/metrics/histograms/histograms_xml/ash/histograms.xml b/tools/metrics/histograms/histograms_xml/ash/histograms.xml index d15c629c..2b99a34 100644 --- a/tools/metrics/histograms/histograms_xml/ash/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
@@ -1902,7 +1902,7 @@ </histogram> <histogram name="Ash.TabletMode.AnimationSmoothness.Enter" units="%" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>oshima@chromium.org</owner> <owner>sammiequon@chromium.org</owner> <summary> @@ -2099,7 +2099,7 @@ </histogram> <histogram name="Ash.WindowCycleController.DesksSwitchDistance" units="units" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>afakhry@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml index cc5eef98..cb16e6c8 100644 --- a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
@@ -176,7 +176,7 @@ </histogram> <histogram name="Assistant.ServiceReadyTime" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>xiaohuic@chromium.org</owner> <owner>jeroendh@google.com</owner> <summary> @@ -186,7 +186,7 @@ </histogram> <histogram name="Assistant.ServiceStartTime" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>updowndota@chromium.org</owner> <summary>Amount of time spent in starting Assistant service.</summary> </histogram> @@ -223,7 +223,7 @@ </histogram> <histogram name="QuickAnswers.ActiveImpression" enum="QuickAnswersResultType" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -262,7 +262,7 @@ </histogram> <histogram name="QuickAnswers.Consent" units="impressions" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -282,7 +282,7 @@ </histogram> <histogram base="true" name="QuickAnswers.Consent.Impression" - units="impressions" expires_after="2021-04-25"> + units="impressions" expires_after="2021-06-27"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -292,7 +292,7 @@ </histogram> <histogram name="QuickAnswers.ContextMenu.Close" enum="BooleanClicked" - expires_after="2021-05-30"> + expires_after="2021-06-27"> <owner>updowndota@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -320,7 +320,7 @@ </histogram> <histogram name="QuickAnswers.Intent" enum="QuickAnswersIntentType" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -340,7 +340,7 @@ </histogram> <histogram name="QuickAnswers.Loading.Status" enum="QuickAnswersLoadStatus" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -349,7 +349,7 @@ </histogram> <histogram name="QuickAnswers.Result" enum="QuickAnswersResultType" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -359,7 +359,7 @@ </histogram> <histogram name="QuickAnswers.Result.Duration" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -369,7 +369,7 @@ </histogram> <histogram name="QuickAnswers.SelectedContent.Length" units="characters" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>llin@google.com</owner> <owner>croissant-eng@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/auth/histograms.xml b/tools/metrics/histograms/histograms_xml/auth/histograms.xml index c6ead64..c453248 100644 --- a/tools/metrics/histograms/histograms_xml/auth/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/auth/histograms.xml
@@ -67,7 +67,7 @@ </histogram> <histogram name="AuthPolicy.ErrorTypeOfJoinADDomain" enum="AuthPolicyErrorType" - expires_after="M90"> + expires_after="2021-06-27"> <owner>fsandrade@chromium.org</owner> <owner>tomdobro@chromium.org</owner> <summary> @@ -180,7 +180,8 @@ </summary> </histogram> -<histogram name="AuthPolicy.TimeToJoinADDomain" units="ms" expires_after="M90"> +<histogram name="AuthPolicy.TimeToJoinADDomain" units="ms" + expires_after="2021-06-27"> <owner>fsandrade@chromium.org</owner> <owner>tomdobro@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml index a2bf075..b9d6d57 100644 --- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -1722,7 +1722,7 @@ </histogram> <histogram name="Blink.PrePaint.UpdateTime" units="microseconds" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" --> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePostFCPSuffixes" --> @@ -2334,7 +2334,7 @@ </histogram> <histogram name="Blink.VisibleLoadTime.LazyLoadEligibleFrames.AboveTheFold" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-06-27"> <owner>sclittle@chromium.org</owner> <summary> Milliseconds spent waiting for an above the fold iframe to load. Only fires @@ -2354,7 +2354,7 @@ </histogram> <histogram base="true" name="Blink.VisibleLoadTime.LazyLoadImages.AboveTheFold" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-06-27"> <owner>rajendrant@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -2366,7 +2366,7 @@ </histogram> <histogram base="true" name="Blink.VisibleLoadTime.LazyLoadImages.BelowTheFold" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-06-27"> <owner>rajendrant@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/browser/histograms.xml b/tools/metrics/histograms/histograms_xml/browser/histograms.xml index 1ff4d8eb..c70e21b 100644 --- a/tools/metrics/histograms/histograms_xml/browser/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/browser/histograms.xml
@@ -22,7 +22,7 @@ <histograms> <histogram name="Browser.BitmapFetcher.Decode" units="ms" - expires_after="2021-04-23"> + expires_after="2021-06-27"> <owner>manukh@chromium.org</owner> <owner>jdonnelly@chromium.org</owner> <owner>chrome-omnibox-team@google.com</owner> @@ -30,7 +30,7 @@ </histogram> <histogram name="Browser.BitmapFetcher.Fetch" units="ms" - expires_after="2021-04-23"> + expires_after="2021-06-27"> <owner>manukh@chromium.org</owner> <owner>jdonnelly@chromium.org</owner> <owner>chrome-omnibox-team@google.com</owner> @@ -53,7 +53,7 @@ </histogram> <histogram name="Browser.DarkModeStatus" enum="DarkModeStatus" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>lgrey@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -84,7 +84,7 @@ </histogram> <histogram name="Browser.PaintPreview.Capture.Success" enum="BooleanSuccess" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>ckitagawa@chromium.org</owner> <owner>mahmoudi@chromium.org</owner> <owner>fredmello@chromium.org</owner> @@ -94,7 +94,7 @@ </histogram> <histogram name="Browser.PaintPreview.Capture.TotalCaptureDuration" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>ckitagawa@chromium.org</owner> <owner>mahmoudi@chromium.org</owner> <owner>fredmello@chromium.org</owner> @@ -185,7 +185,7 @@ </histogram> <histogram name="Browser.PaintPreview.TabbedPlayer.CompositorFailureReason" - enum="TabbedPaintPreviewCompositorFailureReason" expires_after="2021-04-25"> + enum="TabbedPaintPreviewCompositorFailureReason" expires_after="2021-06-27"> <owner>ckitagawa@chromium.org</owner> <owner>mahmoudi@chromium.org</owner> <owner>fredmello@chromium.org</owner> @@ -242,7 +242,7 @@ </histogram> <histogram name="Browser.PaintPreview.TabbedPlayer.TimeToFirstBitmap" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-06-27"> <owner>ckitagawa@chromium.org</owner> <owner>mahmoudi@chromium.org</owner> <owner>fredmello@chromium.org</owner> @@ -418,7 +418,7 @@ </histogram> <histogram base="true" name="Browser.Tabs.TotalSwitchDuration" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <!-- Name completed by histogram_suffixes name="TabSwitchingType" --> <owner>ejoe@google.com</owner> @@ -562,7 +562,7 @@ </histogram> <histogram name="BrowserRenderProcessHost.SpareProcessMaybeTakeAction" - enum="SpareProcessMaybeTakeAction" expires_after="2021-04-25"> + enum="SpareProcessMaybeTakeAction" expires_after="2021-06-27"> <owner>alexmos@chromium.org</owner> <owner>lukasza@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml index 55bb02d..7c9142f 100644 --- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -544,7 +544,7 @@ </histogram> <histogram name="ChromeOS.PlatformVerification.Available" - enum="BooleanAvailable" expires_after="2020-10-04"> + enum="BooleanAvailable" expires_after="2021-12-21"> <owner>apronin@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -554,7 +554,7 @@ </histogram> <histogram name="ChromeOS.PlatformVerification.Result" - enum="ChromeOSPlatformVerificationResult" expires_after="2020-08-31"> + enum="ChromeOSPlatformVerificationResult" expires_after="2021-12-21"> <owner>apronin@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml index 971a95ab..bedca36 100644 --- a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
@@ -38,7 +38,7 @@ </histogram> <histogram name="Compositing.Browser.LayersUpdateTime" units="microseconds" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>schenney@chromium.org</owner> <owner>animations-dev@chromium.org</owner> <summary> @@ -54,7 +54,7 @@ </histogram> <histogram name="Compositing.Browser.LayerTreeImpl.CalculateDrawPropertiesUs" - units="microseconds" expires_after="2021-04-25"> + units="microseconds" expires_after="2021-06-27"> <owner>schenney@chromium.org</owner> <owner>paint-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml index faa903dd..b3a9538 100644 --- a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
@@ -21,6 +21,17 @@ <histograms> +<histogram name="Cookie.AbbreviatedExpirationYear" units="year" + expires_after="2021-06-30"> + <owner>chlily@chromium.org</owner> + <owner>morlovich@chromium.org</owner> + <summary> + Records the abbreviated 2-digit year number used in a cookie's expiration + date. Emitted when parsing a cookie with an Expires attribute that specifies + an expiration year as a number between 0 and 99 inclusive. + </summary> +</histogram> + <histogram name="Cookie.BackingStoreUpdateResults" enum="BackingStoreResults" expires_after="M82"> <owner>morlovich@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/crostini/histograms.xml b/tools/metrics/histograms/histograms_xml/crostini/histograms.xml index 1b05ffa..f841a65 100644 --- a/tools/metrics/histograms/histograms_xml/crostini/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/crostini/histograms.xml
@@ -465,7 +465,7 @@ </histogram> <histogram name="Crostini.UncleanSession.RestarterResult" enum="CrostiniResult" - expires_after="2021-04-04"> + expires_after="2021-06-27"> <owner>clumptini@google.com</owner> <owner>tbuckley@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml index 2ad5345..bb05dac 100644 --- a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
@@ -22,7 +22,7 @@ <histograms> <histogram name="Cryptohome.AsyncDBusRequest" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>zuan@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -502,7 +502,7 @@ </histogram> <histogram name="Cryptohome.TimeToPerformOOPMountCleanup" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>jorgelo@chromium.org</owner> <owner>betuls@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml b/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml index 1c42417e..fde8731 100644 --- a/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml
@@ -47,7 +47,7 @@ </histogram> <histogram name="CustomTabs.CloseButton.ChildTab.ScopeAlgorithm.ClosesOneTab" - enum="BooleanCloseJustCurrentTab" expires_after="2021-02-01"> + enum="BooleanCloseJustCurrentTab" expires_after="M92"> <owner>peconn@chromium.org</owner> <owner> src/chrome/android/java/src/org/chromium/chrome/browser/browserservices/OWNERS
diff --git a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml index ea788a0..36bcf7a 100644 --- a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
@@ -402,7 +402,7 @@ </histogram> <histogram name="DataReductionProxy.UIAction" enum="DataReductionProxyUIAction" - expires_after="2021-04-27"> + expires_after="2021-06-27"> <owner>bengr@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/download/histograms.xml b/tools/metrics/histograms/histograms_xml/download/histograms.xml index b46c4fe6..64ef537d 100644 --- a/tools/metrics/histograms/histograms_xml/download/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/download/histograms.xml
@@ -966,7 +966,7 @@ </histogram> <histogram name="Download.Start.ContentType.NormalProfile" - enum="DownloadContentType" expires_after="2021-04-25"> + enum="DownloadContentType" expires_after="2021-06-27"> <owner>shaktisahu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/event/histograms.xml b/tools/metrics/histograms/histograms_xml/event/histograms.xml index 3bfd60f..a3406be5 100644 --- a/tools/metrics/histograms/histograms_xml/event/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/event/histograms.xml
@@ -470,7 +470,7 @@ </histogram> <histogram name="Event.Latency.ScrollBegin.Scrollbar.GpuSwap2" - units="microseconds" expires_after="2021-04-25"> + units="microseconds" expires_after="2021-06-27"> <owner>nzolghadr@chromium.org</owner> <owner>dlibby@microsoft.com</owner> <owner>input-dev@chromium.org</owner> @@ -831,7 +831,7 @@ </histogram> <histogram name="Event.Latency.ScrollBegin.Wheel.TimeToScrollUpdateSwapBegin4" - units="microseconds" expires_after="2021-04-25"> + units="microseconds" expires_after="2021-06-27"> <owner>flackr@chromium.org</owner> <summary> Time between initial creation of a wheel event and the start of the frame @@ -1390,7 +1390,7 @@ </histogram> <histogram name="Event.Latency.ScrollUpdate.Wheel.TimeToScrollUpdateSwapBegin4" - units="microseconds" expires_after="2021-04-25"> + units="microseconds" expires_after="2021-06-27"> <owner>flackr@chromium.org</owner> <summary> Time between initial creation of a wheel event and start of the frame swap @@ -1621,7 +1621,7 @@ </histogram> <histogram name="Event.VizHitTest.AsyncHitTestReasons" - enum="AsyncHitTestReasons" expires_after="2021-04-25"> + enum="AsyncHitTestReasons" expires_after="2021-06-27"> <owner>yigu@chromium.org</owner> <summary> Tracks the reasons why sychronous hit testing could not be done for each hit
diff --git a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml index 6a37e88..4c5633c 100644 --- a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
@@ -1751,7 +1751,8 @@ <owner>extensions-core@chromium.org</owner> <summary> Recorded when a component extension calls an extension API. Recorded once - per function call. See also Extensions.Functions.WebUICalls and + per function call. See also Extensions.Functions.WebUICalls, + Extensions.Functions.WebUIUntrustedCalls, and Extensions.Functions.ExtensionCalls. </summary> </histogram> @@ -1764,7 +1765,8 @@ <owner>extensions-core@chromium.org</owner> <summary> Recorded when a non-component extension calls an extension API. Recorded - once per function call. See also Extensions.Functions.WebUICalls and + once per function call. See also Extensions.Functions.WebUICalls, + Extensions.Functions.WebUIUntrustedCalls, and Extensions.Functions.ComponentExtensionCalls. </summary> </histogram> @@ -1878,7 +1880,22 @@ <owner>extensions-core@chromium.org</owner> <summary> Recorded when a WebUI context calls an extension API. Recorded once per - function call. See also Extensions.Functions.ComponentExtensionCalls and + function call. See also Extensions.Functions.WebUIUntrustedCalls, + Extensions.Functions.ComponentExtensionCalls and + Extensions.Functions.ExtensionCalls. + </summary> +</histogram> + +<histogram name="Extensions.Functions.WebUIUntrustedCalls" + enum="ExtensionFunctions" expires_after="never"> +<!-- expires-never: Used for monitoring extension API usage. --> + + <owner>rdevlin.cronin@chromium.org</owner> + <owner>extensions-core@chromium.org</owner> + <summary> + Recorded when a WebUI context calls an extension API. Recorded once per + function call. See also Extensions.Functions.WebUICalls, + Extensions.Functions.ComponentExtensionCalls and Extensions.Functions.ExtensionCalls. </summary> </histogram> @@ -3367,7 +3384,7 @@ </histogram> <histogram name="Extensions.WebRequest.KeepaliveRequestState" - enum="ExtensionInProgressRequestState" expires_after="2021-04-25"> + enum="ExtensionInProgressRequestState" expires_after="2021-06-27"> <owner>yhirano@chromium.org</owner> <owner>kinuko@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml b/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml index 673e016..8e85cac 100644 --- a/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml
@@ -198,7 +198,7 @@ </histogram> <histogram name="GeolocationDisclosure.DisclosureResult" - enum="GeolocationDisclosureResult" expires_after="M90"> + enum="GeolocationDisclosureResult" expires_after="2021-06-27"> <owner>benwells@chromium.org</owner> <summary> Records the action the user took after the geolocation disclosure has been
diff --git a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml index 8c97c17..3509123 100644 --- a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
@@ -592,7 +592,7 @@ </histogram> <histogram name="GPU.DirectComposition.VideoPresentationMode" - enum="DirectCompositionVideoPresentationMode" expires_after="2021-04-25"> + enum="DirectCompositionVideoPresentationMode" expires_after="2021-06-27"> <owner>sunnyps@chromium.org</owner> <owner>zmo@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/history/histograms.xml b/tools/metrics/histograms/histograms_xml/history/histograms.xml index b221d0f..525db1c 100644 --- a/tools/metrics/histograms/histograms_xml/history/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/history/histograms.xml
@@ -837,7 +837,7 @@ </histogram> <histogram name="History.URLTableCount" units="units" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>mpearson@chromium.org</owner> <owner>sky@chromium.org</owner> <summary> @@ -868,7 +868,7 @@ </histogram> <histogram name="History.WeeklyURLCount" units="units" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>mpearson@chromium.org</owner> <owner>sky@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/ios/histograms.xml b/tools/metrics/histograms/histograms_xml/ios/histograms.xml index d2ed854..62574a4 100644 --- a/tools/metrics/histograms/histograms_xml/ios/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ios/histograms.xml
@@ -483,7 +483,7 @@ </histogram> <histogram name="IOS.MetricKit.AverageSuspendedMemory" units="MB" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>eugenebut@chromium.org</owner> <owner>olivierrobin@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/media/histograms.xml b/tools/metrics/histograms/histograms_xml/media/histograms.xml index 267a9bc7..df5827e 100644 --- a/tools/metrics/histograms/histograms_xml/media/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/media/histograms.xml
@@ -526,7 +526,7 @@ </histogram> <histogram name="Media.Audio.Render.FramesRequested" units="frames" - expires_after="2021-04-05"> + expires_after="2021-06-27"> <owner>guidou@chromium.org</owner> <owner>olka@chromium.org</owner> <summary> @@ -1513,6 +1513,25 @@ <summary>The time it takes to create the CDM instance.</summary> </histogram> +<histogram name="Media.EME.CrosCdmType" enum="CrosCdmType" + expires_after="2022-01-15"> + <owner>jkardatzke@chromium.org</owner> + <owner>cros-gfx-video@google.com</owner> + <summary> + Whether we used the platform CDM on Chrome OS that includes HW secure + Widevine support, or fell back to the Chrome SW CDM. + </summary> +</histogram> + +<histogram name="Media.EME.CrosPlatformCdm.SystemCode" enum="CdmSystemCode" + expires_after="2022-01-15"> + <owner>jkardatzke@chromium.org</owner> + <owner>cros-gfx-video@google.com</owner> + <summary> + System code count in promise rejection for ChromeOS platform CDM. + </summary> +</histogram> + <histogram name="Media.EME.EncryptedEvent" enum="BooleanEncryptedEvent" expires_after="2021-05-07"> <owner>xhwang@chromium.org</owner> @@ -1674,6 +1693,16 @@ </summary> </histogram> +<histogram name="Media.EME.OutputProtection.PlatformCdm" + enum="MediaOutputProtectionStatus" expires_after="2022-01-15"> + <owner>jkardatzke@chromium.org</owner> + <owner>cros-gfx-video@google.com</owner> + <summary> + Output protection query status and result. One query and one positive (no + unprotected external links) result (if any) are reported per CDM instance. + </summary> +</histogram> + <histogram name="Media.EME.RequestMediaKeySystemAccess" enum="RequestMediaKeySystemAccessStatus" expires_after="2021-06-20"> <owner>sandersd@chromium.org</owner> @@ -1903,7 +1932,7 @@ </histogram> <histogram name="Media.GlobalMediaControls.InteractionDelayAfterPause" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-06-27"> <owner>steimel@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2011,7 +2040,7 @@ </histogram> <histogram name="Media.HardwareKeyPressed" enum="MediaHardwareKeyAction" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>steimel@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -2671,7 +2700,7 @@ </histogram> <histogram name="Media.Notification.Cast.ArtworkPresent" enum="Boolean" - expires_after="2021-06-20"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <owner>media-dev@chromium.org</owner> @@ -2683,7 +2712,7 @@ </histogram> <histogram name="Media.Notification.Cast.Count" units="count" - expires_after="2021-06-06"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <owner>media-dev@chromium.org</owner> @@ -2694,7 +2723,7 @@ </histogram> <histogram name="Media.Notification.Cast.MetadataPresent" - enum="MediaNotificationMetadata" expires_after="2021-06-20"> + enum="MediaNotificationMetadata" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <owner>media-dev@chromium.org</owner> @@ -2707,7 +2736,7 @@ </histogram> <histogram name="Media.Notification.Cast.UserAction" enum="MediaSessionAction" - expires_after="2021-04-25"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <owner>media-dev@chromium.org</owner> @@ -4400,7 +4429,7 @@ </histogram> <histogram base="true" name="MediaRouter.Cast.App.Availability" units="ms" - expires_after="2021-05-23"> + expires_after="2022-02-01"> <!-- Name completed by histogram_suffixes name="MediaRouterSuccess" --> <owner>takumif@chromium.org</owner> @@ -4511,7 +4540,7 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Audio.PlaybackOnReceiver" - enum="Boolean" expires_after="2021-07-01"> + enum="Boolean" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> @@ -4523,14 +4552,14 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Session.Launch" units="ms" - expires_after="2021-06-06"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>Total time to launch a Cast Streaming mirror session.</summary> </histogram> <histogram name="MediaRouter.CastStreaming.Session.Length" units="ms" - expires_after="2021-07-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4584,7 +4613,7 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Start.Failure.Native" - enum="MirroringServiceErrorType" expires_after="2021-05-09"> + enum="MirroringServiceErrorType" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4595,7 +4624,7 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Start.Success" enum="MirrorType" - expires_after="2021-06-06"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4635,7 +4664,7 @@ </histogram> <histogram name="MediaRouter.Dial.AvailableDevicesCount" units="devices" - expires_after="2021-05-09"> + expires_after="2022-02-01"> <owner>mfoltz@chromium.org</owner> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -4646,7 +4675,7 @@ </histogram> <histogram name="MediaRouter.Dial.CreateRoute" - enum="MediaRouterDialCreateRouteResult" expires_after="2021-04-04"> + enum="MediaRouterDialCreateRouteResult" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -4657,7 +4686,7 @@ </histogram> <histogram name="MediaRouter.Dial.FetchAppInfo" - enum="MediaRouterDialFetchAppInfoResult" expires_after="2021-02-01"> + enum="MediaRouterDialFetchAppInfoResult" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -4668,7 +4697,7 @@ </histogram> <histogram name="MediaRouter.Dial.KnownDevicesCount" units="devices" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -4679,7 +4708,7 @@ </histogram> <histogram name="MediaRouter.Dial.ParseMessage" - enum="MediaRouterDialParseMessageResult" expires_after="2021-02-01"> + enum="MediaRouterDialParseMessageResult" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -4691,7 +4720,7 @@ </histogram> <histogram name="MediaRouter.Dial.ParsingError" - enum="MediaRouterDialParsingError" expires_after="2021-06-06"> + enum="MediaRouterDialParsingError" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -4703,7 +4732,7 @@ </histogram> <histogram name="MediaRouter.Dial.TerminateRoute" - enum="MediaRouterDialTerminateRouteResult" expires_after="2021-06-20"> + enum="MediaRouterDialTerminateRouteResult" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -4714,14 +4743,14 @@ </histogram> <histogram name="MediaRouter.Icon.Click.Location" - enum="MediaRouterDialogOpenOrigin" expires_after="2021-02-01"> + enum="MediaRouterDialogOpenOrigin" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>Location the user clicked to open the Media Router dialog.</summary> </histogram> <histogram name="MediaRouter.MirroringService.SessionError" - enum="MirroringServiceErrorType" expires_after="2021-06-06"> + enum="MirroringServiceErrorType" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4752,7 +4781,7 @@ </histogram> <histogram name="MediaRouter.PresentationRequest.AvailabilityUrlType" - enum="PresentationUrlType" expires_after="2021-05-02"> + enum="PresentationUrlType" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -4772,7 +4801,7 @@ </histogram> <histogram name="MediaRouter.Provider.CreateRoute.Result" - enum="MediaRouteProviderResult" expires_after="2021-06-06"> + enum="MediaRouteProviderResult" expires_after="2022-02-01"> <!-- Name completed by histogram_suffixes name="MediaRouteProvider" --> <owner>takumif@chromium.org</owner> @@ -4786,7 +4815,7 @@ </histogram> <histogram name="MediaRouter.Provider.JoinRoute.Result" - enum="MediaRouteProviderResult" expires_after="2021-06-06"> + enum="MediaRouteProviderResult" expires_after="2022-02-01"> <!-- Name completed by histogram_suffixes name="MediaRouteProvider" --> <owner>takumif@chromium.org</owner> @@ -4800,7 +4829,7 @@ </histogram> <histogram name="MediaRouter.Provider.TerminateRoute.Result" - enum="MediaRouteProviderResult" expires_after="2021-06-06"> + enum="MediaRouteProviderResult" expires_after="2022-02-01"> <!-- Name completed by histogram_suffixes name="MediaRouteProvider" --> <owner>takumif@chromium.org</owner> @@ -4842,7 +4871,7 @@ </histogram> <histogram name="MediaRouter.Route.CreationOutcome" - enum="MediaRouterCreateRouteOutcome" expires_after="2021-02-01"> + enum="MediaRouterCreateRouteOutcome" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4852,7 +4881,7 @@ </histogram> <histogram name="MediaRouter.Sink.SelectedType" enum="MediaSinkType" - expires_after="2021-06-06"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4862,7 +4891,7 @@ </histogram> <histogram name="MediaRouter.Source.CastingSource" - enum="MediaRouterSourceTypes" expires_after="2021-06-06"> + enum="MediaRouterSourceTypes" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4872,7 +4901,7 @@ </histogram> <histogram name="MediaRouter.Source.LocalFileFormat" enum="MediaContainers" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4883,7 +4912,7 @@ </histogram> <histogram name="MediaRouter.Source.LocalFileSize" units="MB" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4895,7 +4924,7 @@ </histogram> <histogram name="MediaRouter.Ui.Action.CloseLatency" units="ms" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4906,7 +4935,7 @@ </histogram> <histogram name="MediaRouter.Ui.Action.StartLocal.Latency" units="ms" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4917,14 +4946,14 @@ </histogram> <histogram name="MediaRouter.Ui.Action.StartLocalPosition" - enum="MediaRouterSinkPositionLabel" expires_after="2021-02-01"> + enum="MediaRouterSinkPositionLabel" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>The index of the sink that was selected in the sink list.</summary> </histogram> <histogram name="MediaRouter.Ui.Action.StartLocalSessionSuccessful" - enum="BooleanSuccess" expires_after="2021-02-01"> + enum="BooleanSuccess" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4933,14 +4962,14 @@ </histogram> <histogram name="MediaRouter.Ui.Action.StopRoute" enum="MediaRouteType" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>The number of times a user stops different types of routes.</summary> </histogram> <histogram name="MediaRouter.Ui.Device.Count" units="units" - expires_after="2021-06-06"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4951,7 +4980,7 @@ <histogram name="MediaRouter.Ui.Dialog.ActivationLocationAndCastMode" enum="MediaRouterDialogActivationLocationAndCastMode" - expires_after="2021-04-04"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4961,7 +4990,7 @@ </histogram> <histogram name="MediaRouter.Ui.Dialog.IconStateAtOpen" - enum="MediaRouterIconState" expires_after="2021-02-01"> + enum="MediaRouterIconState" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4971,7 +5000,7 @@ </histogram> <histogram name="MediaRouter.Ui.Dialog.LoadedWithData" units="ms" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4981,7 +5010,7 @@ </histogram> <histogram name="MediaRouter.Ui.Dialog.Paint" units="ms" - expires_after="2021-05-02"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -4991,7 +5020,7 @@ </histogram> <histogram name="MediaRouter.Ui.FirstAction" enum="MediaRouterUserAction" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -5000,7 +5029,7 @@ </histogram> <histogram name="MediaRouter.Ui.IconStateAtInit" enum="MediaRouterIconState" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -5012,7 +5041,7 @@ </histogram> <histogram name="MediaRouter.Ui.Navigate.SourceSelection" - enum="MediaRouterSourceTypes" expires_after="2021-02-01"> + enum="MediaRouterSourceTypes" expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -5021,7 +5050,7 @@ </histogram> <histogram name="MediaRouter.WiredDisplay.AvailableDevicesCount" units="units" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml index 8fcf06d..26634e90 100644 --- a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
@@ -274,6 +274,22 @@ </summary> </histogram> +<histogram name="MultiDevice.SecureChannel.Nearby.EffectiveConnectionResult" + enum="BooleanSuccess" expires_after="2021-11-30"> + <owner>khorimoto@chromium.org</owner> + <owner>better-together-dev@google.com</owner> + <summary> + Measures the effective success rate for Nearby Connections attempts via + SecureChannel. In this context, "effective" means that (1) a + failure followed by a successful retry is counted as a success, and (2) + repeated failures (e.g., due to users stuck in an unrecoverable state due to + Bluetooth issues) are only counted as a single failure. + + Emitted upon each successful connection and one minute after a failed + connection with no subsequent successful retries. + </summary> +</histogram> + <histogram name="MultiDevice.SecureChannel.Nearby.MessageAction" enum="MultiDeviceNearbyMessageAction" expires_after="2021-11-30"> <owner>khorimoto@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml index bd6833f..0fc4364 100644 --- a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
@@ -52,7 +52,7 @@ <histogram name="BackForwardCache.AllSites.HistoryNavigationOutcome.BlocklistedFeature" - enum="WebSchedulerTrackedFeature" expires_after="2021-04-25"> + enum="WebSchedulerTrackedFeature" expires_after="2021-06-27"> <owner>hajimehoshi@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/network/histograms.xml b/tools/metrics/histograms/histograms_xml/network/histograms.xml index db93fe1..5a174b6 100644 --- a/tools/metrics/histograms/histograms_xml/network/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/network/histograms.xml
@@ -1979,7 +1979,7 @@ </histogram> <histogram name="Network.Wifi.Synced.Connection.FailureReason" - enum="ConnectionFailureReason" expires_after="2021-04-22"> + enum="ConnectionFailureReason" expires_after="2021-06-27"> <owner>jonmann@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -1989,7 +1989,7 @@ </histogram> <histogram name="Network.Wifi.Synced.Connection.Result" enum="BooleanSuccess" - expires_after="2021-04-22"> + expires_after="2021-06-27"> <owner>jonmann@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -2009,7 +2009,7 @@ </histogram> <histogram name="Network.Wifi.Synced.ManualConnection.Result" - enum="BooleanSuccess" expires_after="2021-04-22"> + enum="BooleanSuccess" expires_after="2021-06-27"> <owner>jonmann@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -2019,7 +2019,7 @@ </histogram> <histogram name="Network.Wifi.Synced.TotalCount" units="units" - expires_after="2021-04-22"> + expires_after="2021-06-27"> <owner>jonmann@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -2040,7 +2040,7 @@ </histogram> <histogram name="Network.Wifi.Synced.UpdateOperation.Result" - enum="BooleanSuccess" expires_after="2021-04-22"> + enum="BooleanSuccess" expires_after="2021-06-27"> <owner>jonmann@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/notifications/histograms.xml b/tools/metrics/histograms/histograms_xml/notifications/histograms.xml index bde3d24..aee24f8 100644 --- a/tools/metrics/histograms/histograms_xml/notifications/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/notifications/histograms.xml
@@ -703,7 +703,7 @@ </histogram> <histogram name="Notifications.Triggers.ShowTriggerDelay" units="days" - expires_after="M91"> + expires_after="2021-06-27"> <owner>knollr@chromium.org</owner> <owner>peter@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml index 6b45886..6d3b571a5 100644 --- a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
@@ -47,7 +47,7 @@ </histogram> <histogram name="Omnibox.BitmapFetchLatency" units="ms" - expires_after="2021-04-23"> + expires_after="2021-06-27"> <!-- Name completed by histogram_suffixes name="Omnibox.BitmapFetchLatencyCacheSplit" --> <owner>manukh@chromium.org</owner> @@ -610,7 +610,7 @@ </summary> </histogram> -<histogram name="Omnibox.PasteAndGo" units="count" expires_after="2021-04-11"> +<histogram name="Omnibox.PasteAndGo" units="count" expires_after="2021-06-27"> <owner>mpearson@chromium.org</owner> <owner>jdonnelly@chromium.org</owner> <summary> @@ -726,7 +726,7 @@ </histogram> <histogram name="Omnibox.SelectedPosition" units="position" - expires_after="2021-06-30"> + expires_after="2021-06-27"> <owner>jdonnelly@chromium.org</owner> <owner>mpearson@chromium.org</owner> <owner>chrome-omnibox-team@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/oobe/histograms.xml b/tools/metrics/histograms/histograms_xml/oobe/histograms.xml index 141c9df9..de68717 100644 --- a/tools/metrics/histograms/histograms_xml/oobe/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/oobe/histograms.xml
@@ -119,7 +119,7 @@ name="GestureNavigationOOBEPage" --> <owner>mmourgos@chromium.org</owner> - <owner>tbarzic@chormium.org</owner> + <owner>tbarzic@chromium.org</owner> <summary> Records the amount of time that each page within the gesture navigation OOBE screen is shown. Recorded when the gesture navigation oobe screen is
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index 49fe5d2..af7757c 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -1318,7 +1318,7 @@ </histogram> <histogram name="BlueZ.ResultOfConnection" enum="BlueZResultOfConnection" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>mcchou@chromium.org</owner> <summary> This is specific to Chrome OS. Records the outcomes of connection requests @@ -1630,7 +1630,7 @@ </histogram> <histogram name="Bookmarks.EntryPoint" enum="BookmarksEntryPoint" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>ianwen@chromium.org</owner> <summary>How users add a new bookmark.</summary> </histogram> @@ -1703,7 +1703,7 @@ </summary> </histogram> -<histogram name="BootTime.Total2" units="ms" expires_after="2021-04-25"> +<histogram name="BootTime.Total2" units="ms" expires_after="2021-06-27"> <owner>bccheng@chromium.org</owner> <owner>semenzato@chromium.org</owner> <summary>Time from power on to login panel ready (Chrome OS).</summary> @@ -1869,7 +1869,7 @@ </histogram> <histogram name="Cast.Sender.CastMediaType" enum="MediaContainers" - expires_after="2021-02-01"> + expires_after="2022-02-01"> <owner>takumif@chromium.org</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -3298,6 +3298,9 @@ <histogram name="CrashReport.Sender.ActiveRuntime" units="ms" expires_after="2021-05-23"> + <obsolete> + As of 2020-12, we've decided on a timeout and no longer need this metric. + </obsolete> <owner>mutexlox@chromium.org</owner> <owner>iby@chromium.org</owner> <owner>cros-telemetry@google.com</owner> @@ -3310,6 +3313,9 @@ <histogram name="CrashReport.Sender.Runtime" units="ms" expires_after="2021-01-15"> + <obsolete> + As of 2020-12, we've decided on a timeout and no longer need this metric. + </obsolete> <owner>mutexlox@chromium.org</owner> <owner>iby@chromium.org</owner> <owner>cros-telemetry@google.com</owner> @@ -3776,7 +3782,7 @@ </histogram> <histogram name="Discarding.DiscardCandidatesCount" units="tabs" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>sebmarchand@chromium.org</owner> <owner>catan-team@chromium.org</owner> <summary> @@ -6599,6 +6605,16 @@ </summary> </histogram> +<histogram name="HttpCache.MaxFileSizeOnInit" units="KB" + expires_after="2021-05-02"> + <owner>shivanisha@chromium.org</owner> + <owner>jkarlin@chromium.org</owner> + <summary> + Max file size allowed to be cached in the http cache. This is logged at the + time the backend is created. + </summary> +</histogram> + <histogram name="HttpCache.NetworkIsolationKeyPresent2" enum="NetworkIsolationKeyPresent" expires_after="2020-09-10"> <owner>jkarlin@chromium.org</owner> @@ -6779,6 +6795,17 @@ </summary> </histogram> +<histogram name="ImportantFile.FileReplaceRetryCount" units="attempt count" + expires_after="2021-06-30"> + <owner>brucedawson@chromium.org</owner> + <owner>grt@chromium.org</owner> + <summary> + The number of retries needed to successfully move the temporary file to its + final location. Zero means that ReplaceFile worked the first time. Ten means + that it never succeeded. + </summary> +</histogram> + <histogram name="ImportantFile.FileWriteError" enum="PlatformFileError" expires_after="2021-05-23"> <owner>grt@chromium.org</owner> @@ -8324,7 +8351,7 @@ </histogram> <histogram name="LiteVideo.HintAgent.HasHint" units="boolean" - expires_after="M90"> + expires_after="2021-06-27"> <owner>rajendrant@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -8557,7 +8584,7 @@ <histogram name="MachineLearningService.HandwritingModel.LoadModelResult.Event" enum="MachineLearningServiceLoadHandwritingModelResultEvent" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>amoylan@chromium.org</owner> <owner>alanlxl@chromium.org</owner> <owner>charleszhao@chromium.org</owner> @@ -10504,7 +10531,7 @@ </histogram> <histogram name="OAuth2Login.MergeSessionFailure" enum="GoogleServiceAuthError" - expires_after="2020-11-29"> + expires_after="2021-11-29"> <owner>droger@chromium.org</owner> <owner>msarda@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> @@ -10515,7 +10542,7 @@ </histogram> <histogram name="OAuth2Login.MergeSessionRetry" enum="GoogleServiceAuthError" - expires_after="2020-11-29"> + expires_after="2021-11-29"> <owner>droger@chromium.org</owner> <owner>msarda@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> @@ -10550,7 +10577,7 @@ </histogram> <histogram name="OAuth2Login.SessionRestore" enum="GaiaSessionRestoreOutcome" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>droger@chromium.org</owner> <owner>msarda@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> @@ -11605,7 +11632,7 @@ </histogram> <histogram name="Prerender.FinalStatus" enum="PrerenderFinalStatus" - expires_after="2021-04-22"> + expires_after="2021-06-27"> <owner>ryansturm@chromium.org</owner> <owner>tbansal@chromium.org</owner> <summary> @@ -12319,7 +12346,7 @@ </histogram> <histogram name="PushMessaging.ReceivedMessageInBackground" enum="Boolean" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>peter@chromium.org</owner> <owner>knollr@chromium.org</owner> <summary> @@ -14392,7 +14419,10 @@ <histogram name="SiteIsolation.FileSystemApi.CanAccessDataForOriginFailure.IsHttpBasedScheme" - enum="BooleanHttpBasedOrOtherScheme" expires_after="2021-01-31"> + enum="BooleanHttpBasedOrOtherScheme" expires_after="2020-12-21"> + <obsolete> + Removed in Dec 2020 / M89. + </obsolete> <owner>lukasza@chromium.org</owner> <owner>nasko@chromium.org</owner> <summary> @@ -17411,7 +17441,7 @@ </histogram> <histogram name="Webapp.Install.DisplayMode2" enum="WebAppDisplayMode" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>ericwilligers@chromium.org</owner> <owner>peter@chromium.org</owner> <owner>yfriedman@chromium.org</owner> @@ -18058,7 +18088,7 @@ </histogram> <histogram name="WebFont.LocalFontUsed" enum="BooleanUsage" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@chromium.org</owner> <owner>kouhei@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/page/histograms.xml b/tools/metrics/histograms/histograms_xml/page/histograms.xml index db5f75e1..9828747 100644 --- a/tools/metrics/histograms/histograms_xml/page/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/page/histograms.xml
@@ -1419,7 +1419,7 @@ </histogram> <histogram name="PageLoad.InteractiveTiming.FirstInputTimestamp4" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>sullivan@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -2264,7 +2264,7 @@ </histogram> <histogram name="PageSerialization.MhtmlLoading.LoadResult" - enum="MhtmlLoadResult" expires_after="2021-04-04"> + enum="MhtmlLoadResult" expires_after="2021-06-27"> <owner>sclittle@chromium.org</owner> <owner>offline-dev@chromium.org</owner> <summary>Reports the result of an attempt to load an MHTML archive.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/password/histograms.xml b/tools/metrics/histograms/histograms_xml/password/histograms.xml index 59819d86..bb81d17 100644 --- a/tools/metrics/histograms/histograms_xml/password/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/password/histograms.xml
@@ -718,7 +718,7 @@ </histogram> <histogram name="PasswordManager.AutoSigninFirstRunDialog" - enum="AutoSigninFirstRun" expires_after="2021-02-14"> + enum="AutoSigninFirstRun" expires_after="2021-06-27"> <owner>vasilii@chromium.org</owner> <owner>jdoerrie@chromium.org</owner> <summary> @@ -1102,7 +1102,7 @@ </histogram> <histogram name="PasswordManager.FillingSource" - enum="PasswordManagerFillingSource" expires_after="2021-04-25"> + enum="PasswordManagerFillingSource" expires_after="2021-06-27"> <owner>mamir@chromium.org</owner> <owner>treib@chromium.org</owner> <summary> @@ -2148,7 +2148,7 @@ </histogram> <histogram base="true" name="PasswordManager.TotalAccountsHiRes.WithScheme" - units="accounts" expires_after="2021-04-25"> + units="accounts" expires_after="2021-06-27"> <owner>battre@chromium.org</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -2483,7 +2483,7 @@ </histogram> <histogram name="PasswordProtection.SampleReportSent" units="Boolean" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>bdea@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/platform/histograms.xml b/tools/metrics/histograms/histograms_xml/platform/histograms.xml index 2eea1c1..e2241cb 100644 --- a/tools/metrics/histograms/histograms_xml/platform/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/platform/histograms.xml
@@ -703,7 +703,7 @@ </histogram> <histogram name="Platform.MountEncrypted.EncryptionKeyStatus" - enum="MountEncryptedEncryptionKeyStatus" expires_after="M85"> + enum="MountEncryptedEncryptionKeyStatus" expires_after="2021-12-21"> <owner>apronin@chromium.org</owner> <owner>mnissler@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> @@ -715,7 +715,7 @@ </histogram> <histogram name="Platform.MountEncrypted.SystemKeyStatus" - enum="MountEncryptedSystemKeyStatus" expires_after="M85"> + enum="MountEncryptedSystemKeyStatus" expires_after="2021-12-21"> <owner>apronin@chromium.org</owner> <owner>mnissler@chromium.org</owner> <owner>cros-hwsec+uma@chromium.org</owner> @@ -984,7 +984,7 @@ </histogram> <histogram name="Platform.Temperature.Sensor00" units="Celsius" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>fletcherw@chromium.org</owner> <summary> Temperature reading from EC temperature sensor 0 (TSR0) taken every 30s. @@ -1026,7 +1026,7 @@ </histogram> <histogram name="Platform.Temperature.Sensor02" units="Celsius" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>fletcherw@chromium.org</owner> <summary> Temperature reading from EC temperature sensor 2 (TSR2) taken every 30s. @@ -1136,8 +1136,9 @@ </histogram> <histogram name="Platform.TPM.AuthErrorCode" enum="TPMResultCodeEnum" - expires_after="M85"> - <owner>semenzato@chromium.org</owner> + expires_after="2021-12-21"> + <owner>yich@google.com</owner> + <owner>cros-hwsec-userland-eng+uma@chromium.org</owner> <summary> Each sample is the result code of a TPM authorized command issued through tcsd. Success is 0. For the other error codes, see @@ -1166,8 +1167,9 @@ </histogram> <histogram name="Platform.TPM.ErrorCode" enum="TPMResultCodeEnum" - expires_after="M85"> - <owner>semenzato@chromium.org</owner> + expires_after="2021-12-21"> + <owner>yich@google.com</owner> + <owner>cros-hwsec-userland-eng+uma@chromium.org</owner> <summary> Each sample is the result code of a TPM command issued through tcsd. Success is 0. For the other error codes, see /usr/include/tss/tpm_error.h. @@ -1221,14 +1223,14 @@ </histogram> <histogram name="Platform.U2F.Command" enum="Cr50U2FCommands" - expires_after="2020-10-07"> + expires_after="2021-12-21"> <owner>cylai@chromium.org</owner> <owner>cros-hwsec-userland-eng+uma@chromium.org</owner> <summary>Records occurrences of U2F commands sent to cr50.</summary> </histogram> <histogram name="Platform.U2F.LegacyCommand" enum="Cr50U2FCommands" - expires_after="2020-10-07"> + expires_after="2021-12-21"> <owner>cylai@chromium.org</owner> <owner>cros-hwsec-userland-eng+uma@chromium.org</owner> <summary>Records occurrences of legacy U2F commands sent to cr50.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/power/histograms.xml b/tools/metrics/histograms/histograms_xml/power/histograms.xml index bd267f76..4512eb6 100644 --- a/tools/metrics/histograms/histograms_xml/power/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/power/histograms.xml
@@ -46,7 +46,7 @@ </summary> </histogram> -<histogram name="Power.BacklightLevelOnAC" units="%" expires_after="2021-04-25"> +<histogram name="Power.BacklightLevelOnAC" units="%" expires_after="2021-06-27"> <owner>tbroch@chromium.org</owner> <summary> The level of the backlight as a percentage when the user is on AC. Sampled @@ -367,7 +367,7 @@ </histogram> <histogram name="Power.FirmwareResumeTimeOnAC" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>tbroch@chromium.org</owner> <summary> The time that the firmware took to resume the Chrome OS device from @@ -376,7 +376,7 @@ </histogram> <histogram name="Power.FirmwareResumeTimeOnBattery" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>tbroch@chromium.org</owner> <summary> The time that the firmware took to resume the Chrome OS device from @@ -784,7 +784,7 @@ </histogram> <histogram name="Power.Mac.IsOnBattery2" enum="BooleanOnBattery" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>avi@chromium.org</owner> <owner>lgrey@chromium.org</owner> <summary> @@ -882,7 +882,7 @@ </histogram> <histogram name="Power.PowerSupplyMaxPower" units="W" - expires_after="2021-04-04"> + expires_after="2021-06-27"> <owner>bleung@chromium.org</owner> <owner>tbroch@chromium.org</owner> <summary> @@ -903,7 +903,7 @@ </histogram> <histogram name="Power.PowerSupplyType" enum="PowerSupplyType" - expires_after="2021-04-11"> + expires_after="2021-06-27"> <owner>bleung@chromium.org</owner> <owner>tbroch@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/profile/histograms.xml b/tools/metrics/histograms/histograms_xml/profile/histograms.xml index 80a1f0f..73b8f9a 100644 --- a/tools/metrics/histograms/histograms_xml/profile/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/profile/histograms.xml
@@ -58,7 +58,7 @@ </histogram> <histogram name="Profile.AndroidAccountManagementMenu" - enum="ProfileAndroidAccountManagementMenu" expires_after="2021-04-26"> + enum="ProfileAndroidAccountManagementMenu" expires_after="2021-06-27"> <owner>bsazonov@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/quota/histograms.xml b/tools/metrics/histograms/histograms_xml/quota/histograms.xml index c3c49b8..42d3d93 100644 --- a/tools/metrics/histograms/histograms_xml/quota/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/quota/histograms.xml
@@ -131,7 +131,7 @@ </histogram> <histogram name="Quota.GlobalUsageOfPersistentStorage" units="MB" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>jarrydg@chromium.org</owner> <summary>Global usage of persistent storage.</summary> </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml index 58e9a2f..adaaa04 100644 --- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -778,7 +778,7 @@ </histogram> <histogram name="SafeBrowsing.ReferrerAttributionResult" - enum="SafeBrowsingAttributionResultTypes" expires_after="M90"> + enum="SafeBrowsingAttributionResultTypes" expires_after="2021-06-27"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -875,7 +875,7 @@ </histogram> <histogram name="SafeBrowsing.RT.GetCache.Time" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -886,7 +886,7 @@ </histogram> <histogram name="SafeBrowsing.RT.GetCacheResult" - enum="SafeBrowsingRTLookupResponseVerdictType" expires_after="2021-04-25"> + enum="SafeBrowsingRTLookupResponseVerdictType" expires_after="2021-06-27"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -931,7 +931,7 @@ </histogram> <histogram name="SafeBrowsing.RT.HasValidCacheManager" enum="BooleanValid" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml index ef91656..f8e63e1d68 100644 --- a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml
@@ -68,7 +68,7 @@ </histogram> <histogram name="SBClientDownload.DownloadExtensions" - enum="SBClientDownloadExtensions" expires_after="2021-04-25"> + enum="SBClientDownloadExtensions" expires_after="2021-06-27"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <owner>mattm@chromium.org</owner> @@ -322,7 +322,7 @@ </histogram> <histogram name="SBClientPhishing.ClassifierNotReadyReason" - enum="SBClientPhishingClientModelStatus" expires_after="2021-04-25"> + enum="SBClientPhishingClientModelStatus" expires_after="2021-06-27"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -550,7 +550,7 @@ </histogram> <histogram name="SBClientPhishing.TermFeatureIterations" units="units" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/security/histograms.xml b/tools/metrics/histograms/histograms_xml/security/histograms.xml index 2ca2a95..8f67c0e 100644 --- a/tools/metrics/histograms/histograms_xml/security/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/security/histograms.xml
@@ -215,7 +215,7 @@ </histogram> <histogram name="Security.PasswordEntry.SiteEngagementLevel" - enum="SiteEngagementLevel" expires_after="2021-04-25"> + enum="SiteEngagementLevel" expires_after="2021-06-27"> <owner>meacer@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/signin/histograms.xml b/tools/metrics/histograms/histograms_xml/signin/histograms.xml index 5a9afed9..44d4d1d2 100644 --- a/tools/metrics/histograms/histograms_xml/signin/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
@@ -1162,7 +1162,7 @@ <histogram name="Signin.TransactionalReauthGaiaNavigationDuration.FromConfirmClick" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-06-27"> <owner>alexilin@chromium.org</owner> <owner>droger@chromium.org</owner> <summary> @@ -1173,7 +1173,7 @@ <histogram name="Signin.TransactionalReauthGaiaNavigationDuration.FromReauthStart" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-06-27"> <owner>alexilin@chromium.org</owner> <owner>droger@chromium.org</owner> <summary> @@ -1183,7 +1183,7 @@ </histogram> <histogram name="Signin.TransactionalReauthResult" enum="SigninReauthResult" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <!-- Name completed by histogram_suffixes name="TransactionalReauthEntryPoint" --> @@ -1197,7 +1197,7 @@ </histogram> <histogram name="Signin.TransactionalReauthUserAction" - enum="SigninReauthUserAction" expires_after="2021-04-25"> + enum="SigninReauthUserAction" expires_after="2021-06-27"> <!-- Name completed by histogram_suffixes name="TransactionalReauthEntryPoint" --> @@ -1237,7 +1237,7 @@ </histogram> <histogram name="Signin.UserRequestedWipeDataOnSignout" enum="BooleanRequested" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>triploblastic@google.com</owner> <owner>bsazonov@chromium.org</owner> <summary>User requested to wipe local device data on signout.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/simple/histograms.xml b/tools/metrics/histograms/histograms_xml/simple/histograms.xml index 2aa6b5c..7b86069 100644 --- a/tools/metrics/histograms/histograms_xml/simple/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/simple/histograms.xml
@@ -22,8 +22,9 @@ <histograms> <histogram base="true" name="SimpleCache.CacheSizeOnInit" units="KB" - expires_after="M85"> + expires_after="M94"> <owner>jkarlin@chromium.org</owner> + <owner>shivanisha@chromium.org</owner> <summary> The size of the cache at the time that the index has finished initializing. </summary>
diff --git a/tools/metrics/histograms/histograms_xml/stability/histograms.xml b/tools/metrics/histograms/histograms_xml/stability/histograms.xml index ea70d3d7..47b81204b 100644 --- a/tools/metrics/histograms/histograms_xml/stability/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
@@ -22,7 +22,7 @@ <histograms> <histogram name="Stability.Android.OomKillReverseRank" units="rank" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>boliu@chromium.org</owner> <owner>ssid@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/startup/histograms.xml b/tools/metrics/histograms/histograms_xml/startup/histograms.xml index c507a13..bb4d48a 100644 --- a/tools/metrics/histograms/histograms_xml/startup/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/startup/histograms.xml
@@ -83,7 +83,7 @@ </histogram> <histogram name="Startup.Android.Cold.TimeToVisibleContent" units="ms" - expires_after="2021-04-26"> + expires_after="2021-06-27"> <owner>yashard@chromium.org</owner> <owner>ckitagawa@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sync/histograms.xml b/tools/metrics/histograms/histograms_xml/sync/histograms.xml index cea43d0..331fc39a 100644 --- a/tools/metrics/histograms/histograms_xml/sync/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
@@ -517,7 +517,7 @@ </histogram> <histogram base="true" name="Sync.ModelTypeConfigurationTime.Ephemeral" - units="ms" expires_after="2021-04-25"> + units="ms" expires_after="2021-06-27"> <owner>jkrcal@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/tab/histograms.xml b/tools/metrics/histograms/histograms_xml/tab/histograms.xml index 4599e58..798c1e70 100644 --- a/tools/metrics/histograms/histograms_xml/tab/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/tab/histograms.xml
@@ -151,7 +151,7 @@ </summary> </histogram> -<histogram name="Tab.NewTab" enum="NewTabType" expires_after="2021-06-20"> +<histogram name="Tab.NewTab" enum="NewTabType" expires_after="2021-06-27"> <owner>tbergquist@chromium.org</owner> <owner>bsep@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/translate/histograms.xml b/tools/metrics/histograms/histograms_xml/translate/histograms.xml index 3def27d..48715d8 100644 --- a/tools/metrics/histograms/histograms_xml/translate/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/translate/histograms.xml
@@ -260,7 +260,7 @@ </histogram> <histogram name="Translate.HrefHint.Status" enum="HrefTranslateStatus" - expires_after="2021-04-18"> + expires_after="2021-06-27"> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner> <summary> @@ -557,7 +557,7 @@ <histogram name="Translate.PageLoad.IsInitialSourceLanguageInUsersContentLanguages" - enum="Boolean" expires_after="2021-04-04"> + enum="Boolean" expires_after="2021-06-27"> <owner>curranmax@google.com</owner> <owner>megjablon@google.com</owner> <owner>chrome-language@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/ukm/histograms.xml b/tools/metrics/histograms/histograms_xml/ukm/histograms.xml index f23d917a..3bedb0a 100644 --- a/tools/metrics/histograms/histograms_xml/ukm/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ukm/histograms.xml
@@ -295,7 +295,7 @@ </histogram> <histogram name="UKM.UnsentLogs.DroppedSize" units="bytes" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>rkaplow@chromium.org</owner> <owner>ukm-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/uma/histograms.xml b/tools/metrics/histograms/histograms_xml/uma/histograms.xml index f6389c05..484cb6a 100644 --- a/tools/metrics/histograms/histograms_xml/uma/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
@@ -427,7 +427,7 @@ </histogram> <histogram name="UMA.PersistentHistograms.InitResult" - enum="PersistentHistogramsInitResult" expires_after="2021-04-25"> + enum="PersistentHistogramsInitResult" expires_after="2021-06-27"> <owner>bcwhite@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary> @@ -473,7 +473,7 @@ </histogram> <histogram name="UMA.SamplingRatePerMille" units="samples per mille" - expires_after="2021-04-15"> + expires_after="2021-06-27"> <owner>jwd@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary> @@ -571,7 +571,7 @@ </histogram> <histogram name="UMA.TruncatedEvents.UserAction" units="events" - expires_after="2021-06-20"> + expires_after="2021-06-27"> <owner>rkaplow@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/v8/histograms.xml b/tools/metrics/histograms/histograms_xml/v8/histograms.xml index 98fbf7d..909224f 100644 --- a/tools/metrics/histograms/histograms_xml/v8/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/v8/histograms.xml
@@ -600,7 +600,7 @@ </summary> </histogram> -<histogram name="V8.GCMarkCompactor" units="ms" expires_after="2021-04-01"> +<histogram name="V8.GCMarkCompactor" units="ms" expires_after="2021-06-27"> <owner>mlippautz@chromium.org</owner> <owner>v8-memory-sheriffs@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/variations/histograms.xml b/tools/metrics/histograms/histograms_xml/variations/histograms.xml index dfaac34..62459a5 100644 --- a/tools/metrics/histograms/histograms_xml/variations/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/variations/histograms.xml
@@ -99,7 +99,7 @@ </histogram> <histogram name="Variations.FirstRunPrefsDebug" - enum="VariationsFirstRunPrefEvents" expires_after="2021-04-25"> + enum="VariationsFirstRunPrefEvents" expires_after="2021-06-27"> <owner>asvitkine@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml index d1a1fcd..0060bfe 100644 --- a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
@@ -418,7 +418,7 @@ </histogram> <histogram name="WebRTC.Audio.DelayedPacketOutageEventsPerMinute" - units="events/minute" expires_after="2021-04-25"> + units="events/minute" expires_after="2021-06-27"> <owner>hlundin@chromium.org</owner> <summary> Counts the number of delayed packet outage events per minute. The range is @@ -753,7 +753,7 @@ </histogram> <histogram name="WebRTC.Audio.ReceiverDeviceDelayMs" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>hlundin@chromium.org</owner> <summary> The sound card's buffering delay for the receiving side. Sampled once every @@ -762,7 +762,7 @@ </histogram> <histogram name="WebRTC.Audio.ReceiverJitterBufferDelayMs" units="ms" - expires_after="2021-04-25"> + expires_after="2021-06-27"> <owner>hlundin@chromium.org</owner> <summary> The jitter buffer delay for the receiving side. Sampled once every 10 ms
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 6ea3003..1124cc5 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -43,7 +43,7 @@ rendering.mobile,"behdadb@chromium.org, jonross@chromium.org, sadrul@chromium.org",Internals>GPU>Metrics,https://bit.ly/rendering-benchmarks,"backdrop_filter,fastpath,gpu_rasterization,image_decoding,key_hit_test,key_idle_power,key_noop,key_silk,maps,motionmark,pathological_mobile_sites,polymer,representative_mac_desktop,representative_mobile,representative_win_desktop,required_webgl,simple_canvas,simple_mobile_sites,throughput_test,top_real_world_desktop,top_real_world_mobile,tough_animation,tough_canvas,tough_compositor,tough_filters,tough_image_decode,tough_path_rendering,tough_pinch_zoom_mobile,tough_scheduling,tough_scrolling,tough_texture_upload,tough_webgl,use_fake_camera_device" resource_sizes_chrome_modern_minimal_apks,"agrieve@chromium.org, jbudorick@chromium.org",Build,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py, resource_sizes_chrome_modern_public_minimal_apks,"agrieve@chromium.org, jbudorick@chromium.org",Build,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py, -resource_sizes_lacros_chrome,"erikchen@chromium.org, huangs@chormium.org",OS>LaCrOS,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py, +resource_sizes_lacros_chrome,"erikchen@chromium.org, huangs@chromium.org",OS>LaCrOS,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py, resource_sizes_monochrome_minimal_apks,"agrieve@chromium.org, jbudorick@chromium.org",Build,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py, resource_sizes_monochrome_public_minimal_apks,"agrieve@chromium.org, jbudorick@chromium.org",Build,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py, resource_sizes_system_webview_bundle,"agrieve@chromium.org, jbudorick@chromium.org",Build,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py,
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 09c7c1a..d6474d43 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -896,7 +896,7 @@ OTHER_BENCHMARKS.update({ 'resource_sizes_lacros_chrome': BenchmarkMetadata( - emails='erikchen@chromium.org, huangs@chormium.org', + emails='erikchen@chromium.org, huangs@chromium.org', component='OS>LaCrOS', documentation_url=( 'https://chromium.googlesource.com/chromium/'
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 8a71c93c..1665591 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@ { "trace_processor_shell": { "win": { - "hash": "39ef95712bf53c0d07d511d8dc8a7bdb2fce3945", - "remote_path": "perfetto_binaries/trace_processor_shell/win/6005f1179a65bd5e6c63b224a6aaa6ed7b18deeb/trace_processor_shell.exe" + "hash": "def75924a590285e712eb60df8e1e41fad02e0d2", + "remote_path": "perfetto_binaries/trace_processor_shell/win/ecce47e1955f9dd366f9d18b7759de225d54fae6/trace_processor_shell.exe" }, "mac": { - "hash": "b0881dbe95118004765e84f28f036bdf9d4f0807", - "remote_path": "perfetto_binaries/trace_processor_shell/mac/6005f1179a65bd5e6c63b224a6aaa6ed7b18deeb/trace_processor_shell" + "hash": "959ce50fc960e0522e3cc298338bd79f7777eeb4", + "remote_path": "perfetto_binaries/trace_processor_shell/mac/ecce47e1955f9dd366f9d18b7759de225d54fae6/trace_processor_shell" }, "linux": { - "hash": "4ba48a0860ce6b38232b431e8dfaa271c5ce27cd", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/6005f1179a65bd5e6c63b224a6aaa6ed7b18deeb/trace_processor_shell" + "hash": "8000484620791cbdd0dece6a535ea31fe98c98db", + "remote_path": "perfetto_binaries/trace_processor_shell/linux/ecce47e1955f9dd366f9d18b7759de225d54fae6/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/run-swarmed.py b/tools/run-swarmed.py index 73a3201..b8908196 100755 --- a/tools/run-swarmed.py +++ b/tools/run-swarmed.py
@@ -157,10 +157,14 @@ parser.add_argument('--target-os', default='detect', help='gn target_os') parser.add_argument('--arch', '-a', default='detect', help='CPU architecture of the test binary.') - parser.add_argument('--build', dest='build', action='store_true', - help='Build before isolating (default).') - parser.add_argument( '--no-build', dest='build', action='store_false', - help='Do not build, just isolate.') + parser.add_argument('--build', + dest='build', + action='store_true', + help='Build before isolating.') + parser.add_argument('--no-build', + dest='build', + action='store_false', + help='Do not build, just isolate (default).') parser.add_argument('--isolate-map-file', '-i', help='path to isolate map file if not using default') parser.add_argument('--copies', '-n', type=int, default=1,
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index d6d298e..7ce205dc 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -3808,7 +3808,12 @@ return; } - DCHECK(HasCaret()); +#if DCHECK_IS_ON() + AXTree::Selection unignored_selection = + GetDelegate()->GetUnignoredSelection(); + DCHECK(HasCaret(&unignored_selection)); +#endif + std::pair<int, int> selection = GetSelectionOffsetsForAtk(); AtkObject* atk_object = GetOrCreateAtkObject(); @@ -4612,7 +4617,9 @@ } int AXPlatformNodeAuraLinux::GetCaretOffset() { - if (!HasCaret()) { + AXTree::Selection unignored_selection = + GetDelegate()->GetUnignoredSelection(); + if (!HasCaret(&unignored_selection)) { base::Optional<FindInPageResultInfo> result = GetSelectionOffsetsFromFindInPage(); AtkObject* atk_object = GetOrCreateAtkObject();
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index c2ea10b..2a0dcd3 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -889,8 +889,7 @@ return base::nullopt; } -bool AXPlatformNodeBase::HasCaret( - const AXTree::Selection* unignored_selection) { +bool AXPlatformNodeBase::HasCaret(const AXTree::Selection* selection) { if (IsPlainTextField() && HasIntAttribute(ax::mojom::IntAttribute::kTextSelStart) && HasIntAttribute(ax::mojom::IntAttribute::kTextSelEnd)) { @@ -899,10 +898,10 @@ // The caret is always at the focus of the selection. int32_t focus_id; - if (unignored_selection) - focus_id = unignored_selection->focus_object_id; + if (selection) + focus_id = selection->focus_object_id; else - focus_id = delegate_->GetUnignoredSelection().focus_object_id; + focus_id = delegate_->GetTreeData().sel_focus_object_id; AXPlatformNodeBase* focus_object = static_cast<AXPlatformNodeBase*>(delegate_->GetFromNodeID(focus_id));
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h index fb8650d..959a945 100644 --- a/ui/accessibility/platform/ax_platform_node_base.h +++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -225,8 +225,11 @@ // Returns true if either a descendant has selection (sel_focus_object_id) or // if this node is a simple text element and has text selection attributes. - // Optionally accepts an unignored selection to avoid redundant computation. - bool HasCaret(const AXTree::Selection* unignored_selection = nullptr); + // Optionally accepts a selection, which can be useful if checking the + // unignored selection is required. If not provided, uses the selection from + // the tree data, which is safe and fast but does not take ignored nodes into + // account. + bool HasCaret(const AXTree::Selection* selection = nullptr); // See AXPlatformNodeDelegate::IsChildOfLeaf(). bool IsChildOfLeaf() const;
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 77ad405..5079aea6 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -7366,8 +7366,8 @@ msaa_state |= STATE_SYSTEM_HOTTRACKED; } - // If the role is IGNORED, we want these elements to be invisible so that - // these nodes are hidden from the screen reader. + // If the node is ignored, we want these elements to be invisible so that + // they are hidden from the screen reader. if (IsInvisibleOrIgnored()) msaa_state |= STATE_SYSTEM_INVISIBLE;
diff --git a/ui/base/dragdrop/mojom/drag_drop_types.mojom b/ui/base/dragdrop/mojom/drag_drop_types.mojom index bd378c3..bd2c81f2 100644 --- a/ui/base/dragdrop/mojom/drag_drop_types.mojom +++ b/ui/base/dragdrop/mojom/drag_drop_types.mojom
@@ -8,3 +8,14 @@ kMouse, kTouch }; + +// "Verb" of a drag-and-drop operation as negotiated between the source and +// destination. +// These constants match their equivalents in NSDragOperation and +// should not be renumbered. +enum DragOperation { + kNone = 0, + kCopy = 1, + kLink = 2, + kMove = 16, +};
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp index e14b98a..c7bd99e 100644 --- a/ui/chromeos/file_manager_strings.grdp +++ b/ui/chromeos/file_manager_strings.grdp
@@ -736,20 +736,12 @@ <message name="IDS_FILE_BROWSER_CLOUD_IMPORT_ITEMS_REMAINING" desc="File Manager status message."> Importing <ph name="FILE_COUNT">$1<ex>5</ex></ph> files... </message> - <message name="IDS_FILE_BROWSER_COPIED" desc="File Manager status message."> - Copied. - </message> - <message name="IDS_FILE_BROWSER_COPIED_TO" desc="File Manager status message."> - Copied to <ph name="FOLDER_NAME">$1<ex>images</ex></ph>. - </message> - <!-- TODO (crbug/1093603): Clean up after FilesTransferDetails launch. --> <message name="IDS_FILE_BROWSER_COPY_FILE_NAME" desc="File Manager status message."> Copying <ph name="FILE_NAME">$1<ex>movie.avi</ex></ph>... </message> <message name="IDS_FILE_BROWSER_COPY_ITEMS_REMAINING" desc="File Manager status message. 'Item' is used here as a generic term for file or directory."> Copying <ph name="NUMBER_OF_ITEMS">$1<ex>3</ex></ph> items... </message> - <!-- TODO: End. --> <message name="IDS_FILE_BROWSER_COPY_FILE_NAME_LONG" desc="File Manager status message including destination folder when copying one file."> Copying <ph name="FILE_NAME">$1<ex>movie.avi</ex></ph> to <ph name="FOLDER_NAME">$2<ex>images</ex></ph> </message> @@ -791,14 +783,12 @@ <message name="IDS_FILE_BROWSER_FILE_MOVED" desc="File Manager status message. 'Item' is used here as a generic term for file or directory."> <ph name="FILE_NAME">$1<ex>big.xz</ex></ph> moved. </message> - <!-- TODO (crbug/1093603): Clean up after FilesTransferDetails launch. --> <message name="IDS_FILE_BROWSER_MOVE_FILE_NAME" desc="File Manager status message."> Moving <ph name="FILE_NAME">$1<ex>movie.avi</ex></ph>... </message> <message name="IDS_FILE_BROWSER_MOVE_ITEMS_REMAINING" desc="File Manager status message. 'Item' is used here as a generic term for file or directory."> Moving <ph name="NUMBER_OF_ITEMS">$1<ex>3</ex></ph> items... </message> - <!-- TODO: End. --> <message name="IDS_FILE_BROWSER_MOVE_FILE_NAME_LONG" desc="File Manager status message including destination folder when moving one file."> Moving <ph name="FILE_NAME">$1<ex>movie.avi</ex></ph> to <ph name="FOLDER_NAME">$2<ex>images</ex></ph> </message> @@ -817,15 +807,6 @@ <message name="IDS_FILE_BROWSER_MOVE_UNEXPECTED_ERROR" desc="File Manager error message."> Move failed, unexpected error: <ph name="ERROR_MESSAGE">$1<ex>Could not move</ex></ph> </message> - <message name="IDS_FILE_BROWSER_MOVED" desc="File Manager status message."> - Moved. - </message> - <message name="IDS_FILE_BROWSER_MOVED_TO" desc="File Manager status message."> - Moved to <ph name="FOLDER_NAME">$1<ex>images</ex></ph>. - </message> - <message name="IDS_FILE_BROWSER_TO_FOLDER_NAME" desc="File Manager status message."> - To <ph name="FOLDER_NAME">$1<ex>images</ex></ph> - </message> <message name="IDS_FILE_BROWSER_ZIP_FILE_NAME" desc="File Manager status message."> Zipping <ph name="FILE_NAME">$1<ex>movie.avi</ex></ph>... </message>
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_COPIED.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_COPIED.png.sha1 deleted file mode 100644 index 234da81..0000000 --- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_COPIED.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -5eca46944ee40bc7d3a7697113763a49dee4318f \ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_MOVED.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_MOVED.png.sha1 deleted file mode 100644 index 56e6746a..0000000 --- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_MOVED.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -72034fcb299c4592b43bf720ea43a72e4a6f0855 \ No newline at end of file
diff --git a/ui/chromeos/translations/ui_chromeos_strings_en-GB.xtb b/ui/chromeos/translations/ui_chromeos_strings_en-GB.xtb index 0412d391..d769cf0 100644 --- a/ui/chromeos/translations/ui_chromeos_strings_en-GB.xtb +++ b/ui/chromeos/translations/ui_chromeos_strings_en-GB.xtb
@@ -330,7 +330,7 @@ <translation id="4706042980341760088">Tamil with Typewriter keyboard</translation> <translation id="4711094779914110278">Turkish</translation> <translation id="4712283082407695269">Opening '<ph name="PATH" />'</translation> -<translation id="4713544552769165154">This file is designed for a computer using Macintosh software. This is not compatible with your device which runs Chrome OS. Please search the <ph name="BEGIN_LINK" />Chrome Web Store<ph name="END_LINK" /> for a suitable replacement app.<ph name="BEGIN_LINK_HELP" />Learn More<ph name="END_LINK_HELP" /></translation> +<translation id="4713544552769165154">This file is designed for a computer using Macintosh software. This is not compatible with your device which runs Chrome OS. Please search the <ph name="BEGIN_LINK" />Chrome Web Store<ph name="END_LINK" /> for a suitable replacement app.<ph name="BEGIN_LINK_HELP" />Learn more<ph name="END_LINK_HELP" /></translation> <translation id="4724850507808590449"><ph name="FILE_COUNT" /> photos backed up</translation> <translation id="4725511304875193254">Corgi</translation> <translation id="4732760563705710320">Sorry, this video is not supported by your cast device.</translation>
diff --git a/ui/file_manager/image_loader/image_loader.js b/ui/file_manager/image_loader/image_loader.js index 3a7dc1d..368a7fd 100644 --- a/ui/file_manager/image_loader/image_loader.js +++ b/ui/file_manager/image_loader/image_loader.js
@@ -83,7 +83,6 @@ }); } - /** * List of extensions allowed to perform image requests. * @@ -94,6 +93,7 @@ 'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj', // File Manager 'chrome-extension://nlkncpkkdoccmpiclbokaimcnedabhhm', // Gallery 'chrome-extension://jcgeabjmjgoblfofpppfkcoakmfobdko', // Video Player + 'chrome://file-manager', // File Manager SWA ]; /**
diff --git a/ui/file_manager/image_loader/image_loader_client.js b/ui/file_manager/image_loader/image_loader_client.js index c735d7d..04bddf84 100644 --- a/ui/file_manager/image_loader/image_loader_client.js +++ b/ui/file_manager/image_loader/image_loader_client.js
@@ -99,6 +99,12 @@ ImageLoaderClient.CLIENT_URL_REGEX = /filesystem:chrome-extension:\/\/[a-z]+/; /** + * Image loader client chrome://file-manager request URL matcher. + * @const {!RegExp} + */ +ImageLoaderClient.CLIENT_SWA_REGEX = /filesystem:chrome:\/\/file-manager/; + +/** * All client request URL match ImageLoaderClient.CLIENT_URL_REGEX and all are * rewritten: the client extension id part of the request URL is replaced with * the image loader extension id. @@ -119,9 +125,11 @@ ImageLoaderClient.recordPercentage('Cache.Usage', this.cache_.size() / ImageLoaderClient.CACHE_MEMORY_LIMIT * 100.0); - // Replace the client extension id with the image loader extension id. + // Replace the client origin with the image loader extension origin. request.url = request.url.replace( ImageLoaderClient.CLIENT_URL_REGEX, ImageLoaderClient.IMAGE_LOADER_URL); + request.url = request.url.replace( + ImageLoaderClient.CLIENT_SWA_REGEX, ImageLoaderClient.IMAGE_LOADER_URL); // Try to load from cache, if available. const cacheKey = LoadImageRequest.cacheKey(request);
diff --git a/ui/file_manager/image_loader/manifest.json b/ui/file_manager/image_loader/manifest.json index 767e7f5..0e5d5879 100644 --- a/ui/file_manager/image_loader/manifest.json +++ b/ui/file_manager/image_loader/manifest.json
@@ -20,6 +20,16 @@ "page": "background.html", "persistent": false }, + "externally_connectable": { + "ids": [ + "hhaomjibdihmijegdhdafkllkbggdgoj", // File Manager + "nlkncpkkdoccmpiclbokaimcnedabhhm", // Gallery + "jcgeabjmjgoblfofpppfkcoakmfobdko" // Video Player + ], + "matches": [ + "chrome://file-manager/*" // File Manager SWA + ] + }, "natively_connectable": ["com.google.holding_space_thumbnail_loader"], "web_accessible_resources": ["image_loader_client.js"] }
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc index 9b36519..57a0d1db 100644 --- a/ui/gl/direct_composition_surface_win.cc +++ b/ui/gl/direct_composition_surface_win.cc
@@ -653,7 +653,7 @@ // static bool DirectCompositionSurfaceWin::AllowTearing() { // Swap chain tearing is used only if vsync is disabled explicitly. - return features::UseGpuVsync() && + return !features::UseGpuVsync() && DirectCompositionSurfaceWin::IsSwapChainTearingSupported(); }
diff --git a/ui/strings/translations/ui_strings_my.xtb b/ui/strings/translations/ui_strings_my.xtb index 32867025..dc9abae 100644 --- a/ui/strings/translations/ui_strings_my.xtb +++ b/ui/strings/translations/ui_strings_my.xtb
@@ -8,7 +8,7 @@ <translation id="1169783199079129864">{MINUTES,plural, =1{၁ မိနစ်}other{# မိနစ်}}</translation> <translation id="1181037720776840403">ဖယ်ရှားရန်</translation> <translation id="1201402288615127009">ရှေ့သို့</translation> -<translation id="1218444235442067213"><ph name="APP_NAME" />၊ Play စတိုးအက်ပ်</translation> +<translation id="1218444235442067213"><ph name="APP_NAME" />၊ Play Store အက်ပ်</translation> <translation id="1243314992276662751">အာပ်လုဒ် လုပ်ရန်</translation> <translation id="1266864766717917324"><ph name="CONTENT_TYPE" /> ကို မျှဝေ၍မရပါ။</translation> <translation id="1269641567813814718">Win</translation>
diff --git a/ui/views/layout/layout_manager.h b/ui/views/layout/layout_manager.h index 5ff7e10..22a3a60 100644 --- a/ui/views/layout/layout_manager.h +++ b/ui/views/layout/layout_manager.h
@@ -91,7 +91,7 @@ protected: // Sets the visibility of a view without triggering ViewVisibilitySet(). - // During Layout(), use this method instead of View::SetVisibility(). + // During Layout(), use this method instead of View::SetVisible(). void SetViewVisibility(View* view, bool visible); // Gets the child views of the specified view in paint order (reverse
diff --git a/ui/views/layout/layout_manager_base.cc b/ui/views/layout/layout_manager_base.cc index 68f1874..95c9c7e 100644 --- a/ui/views/layout/layout_manager_base.cc +++ b/ui/views/layout/layout_manager_base.cc
@@ -9,6 +9,7 @@ #include "base/auto_reset.h" #include "base/check_op.h" #include "ui/views/view.h" +#include "ui/views/view_class_properties.h" namespace views { @@ -100,9 +101,7 @@ void LayoutManagerBase::SetChildViewIgnoredByLayout(View* child_view, bool ignored) { - auto it = child_infos_.find(child_view); - DCHECK(it != child_infos_.end()); - if (it->second.ignored == ignored) + if (child_view->GetProperty(kViewIgnoredByLayoutKey) == ignored) return; base::AutoReset<bool> setter(&suppress_invalidate_, true); @@ -112,9 +111,7 @@ bool LayoutManagerBase::IsChildViewIgnoredByLayout( const View* child_view) const { - auto it = child_infos_.find(child_view); - DCHECK(it != child_infos_.end()); - return it->second.ignored; + return child_view->GetProperty(kViewIgnoredByLayoutKey); } LayoutManagerBase::LayoutManagerBase() = default; @@ -127,27 +124,12 @@ bool LayoutManagerBase::IsChildIncludedInLayout(const View* child, bool include_hidden) const { - const auto it = child_infos_.find(child); - - // During callbacks when a child is removed we can get in a state where a view - // in the child list of the host view is not in |child_infos_|. In that case, - // the view is being removed and is not part of the layout. - if (it == child_infos_.end()) - return false; - - return !it->second.ignored && (include_hidden || it->second.can_be_visible); + return !child->GetProperty(kViewIgnoredByLayoutKey) && + (include_hidden || child->GetProperty(kViewCanBeVisibleKey)); } bool LayoutManagerBase::CanBeVisible(const View* child) const { - const auto it = child_infos_.find(child); - - // During callbacks when a child is removed we can get in a state where a view - // in the child list of the host view is not in |child_infos_|. In that case, - // the view is being removed and is not part of the layout. - if (it == child_infos_.end()) - return false; - - return it->second.can_be_visible; + return child->GetProperty(kViewCanBeVisibleKey); } void LayoutManagerBase::LayoutImpl() { @@ -253,7 +235,6 @@ void LayoutManagerBase::Installed(View* host_view) { DCHECK(host_view); DCHECK(!host_view_); - DCHECK(child_infos_.empty()); base::AutoReset<bool> setter(&suppress_invalidate_, true); PropagateInstalled(host_view); @@ -261,7 +242,6 @@ void LayoutManagerBase::ViewAdded(View* host, View* view) { DCHECK_EQ(host_view_, host); - DCHECK(!base::Contains(child_infos_, view)); base::AutoReset<bool> setter(&suppress_invalidate_, true); const bool invalidate = PropagateViewAdded(host, view); @@ -271,11 +251,8 @@ void LayoutManagerBase::ViewRemoved(View* host, View* view) { DCHECK_EQ(host_view_, host); - DCHECK(base::Contains(child_infos_, view)); - - auto it = child_infos_.find(view); - DCHECK(it != child_infos_.end()); - const bool removed_visible = it->second.can_be_visible && !it->second.ignored; + const bool removed_visible = view->GetProperty(kViewCanBeVisibleKey) && + !view->GetProperty(kViewIgnoredByLayoutKey); base::AutoReset<bool> setter(&suppress_invalidate_, true); const bool invalidate = PropagateViewRemoved(host, view); @@ -288,10 +265,8 @@ bool old_visibility, bool new_visibility) { DCHECK_EQ(host_view_, host); - auto it = child_infos_.find(view); - DCHECK(it != child_infos_.end()); - const bool was_ignored = it->second.ignored; - if (it->second.can_be_visible == new_visibility) + const bool was_ignored = view->GetProperty(kViewIgnoredByLayoutKey); + if (view->GetProperty(kViewCanBeVisibleKey) == new_visibility) return; base::AutoReset<bool> setter(&suppress_invalidate_, true); @@ -308,11 +283,11 @@ if (host_view_) { owned_layout->Installed(host_view_); for (View* child_view : host_view_->children()) { - const ChildInfo& child_info = child_infos_.find(child_view)->second; - owned_layout->PropagateChildViewIgnoredByLayout(child_view, - child_info.ignored); - owned_layout->PropagateViewVisibilitySet(host_view_, child_view, - child_info.can_be_visible); + owned_layout->PropagateChildViewIgnoredByLayout( + child_view, child_view->GetProperty(kViewIgnoredByLayoutKey)); + owned_layout->PropagateViewVisibilitySet( + host_view_, child_view, + child_view->GetProperty(kViewCanBeVisibleKey)); } } owned_layout->parent_layout_ = this; @@ -328,7 +303,7 @@ bool LayoutManagerBase::PropagateChildViewIgnoredByLayout(View* child_view, bool ignored) { - child_infos_[child_view].ignored = ignored; + child_view->SetProperty(kViewIgnoredByLayoutKey, ignored); bool result = false; for (auto& owned_layout : owned_layouts_) { @@ -340,7 +315,7 @@ } bool LayoutManagerBase::PropagateViewAdded(View* host, View* view) { - child_infos_.emplace(view, ChildInfo{view->GetVisible(), false}); + view->SetProperty(kViewCanBeVisibleKey, view->GetVisible()); bool result = false; @@ -352,7 +327,8 @@ } bool LayoutManagerBase::PropagateViewRemoved(View* host, View* view) { - child_infos_.erase(view); + view->ClearProperty(kViewCanBeVisibleKey); + view->ClearProperty(kViewIgnoredByLayoutKey); bool result = false; @@ -366,7 +342,7 @@ bool LayoutManagerBase::PropagateViewVisibilitySet(View* host, View* view, bool visible) { - child_infos_[view].can_be_visible = visible; + view->SetProperty(kViewCanBeVisibleKey, visible); bool result = false; @@ -379,9 +355,8 @@ void LayoutManagerBase::PropagateInstalled(View* host) { host_view_ = host; - for (auto* it : host->children()) { - child_infos_.emplace(it, ChildInfo{it->GetVisible(), false}); - } + for (auto* child : host->children()) + child->SetProperty(kViewCanBeVisibleKey, child->GetVisible()); for (auto& owned_layout : owned_layouts_) owned_layout->PropagateInstalled(host);
diff --git a/ui/views/layout/layout_manager_base.h b/ui/views/layout/layout_manager_base.h index 8812cb5..39ca2da 100644 --- a/ui/views/layout/layout_manager_base.h +++ b/ui/views/layout/layout_manager_base.h
@@ -106,7 +106,7 @@ // Returns whether the specified child view can be visible. To be able to be // visible, |child| must be a child of the host view, and must have been - // visible when it was added or most recently had GetVisible(true) called on + // visible when it was added or most recently had SetVisible(true) called on // it by non-layout code. bool CanBeVisible(const View* child) const; @@ -171,13 +171,6 @@ private: friend class LayoutManagerBaseAvailableSizeTest; - // Holds bookkeeping data used to determine inclusion of children in the - // layout. - struct ChildInfo { - bool can_be_visible = true; - bool ignored = false; - }; - // LayoutManager: void InvalidateLayout() final; void Installed(View* host) final; @@ -203,7 +196,6 @@ void PropagateInvalidateLayout(); View* host_view_ = nullptr; - std::map<const View*, ChildInfo> child_infos_; std::vector<std::unique_ptr<LayoutManagerBase>> owned_layouts_; LayoutManagerBase* parent_layout_ = nullptr;
diff --git a/ui/views/view.cc b/ui/views/view.cc index 2e1850f14..b6dd5a1 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -56,6 +56,7 @@ #include "ui/views/controls/scroll_view.h" #include "ui/views/drag_controller.h" #include "ui/views/metadata/metadata_impl_macros.h" +#include "ui/views/view_class_properties.h" #include "ui/views/view_observer.h" #include "ui/views/view_tracker.h" #include "ui/views/views_features.h" @@ -3125,14 +3126,18 @@ void View::DefaultFillLayout::Layout(View* host) { const gfx::Rect contents_bounds = host->GetContentsBounds(); - for (auto* child : host->children()) - child->SetBoundsRect(contents_bounds); + for (auto* child : host->children()) { + if (!child->GetProperty(kViewIgnoredByLayoutKey)) + child->SetBoundsRect(contents_bounds); + } } gfx::Size View::DefaultFillLayout::GetPreferredSize(const View* host) const { gfx::Size preferred_size; - for (auto* child : host->children()) - preferred_size.SetToMax(child->GetPreferredSize()); + for (auto* child : host->children()) { + if (!child->GetProperty(kViewIgnoredByLayoutKey)) + preferred_size.SetToMax(child->GetPreferredSize()); + } return preferred_size; } @@ -3140,10 +3145,13 @@ int width) const { const gfx::Insets insets = host->GetInsets(); int preferred_height = 0; - for (auto* child : host->children()) - preferred_height = std::max( - preferred_height, - child->GetHeightForWidth(width - insets.width()) + insets.height()); + for (auto* child : host->children()) { + if (!child->GetProperty(kViewIgnoredByLayoutKey)) { + preferred_height = std::max( + preferred_height, + child->GetHeightForWidth(width - insets.width()) + insets.height()); + } + } return preferred_height; }
diff --git a/ui/views/view_class_properties.cc b/ui/views/view_class_properties.cc index a2799b0..1e8511f4 100644 --- a/ui/views/view_class_properties.cc +++ b/ui/views/view_class_properties.cc
@@ -41,5 +41,7 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(LayoutAlignment, kCrossAxisAlignmentKey, nullptr) +DEFINE_UI_CLASS_PROPERTY_KEY(bool, kViewIgnoredByLayoutKey, false) +DEFINE_UI_CLASS_PROPERTY_KEY(bool, kViewCanBeVisibleKey, false) } // namespace views
diff --git a/ui/views/view_class_properties.h b/ui/views/view_class_properties.h index bf7abfd..cc9bf2c 100644 --- a/ui/views/view_class_properties.h +++ b/ui/views/view_class_properties.h
@@ -58,6 +58,15 @@ VIEWS_EXPORT extern const ui::ClassProperty<LayoutAlignment*>* const kCrossAxisAlignmentKey; +// Property indicating whether a view should be ignored by a layout. Supported +// by LayoutManagerBase and View::DefaultFillLayout +VIEWS_EXPORT extern const ui::ClassProperty<bool>* const + kViewIgnoredByLayoutKey; + +// Property indicating whether a view would can be visible based on the criteria +// outlined in LayoutManagerBase::CanBeVisible(). +VIEWS_EXPORT extern const ui::ClassProperty<bool>* const kViewCanBeVisibleKey; + } // namespace views // Declaring the template specialization here to make sure that the
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc index c97bf189..6960fd33 100644 --- a/ui/views/widget/root_view.cc +++ b/ui/views/widget/root_view.cc
@@ -22,8 +22,8 @@ #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/canvas.h" #include "ui/views/drag_controller.h" -#include "ui/views/layout/fill_layout.h" #include "ui/views/metadata/metadata_impl_macros.h" +#include "ui/views/view_class_properties.h" #include "ui/views/view_targeter.h" #include "ui/views/widget/root_view_targeter.h" #include "ui/views/widget/widget.h" @@ -210,7 +210,7 @@ << "Can't be called until after the native widget is created!"; // The ContentsView must be set up _after_ the window is created so that its // Widget pointer is valid. - SetLayoutManager(std::make_unique<FillLayout>()); + SetUseDefaultFillLayout(true); if (!children().empty()) RemoveAllChildViews(true); AddChildView(contents_view); @@ -268,8 +268,7 @@ DCHECK(GetContentsView()); if (!announce_view_) { announce_view_ = AddChildView(std::make_unique<AnnounceTextView>()); - static_cast<FillLayout*>(GetLayoutManager()) - ->SetChildViewIgnoredByLayout(announce_view_, true); + announce_view_->SetProperty(kViewIgnoredByLayoutKey, true); } announce_view_->Announce(text); #endif
diff --git a/ui/webui/resources/cr_components/BUILD.gn b/ui/webui/resources/cr_components/BUILD.gn index 7b05cda9..23affc3 100644 --- a/ui/webui/resources/cr_components/BUILD.gn +++ b/ui/webui/resources/cr_components/BUILD.gn
@@ -155,6 +155,8 @@ "chromeos/cellular_setup/setup_loading_page.m.js", "chromeos/cellular_setup/subflow_behavior.m.js", "chromeos/cellular_setup/webview_post_util.m.js", + "chromeos/network_health/network_health_summary.m.js", + "chromeos/network_health/network_health_mojo.m.js", "chromeos/network_health/network_diagnostics.m.js", "chromeos/network_health/network_diagnostics_mojo.m.js", "chromeos/network_health/network_diagnostics_types.m.js", @@ -316,6 +318,8 @@ "chromeos/network_health/network_diagnostics_types.js", "chromeos/network_health/network_health_summary.html", "chromeos/network_health/network_health_summary.js", + "chromeos/network_health/network_health_mojo.html", + "chromeos/network_health/network_health_mojo.js", "chromeos/network_health/routine_group.html", "chromeos/network_health/routine_group.js", "chromeos/network/mojo_interface_provider.html",
diff --git a/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn b/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn index 92d161d0..a8662ec 100644 --- a/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn +++ b/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn
@@ -15,6 +15,7 @@ ":network_diagnostics", ":network_diagnostics_mojo", ":network_diagnostics_types", + ":network_health_mojo", ":network_health_summary", ":routine_group", ] @@ -26,6 +27,7 @@ ":network_diagnostics.m", ":network_diagnostics_mojo.m", ":network_diagnostics_types.m", + ":network_health_mojo.m", ":network_health_summary.m", ":routine_group.m", ] @@ -35,12 +37,20 @@ js_library("network_health_summary") { deps = [ - "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile", + ":network_health_mojo", "//ui/webui/resources/cr_components/chromeos/network:onc_mojo", "//ui/webui/resources/js:i18n_behavior", ] } +js_library("network_health_mojo") { + deps = [ + "//chromeos/services/network_config/public/mojom:mojom_js_library_for_compile", + "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile", + "//ui/webui/resources/js:cr", + ] +} + js_library("network_diagnostics") { deps = [ ":network_diagnostics_mojo", @@ -72,7 +82,7 @@ js_library("network_health_summary.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.m.js" ] deps = [ - "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile", + ":network_health_mojo.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/cr_components/chromeos/network:onc_mojo", "//ui/webui/resources/js:i18n_behavior.m", @@ -80,6 +90,12 @@ extra_deps = [ ":network_health_summary_module" ] } +js_library("network_health_mojo.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.m.js" ] + deps = [ "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile" ] + extra_deps = [ ":modulize" ] +} + js_library("network_diagnostics.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.m.js" ] deps = [ @@ -123,6 +139,9 @@ js_file = "network_health_summary.js" html_file = "network_health_summary.html" html_type = "dom-module" + auto_imports = [ + "ui/webui/resources/cr_components/chromeos/network/onc_mojo.html|OncMojo", + ] } polymer_modulizer("network_diagnostics") { @@ -141,6 +160,7 @@ js_modulizer("modulize") { input_files = [ + "network_health_mojo.js", "network_diagnostics_mojo.js", "network_diagnostics_types.js", ]
diff --git a/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html b/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html new file mode 100644 index 0000000..ec34eaa --- /dev/null +++ b/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html
@@ -0,0 +1,4 @@ +<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html"> + +<script src="chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom-lite.js"></script> +<script src="network_health_mojo.js"></script>
diff --git a/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js b/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js new file mode 100644 index 0000000..c923f0eb --- /dev/null +++ b/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js
@@ -0,0 +1,16 @@ +// 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. + +// clang-format off +// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; +// #import 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-lite.js'; +// #import 'chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom-lite.js'; +// clang-format on + +/** + * @fileoverview Wrapper around Network Health mojom file and associated + * utilities. + * TODO(crbug/1111852): Remove this wrapper once Polymer2 no longer needs to be + * supported. These imports can be used directly. + */
diff --git a/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html b/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html index e739493..9624873 100644 --- a/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html +++ b/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html
@@ -1,9 +1,9 @@ <link rel="import" href="../../../html/polymer.html"> -<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html"> -<link rel="import" href="chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom.html"> <link rel="import" href="../../../cr_elements/shared_style_css.html"> <link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="../network/onc_mojo.html"> +<link rel="import" href="network_health_mojo.html"> <dom-module id="network-health-summary">
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html b/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html index 3312e3e..54c66f5 100644 --- a/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html +++ b/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
@@ -55,6 +55,7 @@ color: var(--cr-input-color); font-family: inherit; font-size: inherit; + font-weight: inherit; line-height: inherit; min-height: var(--cr-input-min-height, auto); outline: none;
diff --git a/ui/webui/resources/cr_elements/shared_style_css.html b/ui/webui/resources/cr_elements/shared_style_css.html index 157e0b3..a71eec2 100644 --- a/ui/webui/resources/cr_elements/shared_style_css.html +++ b/ui/webui/resources/cr_elements/shared_style_css.html
@@ -168,6 +168,7 @@ border-radius: 0 3px 3px 0; content: ''; display: block; + flex-shrink: 0; height: var(--cr-vertical-tab-height, 100%); width: 4px; }
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc index 30c7c63..c3b051e 100644 --- a/url/origin_unittest.cc +++ b/url/origin_unittest.cc
@@ -673,11 +673,18 @@ TEST_F(OriginTest, NonStandardSchemeWithAndroidWebViewHack) { EnableNonStandardSchemesForAndroidWebView(); + + // Regression test for https://crbug.com/896059. Origin origin = Origin::Create(GURL("cow://")); EXPECT_FALSE(origin.opaque()); EXPECT_EQ("cow", origin.scheme()); EXPECT_EQ("", origin.host()); EXPECT_EQ(0, origin.port()); + + // about:blank translates into an opaque origin, even in presence of + // EnableNonStandardSchemesForAndroidWebView. + origin = Origin::Create(GURL("about:blank")); + EXPECT_TRUE(origin.opaque()); } TEST_F(OriginTest, CanBeDerivedFrom) {
diff --git a/url/scheme_host_port.cc b/url/scheme_host_port.cc index 394f4369b..233c2923 100644 --- a/url/scheme_host_port.cc +++ b/url/scheme_host_port.cc
@@ -72,6 +72,10 @@ if (base::Contains(GetLocalSchemes(), scheme) && host.empty() && port == 0) return true; + // about:blank and other no-access schemes translate into an opaque origin. + if (base::Contains(GetNoAccessSchemes(), scheme)) + return false; + // Otherwise, allow non-standard schemes only if the Android WebView // workaround is enabled. return AllowNonStandardSchemesForAndroidWebView();
diff --git a/url/scheme_host_port_unittest.cc b/url/scheme_host_port_unittest.cc index 0f3913b..bd16071 100644 --- a/url/scheme_host_port_unittest.cc +++ b/url/scheme_host_port_unittest.cc
@@ -55,8 +55,15 @@ EXPECT_EQ(invalid, invalid); const char* urls[] = { - "data:text/html,Hello!", "javascript:alert(1)", - "file://example.com:443/etc/passwd", + // about:, data:, javascript: and other no-access schemes translate into + // an invalid SchemeHostPort + "about:blank", "about:blank#ref", "about:blank?query=123", "about:srcdoc", + "about:srcdoc#ref", "about:srcdoc?query=123", "data:text/html,Hello!", + "javascript:alert(1)", + + // GURLs where GURL::is_valid returns false translate into an invalid + // SchemeHostPort. + "file://example.com:443/etc/passwd", "#!^%!$!&*", // These schemes do not follow the generic URL syntax, so make sure we // treat them as invalid (scheme, host, port) tuples (even though such
diff --git a/weblayer/BUILD.gn b/weblayer/BUILD.gn index 5e457ee2..d47ccad 100644 --- a/weblayer/BUILD.gn +++ b/weblayer/BUILD.gn
@@ -261,6 +261,8 @@ "browser/stateful_ssl_host_state_delegate_factory.h", "browser/subresource_filter_client_impl.cc", "browser/subresource_filter_client_impl.h", + "browser/subresource_filter_profile_context_factory.cc", + "browser/subresource_filter_profile_context_factory.h", "browser/system_network_context_manager.cc", "browser/system_network_context_manager.h", "browser/tab_impl.cc",
diff --git a/weblayer/browser/browser_main_parts_impl.cc b/weblayer/browser/browser_main_parts_impl.cc index 0de1b986..652d2df 100644 --- a/weblayer/browser/browser_main_parts_impl.cc +++ b/weblayer/browser/browser_main_parts_impl.cc
@@ -36,6 +36,7 @@ #include "weblayer/browser/no_state_prefetch/prerender_manager_factory.h" #include "weblayer/browser/permissions/weblayer_permissions_client.h" #include "weblayer/browser/stateful_ssl_host_state_delegate_factory.h" +#include "weblayer/browser/subresource_filter_profile_context_factory.h" #include "weblayer/browser/translate_accept_languages_factory.h" #include "weblayer/browser/translate_ranker_factory.h" #include "weblayer/browser/webui/web_ui_controller_factory.h" @@ -115,6 +116,7 @@ TranslateRankerFactory::GetInstance(); PrerenderLinkManagerFactory::GetInstance(); PrerenderManagerFactory::GetInstance(); + SubresourceFilterProfileContextFactory::GetInstance(); #if defined(OS_ANDROID) if (MediaRouterFactory::IsFeatureEnabled()) { LocalPresentationManagerFactory::GetInstance();
diff --git a/weblayer/browser/subresource_filter_profile_context_factory.cc b/weblayer/browser/subresource_filter_profile_context_factory.cc new file mode 100644 index 0000000..a31f985 --- /dev/null +++ b/weblayer/browser/subresource_filter_profile_context_factory.cc
@@ -0,0 +1,52 @@ +// 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 "weblayer/browser/subresource_filter_profile_context_factory.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/subresource_filter/content/browser/subresource_filter_profile_context.h" +#include "weblayer/browser/host_content_settings_map_factory.h" + +namespace weblayer { + +// static +subresource_filter::SubresourceFilterProfileContext* +SubresourceFilterProfileContextFactory::GetForBrowserContext( + content::BrowserContext* browser_context) { + return static_cast<subresource_filter::SubresourceFilterProfileContext*>( + GetInstance()->GetServiceForBrowserContext(browser_context, + true /* create */)); +} + +// static +SubresourceFilterProfileContextFactory* +SubresourceFilterProfileContextFactory::GetInstance() { + static base::NoDestructor<SubresourceFilterProfileContextFactory> factory; + return factory.get(); +} + +SubresourceFilterProfileContextFactory::SubresourceFilterProfileContextFactory() + : BrowserContextKeyedServiceFactory( + "SubresourceFilterProfileContext", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(HostContentSettingsMapFactory::GetInstance()); +} + +KeyedService* SubresourceFilterProfileContextFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + auto* subresource_filter_profile_context = + new subresource_filter::SubresourceFilterProfileContext( + HostContentSettingsMapFactory::GetForBrowserContext(context)); + + return subresource_filter_profile_context; +} + +content::BrowserContext* +SubresourceFilterProfileContextFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return context; +} + +} // namespace weblayer
diff --git a/weblayer/browser/subresource_filter_profile_context_factory.h b/weblayer/browser/subresource_filter_profile_context_factory.h new file mode 100644 index 0000000..6ada0736 --- /dev/null +++ b/weblayer/browser/subresource_filter_profile_context_factory.h
@@ -0,0 +1,49 @@ +// 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 WEBLAYER_BROWSER_SUBRESOURCE_FILTER_PROFILE_CONTEXT_FACTORY_H_ +#define WEBLAYER_BROWSER_SUBRESOURCE_FILTER_PROFILE_CONTEXT_FACTORY_H_ + +#include "base/no_destructor.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace content { +class BrowserContext; +} + +namespace subresource_filter { +class SubresourceFilterProfileContext; +} + +namespace weblayer { + +// This class is responsible for instantiating a profile-scoped context for +// subresource filtering. +class SubresourceFilterProfileContextFactory + : public BrowserContextKeyedServiceFactory { + public: + static SubresourceFilterProfileContextFactory* GetInstance(); + static subresource_filter::SubresourceFilterProfileContext* + GetForBrowserContext(content::BrowserContext* browser_context); + + SubresourceFilterProfileContextFactory( + const SubresourceFilterProfileContextFactory&) = delete; + SubresourceFilterProfileContextFactory& operator=( + const SubresourceFilterProfileContextFactory&) = delete; + + private: + friend class base::NoDestructor<SubresourceFilterProfileContextFactory>; + + SubresourceFilterProfileContextFactory(); + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace weblayer + +#endif // WEBLAYER_BROWSER_SUBRESOURCE_FILTER_PROFILE_CONTEXT_FACTORY_H_