From d30d8a8de02bab9434bd634272cf07e4e6e40792 Mon Sep 17 00:00:00 2001 From: Carmelo Messina Date: Sun, 29 Oct 2023 17:52:09 +0100 Subject: [PATCH] v119 final patches --- .../00Add-setting-to-clear-data-on-exit.patch | 14 +- build/patches/00Add-support-to-jxl.patch | 105 +- ...00Eyeo-Adblock-Remove-Privacy-Issues.patch | 4267 ++++++++++++++++- build/patches/00Fix-chromium-build-bugs.patch | 206 +- build/patches/00Internal-firewall.patch | 213 +- ...ning-all-cookies-by-top-frame-domain.patch | 30 +- ...th-header-upon-cross-origin-redirect.patch | 38 +- build/patches/00WIN-Fix-log-to-file.patch | 13 +- build/patches/00add-browser-policy.patch | 2 +- .../Add-an-always-incognito-mode.patch | 36 +- ...dd-custom-tab-intents-privacy-option.patch | 4 +- ...Add-lifetime-options-for-permissions.patch | 19 +- .../Add-option-to-use-home-page-as-NTP.patch | 31 +- .../Bromite-subresource-adblocker.patch | 4 +- .../Content-settings-infrastructure.patch | 75 +- build/patches/Disable-PrivacyGuide.patch | 17 +- .../patches/Disable-all-predictors-code.patch | 22 +- .../Experimental-user-scripts-support.patch | 9 +- ...story-number-of-days-privacy-setting.patch | 10 +- .../Keep-empty-tabs-between-sessions.patch | 14 +- .../Move-navigation-bar-to-bottom.patch | 369 +- ...nt-settings-back-to-privacy-settings.patch | 11 +- build/patches/Remove-help-menu-item.patch | 195 +- build/patches/User-agent-customization.patch | 14 +- build/patches/bromite-build-utils.patch | 7 +- 25 files changed, 4986 insertions(+), 739 deletions(-) diff --git a/build/patches/00Add-setting-to-clear-data-on-exit.patch b/build/patches/00Add-setting-to-clear-data-on-exit.patch index 1f553ff7..4da4be82 100644 --- a/build/patches/00Add-setting-to-clear-data-on-exit.patch +++ b/build/patches/00Add-setting-to-clear-data-on-exit.patch @@ -22,13 +22,13 @@ License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html .../clear_browsing_data_dialog.ts | 1 + .../strings/android_chrome_strings.grd | 3 + .../settings_localized_strings_provider.cc | 1 + - .../core/browsing_data_policies_utils.cc | 16 ++-- + .../core/browsing_data_policies_utils.cc | 20 ++--- .../core/browsing_data_policies_utils.h | 11 +++ .../browsing_data/core/browsing_data_utils.cc | 34 +++++++++ .../core/clear_browsing_data_tab.h | 2 +- components/browsing_data/core/pref_names.cc | 27 +++++++ components/browsing_data/core/pref_names.h | 9 +++ - 24 files changed, 316 insertions(+), 14 deletions(-) + 24 files changed, 318 insertions(+), 16 deletions(-) create mode 100644 chrome/android/java/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentAtStart.java diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni @@ -508,8 +508,12 @@ diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provide diff --git a/components/browsing_data/core/browsing_data_policies_utils.cc b/components/browsing_data/core/browsing_data_policies_utils.cc --- a/components/browsing_data/core/browsing_data_policies_utils.cc +++ b/components/browsing_data/core/browsing_data_policies_utils.cc -@@ -21,15 +21,15 @@ namespace { +@@ -17,21 +17,21 @@ + namespace browsing_data { + +-namespace { +- namespace policy_data_types { // Data retention policy types that require sync to be disabled. -constexpr char kBrowsingHistoryName[] = "browsing_history"; @@ -531,7 +535,11 @@ diff --git a/components/browsing_data/core/browsing_data_policies_utils.cc b/com +extern constexpr char kCachedImagesAndFilesName[] = "cached_images_and_files"; } // namespace policy_data_types ++namespace { ++ // The format of the log message shown in chrome://policy/logs when sync types + // are automatically disabled. + constexpr char kDisabledSyncTypesLogFormat[] = diff --git a/components/browsing_data/core/browsing_data_policies_utils.h b/components/browsing_data/core/browsing_data_policies_utils.h --- a/components/browsing_data/core/browsing_data_policies_utils.h +++ b/components/browsing_data/core/browsing_data_policies_utils.h diff --git a/build/patches/00Add-support-to-jxl.patch b/build/patches/00Add-support-to-jxl.patch index 7ec3e05b..45e97ac7 100644 --- a/build/patches/00Add-support-to-jxl.patch +++ b/build/patches/00Add-support-to-jxl.patch @@ -8,7 +8,7 @@ Enabled by default DEPS | 7 + build/linux/unbundle/libjxl.gn | 34 + build/linux/unbundle/replace_gn_files.py | 1 + - cc/base/devtools_instrumentation.cc | 6 + + cc/base/devtools_instrumentation.cc | 3 + cc/base/devtools_instrumentation.h | 2 +- cc/paint/paint_image.h | 2 +- cc/tiles/image_decode_cache.h | 2 + @@ -19,6 +19,8 @@ Enabled by default content/common/content_constants_internal.cc | 11 +- content/common/content_constants_internal.h | 3 +- content/public/browser/frame_accept_header.cc | 13 +- + media/BUILD.gn | 1 + + media/media_options.gni | 3 + net/base/mime_util.cc | 2 + net/base/mime_util_unittest.cc | 3 + third_party/.gitignore | 1 + @@ -26,17 +28,16 @@ Enabled by default .../blink/common/loader/network_utils.cc | 16 +- .../blink/common/mime_util/mime_util.cc | 7 + .../common/mime_util/mime_util_unittest.cc | 6 + - third_party/blink/public/common/BUILD.gn | 1 + third_party/blink/public/common/features.h | 2 + .../devtools_protocol/browser_protocol.pdl | 1 + - third_party/blink/public/public_features.gni | 5 + .../inspector/inspector_emulation_agent.cc | 7 +- .../inspector_emulation_agent_test.cc | 37 + .../generate_image_corpus.py | 1 + .../modules/webcodecs/image_decoder_fuzzer.cc | 5 + - third_party/blink/renderer/platform/BUILD.gn | 14 + + third_party/blink/renderer/platform/BUILD.gn | 5 + .../platform/graphics/bitmap_image_metrics.cc | 9 +- .../platform/graphics/bitmap_image_metrics.h | 4 +- + .../renderer/platform/image-decoders/BUILD.gn | 9 + .../platform/image-decoders/image_decoder.cc | 23 + .../image-decoders/jxl/jxl_image_decoder.cc | 683 ++++++++++++++++++ .../image-decoders/jxl/jxl_image_decoder.h | 123 ++++ @@ -59,7 +60,7 @@ Enabled by default third_party/libjxl/README.chromium | 15 + .../libjxl/gen_headers/jxl/jxl_export.h | 11 + tools/metrics/histograms/enums.xml | 3 +- - 54 files changed, 2010 insertions(+), 17 deletions(-) + 55 files changed, 2005 insertions(+), 17 deletions(-) create mode 100644 build/linux/unbundle/libjxl.gn create mode 100644 third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc create mode 100644 third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.h @@ -156,15 +157,12 @@ diff --git a/build/linux/unbundle/replace_gn_files.py b/build/linux/unbundle/rep diff --git a/cc/base/devtools_instrumentation.cc b/cc/base/devtools_instrumentation.cc --- a/cc/base/devtools_instrumentation.cc +++ b/cc/base/devtools_instrumentation.cc -@@ -90,6 +90,12 @@ ScopedImageDecodeTask::~ScopedImageDecodeTask() { +@@ -90,6 +90,9 @@ ScopedImageDecodeTask::~ScopedImageDecodeTask() { auto duration = base::TimeTicks::Now() - start_time_; const char* histogram_name = nullptr; switch (image_type_) { + case ImageType::kJxl: + histogram_name = "Renderer4.ImageUploadTaskDurationUs.Jxl"; -+ break; -+ case ImageType::kJxl: -+ histogram_name = "Renderer4.ImageUploadTaskDurationUs.Jxl"; + break; case ImageType::kAvif: histogram_name = "Renderer4.ImageDecodeTaskDurationUs.Avif"; @@ -333,6 +331,30 @@ diff --git a/content/public/browser/frame_accept_header.cc b/content/public/brow if (allow_sxg_responses && content::signed_exchange_utils::IsSignedExchangeHandlingEnabled( browser_context)) { +diff --git a/media/BUILD.gn b/media/BUILD.gn +--- a/media/BUILD.gn ++++ b/media/BUILD.gn +@@ -37,6 +37,7 @@ buildflag_header("media_buildflags") { + "ENABLE_CAST_AUDIO_RENDERER=$enable_cast_audio_renderer", + "ENABLE_DAV1D_DECODER=$enable_dav1d_decoder", + "ENABLE_AV1_DECODER=$enable_av1_decoder", ++ "ENABLE_JXL_DECODER=$enable_jxl_decoder", + "ENABLE_PLATFORM_DOLBY_VISION=$enable_platform_dolby_vision", + "ENABLE_PLATFORM_ENCRYPTED_DOLBY_VISION=$enable_platform_encrypted_dolby_vision", + "ENABLE_FFMPEG=$media_use_ffmpeg", +diff --git a/media/media_options.gni b/media/media_options.gni +--- a/media/media_options.gni ++++ b/media/media_options.gni +@@ -125,6 +125,9 @@ declare_args() { + # `enable_libaom` should likely also be overriddent to false. + enable_av1_decoder = enable_dav1d_decoder + ++ # If true, adds support for JPEG XL image decoding. ++ enable_jxl_decoder = is_android || is_win ++ + # Enable HEVC/H265 demuxing. Actual decoding must be provided by the + # platform. Always enable this for Lacros, it determines support at runtime. + # TODO(crbug.com/1336055): Revisit the default value for this setting as it diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc --- a/net/base/mime_util.cc +++ b/net/base/mime_util.cc @@ -484,17 +506,6 @@ diff --git a/third_party/blink/common/mime_util/mime_util_unittest.cc b/third_pa EXPECT_EQ(IsSupportedImageMimeType("image/avif"), BUILDFLAG(ENABLE_AV1_DECODER)); EXPECT_FALSE(IsSupportedImageMimeType("image/lolcat")); -diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn ---- a/third_party/blink/public/common/BUILD.gn -+++ b/third_party/blink/public/common/BUILD.gn -@@ -103,6 +103,7 @@ component("common") { - buildflag_header("buildflags") { - header = "buildflags.h" - flags = [ -+ "ENABLE_JXL_DECODER=$enable_jxl_decoder", - "RTC_USE_H264=$rtc_use_h264", - "ENABLE_RUST_CRASH=$enable_rust_crash", - "USE_FONTATIONS_BACKEND=$use_typeface_fontations", diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h @@ -518,21 +529,6 @@ diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/t webp experimental command setDisabledImageTypes -diff --git a/third_party/blink/public/public_features.gni b/third_party/blink/public/public_features.gni ---- a/third_party/blink/public/public_features.gni -+++ b/third_party/blink/public/public_features.gni -@@ -4,6 +4,11 @@ - - import("//build/config/ui.gni") - -+declare_args() { -+ # If true, adds support for JPEG XL image decoding. -+ enable_jxl_decoder = is_android || is_win -+} -+ - # Unhandled Tap enable means Contextual Search aka Touch to Search. - # TODO(donnd): remove all unhandled-tap handling after the Long-press experiment - # is fully launched. diff --git a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc --- a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc @@ -666,23 +662,7 @@ diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.c diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn -@@ -1816,6 +1816,15 @@ component("platform") { - sources += [ "text/hyphenation/hyphenation_null.cc" ] - } - -+ if (enable_jxl_decoder) { -+ sources += [ -+ "image-decoders/jxl/jxl_image_decoder.cc", -+ "image-decoders/jxl/jxl_image_decoder.h", -+ ] -+ -+ deps += [ "//third_party/libjxl:libjxl" ] -+ } -+ - if (current_cpu == "x86" || current_cpu == "x64") { - deps += [ ":blink_x86_avx" ] - sources += [ "audio/cpu/x86/delay_sse2.cc" ] -@@ -2232,6 +2241,10 @@ source_set("blink_platform_unittests_sources") { +@@ -2232,6 +2232,10 @@ source_set("blink_platform_unittests_sources") { sources += [ "text/locale_icu_test.cc" ] } @@ -693,7 +673,7 @@ diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/re sources += [ "testing/run_all_tests.cc" ] configs += [ -@@ -2275,6 +2288,7 @@ source_set("blink_platform_unittests_sources") { +@@ -2275,6 +2279,7 @@ source_set("blink_platform_unittests_sources") { "//third_party/blink/renderer/platform/scheduler:unit_tests", "//third_party/blink/renderer/platform/wtf", "//third_party/libavif:libavif", @@ -748,6 +728,25 @@ diff --git a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h }; // Categories for the JPEG color space histogram. Synced with 'JpegColorSpace' +diff --git a/third_party/blink/renderer/platform/image-decoders/BUILD.gn b/third_party/blink/renderer/platform/image-decoders/BUILD.gn +--- a/third_party/blink/renderer/platform/image-decoders/BUILD.gn ++++ b/third_party/blink/renderer/platform/image-decoders/BUILD.gn +@@ -70,6 +70,15 @@ component("image_decoders") { + "//third_party/libyuv", + ] + ++ if (enable_jxl_decoder) { ++ sources += [ ++ "jxl/jxl_image_decoder.cc", ++ "jxl/jxl_image_decoder.h", ++ ] ++ ++ deps += [ "//third_party/libjxl:libjxl" ] ++ } ++ + if (enable_av1_decoder) { + sources += [ + "avif/avif_image_decoder.cc", diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc --- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc +++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc diff --git a/build/patches/00Eyeo-Adblock-Remove-Privacy-Issues.patch b/build/patches/00Eyeo-Adblock-Remove-Privacy-Issues.patch index dc850b87..50e9c29d 100644 --- a/build/patches/00Eyeo-Adblock-Remove-Privacy-Issues.patch +++ b/build/patches/00Eyeo-Adblock-Remove-Privacy-Issues.patch @@ -8,9 +8,9 @@ suit Bromite logic .../android/java/res/xml/main_preferences.xml | 19 +- chrome/browser/BUILD.gn | 2 - .../adblock/adblock_content_browser_client.cc | 26 +- - .../adblock_private/adblock_private_api.cc | 66 +- + .../adblock_private/adblock_private_api.cc | 74 +- .../api/adblock_private/adblock_private_api.h | 49 + - .../eyeo_filtering_private_api.cc | 20 +- + .../eyeo_filtering_private_api.cc | 25 +- ...hrome_browser_main_extra_parts_profiles.cc | 2 - chrome/browser/resources/settings/BUILD.gn | 2 + .../settings/adblock_page/adblock_page.html | 207 + @@ -23,11 +23,12 @@ suit Bromite logic chrome/browser/resources/settings/settings.ts | 1 + .../settings/settings_menu/settings_menu.html | 5 + chrome/browser/ui/tab_helpers.cc | 6 +- + .../adblock_internals_page_handler_impl.cc | 20 +- .../extensions/api/_permission_features.json | 8 - .../common/extensions/api/adblock_private.idl | 8 + chrome/test/BUILD.gn | 5 - components/adblock/android/BUILD.gn | 3 +- - components/adblock/android/adblock_jni.cc | 50 +- + components/adblock/android/adblock_jni.cc | 53 +- .../adblock/android/adblock_strings.grd | 54 +- .../java/res/layout/adblock_custom_item.xml | 14 +- .../layout/adblock_filter_lists_list_item.xml | 15 + @@ -38,7 +39,7 @@ suit Bromite logic .../AdblockCustomFiltersFragment.java | 7 +- .../settings/AdblockCustomItemFragment.java | 20 +- .../settings/AdblockFilterListsAdapter.java | 6 + - .../settings/AdblockSettingsFragment.java | 44 +- + .../settings/AdblockSettingsFragment.java | 45 +- components/adblock/content/browser/BUILD.gn | 18 +- .../adblock_controller_factory_base.cc | 5 +- .../browser/adblock_webcontents_observer.cc | 25 +- @@ -50,9 +51,7 @@ suit Bromite logic components/adblock/core/BUILD.gn | 39 - .../activeping_telemetry_topic_provider.cc | 285 -- .../activeping_telemetry_topic_provider.h | 87 - - components/adblock/core/adblock_controller.h | 8 + - .../adblock/core/adblock_controller_impl.cc | 58 +- - .../adblock/core/adblock_controller_impl.h | 7 + + .../adblock/core/adblock_controller_impl.cc | 10 +- components/adblock/core/adblock_switches.cc | 1 - components/adblock/core/adblock_switches.h | 1 - .../adblock/core/adblock_telemetry_service.cc | 258 -- @@ -89,9 +88,9 @@ suit Bromite logic .../subscription_persistent_metadata_impl.cc | 7 + .../subscription_persistent_metadata_impl.h | 1 + .../subscription_persistent_storage_impl.cc | 11 +- - .../core/subscription/subscription_service.h | 3 + - .../subscription/subscription_service_impl.cc | 23 +- - .../subscription/subscription_service_impl.h | 3 + + .../core/subscription/subscription_service.h | 9 + + .../subscription/subscription_service_impl.cc | 78 +- + .../subscription/subscription_service_impl.h | 9 + .../subscription/subscription_updater_impl.cc | 8 +- .../subscription_validator_impl.cc | 4 +- .../browser/bromite_content_settings/ads.inc | 3 + @@ -101,14 +100,15 @@ suit Bromite logic components/resources/adblocking/BUILD.gn | 30 +- .../adblocking/elemhide_for_selector.jst | 2 +- .../resources/adblocking/elemhideemu.jst | 2 + + .../snippets/dist/isolated-first-xpath3.jst | 62 + + .../dist/isolated-first-xpath3.source.jst | 3696 +++++++++++++++++ .../snippets/dist/isolated-first.jst | 65 + - .../snippets/dist/isolated-first.source.jst | 3624 +++++++++++++++++ + .../snippets/dist/isolated-first.source.jst | 3624 ++++++++++++++++ .../blink/renderer/core/css/style_engine.cc | 8 + .../blink/renderer/core/css/style_engine.h | 1 + - .../renderer/core/exported/web_document.cc | 13 +- - tools/gritsettings/resource_ids.spec | 1 - + .../renderer/core/exported/web_document.cc | 15 +- .../definitions/adblock_private.d.ts | 14 + - 103 files changed, 5070 insertions(+), 1153 deletions(-) + 103 files changed, 8857 insertions(+), 1166 deletions(-) create mode 100644 chrome/browser/resources/settings/adblock_page/adblock_page.html create mode 100644 chrome/browser/resources/settings/adblock_page/adblock_page.ts rename components/adblock/android/java/res/xml/{adblock_preferences.xml => eyeo_adblock_preferences.xml} (56%) @@ -118,6 +118,8 @@ suit Bromite logic delete mode 100644 components/adblock/core/adblock_telemetry_service.h create mode 100644 components/adblock/core/converter/parser/test/test_rules.txt create mode 100644 components/content_settings/core/browser/bromite_content_settings/ads.inc + create mode 100644 components/resources/adblocking/snippets/dist/isolated-first-xpath3.jst + create mode 100644 components/resources/adblocking/snippets/dist/isolated-first-xpath3.source.jst create mode 100755 components/resources/adblocking/snippets/dist/isolated-first.jst create mode 100755 components/resources/adblocking/snippets/dist/isolated-first.source.jst @@ -227,7 +229,17 @@ diff --git a/chrome/browser/adblock/adblock_content_browser_client.cc b/chrome/b diff --git a/chrome/browser/extensions/api/adblock_private/adblock_private_api.cc b/chrome/browser/extensions/api/adblock_private/adblock_private_api.cc --- a/chrome/browser/extensions/api/adblock_private/adblock_private_api.cc +++ b/chrome/browser/extensions/api/adblock_private/adblock_private_api.cc -@@ -77,26 +77,12 @@ std::vector CopySessionsStats( +@@ -18,7 +18,8 @@ + #include "base/containers/flat_map.h" + #include "base/logging.h" + #include "base/no_destructor.h" +-#include "base/time/time_to_iso8601.h" ++#include "base/i18n/time_formatting.h" ++#include "base/strings/utf_string_conversions.h" + #include "base/values.h" + #include "chrome/browser/adblock/resource_classification_runner_factory.h" + #include "chrome/browser/adblock/session_stats_factory.h" +@@ -77,26 +78,12 @@ std::vector CopySessionsStats( return result; } @@ -249,22 +261,23 @@ diff --git a/chrome/browser/extensions/api/adblock_private/adblock_private_api.c -} - std::vector CopySubscriptions( -+ raw_ptr controller, ++ raw_ptr subscription_service, const std::vector> current_subscriptions) { + raw_ptr metadata = -+ controller->GetMetadata(); ++ subscription_service->GetMetadata(); std::vector result; for (auto& sub : current_subscriptions) { api::adblock_private::Subscription js_sub; -@@ -104,9 +90,13 @@ std::vector CopySubscriptions( +@@ -104,9 +91,13 @@ std::vector CopySubscriptions( js_sub.title = sub->GetTitle(); js_sub.current_version = sub->GetCurrentVersion(); js_sub.installation_state = - SubscriptionInstallationStateToString(sub->GetInstallationState()); + adblock::Subscription::SubscriptionInstallationStateToString(sub->GetInstallationState()); js_sub.last_installation_time = - base::TimeToISO8601(sub->GetInstallationTime()); +- base::TimeToISO8601(sub->GetInstallationTime()); ++ base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(sub->GetInstallationTime())); + if (metadata) { + js_sub.download_success_count = metadata->GetDownloadSuccessCount(sub->GetSourceUrl()); + js_sub.download_error_count = metadata->GetDownloadErrorCount(sub->GetSourceUrl()); @@ -272,7 +285,7 @@ diff --git a/chrome/browser/extensions/api/adblock_private/adblock_private_api.c result.emplace_back(std::move(js_sub)); } return result; -@@ -347,6 +337,44 @@ void AdblockPrivateAPI::OnListenerAdded( +@@ -347,6 +338,47 @@ void AdblockPrivateAPI::OnListenerAdded( namespace api { @@ -281,9 +294,10 @@ diff --git a/chrome/browser/extensions/api/adblock_private/adblock_private_api.c +AdblockPrivateStartUpdateFunction::~AdblockPrivateStartUpdateFunction() {} + +ExtensionFunction::ResponseAction AdblockPrivateStartUpdateFunction::Run() { -+ auto* controller = adblock::AdblockControllerFactory::GetForBrowserContext( -+ browser_context()); -+ controller->StartUpdate(); ++ auto* subscription_service = ++ adblock::SubscriptionServiceFactory::GetForBrowserContext( ++ browser_context()); ++ subscription_service->StartUpdate(); + return RespondNow(NoArguments()); +} + @@ -296,9 +310,10 @@ diff --git a/chrome/browser/extensions/api/adblock_private/adblock_private_api.c + api::adblock_private::SetEnabled::Params::Create(args()); + EXTENSION_FUNCTION_VALIDATE(params); + -+ auto* controller = adblock::AdblockControllerFactory::GetForBrowserContext( -+ browser_context()); -+ controller->SetPrivilegedFiltersEnabled(params->enabled); ++ auto* subscription_service = ++ adblock::SubscriptionServiceFactory::GetForBrowserContext( ++ browser_context()); ++ subscription_service->SetPrivilegedFiltersEnabled(params->enabled); + return RespondNow(NoArguments()); +} + @@ -307,22 +322,23 @@ diff --git a/chrome/browser/extensions/api/adblock_private/adblock_private_api.c +AdblockPrivateIsPrivilegedFiltersEnabledFunction::~AdblockPrivateIsPrivilegedFiltersEnabledFunction() {} + +ExtensionFunction::ResponseAction AdblockPrivateIsPrivilegedFiltersEnabledFunction::Run() { -+ auto* controller = adblock::AdblockControllerFactory::GetForBrowserContext( -+ browser_context()); ++ auto* subscription_service = ++ adblock::SubscriptionServiceFactory::GetForBrowserContext( ++ browser_context()); + return RespondNow( + ArgumentList(api::adblock_private::IsEnabled::Results::Create( -+ controller->IsPrivilegedFiltersEnabled()))); ++ subscription_service->IsPrivilegedFiltersEnabled()))); +} + AdblockPrivateSetEnabledFunction::AdblockPrivateSetEnabledFunction() {} AdblockPrivateSetEnabledFunction::~AdblockPrivateSetEnabledFunction() {} -@@ -514,7 +542,7 @@ AdblockPrivateGetInstalledSubscriptionsFunction::Run() { +@@ -514,7 +546,7 @@ AdblockPrivateGetInstalledSubscriptionsFunction::Run() { << "adblock_private expects \"adblock\" configuration"; return RespondNow(ArgumentList( api::adblock_private::GetInstalledSubscriptions::Results::Create( - CopySubscriptions(subscription_service->GetCurrentSubscriptions( -+ CopySubscriptions(controller, subscription_service->GetCurrentSubscriptions( ++ CopySubscriptions(subscription_service, subscription_service->GetCurrentSubscriptions( subscription_service->GetAdblockFilteringConfiguration()))))); } @@ -388,7 +404,17 @@ diff --git a/chrome/browser/extensions/api/adblock_private/adblock_private_api.h diff --git a/chrome/browser/extensions/api/eyeo_filtering_private/eyeo_filtering_private_api.cc b/chrome/browser/extensions/api/eyeo_filtering_private/eyeo_filtering_private_api.cc --- a/chrome/browser/extensions/api/eyeo_filtering_private/eyeo_filtering_private_api.cc +++ b/chrome/browser/extensions/api/eyeo_filtering_private/eyeo_filtering_private_api.cc -@@ -29,6 +29,7 @@ +@@ -18,7 +18,8 @@ + #include "base/containers/flat_map.h" + #include "base/logging.h" + #include "base/no_destructor.h" +-#include "base/time/time_to_iso8601.h" ++#include "base/i18n/time_formatting.h" ++#include "base/strings/utf_string_conversions.h" + #include "base/values.h" + #include "chrome/browser/adblock/resource_classification_runner_factory.h" + #include "chrome/browser/adblock/session_stats_factory.h" +@@ -29,6 +30,7 @@ #include "components/adblock/content/browser/resource_classification_runner.h" #include "components/adblock/core/common/adblock_utils.h" #include "components/adblock/core/common/content_type.h" @@ -396,7 +422,7 @@ diff --git a/chrome/browser/extensions/api/eyeo_filtering_private/eyeo_filtering #include "components/adblock/core/configuration/filtering_configuration.h" #include "components/adblock/core/configuration/persistent_filtering_configuration.h" #include "components/adblock/core/session_stats.h" -@@ -94,23 +95,6 @@ std::vector CopySessionsStats( +@@ -94,23 +96,6 @@ std::vector CopySessionsStats( return result; } @@ -420,15 +446,18 @@ diff --git a/chrome/browser/extensions/api/eyeo_filtering_private/eyeo_filtering std::vector CopySubscriptions( const std::vector> current_subscriptions) { -@@ -121,7 +105,7 @@ std::vector CopySubscriptions( +@@ -121,9 +106,9 @@ std::vector CopySubscriptions( js_sub.title = sub->GetTitle(); js_sub.current_version = sub->GetCurrentVersion(); js_sub.installation_state = - SubscriptionInstallationStateToString(sub->GetInstallationState()); + adblock::Subscription::SubscriptionInstallationStateToString(sub->GetInstallationState()); js_sub.last_installation_time = - base::TimeToISO8601(sub->GetInstallationTime()); +- base::TimeToISO8601(sub->GetInstallationTime()); ++ base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(sub->GetInstallationTime())); result.emplace_back(std::move(js_sub)); + } + return result; diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc @@ -1090,6 +1119,57 @@ diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc autofill::ChromeAutofillClient::CreateForWebContents(web_contents); if (breadcrumbs::IsEnabled()) BreadcrumbManagerTabHelper::CreateForWebContents(web_contents); +diff --git a/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.cc b/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.cc +--- a/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.cc ++++ b/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.cc +@@ -17,11 +17,10 @@ + + #include "chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.h" + +-#include "base/time/time_to_iso8601.h" +-#include "chrome/browser/adblock/adblock_telemetry_service_factory.h" ++#include "base/i18n/time_formatting.h" ++#include "base/strings/utf_string_conversions.h" + #include "chrome/browser/adblock/session_stats_factory.h" + #include "chrome/browser/adblock/subscription_service_factory.h" +-#include "components/adblock/core/adblock_telemetry_service.h" + #include "components/adblock/core/session_stats.h" + #include "components/adblock/core/subscription/subscription_config.h" + #include "components/adblock/core/subscription/subscription_service.h" +@@ -53,6 +52,13 @@ std::string DebugLine(std::string name, int value, int level) { + return DebugLine(name, std::to_string(value), level); + } + ++std::string FormatInstallationTime(base::Time time) { ++ if (time.is_null()) { ++ return "Never"; ++ } ++ return base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(time)); ++} ++ + } // namespace + + AdblockInternalsPageHandlerImpl::AdblockInternalsPageHandlerImpl( +@@ -90,17 +96,13 @@ void AdblockInternalsPageHandlerImpl::GetDebugInfo( + content += DebugLine("Title", it->GetTitle(), 2); + content += DebugLine("Version", it->GetCurrentVersion(), 2); + content += DebugLine("Last update", +- base::TimeToISO8601(it->GetInstallationTime()), 2); ++ FormatInstallationTime(it->GetInstallationTime()), 2); + content += DebugLine("Total allowed", allowed[url], 2); + content += DebugLine("Total blocked", blocked[url], 2); + } + } + +- auto* telemetry_service = +- adblock::AdblockTelemetryServiceFactory::GetForProfile(profile_); +- telemetry_service->GetTopicProvidersDebugInfo(base::BindOnce( +- &AdblockInternalsPageHandlerImpl::OnTelemetryServiceInfoArrived, +- std::move(callback), std::move(content))); ++ std::move(callback).Run(std::move(content)); + } + + void AdblockInternalsPageHandlerImpl::OnTelemetryServiceInfoArrived( diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json @@ -1165,14 +1245,14 @@ diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn diff --git a/components/adblock/android/BUILD.gn b/components/adblock/android/BUILD.gn --- a/components/adblock/android/BUILD.gn +++ b/components/adblock/android/BUILD.gn -@@ -95,6 +95,7 @@ android_library("adblock_ui_java") { - "//third_party/androidx:androidx_preference_preference_java", - ] - -+ srcjar_deps = [ ":jni_headers" ] - resources_package = "org.chromium.components.adblock" - } +@@ -14,6 +14,7 @@ + import("//build/config/android/rules.gni") + import("//build/config/locales.gni") + import("//tools/grit/grit_rule.gni") ++import("//third_party/jni_zero/jni_zero.gni") + source_set("java_bindings") { + sources = [ @@ -120,7 +121,7 @@ android_resources("java_ui_resources") { "java/res/layout/adblock_custom_item_settings.xml", "java/res/layout/adblock_filter_lists_list_item.xml", @@ -1185,15 +1265,16 @@ diff --git a/components/adblock/android/BUILD.gn b/components/adblock/android/BU diff --git a/components/adblock/android/adblock_jni.cc b/components/adblock/android/adblock_jni.cc --- a/components/adblock/android/adblock_jni.cc +++ b/components/adblock/android/adblock_jni.cc -@@ -25,6 +25,7 @@ +@@ -25,6 +25,8 @@ #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/android/jni_weak_ref.h" -+#include "base/time/time_to_iso8601.h" ++#include "base/i18n/time_formatting.h" ++#include "base/strings/utf_string_conversions.h" #include "base/logging.h" #include "components/adblock/android/java_bindings_getters.h" #include "components/adblock/android/jni_headers/AdblockController_jni.h" -@@ -54,6 +55,10 @@ ScopedJavaLocalRef ToJava(JNIEnv* env, +@@ -54,6 +56,10 @@ ScopedJavaLocalRef ToJava(JNIEnv* env, const std::string& url, const std::string& title, const std::string& version, @@ -1204,7 +1285,7 @@ diff --git a/components/adblock/android/adblock_jni.cc b/components/adblock/andr const std::vector& languages) { ScopedJavaLocalRef url_param( env, env->NewObject(url_class.obj(), url_constructor, -@@ -62,12 +67,19 @@ ScopedJavaLocalRef ToJava(JNIEnv* env, +@@ -62,12 +68,19 @@ ScopedJavaLocalRef ToJava(JNIEnv* env, return Java_Subscription_Constructor(env, url_param, ConvertUTF8ToJavaString(env, title), ConvertUTF8ToJavaString(env, version), @@ -1218,26 +1299,26 @@ diff --git a/components/adblock/android/adblock_jni.cc b/components/adblock/andr std::vector> CSubscriptionsToJObjects( JNIEnv* env, const std::vector>& subscriptions) { -+ auto* controller = adblock::GetController(); ++ auto* subscription_service = adblock::GetSubscriptionService(); + raw_ptr metadata = -+ controller->GetMetadata(); ++ subscription_service->GetMetadata(); ScopedJavaLocalRef url_class = GetClass(env, "java/net/URL"); jmethodID url_constructor = MethodID::Get( env, url_class.obj(), "", "(Ljava/lang/String;)V"); -@@ -76,7 +88,11 @@ std::vector> CSubscriptionsToJObjects( +@@ -76,7 +89,11 @@ std::vector> CSubscriptionsToJObjects( for (auto& sub : subscriptions) { jobjects.push_back(ToJava( env, url_class, url_constructor, sub->GetSourceUrl().spec(), - sub->GetTitle(), sub->GetCurrentVersion(), std::vector{})); + sub->GetTitle(), sub->GetCurrentVersion(), -+ sub->GetInstallationState(), base::TimeToISO8601(sub->GetInstallationTime()), ++ sub->GetInstallationState(), base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(sub->GetInstallationTime())), + metadata ? metadata->GetDownloadSuccessCount(sub->GetSourceUrl()) : 0, + metadata ? metadata->GetDownloadErrorCount(sub->GetSourceUrl()) : 0, + std::vector{})); } return jobjects; } -@@ -96,6 +112,9 @@ std::vector> CSubscriptionsToJObjects( +@@ -96,6 +113,9 @@ std::vector> CSubscriptionsToJObjects( if (sub.url.is_valid()) { jobjects.push_back(ToJava(env, url_class, url_constructor, sub.url.spec(), sub.title, "", @@ -1247,42 +1328,44 @@ diff --git a/components/adblock/android/adblock_jni.cc b/components/adblock/andr sub.languages)); } } -@@ -125,6 +144,35 @@ void AdblockJNI::Bind(JavaObjectWeakGlobalRef weak_java_controller) { - weak_java_controller_ = weak_java_controller; - } +@@ -139,6 +159,37 @@ void AdblockJNI::OnSubscriptionInstalled(const GURL& url) { + + } // namespace adblock +static void +JNI_AdblockController_StartUpdate(JNIEnv* env) { -+ adblock::GetController()->StartUpdate(); ++ adblock::GetSubscriptionService()->StartUpdate(); +} + +static base::android::ScopedJavaLocalRef +JNI_AdblockController_GetCustomSubscriptions(JNIEnv* env) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); -+ if (!adblock::GetController()) { ++ auto* subscription_service = adblock::GetSubscriptionService(); ++ if (!subscription_service) { + return ToJavaArrayOfObjects(env, + std::vector>{}); + } + + return ToJavaArrayOfObjects( + env, adblock::CSubscriptionsToJObjects( -+ env, adblock::GetController()->GetCustomSubscriptions())); ++ env, subscription_service->GetCustomSubscriptions( ++ subscription_service->GetAdblockFilteringConfiguration()))); +} + +static jboolean JNI_AdblockController_IsPrivilegedFiltersEnabled( + JNIEnv* env) { -+ return adblock::GetController()->IsPrivilegedFiltersEnabled() ? JNI_TRUE : JNI_FALSE; ++ return adblock::GetSubscriptionService()->IsPrivilegedFiltersEnabled() ? JNI_TRUE : JNI_FALSE; +} + +static void JNI_AdblockController_SetPrivilegedFiltersEnabled( + JNIEnv* env, + jboolean j_enabled) { -+ adblock::GetController()->SetPrivilegedFiltersEnabled(j_enabled == JNI_TRUE); ++ adblock::GetSubscriptionService()->SetPrivilegedFiltersEnabled(j_enabled == JNI_TRUE); +} + - void AdblockJNI::OnSubscriptionInstalled(const GURL& url) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - JNIEnv* env = AttachCurrentThread(); + static void JNI_AdblockController_Bind( + JNIEnv* env, + const base::android::JavaParamRef& caller) { diff --git a/components/adblock/android/adblock_strings.grd b/components/adblock/android/adblock_strings.grd --- a/components/adblock/android/adblock_strings.grd +++ b/components/adblock/android/adblock_strings.grd @@ -1799,7 +1882,7 @@ diff --git a/components/adblock/android/java/src/org/chromium/components/adblock private static final String SETTINGS_ENABLED_KEY = "fragment_adblock_settings_enabled_key"; private static final String SETTINGS_FILTER_LISTS_KEY = "fragment_adblock_settings_filter_lists_key"; -@@ -49,6 +62,16 @@ public class AdblockSettingsFragment +@@ -49,9 +62,20 @@ public class AdblockSettingsFragment private long mOnOffTogleTimestamp; private void bindPreferences() { @@ -1816,7 +1899,11 @@ diff --git a/components/adblock/android/java/src/org/chromium/components/adblock mAdblockEnabled = (ChromeSwitchPreference) findPreference(SETTINGS_ENABLED_KEY); mFilterLists = findPreference(SETTINGS_FILTER_LISTS_KEY); mAcceptableAdsEnabled = (ChromeSwitchPreference) findPreference(SETTINGS_AA_ENABLED_KEY); -@@ -62,14 +85,25 @@ public class AdblockSettingsFragment ++ mAcceptableAdsEnabled.setVisible(false); + mAllowedDomains = findPreference(SETTINGS_ALLOWED_DOMAINS_KEY); + mMoreOptions = findPreference(SETTINGS_MORE_OPTIONS_KEY); + } +@@ -62,14 +86,25 @@ public class AdblockSettingsFragment } private void applyAdblockEnabled(boolean enabledValue) { @@ -1844,7 +1931,7 @@ diff --git a/components/adblock/android/java/src/org/chromium/components/adblock boolean enabled = AdblockController.getInstance().isEnabled(); mAdblockEnabled.setChecked(enabled); mAdblockEnabled.setOnPreferenceChangeListener(this); -@@ -107,7 +141,7 @@ public class AdblockSettingsFragment +@@ -107,7 +142,7 @@ public class AdblockSettingsFragment @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { @@ -1853,7 +1940,7 @@ diff --git a/components/adblock/android/java/src/org/chromium/components/adblock bindPreferences(); synchronizePreferences(); } -@@ -126,6 +160,8 @@ public class AdblockSettingsFragment +@@ -126,6 +161,8 @@ public class AdblockSettingsFragment maybeEnableMoreOptions(); applyAdblockEnabled((Boolean) newValue); @@ -2567,55 +2654,10 @@ deleted file mode 100644 -} // namespace adblock - -#endif // COMPONENTS_ADBLOCK_CORE_ACTIVEPING_TELEMETRY_TOPIC_PROVIDER_H_ -diff --git a/components/adblock/core/adblock_controller.h b/components/adblock/core/adblock_controller.h ---- a/components/adblock/core/adblock_controller.h -+++ b/components/adblock/core/adblock_controller.h -@@ -24,6 +24,7 @@ - #include "base/observer_list.h" - #include "components/adblock/core/subscription/installed_subscription.h" - #include "components/adblock/core/subscription/subscription_config.h" -+#include "components/adblock/core/subscription/subscription_persistent_metadata.h" - #include "components/keyed_service/core/keyed_service.h" - - class GURL; -@@ -43,10 +44,17 @@ class AdblockController : public KeyedService { - virtual void SetAcceptableAdsEnabled(bool enabled) = 0; - virtual bool IsAcceptableAdsEnabled() const = 0; - -+ virtual void StartUpdate() = 0; -+ virtual raw_ptr GetMetadata() = 0; -+ virtual void SetPrivilegedFiltersEnabled(bool enabled) = 0; -+ virtual bool IsPrivilegedFiltersEnabled() = 0; -+ - virtual void InstallSubscription(const GURL& url) = 0; - virtual void UninstallSubscription(const GURL& url) = 0; - virtual std::vector> GetInstalledSubscriptions() - const = 0; -+ virtual std::vector> GetCustomSubscriptions() -+ const = 0; - - virtual void AddAllowedDomain(const std::string& domain) = 0; - virtual void RemoveAllowedDomain(const std::string& domain) = 0; diff --git a/components/adblock/core/adblock_controller_impl.cc b/components/adblock/core/adblock_controller_impl.cc --- a/components/adblock/core/adblock_controller_impl.cc +++ b/components/adblock/core/adblock_controller_impl.cc -@@ -73,6 +73,15 @@ absl::optional MigrateBoolFromPrefs(PrefService* pref_service, - return absl::nullopt; - } - -+bool IsKnownSubscription( -+ const std::vector& known_subscriptions, -+ const GURL& url) { -+ return base::ranges::any_of(known_subscriptions, -+ [&](const auto& known_subscription) { -+ return known_subscription.url == url; -+ }); -+} -+ - } // namespace - - AdblockControllerImpl::AdblockControllerImpl( -@@ -103,6 +112,7 @@ bool AdblockControllerImpl::IsAdblockEnabled() const { +@@ -103,6 +103,7 @@ bool AdblockControllerImpl::IsAdblockEnabled() const { } void AdblockControllerImpl::SetAcceptableAdsEnabled(bool enabled) { @@ -2623,62 +2665,15 @@ diff --git a/components/adblock/core/adblock_controller_impl.cc b/components/adb if (enabled) { InstallSubscription(AcceptableAdsUrl()); } else { -@@ -116,7 +126,33 @@ bool AdblockControllerImpl::IsAcceptableAdsEnabled() const { - [&](const auto& url) { return url == AcceptableAdsUrl(); }); +@@ -117,6 +118,7 @@ bool AdblockControllerImpl::IsAcceptableAdsEnabled() const { } -+void AdblockControllerImpl::StartUpdate() { -+ subscription_service_->StartUpdate(); -+} -+ -+raw_ptr AdblockControllerImpl::GetMetadata() { -+ return subscription_service_->GetMetadataFor(adblock_filtering_configuration_); -+} -+ -+bool AdblockControllerImpl::IsPrivilegedFiltersEnabled() { -+ return adblock_filtering_configuration_->IsPrivilegedFiltersEnabled(); -+} -+ -+void AdblockControllerImpl::SetPrivilegedFiltersEnabled(bool enabled) { -+ adblock_filtering_configuration_->SetPrivilegedFiltersEnabled(enabled); -+ for (const auto& cur : known_subscriptions_) { -+ if (config::AllowPrivilegedFilters(cur.url)) { -+ if (enabled) -+ InstallSubscription(cur.url); -+ else -+ UninstallSubscription(cur.url); -+ } -+ } -+ StartUpdate(); -+} -+ void AdblockControllerImpl::InstallSubscription(const GURL& url) { + if (url == AcceptableAdsUrl()) return; adblock_filtering_configuration_->AddFilterList(url); } -@@ -129,6 +165,20 @@ AdblockControllerImpl::GetInstalledSubscriptions() const { - return GetSubscriptionsThatMatchConfiguration(); - } - -+std::vector> -+AdblockControllerImpl::GetCustomSubscriptions() const { -+ auto selected = GetInstalledSubscriptions(); -+ std::vector known = GetKnownSubscriptions(); -+ selected.erase(base::ranges::remove_if(selected, -+ [&](const auto& subscription) { -+ return IsKnownSubscription( -+ known, -+ subscription->GetSourceUrl()); -+ }), -+ selected.end()); -+ return selected; -+} -+ - void AdblockControllerImpl::AddAllowedDomain(const std::string& domain) { - adblock_filtering_configuration_->AddAllowedDomain(domain); - } -@@ -165,10 +215,8 @@ void AdblockControllerImpl::RunFirstRunLogic(PrefService* pref_service) { +@@ -165,10 +167,8 @@ void AdblockControllerImpl::RunFirstRunLogic(PrefService* pref_service) { common::prefs::kInstallFirstStartSubscriptions)) { // On first run, install additional subscriptions. for (const auto& cur : known_subscriptions_) { @@ -2691,7 +2686,7 @@ diff --git a/components/adblock/core/adblock_controller_impl.cc b/components/adb // Do not install Acceptable Ads on first run because a command line // switch forbids it. Mostly used for testing. continue; -@@ -236,7 +284,7 @@ void AdblockControllerImpl::InstallLanguageBasedRecommendedSubscriptions() { +@@ -236,7 +236,7 @@ void AdblockControllerImpl::InstallLanguageBasedRecommendedSubscriptions() { SubscriptionFirstRunBehavior::SubscribeIfLocaleMatch && std::find(subscription.languages.begin(), subscription.languages.end(), language_) != subscription.languages.end()) { @@ -2700,27 +2695,6 @@ diff --git a/components/adblock/core/adblock_controller_impl.cc b/components/adb << language_ << "\": " << subscription.title; language_specific_subscription_installed = true; InstallSubscription(subscription.url); -diff --git a/components/adblock/core/adblock_controller_impl.h b/components/adblock/core/adblock_controller_impl.h ---- a/components/adblock/core/adblock_controller_impl.h -+++ b/components/adblock/core/adblock_controller_impl.h -@@ -58,10 +58,17 @@ class AdblockControllerImpl : public AdblockController { - void SetAcceptableAdsEnabled(bool enabled) override; - bool IsAcceptableAdsEnabled() const override; - -+ void StartUpdate() override; -+ raw_ptr GetMetadata() override; -+ void SetPrivilegedFiltersEnabled(bool enabled) override; -+ bool IsPrivilegedFiltersEnabled() override; -+ - void InstallSubscription(const GURL& url) override; - void UninstallSubscription(const GURL& url) override; - std::vector> GetInstalledSubscriptions() - const override; -+ std::vector> GetCustomSubscriptions() -+ const override; - - void AddAllowedDomain(const std::string& domain) override; - void RemoveAllowedDomain(const std::string& domain) override; diff --git a/components/adblock/core/adblock_switches.cc b/components/adblock/core/adblock_switches.cc --- a/components/adblock/core/adblock_switches.cc +++ b/components/adblock/core/adblock_switches.cc @@ -4229,23 +4203,103 @@ diff --git a/components/adblock/core/subscription/subscription_persistent_storag diff --git a/components/adblock/core/subscription/subscription_service.h b/components/adblock/core/subscription/subscription_service.h --- a/components/adblock/core/subscription/subscription_service.h +++ b/components/adblock/core/subscription/subscription_service.h -@@ -77,6 +77,9 @@ class SubscriptionService : public KeyedService { - // concurrently, and future changes to the installed subscriptions will not - // impact it. - virtual Snapshot GetCurrentSnapshot() const = 0; +@@ -38,6 +38,15 @@ namespace adblock { + // FilteringConfigurations. + class SubscriptionService : public KeyedService { + public: + virtual void StartUpdate() = 0; ++ virtual raw_ptr GetMetadata() = 0; + virtual raw_ptr GetMetadataFor( + raw_ptr configuration) = 0; - - virtual void AddObserver(SubscriptionObserver*) = 0; - virtual void RemoveObserver(SubscriptionObserver*) = 0; ++ virtual void SetPrivilegedFiltersEnabled(bool enabled) = 0; ++ virtual bool IsPrivilegedFiltersEnabled() = 0; ++ virtual std::vector> GetCustomSubscriptions( ++ FilteringConfiguration* configuration) const = 0; ++ + using Snapshot = std::vector>; + class SubscriptionObserver : public base::CheckedObserver { + public: diff --git a/components/adblock/core/subscription/subscription_service_impl.cc b/components/adblock/core/subscription/subscription_service_impl.cc --- a/components/adblock/core/subscription/subscription_service_impl.cc +++ b/components/adblock/core/subscription/subscription_service_impl.cc -@@ -133,6 +133,18 @@ void SubscriptionServiceImpl::UninstallFilteringConfiguration( +@@ -36,9 +36,23 @@ + #include "components/adblock/core/subscription/filtering_configuration_maintainer.h" + #include "components/adblock/core/subscription/subscription_collection.h" + #include "components/adblock/core/subscription/subscription_service.h" ++#include "components/adblock/core/subscription/subscription_config.h" + + namespace adblock { + ++namespace { ++ ++bool IsKnownSubscription( ++ const std::vector& known_subscriptions, ++ const GURL& url) { ++ return base::ranges::any_of(known_subscriptions, ++ [&](const auto& known_subscription) { ++ return known_subscription.url == url; ++ }); ++} ++ ++} ++ + class EmptySubscription : public Subscription { + public: + EmptySubscription(const GURL& url) : url_(url) {} +@@ -133,6 +147,68 @@ void SubscriptionServiceImpl::UninstallFilteringConfiguration( maintainers_.erase(it); } ++void SubscriptionServiceImpl::StartUpdate() { ++ for (auto& entry : maintainers_) { ++ if (!entry.second) { ++ continue; // Configuration is disabled ++ } ++ entry.second->StartUpdate(); ++ } ++} ++ ++bool SubscriptionServiceImpl::IsPrivilegedFiltersEnabled() { ++ auto* adblock_filtering_configuration = GetAdblockFilteringConfiguration(); ++ return adblock_filtering_configuration->IsPrivilegedFiltersEnabled(); ++} ++ ++void SubscriptionServiceImpl::SetPrivilegedFiltersEnabled(bool enabled) { ++ auto* adblock_filtering_configuration = GetAdblockFilteringConfiguration(); ++ adblock_filtering_configuration->SetPrivilegedFiltersEnabled(enabled); ++ auto known_subscriptions = adblock::config::GetKnownSubscriptions(); ++ for (const auto& cur : known_subscriptions) { ++ if (config::AllowPrivilegedFilters(cur.url)) { ++ if (enabled) ++ adblock_filtering_configuration->AddFilterList(cur.url); ++ else ++ adblock_filtering_configuration->RemoveFilterList(cur.url); ++ } ++ } ++ StartUpdate(); ++} ++ ++std::vector> ++SubscriptionServiceImpl::GetCustomSubscriptions( ++ FilteringConfiguration* configuration) const { ++ std::vector> selected = ++ GetCurrentSubscriptions(configuration); ++ ++ auto known_subscriptions = adblock::config::GetKnownSubscriptions(); ++ selected.erase(base::ranges::remove_if(selected, ++ [&](const auto& subscription) { ++ return IsKnownSubscription( ++ known_subscriptions, ++ subscription->GetSourceUrl()); ++ }), ++ selected.end()); ++ return selected; ++} ++ ++raw_ptr SubscriptionServiceImpl::GetMetadata() { ++ return GetMetadataFor(GetAdblockFilteringConfiguration()); ++} ++ +raw_ptr SubscriptionServiceImpl::GetMetadataFor( + raw_ptr configuration) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -4261,23 +4315,7 @@ diff --git a/components/adblock/core/subscription/subscription_service_impl.cc b std::vector SubscriptionServiceImpl::GetInstalledFilteringConfigurations() { std::vector result; -@@ -163,6 +175,15 @@ SubscriptionService::Snapshot SubscriptionServiceImpl::GetCurrentSnapshot() - return snapshot; - } - -+void SubscriptionServiceImpl::StartUpdate() { -+ for (auto& entry : maintainers_) { -+ if (!entry.second) { -+ continue; // Configuration is disabled -+ } -+ entry.second->StartUpdate(); -+ } -+} -+ - void SubscriptionServiceImpl::AddObserver(SubscriptionObserver* o) { - observers_.AddObserver(o); - } -@@ -178,7 +199,7 @@ void SubscriptionServiceImpl::OnEnabledStateChanged( +@@ -178,7 +254,7 @@ void SubscriptionServiceImpl::OnEnabledStateChanged( }); DCHECK(it != maintainers_.end()) << "Received OnEnabledStateChanged from " "unregistered FilteringConfiguration"; @@ -4289,16 +4327,22 @@ diff --git a/components/adblock/core/subscription/subscription_service_impl.cc b diff --git a/components/adblock/core/subscription/subscription_service_impl.h b/components/adblock/core/subscription/subscription_service_impl.h --- a/components/adblock/core/subscription/subscription_service_impl.h +++ b/components/adblock/core/subscription/subscription_service_impl.h -@@ -70,6 +70,9 @@ class SubscriptionServiceImpl final : public SubscriptionService, - final; - FilteringConfiguration* GetAdblockFilteringConfiguration() const final; - Snapshot GetCurrentSnapshot() const final; -+ void StartUpdate() final; +@@ -43,6 +43,15 @@ namespace adblock { + class SubscriptionServiceImpl final : public SubscriptionService, + public FilteringConfiguration::Observer { + public: ++ void StartUpdate() override; ++ raw_ptr GetMetadata() override; + raw_ptr GetMetadataFor( + raw_ptr configuration) final; - void AddObserver(SubscriptionObserver*) final; - void RemoveObserver(SubscriptionObserver*) final; - ++ void SetPrivilegedFiltersEnabled(bool enabled) override; ++ bool IsPrivilegedFiltersEnabled() override; ++ std::vector> GetCustomSubscriptions( ++ FilteringConfiguration* configuration) const override; ++ + // Used to notify this about updates to installed subscriptions. + using SubscriptionUpdatedCallback = + base::RepeatingCallback; diff --git a/components/adblock/core/subscription/subscription_updater_impl.cc b/components/adblock/core/subscription/subscription_updater_impl.cc --- a/components/adblock/core/subscription/subscription_updater_impl.cc +++ b/components/adblock/core/subscription/subscription_updater_impl.cc @@ -4454,6 +4498,3775 @@ diff --git a/components/resources/adblocking/elemhideemu.jst b/components/resour elemHideEmulation.apply(elemHidingEmulatedPatterns); +})() +diff --git a/components/resources/adblocking/snippets/dist/isolated-first-xpath3.jst b/components/resources/adblocking/snippets/dist/isolated-first-xpath3.jst +new file mode 100644 +--- /dev/null ++++ b/components/resources/adblocking/snippets/dist/isolated-first-xpath3.jst +@@ -0,0 +1,62 @@ ++(e, ...t) => { ++/*! ++ * This file is part of eyeo's Anti-Circumvention Snippets module (@eyeo/snippets), ++ * Copyright (C) 2006-present eyeo GmbH ++ * ++ * @eyeo/snippets is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 3 as ++ * published by the Free Software Foundation. ++ * ++ * @eyeo/snippets is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with @eyeo/snippets. If not, see . ++ */ ++ ((environment, ...filters) => { ++const e=Proxy,{apply:t,bind:n,call:o}=Function,r=o.bind(t),i=o.bind(n),s=o.bind(o),a={get:(e,t)=>i(o,e[t])},c=t=>new e(t,a),l={get:(e,t)=>i(e[t],e)},u=t=>new e(t,l),{assign:d,defineProperties:h,freeze:f,getOwnPropertyDescriptor:p,getOwnPropertyDescriptors:w,getPrototypeOf:m}=u(Object),{hasOwnProperty:g}=c({}),{species:b}=Symbol,y={get(e,t){const n=e[t];class o extends n{}const r=w(n.prototype);delete r.constructor,f(h(o.prototype,r));const i=w(n);return delete i.length,delete i.prototype,i[b]={value:o},f(h(o,i))}},v=t=>new e(t,y),S="undefined"!=typeof environment?environment:{};"undefined"==typeof globalThis&&(window.globalThis=window);const{apply:k,ownKeys:E}=u(Reflect),x="world"in S,M=x&&"ISOLATED"===S.world,C=x&&"MAIN"===S.world,T="object"==typeof chrome&&!!chrome.runtime,W="object"==typeof browser&&!!browser.runtime,L=!C&&(M||T||W),O=e=>L?e:P(e,R(e)),{create:P,defineProperties:D,defineProperty:N,freeze:A,getOwnPropertyDescriptor:I,getOwnPropertyDescriptors:R}=u(Object),V=u(globalThis),$=L?globalThis:v(globalThis),{Map:H,RegExp:_,Set:j,WeakMap:X,WeakSet:F}=$,q=(e,t,n=null)=>{const o=E(t);for(const r of E(e)){if(o.includes(r))continue;const i=I(e,r);if(n&&"value"in i){const{value:e}=i;"function"==typeof e&&(i.value=n(e))}N(t,r,i)}},B=e=>{const t=$[e];class n extends t{}const{toString:o,valueOf:r}=t.prototype;D(n.prototype,{toString:{value:o},valueOf:{value:r}});const i=e.toLowerCase(),s=e=>function(){const t=k(e,this,arguments);return typeof t===i?new n(t):t};return q(t,n,s),q(t.prototype,n.prototype,s),n},z=A({frozen:new X,hidden:new F,iframePropertiesToAbort:{read:new j,write:new j},abortedIframes:new X}),U=new _("^[A-Z]");var G=new Proxy(new H([["chrome",L&&(T&&chrome||W&&browser)||void 0],["isExtensionContext",L],["variables",z],["console",O(console)],["document",globalThis.document],["performance",O(performance)],["JSON",O(JSON)],["Map",H],["Math",O(Math)],["Number",L?Number:B("Number")],["RegExp",_],["Set",j],["String",L?String:B("String")],["WeakMap",X],["WeakSet",F],["MouseEvent",MouseEvent]]),{get(e,t){if(e.has(t))return e.get(t);let n=globalThis[t];return"function"==typeof n&&(n=(U.test(t)?$:V)[t]),e.set(t,n),n},has:(e,t)=>e.has(t)});const J={WeakSet:WeakSet,WeakMap:WeakMap,WeakValue:class{has(){return!1}set(){}}},{apply:Q}=Reflect;const{Map:Y,WeakMap:K,WeakSet:Z,setTimeout:ee}=G;let te=!0,ne=e=>{e.clear(),te=!te};var oe=function(e){const{WeakSet:t,WeakMap:n,WeakValue:o}=this||J,r=new t,i=new n,s=new o;return function(t){if(r.has(t))return t;if(i.has(t))return i.get(t);if(s.has(t))return s.get(t);const n=Q(e,this,arguments);return r.add(n),n!==t&&("object"==typeof t&&t?i:s).set(t,n),n}}.bind({WeakMap:K,WeakSet:Z,WeakValue:class extends Y{set(e,t){return te&&(te=!te,ee(ne,0,this)),super.set(e,t)}}});const{concat:re,includes:ie,join:se,reduce:ae,unshift:ce}=c([]),le=v(globalThis),{Map:ue,WeakMap:de}=le,he=new ue,fe=t=>{const n=(e=>{const t=[];let n=e;for(;n;){if(he.has(n))ce(t,he.get(n));else{const e=w(n);he.set(n,e),ce(t,e)}n=m(n)}return ce(t,{}),r(d,null,t)})("function"==typeof t?t.prototype:t),o={get(e,t){if(t in n){const{value:o,get:r}=n[t];if(r)return s(r,e);if("function"==typeof o)return i(o,e)}return e[t]},set(e,t,o){if(t in n){const{set:r}=n[t];if(r)return s(r,e,o),!0}return e[t]=o,!0}};return t=>new e(t,o)},{isExtensionContext:pe,Array:we,Number:me,String:ge,Object:be}=G,{isArray:ye}=we,{getOwnPropertyDescriptor:ve,setPrototypeOf:Se}=be,{toString:ke}=be.prototype,{slice:Ee}=ge.prototype,{get:xe}=ve(Node.prototype,"nodeType"),Me=pe?{}:{Attr:fe(Attr),CanvasRenderingContext2D:fe(CanvasRenderingContext2D),CSSStyleDeclaration:fe(CSSStyleDeclaration),Document:fe(Document),Element:fe(Element),HTMLCanvasElement:fe(HTMLCanvasElement),HTMLElement:fe(HTMLElement),HTMLImageElement:fe(HTMLImageElement),HTMLScriptElement:fe(HTMLScriptElement),MutationRecord:fe(MutationRecord),Node:fe(Node),ShadowRoot:fe(ShadowRoot),get CSS2Properties(){return Me.CSSStyleDeclaration}},Ce=(e,t)=>{if("Element"!==t&&t in Me)return Me[t](e);if(ye(e))return Se(e,we.prototype);const n=(e=>s(Ee,s(ke,e),8,-1))(e);if(n in Me)return Me[n](e);if(n in G)return Se(e,G[n].prototype);if("nodeType"in e)switch(s(xe,e)){case 1:if(!(t in Me))throw new Error("unknown hint "+t);return Me[t](e);case 2:return Me.Attr(e);case 3:return Me.Node(e);case 9:return Me.Document(e)}throw new Error("unknown brand "+n)};var Te=pe?e=>e===window||e===globalThis?G:e:oe(((e,t="Element")=>{if(e===window||e===globalThis)return G;switch(typeof e){case"object":return e&&Ce(e,t);case"string":return new ge(e);case"number":return new me(e);default:throw new Error("unsupported value")}}));let{document:We,getComputedStyle:Le,isExtensionContext:Oe,variables:Pe,Array:De,MutationObserver:Ne,Object:Ae,XPathEvaluator:Ie,XPathExpression:Re,XPathResult:Ve}=Te(window),{querySelectorAll:$e}=We,He=$e&&i($e,We);const{assign:_e,setPrototypeOf:je}=Ae;class Xe extends Re{evaluate(...e){return je(r(super.evaluate,this,e),Ve.prototype)}}class Fe extends Ie{createExpression(...e){return je(r(super.createExpression,this,e),Xe.prototype)}}function qe(e){if(Pe.hidden.has(e))return;!function(e){Oe&&"function"==typeof checkElement&&checkElement(e)}(e),Pe.hidden.add(e);let{style:t}=Te(e),n=Te(t,"CSSStyleDeclaration"),o=Te([]),{debugCSSProperties:r}=S;for(let[e,t]of r||[["display","none"]])n.setProperty(e,t,"important"),o.push([e,n.getPropertyValue(e)]);new Ne((()=>{for(let[e,t]of o){let o=n.getPropertyValue(e),r=n.getPropertyPriority(e);o==t&&"important"==r||n.setProperty(e,t,"important")}})).observe(e,{attributes:!0,attributeFilter:["style"]})}function Be(e){let t=e;if(t.startsWith("xpath(")&&t.endsWith(")")){let e=t.slice(6,-1),n=(new Fe).createExpression(e,null),o=Ve.ORDERED_NODE_SNAPSHOT_TYPE;return e=>{if(!e)return;let t=n.evaluate(We,o,null),{snapshotLength:r}=t;for(let n=0;nHe(e).forEach(t)}function ze(e,t,n,o){let r;null==n&&(n=t);const i=()=>{for(const i of He(n)){const n=Te(i).closest(t);n&&e(i,n)&&(r(),qe(n),"function"==typeof o&&o(n))}};return _e(new Ne(i),{race(e){r=e,this.observe(We,{childList:!0,characterData:!0,subtree:!0}),i()}})}function Ue(e,t,n){let o=Te(t,"CSSStyleDeclaration");if("none"==o.getPropertyValue("display"))return!1;let r=o.getPropertyValue("visibility");if("hidden"==r||"collapse"==r)return!1;if(!n||e==n)return!0;let i=Te(e).parentElement;return!i||Ue(i,Le(i),n)}function Ge(e){let t=Le(e),{cssText:n}=t;if(n)return n;for(let e of t)n+=`${e}: ${t[e]}; `;return Te(n).trim()}let{Math:Je,RegExp:Qe}=Te(window);function Ye(e){let{length:t}=e;if(t>1&&"/"===e[0]){let n="/"===e[t-1];if(n||t>2&&Te(e).endsWith("/i")){let t=[Te(e).slice(1,n?-1:-2)];return n||t.push("i"),new Qe(...t)}}return new Qe(Te(e).replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"))}let Ke=!1;function Ze(){return Ke}const{console:et}=Te(window),tt=()=>{};function nt(...e){Ze()&&Te(e).unshift("%c DEBUG","font-weight: bold"),et.log(...e)}function ot(e){return i(Ze()?nt:tt,null,e)}let{Array:rt,Error:it,Map:st,parseInt:at}=Te(window),ct=null,lt=null;function ut(e,t){if(null===ct)return tt;let n=ct,{participants:o}=n;return o.set(r,t),r;function r(){if(n.winners<1)return;if(ot("race")(`${e} won the race`),n===ct)lt.push(r);else if(o.delete(r),--n.winners<1){for(let e of o.values())e();o.clear()}}}const dt={get(e,t){const n=e;for(;!g(e,t);)e=m(e);const{get:o,set:i}=p(e,t);return function(){return arguments.length?r(i,n,arguments):s(o,n)}}};var ht;function ft(e,t,n){var o,r;n?"load"===n?(e("Waiting until window.load"),window.onload=()=>{e("Window.load fired."),t()}):"loading"===n||"interactive"===n||"complete"===n?(e("Waiting document state until :",n),document.onreadystatechange=()=>{e("Document state changed:",document.readyState),document.readyState===n&&t()}):(e("Waiting until ",n," event is triggered on document"),(o=document,r=n,new Promise((e=>{const t=()=>{o.removeEventListener(r,t),e()};o.addEventListener(r,t)}))).then((()=>{e(n," is triggered on document, starting the snippet"),t()})).catch((t=>{e("There was an error while waiting for the event.",t)}))):t()}Te(window),ht=window,new e(ht,dt),Te(/^\d+$/);let{MutationObserver:pt,WeakSet:wt,getComputedStyle:mt}=Te(window);let{clearTimeout:gt,fetch:bt,getComputedStyle:yt,setTimeout:vt,Map:St,MutationObserver:kt,Uint8Array:Et}=Te(window);let xt=new St;function Mt(e,{as:t="arrayBuffer",cleanup:n=6e4}={}){let o=t+":"+e,r=xt.get(o)||{remove:()=>xt.delete(o),result:null,timer:0};return gt(r.timer),r.timer=vt(r.remove,n),r.result||(r.result=bt(e).then((e=>e[t]())).catch(r.remove),xt.set(o,r)),r.result}function Ct(e){return e.reduce(((e,t)=>e+function(e,t=2){let n=Te(e).toString(16);return n.length{const n=e.length+1,o=t.length+1,r=[[0]];let i=0,s=0;for(;++i"{mark(){},end(){}}"};function zt(e,t=10){return Bt}let{MutationObserver:Ut,WeakSet:Gt}=Te(window);const{ELEMENT_NODE:Jt}=Node;let{MutationObserver:Qt,WeakSet:Yt}=Te(window);const{ELEMENT_NODE:Kt}=Node;let{parseInt:Zt,setTimeout:en,Error:tn,MouseEvent:nn,MutationObserver:on,WeakSet:rn}=Te(window);let{parseInt:sn,setTimeout:an,Error:cn,MouseEvent:ln,MutationObserver:un,WeakSet:dn}=Te(window);const hn=["auxclick","click","dblclick","gotpointercapture","lostpointercapture","mouseenter","mousedown","mouseleave","mousemove","mouseout","mouseover","mouseup","pointerdown","pointerenter","pointermove","pointerover","pointerout","pointerup","pointercancel","pointerleave"];const fn={log:nt,race:function(e,t="1"){switch(e){case"start":ct={winners:at(t,10)||1,participants:new st},lt=new rt;break;case"end":case"finish":case"stop":ct=null;for(let e of lt)e();lt=null;break;default:throw new it(`Invalid action: ${e}`)}},debug:function(){Ke=!0},"hide-if-matches-xpath":function(e,t){const{mark:n,end:o}=zt(),r=ot("hide-if-matches-xpath"),i=t=>{const i=Be(`xpath(${e})`),s=new Gt,a=()=>{n(),i((t=>{if(s.has(t))return!1;s.add(t),l(),Te(t).nodeType===Jt?qe(t):Te(t).textContent="",r("Matched: ",t," for selector: ",e)})),o()},c=new Ut(a),l=ut("hide-if-matches-xpath",(()=>c.disconnect()));c.observe(t,{characterData:!0,childList:!0,subtree:!0}),a()};if(t){let e,n=0;const o=Be(`xpath(${t})`),r=()=>{o((e=>{i(e),n++})),n>0&&e.disconnect()};e=new Ut(r),e.observe(document,{characterData:!0,childList:!0,subtree:!0}),r()}else i(document)},"hide-if-matches-computed-xpath":function(e,t,n,o){const{mark:r,end:i}=zt(),s=ot("hide-if-matches-computed-xpath");if(!t||!e)return void s("No query or searchQuery provided.");const a=t=>{const n=(t=>e.replace("{{}}",t))(t);s("Starting hiding elements that match query: ",n);const o=Be(`xpath(${n})`),a=new Yt,c=()=>{r(),o((t=>{if(a.has(t))return!1;a.add(t),u(),Te(t).nodeType===Kt?qe(t):Te(t).textContent="",s("Matched: ",t," for selector: ",e)})),i()},l=new Qt(c),u=ut("hide-if-matches-computed-xpath",(()=>l.disconnect()));l.observe(document,{characterData:!0,childList:!0,subtree:!0}),c()},c=Ye(n);ft(s,(()=>{if(t){s("Started searching for: ",t);const e=new Yt;let n;const o=Be(`xpath(${t})`),r=()=>{o((t=>{if(e.has(t))return!1;if(e.add(t),s("Found node: ",t),t.innerHTML){s("Searching in: ",t.innerHTML);const e=t.innerHTML.match(c);if(e&&e.length){let t="";t=e[1]?e[1]:e[0],s("Matched search query: ",t),a(t)}}}))};n=new Qt(r),n.observe(document,{characterData:!0,childList:!0,subtree:!0}),r()}}),o)},"hide-if-contains":function(e,t="*",n=null){const o=ot("hide-if-contains");let r=Ye(e);const i=ze((e=>r.test(Te(e).textContent)),t,n,(e=>{o("Matched: ",e," for selector: ",t,n)}));i.race(ut("hide-if-contains",(()=>{i.disconnect()})))},"hide-if-contains-similar-text":function(e,t,n=null,o=0,r=0){const i=new Ot,s=ot("hide-if-contains-similar-text"),a=Te(e),{length:c}=a,l=c+Tt(o)||0,u=Te([...a]).sort(),d=Tt(r)||1/0;null==n&&(n=t),s("Looking for similar text: "+a);const h=()=>{for(const e of He(n)){if(i.has(e))continue;i.add(e);const{innerText:n}=Te(e),r=Pt(d,n.length-l+1);for(let i=0;if.disconnect()));f.observe(document,{childList:!0,characterData:!0,subtree:!0}),h()},"hide-if-contains-visible-text":function(e,t,n=null,...o){let r=Te([]);const i=new At([["-snippet-box-margin","2"],["-disable-bg-color-check","false"],["-check-is-contained","false"]]);for(let e of o){e=Te(e);let t=e.indexOf(":");if(t<0)continue;let n=e.slice(0,t).trim().toString(),o=e.slice(t+1).trim().toString();n&&o&&(i.has(n)?i.set(n,o):r.push([n,o]))}let s=Te([["opacity","0"],["font-size","0px"],["color","rgba(0, 0, 0, 0)"]]),a=new At(s.concat(r));function c(e,t,{bgColorCheck:n=!0}={}){t||(t=Nt(e)),t=Te(t);for(const[e,n]of a){if(Ye(n).test(t.getPropertyValue(e)))return!1}let o=t.getPropertyValue("color");return!n||t.getPropertyValue("background-color")!=o}function l(e,t,{bgColorCheck:n=!0}={}){let o=Nt(e,t);if(!Ue(e,o)||!c(e,o,{bgColorCheck:n}))return"";let{content:r}=Te(o);if(r&&"none"!==r){let t=Te([]);return r=Te(r).trim().replace(/(["'])(?:(?=(\\?))\2.)*?\1/g,(e=>""+(t.push(Te(e).slice(1,-1))-1))),r=r.replace(/\s*attr\(\s*([^\s,)]+)[^)]*?\)\s*/g,((t,n)=>Te(e).getAttribute(n)||"")),r.replace(/\x01(\d+)/g,((e,n)=>t[n]))}return""}function u(e,t,{boxMargin:n=2}={}){const o=Te(e).getBoundingClientRect(),r=Te(t).getBoundingClientRect(),i=r.left-n,s=r.right+n,a=r.top-n,c=r.bottom+n;return i<=o.left&&o.left<=s&&a<=o.top&&o.top<=c&&a<=o.bottom&&o.bottom<=c&&i<=o.right&&o.right<=s}function d(e,t,n,o,r,{boxMargin:i=2,bgColorCheck:s,checkIsContained:a}={}){let h=!n;if(h&&(n=Nt(e)),!Ue(e,n,h&&t))return"";o||"hidden"!==Te(n).getPropertyValue("overflow-x")&&"hidden"!==Te(n).getPropertyValue("overflow-y")||(o=e);let f=l(e,":before",{bgColorCheck:s});for(let t of Te(e).childNodes)switch(Te(t).nodeType){case Vt:f+=d(t,e,Nt(t),o,r,{boxMargin:i,bgColorCheck:s,checkIsContained:a});break;case $t:if(o)u(e,o,{boxMargin:i})&&c(e,n,{bgColorCheck:s})&&(f+=Te(t).nodeValue);else if(c(e,n,{bgColorCheck:s})){if(a&&!u(e,r,{boxMargin:i}))continue;f+=Te(t).nodeValue}}return f+l(e,":after",{bgColorCheck:s})}const h=i.get("-snippet-box-margin"),f=Rt(h)||0,p=!("true"===i.get("-disable-bg-color-check")),w="true"===i.get("-check-is-contained");let m=Ye(e),g=new It;const b=ze(((e,t)=>{if(g.has(e))return!1;g.add(e);let n=d(e,t,null,null,e,{boxMargin:f,bgColorCheck:p,checkIsContained:w}),o=m.test(n);return Ze()&&n.length&&nt(o,m,n),o}),t,n);b.race(ut("hide-if-contains-visible-text",(()=>{b.disconnect()})))},"hide-if-contains-and-matches-style":function(e,t="*",n=null,o=null,r=null,i,s=null,a=null){const c=ot("hide-if-contains-and-matches-style"),l=new wt;null==n&&(n=t);const u=Ye(e),d=o?Ye(o):null,h=r?Ye(r):null,f=()=>{const e=()=>{if(!(s&&window.innerWidtha))for(const e of He(n))if(!l.has(e)&&u.test(Te(e).textContent))if(!h||h.test(Ge(e))){const n=Te(e).closest(t);if(!n)continue;!d||d.test(Ge(n))?(r(),qe(n),l.add(e),c("Matched: ",n,"which contains: ",e," for params: ",...arguments)):c("In this element the searchStyle matched but style didn't:\n",n,mt(n),...arguments)}else c("In this element the searchStyle didn't match:\n",e,mt(e),...arguments)},o=new pt(e),r=ut("hide-if-contains-and-matches-style",(()=>o.disconnect()));o.observe(document,{childList:!0,characterData:!0,subtree:!0}),e()};ft(c,f,i)},"hide-if-has-and-matches-style":function(e,t="*",n=null,o=null,r=null,i=null,s=null,a=null){const c=ot("hide-if-has-and-matches-style"),l=new _t;null==n&&(n=t);const u=o?Ye(o):null,d=r?Ye(r):null,h=()=>{const o=()=>{if(!(s&&window.innerWidtha))for(const o of He(n))if(!l.has(o))if(!Te(o).querySelector(e)||d&&!d.test(Ge(o)))c("In this element the searchStyle didn't match:\n",o,jt(o),...arguments);else{const e=Te(o).closest(t);!e||u&&!u.test(Ge(e))?c("In this element the searchStyle matched but style didn't:\n",e,jt(e),...arguments):(i(),qe(e),l.add(o),c("Matched: ",e,"which contains: ",o," for params: ",...arguments))}},r=new Ht(o),i=ut("hide-if-has-and-matches-style",(()=>r.disconnect()));r.observe(document,{childList:!0,subtree:!0}),o()};ft(c,h,i)},"hide-if-labelled-by":function(e,t,n=null){let o=null==n,r=Ye(e),i=new qt,s=()=>{for(let e of He(t)){let t=o?e:Te(e).closest(n);if(!t||!Ue(e,Xt(e),t))continue;let s=Te(e).getAttribute("aria-labelledby"),a=()=>{i.has(t)||r.test(Te(e).getAttribute("aria-label")||"")&&(c(),i.add(t),qe(t))};if(s)for(let e of Te(s).split(/\s+/)){let n=Te(document).getElementById(e);n?!i.has(n)&&r.test(n.innerText)&&(c(),i.add(n),qe(t)):a()}else a()}},a=new Ft(s),c=ut("hide-if-labelled-by",(()=>a.disconnect()));a.observe(document,{characterData:!0,childList:!0,subtree:!0}),s()},"hide-if-contains-image":function(e,t,n){null==n&&(n=t);let o=Ye(e);const r=ot("hide-if-contains-image");let i=()=>{for(let e of He(n)){let n=yt(e),i=Te(n["background-image"]).match(/^url\("(.*)"\)$/);i&&Mt(i[1]).then((n=>{if(o.test(Ct(new Et(n)))){let n=Te(e).closest(t);n&&(a(),qe(n),r("Matched: ",n," for:",...arguments))}}))}},s=new kt(i),a=ut("hide-if-contains-image",(()=>s.disconnect()));s.observe(document,{childList:!0,subtree:!0}),i()},"simulate-event-poc":function(e,t,n="0"){if(!e)throw new tn("[simulate-event snippet]: No event type provided.");if(!t)throw new tn("[simulate-event snippet]: No selector provided.");let o=Be(t),r=Zt(n,10),i=new rn;function s(){o((t=>{i.has(t)||(i.add(t),en((()=>{Te(t).dispatchEvent(new nn(e,{bubbles:!0,cancelable:!0}))}),r))}))}new on(s).observe(document,{childList:!0,subtree:!0}),s()},"simulate-mouse-event":function(...e){const t=ot("simulate-mouse-event");if(e.length<1)throw new cn("[simulate-mouse-event snippet]: No selector provided.");e.length>7&&(e=e.slice(0,7));const n=Te([]);function o(){return n.forEach((e=>{if(!e.found){(function(e){let t=e;if(t.startsWith("xpath(")&&t.endsWith(")")){let t=Be(e);return()=>{let e=Te([]);return t((t=>e.push(t))),e}}return()=>De.from(He(e))})(e.selector)().length>0&&(e.found=!0)}})),n.every((e=>e.found))}function r(e,n,o){e&&n&&("click"===n&&e.click?(e.click(),t("Clicked on this node:\n",e,"\nwith a delay of",o,"ms")):(e.dispatchEvent(new ln(n,{bubbles:!0,cancelable:!0})),t("A",n,"event was dispatched with a delay of",o,"ms on this node:\n",e)))}Te(e).forEach((e=>{const o=function(e){if(!e)return null;const n={selector:"",continue:!1,trigger:!1,event:"click",delay:"500",clicked:!1,found:!1},o=e.split("$");let r=[];o.length>=2&&(r=o[1].toLowerCase().split(",")),[n.selector]=o;for(const e of r)if("trigger"===e)n.trigger=!0;else if("continue"===e)n.continue=!0;else if(e.startsWith("event")){const t=e.toLowerCase().split("=");t[1]?n.event=t[1]:n.event="click"}else if(e.startsWith("delay")){const t=e.toLowerCase().split("=");t[1]?n.delay=t[1]:n.delay="500"}return hn.includes(n.event)||t(n.event," might be misspelled, check for typos.\n","These are the supported events:",hn),n}(e);n.push(o)}));let i=!1;const[s]=n.slice(-1);s.trigger=!0;let a=new dn;function c(){if(i||(i=o()),i)for(const e of n){const t=Be(e.selector),n=sn(e.delay,10);e.trigger&&t((t=>{a.has(t)||(a.add(t),e.continue?setInterval((()=>{r(t,e.event,e.delay)}),n):an((()=>{r(t,e.event,e.delay)}),n))}))}}new un(c).observe(document,{childList:!0,subtree:!0}),c()}};let{MutationObserver:pn}=Te(window);const{ELEMENT_NODE:wn}=Node;fn["hide-if-matches-xpath3"]=function(e,t){let{mark:n,end:o}=zt();function r(){return fontoxpath.evaluateXPathToNodes(e,document,null,null,{language:fontoxpath.evaluateXPath.XQUERY_3_1_LANGUAGE})}let i=ot("hide-if-matches-xpath3");const s=t=>{const s=new WeakSet,a=()=>{n();const t=r();for(const n of Te(t)){if(s.has(n))return!1;s.add(n),l(),Te(n).nodeType===wn?qe(n):Te(n).textContent="",i("Matched: ",n," for selector: ",e)}o()},c=new pn(a),l=ut("hide-if-matches-xpath3",(()=>c.disconnect()));c.observe(t,{characterData:!0,childList:!0,subtree:!0}),a()};if(t){let e,t=0;const n=r(),o=()=>{for(const e of Te(n))s(e),t++;t>0&&e.disconnect()};e=new pn(o),e.observe(document,{characterData:!0,childList:!0,subtree:!0}),o()}else s(document)}; ++const snippets=fn; ++let context; ++for (const [name, ...args] of filters) { ++if (snippets.hasOwnProperty(name)) { ++try { context = snippets[name].apply(context, args); } ++catch (error) { console.error(error); } ++} ++} ++context = void 0; ++})(e, ...t); ++ ++const callback = (environment, ...filters) => { ++const e=Proxy,{apply:t,bind:r,call:n}=Function,o=n.bind(t),i=n.bind(r),s=n.bind(n),a={get:(e,t)=>i(n,e[t])},l=t=>new e(t,a),c=(t,r)=>new e(t,{apply:(e,t,n)=>o(r,t,n)}),u={get:(e,t)=>i(e[t],e)},f=t=>new e(t,u),{assign:p,defineProperties:d,freeze:h,getOwnPropertyDescriptor:w,getOwnPropertyDescriptors:g,getPrototypeOf:y}=f(Object),{hasOwnProperty:m}=l({}),{species:b}=Symbol,v={get(e,t){const r=e[t];class n extends r{}const o=g(r.prototype);delete o.constructor,h(d(n.prototype,o));const i=g(r);return delete i.length,delete i.prototype,i[b]={value:n},h(d(n,i))}},E=t=>new e(t,v),S="undefined"!=typeof environment?environment:{};"undefined"==typeof globalThis&&(window.globalThis=window);const{apply:M,ownKeys:T}=f(Reflect),x="world"in S,O=x&&"ISOLATED"===S.world,P=x&&"MAIN"===S.world,j="object"==typeof chrome&&!!chrome.runtime,N="object"==typeof browser&&!!browser.runtime,L=!P&&(O||j||N),k=e=>L?e:C(e,H(e)),{create:C,defineProperties:A,defineProperty:W,freeze:$,getOwnPropertyDescriptor:D,getOwnPropertyDescriptors:H}=f(Object),z=f(globalThis),R=L?globalThis:E(globalThis),{Map:F,RegExp:I,Set:J,WeakMap:V,WeakSet:B}=R,U=(e,t,r=null)=>{const n=T(t);for(const o of T(e)){if(n.includes(o))continue;const i=D(e,o);if(r&&"value"in i){const{value:e}=i;"function"==typeof e&&(i.value=r(e))}W(t,o,i)}},_=e=>{const t=R[e];class r extends t{}const{toString:n,valueOf:o}=t.prototype;A(r.prototype,{toString:{value:n},valueOf:{value:o}});const i=e.toLowerCase(),s=e=>function(){const t=M(e,this,arguments);return typeof t===i?new r(t):t};return U(t,r,s),U(t.prototype,r.prototype,s),r},X=$({frozen:new V,hidden:new B,iframePropertiesToAbort:{read:new J,write:new J},abortedIframes:new V}),q=new I("^[A-Z]");var G=new Proxy(new F([["chrome",L&&(j&&chrome||N&&browser)||void 0],["isExtensionContext",L],["variables",X],["console",k(console)],["document",globalThis.document],["performance",k(performance)],["JSON",k(JSON)],["Map",F],["Math",k(Math)],["Number",L?Number:_("Number")],["RegExp",I],["Set",J],["String",L?String:_("String")],["WeakMap",V],["WeakSet",B],["MouseEvent",MouseEvent]]),{get(e,t){if(e.has(t))return e.get(t);let r=globalThis[t];return"function"==typeof r&&(r=(q.test(t)?R:z)[t]),e.set(t,r),r},has:(e,t)=>e.has(t)});const K={WeakSet:WeakSet,WeakMap:WeakMap,WeakValue:class{has(){return!1}set(){}}},{apply:Y}=Reflect;const{Map:Z,WeakMap:Q,WeakSet:ee,setTimeout:te}=G;let re=!0,ne=e=>{e.clear(),re=!re};var oe=function(e){const{WeakSet:t,WeakMap:r,WeakValue:n}=this||K,o=new t,i=new r,s=new n;return function(t){if(o.has(t))return t;if(i.has(t))return i.get(t);if(s.has(t))return s.get(t);const r=Y(e,this,arguments);return o.add(r),r!==t&&("object"==typeof t&&t?i:s).set(t,r),r}}.bind({WeakMap:Q,WeakSet:ee,WeakValue:class extends Z{set(e,t){return re&&(re=!re,te(ne,0,this)),super.set(e,t)}}});const{concat:ie,includes:se,join:ae,reduce:le,unshift:ce}=l([]),ue=E(globalThis),{Map:fe,WeakMap:pe}=ue,de=new fe,he=t=>{const r=(e=>{const t=[];let r=e;for(;r;){if(de.has(r))ce(t,de.get(r));else{const e=g(r);de.set(r,e),ce(t,e)}r=y(r)}return ce(t,{}),o(p,null,t)})("function"==typeof t?t.prototype:t),n={get(e,t){if(t in r){const{value:n,get:o}=r[t];if(o)return s(o,e);if("function"==typeof n)return i(n,e)}return e[t]},set(e,t,n){if(t in r){const{set:o}=r[t];if(o)return s(o,e,n),!0}return e[t]=n,!0}};return t=>new e(t,n)},{isExtensionContext:we,Array:ge,Number:ye,String:me,Object:be}=G,{isArray:ve}=ge,{getOwnPropertyDescriptor:Ee,setPrototypeOf:Se}=be,{toString:Me}=be.prototype,{slice:Te}=me.prototype,{get:xe}=Ee(Node.prototype,"nodeType"),Oe=we?{}:{Attr:he(Attr),CanvasRenderingContext2D:he(CanvasRenderingContext2D),CSSStyleDeclaration:he(CSSStyleDeclaration),Document:he(Document),Element:he(Element),HTMLCanvasElement:he(HTMLCanvasElement),HTMLElement:he(HTMLElement),HTMLImageElement:he(HTMLImageElement),HTMLScriptElement:he(HTMLScriptElement),MutationRecord:he(MutationRecord),Node:he(Node),ShadowRoot:he(ShadowRoot),get CSS2Properties(){return Oe.CSSStyleDeclaration}},Pe=(e,t)=>{if("Element"!==t&&t in Oe)return Oe[t](e);if(ve(e))return Se(e,ge.prototype);const r=(e=>s(Te,s(Me,e),8,-1))(e);if(r in Oe)return Oe[r](e);if(r in G)return Se(e,G[r].prototype);if("nodeType"in e)switch(s(xe,e)){case 1:if(!(t in Oe))throw new Error("unknown hint "+t);return Oe[t](e);case 2:return Oe.Attr(e);case 3:return Oe.Node(e);case 9:return Oe.Document(e)}throw new Error("unknown brand "+r)};var je=we?e=>e===window||e===globalThis?G:e:oe(((e,t="Element")=>{if(e===window||e===globalThis)return G;switch(typeof e){case"object":return e&&Pe(e,t);case"string":return new me(e);case"number":return new ye(e);default:throw new Error("unsupported value")}}));const Ne={get(e,t){const r=e;for(;!m(e,t);)e=y(e);const{get:n,set:i}=w(e,t);return function(){return arguments.length?o(i,r,arguments):s(n,r)}}},Le=t=>new e(t,Ne);let ke=!1;function Ce(){return ke}const{console:Ae}=je(window),We=()=>{};function $e(...e){Ce()&&je(e).unshift("%c DEBUG","font-weight: bold"),Ae.log(...e)}function De(e){return i(Ce()?$e:We,null,e)}let{Math:He,RegExp:ze}=je(window);function Re(e){let{length:t}=e;if(t>1&&"/"===e[0]){let r="/"===e[t-1];if(r||t>2&&je(e).endsWith("/i")){let t=[je(e).slice(1,r?-1:-2)];return r||t.push("i"),new ze(...t)}}return new ze(je(e).replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"))}function Fe(){return je(He.floor(2116316160*He.random()+60466176)).toString(36)}let{parseFloat:Ie,variables:Je,Array:Ve,Error:Be,Map:Ue,Object:_e,ReferenceError:Xe,Set:qe,WeakMap:Ge}=je(window),{onerror:Ke}=Le(window),Ye=Node.prototype,Ze=Element.prototype,Qe=null;function et(e,t,r,n=!0){let o=je(t),i=o.indexOf(".");if(-1==i){let o=_e.getOwnPropertyDescriptor(e,t);if(o&&!o.configurable)return;let i=_e.assign({},r,{configurable:n});if(!o&&!i.get&&i.set){let r=e[t];i.get=()=>r}return void _e.defineProperty(e,t,i)}let s=o.slice(0,i).toString();t=o.slice(i+1).toString();let a=e[s];!a||"object"!=typeof a&&"function"!=typeof a||et(a,t,r);let l=_e.getOwnPropertyDescriptor(e,s);if(l&&!l.configurable)return;Qe||(Qe=new Ge),Qe.has(e)||Qe.set(e,new Ue);let c=Qe.get(e);if(c.has(s))return void c.get(s).set(t,r);let u=new Ue([[t,r]]);c.set(s,u),_e.defineProperty(e,s,{get:()=>a,set(e){if(a=e,a&&("object"==typeof a||"function"==typeof a))for(let[e,t]of u)et(a,e,t)},configurable:n})}function tt(e){let t=Ke();Ke(((...r)=>{let n=r.length&&r[0];return!("string"!=typeof n||!je(n).includes(e))||("function"==typeof t?o(t,this,r):void 0)}))}function rt(e,t,r,n=!0){let o=De(e);if(!r)return void o("no property to abort on read");let i=Fe();o(`aborting on ${r} access`),et(t,r,{get:function(){throw o(`${r} access aborted`),new Xe(i)},set(){}},n),tt(i)}function nt(e,t,r,n=!0){let o=De(e);if(!r)return void o("no property to abort on write");let i=Fe();o(`aborting when setting ${r}`),et(t,r,{set:function(){throw o(`setting ${r} aborted`),new Xe(i)}},n),tt(i)}function ot(e,t=!1,r=!1){let n=Je.abortedIframes,i=Je.iframePropertiesToAbort;for(let o of Ve.from(window.frames))if(n.has(o))for(let i of e)t&&n.get(o).read.add(i),r&&n.get(o).write.add(i);for(let n of e)t&&i.read.add(n),r&&i.write.add(n);function a(){for(let e of Ve.from(window.frames)){n.has(e)||n.set(e,{read:new qe(i.read),write:new qe(i.write)});let t=n.get(e).read;if(t.size>0){let r=Ve.from(t);t.clear();for(let t of r)rt("abort-on-iframe-property-read",e,t)}let r=n.get(e).write;if(r.size>0){let t=Ve.from(r);r.clear();for(let r of t)nt("abort-on-iframe-property-write",e,r)}}}a(),n.has(document)||(n.set(document,!0),function(e){let t;function r(e,t){for(let r of t){et(e,r,n(e,r))}}function n(t,r){let n=t[r];return{get:()=>function(...t){let r;return r=o(n,this,t),e&&e(),r}}}function i(t,r){let n=_e.getOwnPropertyDescriptor(t,r),{set:o}=n||{};return{set(t){let r;return r=s(o,this,t),e&&e(),r}}}r(Ye,["appendChild","insertBefore","replaceChild"]),r(Ze,["append","prepend","replaceWith","after","before","insertAdjacentElement","insertAdjacentHTML"]),t=i(Ze,"innerHTML"),et(Ze,"innerHTML",t),t=i(Ze,"outerHTML"),et(Ze,"outerHTML",t)}(a))}let{Object:it}=window;function st(e,t){if(!(e instanceof it))return;let r=e,n=je(t).split(".");if(0===n.length)return;for(let e=0;e{};case"trueFunc":return()=>!0;case"falseFunc":return()=>!1;case"emptyArray":return[];case"emptyObj":return{};case"undefined":return;case"":return e;default:if(at.test(e))return Ie(e);throw new Be(`[override-property-read snippet]: Value "${e}" is not valid.`)}}let{HTMLScriptElement:ct,Object:ut,ReferenceError:ft}=je(window),pt=ut.getPrototypeOf(ct);let{Error:dt}=je(window),{cookie:ht}=Le(document);let{document:wt,getComputedStyle:gt,isExtensionContext:yt,variables:mt,Array:bt,MutationObserver:vt,Object:Et,XPathEvaluator:St,XPathExpression:Mt,XPathResult:Tt}=je(window),{querySelectorAll:xt}=wt,Ot=xt&&i(xt,wt);const{assign:Pt,setPrototypeOf:jt}=Et;class Nt extends Mt{evaluate(...e){return jt(o(super.evaluate,this,e),Tt.prototype)}}class Lt extends St{createExpression(...e){return jt(o(super.createExpression,this,e),Nt.prototype)}}function kt(e){if(mt.hidden.has(e))return;!function(e){yt&&"function"==typeof checkElement&&checkElement(e)}(e),mt.hidden.add(e);let{style:t}=je(e),r=je(t,"CSSStyleDeclaration"),n=je([]),{debugCSSProperties:o}=S;for(let[e,t]of o||[["display","none"]])r.setProperty(e,t,"important"),n.push([e,r.getPropertyValue(e)]);new vt((()=>{for(let[e,t]of n){let n=r.getPropertyValue(e),o=r.getPropertyPriority(e);n==t&&"important"==o||r.setProperty(e,t,"important")}})).observe(e,{attributes:!0,attributeFilter:["style"]})}function Ct(e){let t=e;if(t.startsWith("xpath(")&&t.endsWith(")")){let t=function(e){let t=e;if(t.startsWith("xpath(")&&t.endsWith(")")){let e=t.slice(6,-1),r=(new Lt).createExpression(e,null),n=Tt.ORDERED_NODE_SNAPSHOT_TYPE;return e=>{if(!e)return;let t=r.evaluate(wt,n,null),{snapshotLength:o}=t;for(let r=0;rOt(e).forEach(t)}(e);return()=>{let e=je([]);return t((t=>e.push(t))),e}}return()=>bt.from(Ot(e))}let{ELEMENT_NODE:At,TEXT_NODE:Wt,prototype:$t}=Node,{prototype:Dt}=Element,{prototype:Ht}=HTMLElement,{console:zt,variables:Rt,DOMParser:Ft,Error:It,MutationObserver:Jt,Object:Vt,ReferenceError:Bt}=je(window),{getOwnPropertyDescriptor:Ut}=Vt;function _t(e,t){return We}je(window);const{Map:Xt,MutationObserver:qt,Object:Gt,Set:Kt,WeakSet:Yt}=je(window);let Zt=Element.prototype,{attachShadow:Qt}=Zt,er=new Yt,tr=new Xt,rr=null;const{Error:nr,JSON:or,Map:ir,Object:sr}=je(window);let ar=null;let{Error:lr,JSON:cr,Map:ur,Object:fr}=je(window),pr=null;let{Error:dr}=je(window);let{Error:hr,Map:wr,Object:gr,console:yr}=je(window),{toString:mr}=Function.prototype,br=EventTarget.prototype,{addEventListener:vr}=br,Er=null;let Sr,{URL:Mr,fetch:Tr}=je(window),{delete:xr,has:Or}=l(URLSearchParams.prototype);const Pr={"abort-current-inline-script":function(e,t=null){const r=De("abort-current-inline-script"),n=t?Re(t):null,o=Fe(),i=je(document).currentScript;let a=window;const l=je(e).split("."),c=je(l).pop();for(let e of je(l))if(a=a[e],!a||"object"!=typeof a&&"function"!=typeof a)return void r(l," is not found");const{get:u,set:f}=ut.getOwnPropertyDescriptor(a,c)||{};let p=a[c];void 0===p&&r("The property",c,"doesn't exist yet. Check typos.");const d=()=>{const e=je(document).currentScript;if(e instanceof pt&&""==je(e,"HTMLScriptElement").src&&e!=i&&(!n||n.test(je(e).textContent)))throw r(l," is aborted \n",e),new ft(o)};et(a,c,{get(){return d(),u?s(u,this):p},set(e){d(),f?s(f,this,e):p=e}}),tt(o)},"abort-on-iframe-property-read":function(...e){ot(e,!0,!1)},"abort-on-iframe-property-write":function(...e){ot(e,!1,!0)},"abort-on-property-read":function(e,t){rt("abort-on-property-read",window,e,!("false"===t))},"abort-on-property-write":function(e,t){nt("abort-on-property-write",window,e,!("false"===t))},"cookie-remover":function(e){if(!e)throw new dt("[cookie-remover snippet]: No cookie to remove.");let t=De("cookie-remover"),r=Re(e);if(je(/^http|^about/).test(location.protocol)){t("Parsing cookies for matches");for(const e of je(je(ht()).split(";").filter((e=>r.test(je(e).split("=")[0]))))){let r=je(location.hostname),n=je(e).split("=")[0],o="expires=Thu, 01 Jan 1970 00:00:00 GMT",i="path=/",s="domain="+r.slice(r.indexOf(".")+1);ht(`${je(n).trim()}=;${o};${i};${s}`),t(`Set expiration date on ${n}`)}}else t("Snippet only works for http or https and about.")},debug:function(){ke=!0},"freeze-element":function(e,t="",...r){let n,i,a=!1,l=!1,c=je(r).filter((e=>!h(e))),u=je(r).filter((e=>h(e))).map(Re),f=Fe(),p=Ct(e);!function(){let r=je(t).split("+");1===r.length&&""===r[0]&&(r=[]);for(let t of r)switch(t){case"subtree":a=!0;break;case"abort":l=!0;break;default:throw new It("[freeze] Unknown option passed to the snippet. [selector]: "+e+" [option]: "+t)}}();let d={selector:e,shouldAbort:l,rid:f,exceptionSelectors:c,regexExceptions:u,changeId:0};function h(e){return e.length>=2&&"/"==e[0]&&"/"==e[e.length-1]}function w(){i=p(),g(i,!1)}function g(e,t=!0){for(let r of e)Rt.frozen.has(r)||(Rt.frozen.set(r,d),!t&&a&&new Jt((e=>{for(let t of je(e))g(je(t,"MutationRecord").addedNodes)})).observe(r,{childList:!0,subtree:!0}),a&&je(r).nodeType===At&&g(je(r).childNodes))}function y(e,...t){$e(`[freeze][${e}] `,...t)}function m(e,t,r,n){let o=n.selector,i=n.changeId,s="string"==typeof e,a=n.shouldAbort?"aborting":"watching";switch(zt.groupCollapsed(`[freeze][${i}] ${a}: ${o}`),r){case"appendChild":case"append":case"prepend":case"insertBefore":case"replaceChild":case"insertAdjacentElement":case"insertAdjacentHTML":case"insertAdjacentText":case"innerHTML":case"outerHTML":y(i,s?"text: ":"node: ",e),y(i,"added to node: ",t);break;case"replaceWith":case"after":case"before":y(i,s?"text: ":"node: ",e),y(i,"added to node: ",je(t).parentNode);break;case"textContent":case"innerText":case"nodeValue":y(i,"content of node: ",t),y(i,"changed to: ",e)}y(i,`using the function "${r}"`),zt.groupEnd(),n.changeId++}function b(e,t){if(t)for(let r of t)if(r.test(e))return!0;return!1}function v(e){throw new Bt(e)}function E(e,t,r,n){let o=new Ft,{body:i}=je(o.parseFromString(e,"text/html")),s=S(je(i).childNodes,t,r,n);return je(s).map((e=>{switch(je(e).nodeType){case At:return je(e).outerHTML;case Wt:return je(e).textContent;default:return""}})).join("")}function S(e,t,r,n){let o=je([]);for(let i of e)M(i,t,r,n)&&o.push(i);return o}function M(e,t,r,n){let o=n.shouldAbort,i=n.regexExceptions,s=n.exceptionSelectors,a=n.rid;if("string"==typeof e){let s=e;return!!b(s,i)||(Ce()&&m(s,t,r,n),o&&v(a),Ce())}let l=e;switch(je(l).nodeType){case At:return!!function(e,t){if(t){let r=je(e);for(let e of t)if(r.matches(e))return!0}return!1}(l,s)||(o&&(Ce()&&m(l,t,r,n),v(a)),!!Ce()&&(kt(l),m(l,t,r,n),!0));case Wt:return!!b(je(l).textContent,i)||(Ce()&&m(l,t,r,n),o&&v(a),!1);default:return!0}}function T(e,t,r,n){let i=Ut(e,t)||{},a=i.get&&s(i.get,e)||i.value;if(a)return{get:()=>function(...e){if(r(this)){let r=n(this);if(r){let n=e[0];if(!M(n,this,t,r))return n}}return o(a,this,e)}}}function x(e,t,r,n){let i=Ut(e,t)||{},a=i.get&&s(i.get,e)||i.value;if(a)return{get:()=>function(...e){if(!r(this))return o(a,this,e);let i=n(this);if(!i)return o(a,this,e);let s=S(e,this,t,i);return s.length>0?o(a,this,s):void 0}}}function O(e,t,r,n){let i=Ut(e,t)||{},a=i.get&&s(i.get,e)||i.value;if(a)return{get:()=>function(...e){let[i,l]=e,c="afterbegin"===i||"beforeend"===i;if(r(this,c)){let e=n(this,c);if(e){let r,n=c?this:je(this).parentNode;switch(t){case"insertAdjacentElement":if(!M(l,n,t,e))return l;break;case"insertAdjacentHTML":return r=E(l,n,t,e),r?s(a,this,i,r):void 0;case"insertAdjacentText":if(!M(l,n,t,e))return}}}return o(a,this,e)}}}function P(e,t,r,n){let o=Ut(e,t)||{},{set:i}=o;if(i)return{set(e){if(!r(this))return s(i,this,e);let o=n(this);if(!o)return s(i,this,e);let a=E(e,this,t,o);return a?s(i,this,a):void 0}}}function j(e,t,r,n){let o=Ut(e,t)||{},{set:i}=o;if(i)return{set(e){if(!r(this))return s(i,this,e);let o=n(this);return o?M(e,this,t,o)?s(i,this,e):void 0:s(i,this,e)}}}Rt.frozen.has(document)||(Rt.frozen.set(document,!0),function(){let e;function t(e){return e&&Rt.frozen.has(e)}function r(e){try{return e&&(Rt.frozen.has(e)||Rt.frozen.has(je(e).parentNode))}catch(e){return!1}}function n(e,t){try{return e&&(Rt.frozen.has(e)&&t||Rt.frozen.has(je(e).parentNode)&&!t)}catch(e){return!1}}function o(e){return Rt.frozen.get(e)}function i(e){try{if(Rt.frozen.has(e))return Rt.frozen.get(e);let t=je(e).parentNode;return Rt.frozen.get(t)}catch(e){}}function s(e,t){try{if(Rt.frozen.has(e)&&t)return Rt.frozen.get(e);let r=je(e).parentNode;return Rt.frozen.get(r)}catch(e){}}e=T($t,"appendChild",t,o),et($t,"appendChild",e),e=T($t,"insertBefore",t,o),et($t,"insertBefore",e),e=T($t,"replaceChild",t,o),et($t,"replaceChild",e),e=x(Dt,"append",t,o),et(Dt,"append",e),e=x(Dt,"prepend",t,o),et(Dt,"prepend",e),e=x(Dt,"replaceWith",r,i),et(Dt,"replaceWith",e),e=x(Dt,"after",r,i),et(Dt,"after",e),e=x(Dt,"before",r,i),et(Dt,"before",e),e=O(Dt,"insertAdjacentElement",n,s),et(Dt,"insertAdjacentElement",e),e=O(Dt,"insertAdjacentHTML",n,s),et(Dt,"insertAdjacentHTML",e),e=O(Dt,"insertAdjacentText",n,s),et(Dt,"insertAdjacentText",e),e=P(Dt,"innerHTML",t,o),et(Dt,"innerHTML",e),e=P(Dt,"outerHTML",r,i),et(Dt,"outerHTML",e),e=j($t,"textContent",t,o),et($t,"textContent",e),e=j(Ht,"innerText",t,o),et(Ht,"innerText",e),e=j($t,"nodeValue",t,o),et($t,"nodeValue",e)}()),n=new Jt(w),n.observe(document,{childList:!0,subtree:!0}),w()},"hide-if-shadow-contains":function(e,t="*"){let r=`${e}\\${t}`;tr.has(r)||tr.set(r,[Re(e),t,_t()]);const n=De("hide-if-shadow-contain");rr||(rr=new qt((e=>{let t=new Kt;for(let{target:r}of je(e)){let e=je(r).parentNode;for(;e;)[r,e]=[e,je(r).parentNode];if(!er.has(r)&&!t.has(r)){t.add(r);for(let[e,t,o]of tr.values())if(e.test(je(r).textContent)){let e=je(r.host).closest(t);e&&(o(),je(r).appendChild(document.createElement("style")).textContent=":host {display: none !important}",kt(e),er.add(r),n("Hiding: ",e," for params: ",...arguments))}}}})),Gt.defineProperty(Zt,"attachShadow",{value:c(Qt,(function(){let e=o(Qt,this,arguments);return n("attachShadow is called for: ",e),rr.observe(e,{childList:!0,characterData:!0,subtree:!0}),e}))}))},"json-override":function(e,t,r="",n=""){if(!e)throw new nr("[json-override snippet]: Missing paths to override.");if(void 0===t)throw new nr("[json-override snippet]: No value to override with.");if(!ar){let e=De("json-override"),{parse:t}=or;ar=new ir,sr.defineProperty(window.JSON,"parse",{value:c(t,(function(r){let n=o(t,this,arguments);for(let{prune:t,needle:o,filter:i,value:s}of ar.values())if(!i||i.test(r)){if(je(o).some((e=>!st(n,e))))return n;for(let r of t){let t=st(n,r);void 0!==t&&(e(`Found ${r} replaced it with ${s}`),t[0][t[1]]=lt(s))}}return n}))}),e("Wrapped JSON.parse for override")}ar.set(e,{prune:je(e).split(/ +/),needle:r.length?je(r).split(/ +/):[],filter:n?Re(n):null,value:t})},"json-prune":function(e,t=""){if(!e)throw new lr("Missing paths to prune");if(!pr){let e=De("json-prune"),{parse:t}=cr;pr=new ur,fr.defineProperty(window.JSON,"parse",{value:c(t,(function(){let r=o(t,this,arguments);for(let{prune:t,needle:n}of pr.values()){if(je(n).some((e=>!st(r,e))))return r;for(let n of t){let t=st(r,n);void 0!==t&&(e(`Found ${n} and deleted`),delete t[0][t[1]])}}return r}))}),e("Wrapped JSON.parse for prune")}pr.set(e,{prune:je(e).split(/ +/),needle:t.length?je(t).split(/ +/):[]})},"override-property-read":function(e,t){if(!e)throw new dr("[override-property-read snippet]: No property to override.");if(void 0===t)throw new dr("[override-property-read snippet]: No value to override with.");let r=De("override-property-read"),n=lt(t);r(`Overriding ${e}.`),et(window,e,{get:()=>(r(`${e} override done.`),n),set(){}})},"prevent-listener":function(e,t,r){if(!e)throw new hr("[prevent-listener snippet]: No event type.");if(!Er){Er=new wr;let e=De("[prevent]");gr.defineProperty(br,"addEventListener",{value:c(vr,(function(t,r){for(let{evt:n,handlers:o,selectors:i}of Er.values()){if(!n.test(t))continue;let a=this instanceof Element;for(let l=0;lc.test(s(mr,"function"==typeof r?r:r.handleEvent));if((!c||f())&&(!u||a&&je(this).matches(u)))return void(Ce()&&(yr.groupCollapsed("DEBUG [prevent] was successful"),e(`type: ${t} matching ${n}`),e("handler:",r),c&&e(`matching ${c}`),u&&e("on element: ",this,` matching ${u}`),e("was prevented from being added"),yr.groupEnd()))}}return o(vr,this,arguments)}))}),e("Wrapped addEventListener")}Er.has(e)||Er.set(e,{evt:Re(e),handlers:[],selectors:[]});let{handlers:n,selectors:i}=Er.get(e);n.push(t?Re(t):null),i.push(r)},"strip-fetch-query-parameter":function(e,t=null){const r=De("strip-fetch-query-parameter");Sr||(Sr=new Map,window.fetch=c(Tr,((...e)=>{let[t]=e;if("string"==typeof t){let n=new Mr(t);for(let[o,i]of Sr)i&&!i.test(t)||Or(n.searchParams,o)&&(r(`${o} has been stripped from url ${t}`),xr(n.searchParams,o),e[0]=n.href)}return o(Tr,self,e)}))),Sr.set(e,t&&Re(t))},trace:function(...e){o($e,null,e)}}; ++const snippets=Pr; ++let context; ++for (const [name, ...args] of filters) { ++if (snippets.hasOwnProperty(name)) { ++try { context = snippets[name].apply(context, args); } ++catch (error) { console.error(error); } ++} ++} ++context = void 0; ++}; ++const graph = new Map([["abort-current-inline-script",null],["abort-on-iframe-property-read",null],["abort-on-iframe-property-write",null],["abort-on-property-read",null],["abort-on-property-write",null],["cookie-remover",null],["debug",null],["freeze-element",null],["hide-if-shadow-contains",null],["json-override",null],["json-prune",null],["override-property-read",null],["prevent-listener",null],["strip-fetch-query-parameter",null],["trace",null]]); ++callback.get = snippet => graph.get(snippet); ++callback.has = snippet => graph.has(snippet); ++ ++ if (t.every(([name]) => !callback.has(name))) return; ++ const append = () => { ++ URL.revokeObjectURL( ++ Object.assign( ++ document.documentElement.appendChild(document.createElement("script")), ++ {async: false, src: URL.createObjectURL(new Blob([ ++ "(" + callback + ")(..." + JSON.stringify([e, ...t]) + ")" ++ ]))} ++ ).src ++ ); ++ }; ++ try { append(); } ++ catch (_) { ++ document.addEventListener("readystatechange", append, {once:true}); ++ } ++} +\ No newline at end of file +diff --git a/components/resources/adblocking/snippets/dist/isolated-first-xpath3.source.jst b/components/resources/adblocking/snippets/dist/isolated-first-xpath3.source.jst +new file mode 100644 +--- /dev/null ++++ b/components/resources/adblocking/snippets/dist/isolated-first-xpath3.source.jst +@@ -0,0 +1,3696 @@ ++(e, ...t) => { ++/*! ++ * snippets v0.8.1 (https://gitlab.com/eyeo/anti-cv/snippets/-/tree/5f54b58f039a604088d65991f2829a9a081832f6/dist) ++ * This file is part of eyeo's Anti-Circumvention Snippets module (@eyeo/snippets), ++ * Copyright (C) 2006-present eyeo GmbH ++ * ++ * @eyeo/snippets is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 3 as ++ * published by the Free Software Foundation. ++ * ++ * @eyeo/snippets is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with @eyeo/snippets. If not, see . ++ */ ++ ((environment, ...filters) => { ++ /*! ++ * This file is part of eyeo's Anti-Circumvention Snippets module (@eyeo/snippets), ++ * Copyright (C) 2006-present eyeo GmbH ++ * ++ * @eyeo/snippets is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 3 as ++ * published by the Free Software Foundation. ++ * ++ * @eyeo/snippets is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with @eyeo/snippets. If not, see . ++ */ ++ const $$1 = Proxy; ++ ++ const {apply: a, bind: b, call: c} = Function; ++ const apply$2 = c.bind(a); ++ const bind = c.bind(b); ++ const call = c.bind(c); ++ ++ const callerHandler = { ++ get(target, name) { ++ return bind(c, target[name]); ++ } ++ }; ++ ++ const caller = target => new $$1(target, callerHandler); ++ ++ const handler$2 = { ++ get(target, name) { ++ return bind(target[name], target); ++ } ++ }; ++ ++ const bound = target => new $$1(target, handler$2); ++ ++ const { ++ assign: assign$1, ++ defineProperties: defineProperties$1, ++ freeze: freeze$1, ++ getOwnPropertyDescriptor: getOwnPropertyDescriptor$2, ++ getOwnPropertyDescriptors: getOwnPropertyDescriptors$1, ++ getPrototypeOf ++ } = bound(Object); ++ ++ const {hasOwnProperty} = caller({}); ++ ++ const {species} = Symbol; ++ ++ const handler$1 = { ++ get(target, name) { ++ const Native = target[name]; ++ class Secure extends Native {} ++ ++ const proto = getOwnPropertyDescriptors$1(Native.prototype); ++ delete proto.constructor; ++ freeze$1(defineProperties$1(Secure.prototype, proto)); ++ ++ const statics = getOwnPropertyDescriptors$1(Native); ++ delete statics.length; ++ delete statics.prototype; ++ statics[species] = {value: Secure}; ++ return freeze$1(defineProperties$1(Secure, statics)); ++ } ++ }; ++ ++ const secure = target => new $$1(target, handler$1); ++ ++ const libEnvironment = typeof environment !== "undefined" ? environment : ++ {}; ++ ++ if (typeof globalThis === "undefined") ++ window.globalThis = window; ++ ++ const {apply: apply$1, ownKeys} = bound(Reflect); ++ ++ const worldEnvDefined = "world" in libEnvironment; ++ const isIsolatedWorld = worldEnvDefined && libEnvironment.world === "ISOLATED"; ++ const isMainWorld = worldEnvDefined && libEnvironment.world === "MAIN"; ++ const isChrome = typeof chrome === "object" && !!chrome.runtime; ++ const isOtherThanChrome = typeof browser === "object" && !!browser.runtime; ++ const isExtensionContext$2 = !isMainWorld && ++ (isIsolatedWorld || isChrome || isOtherThanChrome); ++ const copyIfExtension = value => isExtensionContext$2 ? ++ value : ++ create(value, getOwnPropertyDescriptors(value)); ++ ++ const { ++ create, ++ defineProperties, ++ defineProperty, ++ freeze, ++ getOwnPropertyDescriptor: getOwnPropertyDescriptor$1, ++ getOwnPropertyDescriptors ++ } = bound(Object); ++ ++ const invokes = bound(globalThis); ++ const classes = isExtensionContext$2 ? globalThis : secure(globalThis); ++ const {Map: Map$5, RegExp: RegExp$1, Set, WeakMap: WeakMap$3, WeakSet: WeakSet$b} = classes; ++ ++ const augment = (source, target, method = null) => { ++ const known = ownKeys(target); ++ for (const key of ownKeys(source)) { ++ if (known.includes(key)) ++ continue; ++ ++ const descriptor = getOwnPropertyDescriptor$1(source, key); ++ if (method && "value" in descriptor) { ++ const {value} = descriptor; ++ if (typeof value === "function") ++ descriptor.value = method(value); ++ } ++ defineProperty(target, key, descriptor); ++ } ++ }; ++ ++ const primitive = name => { ++ const Super = classes[name]; ++ class Class extends Super {} ++ const {toString, valueOf} = Super.prototype; ++ defineProperties(Class.prototype, { ++ toString: {value: toString}, ++ valueOf: {value: valueOf} ++ }); ++ const type = name.toLowerCase(); ++ const method = callback => function() { ++ const result = apply$1(callback, this, arguments); ++ return typeof result === type ? new Class(result) : result; ++ }; ++ augment(Super, Class, method); ++ augment(Super.prototype, Class.prototype, method); ++ return Class; ++ }; ++ ++ const variables$1 = freeze({ ++ frozen: new WeakMap$3(), ++ hidden: new WeakSet$b(), ++ iframePropertiesToAbort: { ++ read: new Set(), ++ write: new Set() ++ }, ++ abortedIframes: new WeakMap$3() ++ }); ++ ++ const startsCapitalized = new RegExp$1("^[A-Z]"); ++ ++ var env = new Proxy(new Map$5([ ++ ++ ["chrome", ( ++ isExtensionContext$2 && ( ++ (isChrome && chrome) || ++ (isOtherThanChrome && browser) ++ ) ++ ) || void 0], ++ ["isExtensionContext", isExtensionContext$2], ++ ["variables", variables$1], ++ ++ ["console", copyIfExtension(console)], ++ ["document", globalThis.document], ++ ["performance", copyIfExtension(performance)], ++ ["JSON", copyIfExtension(JSON)], ++ ["Map", Map$5], ++ ["Math", copyIfExtension(Math)], ++ ["Number", isExtensionContext$2 ? Number : primitive("Number")], ++ ["RegExp", RegExp$1], ++ ["Set", Set], ++ ["String", isExtensionContext$2 ? String : primitive("String")], ++ ["WeakMap", WeakMap$3], ++ ["WeakSet", WeakSet$b], ++ ++ ["MouseEvent", MouseEvent] ++ ]), { ++ get(map, key) { ++ if (map.has(key)) ++ return map.get(key); ++ ++ let value = globalThis[key]; ++ if (typeof value === "function") ++ value = (startsCapitalized.test(key) ? classes : invokes)[key]; ++ ++ map.set(key, value); ++ return value; ++ }, ++ has(map, key) { ++ return map.has(key); ++ } ++ }); ++ ++ class WeakValue { ++ has() { return false; } ++ set() {} ++ } ++ ++ const helpers = {WeakSet, WeakMap, WeakValue}; ++ const {apply} = Reflect; ++ ++ function transformOnce (callback) { const {WeakSet, WeakMap, WeakValue} = (this || helpers); ++ const ws = new WeakSet; ++ const wm = new WeakMap; ++ const wv = new WeakValue; ++ return function (any) { ++ if (ws.has(any)) ++ return any; ++ ++ if (wm.has(any)) ++ return wm.get(any); ++ ++ if (wv.has(any)) ++ return wv.get(any); ++ ++ const value = apply(callback, this, arguments); ++ ws.add(value); ++ if (value !== any) ++ (typeof any === 'object' && any ? wm : wv).set(any, value); ++ return value; ++ }; ++ } ++ ++ const {Map: Map$4, WeakMap: WeakMap$2, WeakSet: WeakSet$a, setTimeout: setTimeout$3} = env; ++ ++ let cleanup = true; ++ let cleanUpCallback = map => { ++ map.clear(); ++ cleanup = !cleanup; ++ }; ++ ++ var transformer = transformOnce.bind({ ++ WeakMap: WeakMap$2, ++ WeakSet: WeakSet$a, ++ ++ WeakValue: class extends Map$4 { ++ set(key, value) { ++ if (cleanup) { ++ cleanup = !cleanup; ++ setTimeout$3(cleanUpCallback, 0, this); ++ } ++ return super.set(key, value); ++ } ++ } ++ }); ++ ++ const {concat, includes, join, reduce, unshift} = caller([]); ++ ++ const globals = secure(globalThis); ++ ++ const { ++ Map: Map$3, ++ WeakMap: WeakMap$1 ++ } = globals; ++ ++ const map = new Map$3; ++ const descriptors = target => { ++ const chain = []; ++ let current = target; ++ while (current) { ++ if (map.has(current)) ++ unshift(chain, map.get(current)); ++ else { ++ const descriptors = getOwnPropertyDescriptors$1(current); ++ map.set(current, descriptors); ++ unshift(chain, descriptors); ++ } ++ current = getPrototypeOf(current); ++ } ++ unshift(chain, {}); ++ return apply$2(assign$1, null, chain); ++ }; ++ ++ const chain = source => { ++ const target = typeof source === 'function' ? source.prototype : source; ++ const chained = descriptors(target); ++ const handler = { ++ get(target, key) { ++ if (key in chained) { ++ const {value, get} = chained[key]; ++ if (get) ++ return call(get, target); ++ if (typeof value === 'function') ++ return bind(value, target); ++ } ++ return target[key]; ++ }, ++ set(target, key, value) { ++ if (key in chained) { ++ const {set} = chained[key]; ++ if (set) { ++ call(set, target, value); ++ return true; ++ } ++ } ++ target[key] = value; ++ return true; ++ } ++ }; ++ return target => new $$1(target, handler); ++ }; ++ ++ const { ++ isExtensionContext: isExtensionContext$1, ++ Array: Array$2, ++ Number: Number$1, ++ String: String$1, ++ Object: Object$2 ++ } = env; ++ ++ const {isArray} = Array$2; ++ const {getOwnPropertyDescriptor, setPrototypeOf: setPrototypeOf$1} = Object$2; ++ ++ const {toString} = Object$2.prototype; ++ const {slice} = String$1.prototype; ++ const getBrand = value => call(slice, call(toString, value), 8, -1); ++ ++ const {get: nodeType} = getOwnPropertyDescriptor(Node.prototype, "nodeType"); ++ ++ const chained = isExtensionContext$1 ? {} : { ++ Attr: chain(Attr), ++ CanvasRenderingContext2D: chain(CanvasRenderingContext2D), ++ CSSStyleDeclaration: chain(CSSStyleDeclaration), ++ Document: chain(Document), ++ Element: chain(Element), ++ HTMLCanvasElement: chain(HTMLCanvasElement), ++ HTMLElement: chain(HTMLElement), ++ HTMLImageElement: chain(HTMLImageElement), ++ HTMLScriptElement: chain(HTMLScriptElement), ++ MutationRecord: chain(MutationRecord), ++ Node: chain(Node), ++ ShadowRoot: chain(ShadowRoot), ++ ++ get CSS2Properties() { ++ return chained.CSSStyleDeclaration; ++ } ++ }; ++ ++ const upgrade = (value, hint) => { ++ if (hint !== "Element" && hint in chained) ++ return chained[hint](value); ++ ++ if (isArray(value)) ++ return setPrototypeOf$1(value, Array$2.prototype); ++ ++ const brand = getBrand(value); ++ if (brand in chained) ++ return chained[brand](value); ++ ++ if (brand in env) ++ return setPrototypeOf$1(value, env[brand].prototype); ++ ++ if ("nodeType" in value) { ++ switch (call(nodeType, value)) { ++ case 1: ++ if (!(hint in chained)) ++ throw new Error("unknown hint " + hint); ++ return chained[hint](value); ++ case 2: ++ return chained.Attr(value); ++ case 3: ++ return chained.Node(value); ++ case 9: ++ return chained.Document(value); ++ } ++ } ++ ++ throw new Error("unknown brand " + brand); ++ }; ++ ++ var $ = isExtensionContext$1 ? ++ value => (value === window || value === globalThis ? env : value) : ++ transformer((value, hint = "Element") => { ++ if (value === window || value === globalThis) ++ return env; ++ ++ switch (typeof value) { ++ case "object": ++ return value && upgrade(value, hint); ++ ++ case "string": ++ return new String$1(value); ++ ++ case "number": ++ return new Number$1(value); ++ ++ default: ++ throw new Error("unsupported value"); ++ } ++ }); ++ ++ let { ++ document: document$1, ++ getComputedStyle: getComputedStyle$5, ++ isExtensionContext, ++ variables, ++ Array: Array$1, ++ MutationObserver: MutationObserver$a, ++ Object: Object$1, ++ XPathEvaluator, ++ XPathExpression, ++ XPathResult ++ } = $(window); ++ ++ let {querySelectorAll} = document$1; ++ let $$ = querySelectorAll && bind(querySelectorAll, document$1); ++ ++ const {assign, setPrototypeOf} = Object$1; ++ ++ class $XPathExpression extends XPathExpression { ++ evaluate(...args) { ++ return setPrototypeOf( ++ apply$2(super.evaluate, this, args), ++ XPathResult.prototype ++ ); ++ } ++ } ++ ++ class $XPathEvaluator extends XPathEvaluator { ++ createExpression(...args) { ++ return setPrototypeOf( ++ apply$2(super.createExpression, this, args), ++ $XPathExpression.prototype ++ ); ++ } ++ } ++ ++ function hideElement(element) { ++ if (variables.hidden.has(element)) ++ return; ++ ++ notifyElementHidden(element); ++ ++ variables.hidden.add(element); ++ ++ let {style} = $(element); ++ let $style = $(style, "CSSStyleDeclaration"); ++ let properties = $([]); ++ let {debugCSSProperties} = libEnvironment; ++ ++ for (let [key, value] of (debugCSSProperties || [["display", "none"]])) { ++ $style.setProperty(key, value, "important"); ++ properties.push([key, $style.getPropertyValue(key)]); ++ } ++ ++ new MutationObserver$a(() => { ++ for (let [key, value] of properties) { ++ let propertyValue = $style.getPropertyValue(key); ++ let propertyPriority = $style.getPropertyPriority(key); ++ if (propertyValue != value || propertyPriority != "important") ++ $style.setProperty(key, value, "important"); ++ } ++ }).observe(element, {attributes: true, ++ attributeFilter: ["style"]}); ++ } ++ ++ function notifyElementHidden(element) { ++ if (isExtensionContext && typeof checkElement === "function") ++ checkElement(element); ++ } ++ ++ function initQueryAndApply(selector) { ++ let $selector = selector; ++ if ($selector.startsWith("xpath(") && ++ $selector.endsWith(")")) { ++ let xpathQuery = $selector.slice(6, -1); ++ let evaluator = new $XPathEvaluator(); ++ let expression = evaluator.createExpression(xpathQuery, null); ++ ++ let flag = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE; ++ ++ return cb => { ++ if (!cb) ++ return; ++ let result = expression.evaluate(document$1, flag, null); ++ let {snapshotLength} = result; ++ for (let i = 0; i < snapshotLength; i++) ++ cb(result.snapshotItem(i)); ++ }; ++ } ++ return cb => $$(selector).forEach(cb); ++ } ++ ++ function initQueryAll(selector) { ++ let $selector = selector; ++ if ($selector.startsWith("xpath(") && ++ $selector.endsWith(")")) { ++ let queryAndApply = initQueryAndApply(selector); ++ return () => { ++ let elements = $([]); ++ queryAndApply(e => elements.push(e)); ++ return elements; ++ }; ++ } ++ return () => Array$1.from($$(selector)); ++ } ++ ++ function hideIfMatches(match, selector, searchSelector, onHideCallback) { ++ if (searchSelector == null) ++ searchSelector = selector; ++ ++ let won; ++ const callback = () => { ++ for (const element of $$(searchSelector)) { ++ const closest = $(element).closest(selector); ++ if (closest && match(element, closest)) { ++ won(); ++ hideElement(closest); ++ if (typeof onHideCallback === "function") ++ onHideCallback(closest); ++ } ++ } ++ }; ++ return assign( ++ new MutationObserver$a(callback), ++ { ++ race(win) { ++ won = win; ++ this.observe(document$1, {childList: true, ++ characterData: true, ++ subtree: true}); ++ callback(); ++ } ++ } ++ ); ++ } ++ ++ function isVisible(element, style, closest) { ++ let $style = $(style, "CSSStyleDeclaration"); ++ if ($style.getPropertyValue("display") == "none") ++ return false; ++ ++ let visibility = $style.getPropertyValue("visibility"); ++ if (visibility == "hidden" || visibility == "collapse") ++ return false; ++ ++ if (!closest || element == closest) ++ return true; ++ ++ let parent = $(element).parentElement; ++ if (!parent) ++ return true; ++ ++ return isVisible(parent, getComputedStyle$5(parent), closest); ++ } ++ ++ function getComputedCSSText(element) { ++ let style = getComputedStyle$5(element); ++ let {cssText} = style; ++ ++ if (cssText) ++ return cssText; ++ ++ for (let property of style) ++ cssText += `${property}: ${style[property]}; `; ++ ++ return $(cssText).trim(); ++ } ++ ++ let {Math: Math$2, RegExp} = $(window); ++ ++ function regexEscape(string) { ++ return $(string).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); ++ } ++ ++ function toRegExp(pattern) { ++ let {length} = pattern; ++ ++ if (length > 1 && pattern[0] === "/") { ++ let isCaseSensitive = pattern[length - 1] === "/"; ++ ++ if (isCaseSensitive || (length > 2 && $(pattern).endsWith("/i"))) { ++ let args = [$(pattern).slice(1, isCaseSensitive ? -1 : -2)]; ++ if (!isCaseSensitive) ++ args.push("i"); ++ ++ return new RegExp(...args); ++ } ++ } ++ ++ return new RegExp(regexEscape(pattern)); ++ } ++ ++ let debugging = false; ++ ++ function debug() { ++ return debugging; ++ } ++ ++ function setDebug() { ++ debugging = true; ++ } ++ ++ const {console: console$1} = $(window); ++ ++ const noop = () => {}; ++ ++ function log(...args) { ++ if (debug()) ++ $(args).unshift("%c DEBUG", "font-weight: bold"); ++ ++ console$1.log(...args); ++ } ++ ++ function getDebugger(name) { ++ return bind(debug() ? log : noop, null, name); ++ } ++ ++ let {Array, Error: Error$3, Map: Map$2, parseInt: parseInt$2} = $(window); ++ ++ let stack = null; ++ let won = null; ++ ++ function race(action, winners = "1") { ++ switch (action) { ++ case "start": ++ stack = { ++ winners: parseInt$2(winners, 10) || 1, ++ participants: new Map$2() ++ }; ++ won = new Array(); ++ break; ++ case "end": ++ case "finish": ++ case "stop": ++ stack = null; ++ for (let win of won) ++ win(); ++ won = null; ++ break; ++ default: ++ throw new Error$3(`Invalid action: ${action}`); ++ } ++ } ++ ++ function raceWinner(name, lose) { ++ ++ if (stack === null) ++ return noop; ++ ++ let current = stack; ++ let {participants} = current; ++ participants.set(win, lose); ++ ++ return win; ++ ++ function win() { ++ ++ if (current.winners < 1) ++ return; ++ ++ let debugLog = getDebugger("race"); ++ debugLog(`${name} won the race`); ++ ++ if (current === stack) { ++ won.push(win); ++ } ++ else { ++ participants.delete(win); ++ if (--current.winners < 1) { ++ for (let looser of participants.values()) ++ looser(); ++ ++ participants.clear(); ++ } ++ } ++ } ++ } ++ ++ function hideIfContains(search, selector = "*", searchSelector = null) { ++ const debugLog = getDebugger("hide-if-contains"); ++ const onHideCallback = node => { ++ debugLog("Matched: ", node, " for selector: ", selector, searchSelector); ++ }; ++ let re = toRegExp(search); ++ ++ const mo = hideIfMatches(element => re.test($(element).textContent), ++ selector, ++ searchSelector, ++ onHideCallback); ++ mo.race(raceWinner( ++ "hide-if-contains", ++ () => { ++ mo.disconnect(); ++ } ++ )); ++ } ++ ++ const handler = { ++ get(target, name) { ++ const context = target; ++ while (!hasOwnProperty(target, name)) ++ target = getPrototypeOf(target); ++ const {get, set} = getOwnPropertyDescriptor$2(target, name); ++ return function () { ++ return arguments.length ? ++ apply$2(set, context, arguments) : ++ call(get, context); ++ }; ++ } ++ }; ++ ++ const accessor = target => new $$1(target, handler); ++ ++ $(window); ++ ++ accessor(window); ++ ++ $(/^\d+$/); ++ ++ function getPromiseFromEvent(item, event) { ++ return new Promise( ++ resolve => { ++ const listener = () => { ++ item.removeEventListener(event, listener); ++ resolve(); ++ }; ++ item.addEventListener(event, listener); ++ } ++ ); ++ } ++ ++ function waitUntilEvent( ++ debugLog, ++ mainLogic, ++ waitUntil) { ++ if (waitUntil) { ++ ++ if (waitUntil === "load") { ++ debugLog("Waiting until window.load"); ++ ++ window.onload = () => { ++ debugLog("Window.load fired."); ++ mainLogic(); ++ }; ++ } ++ ++ else if (waitUntil === "loading" || ++ waitUntil === "interactive" || ++ waitUntil === "complete") { ++ debugLog("Waiting document state until :", waitUntil); ++ ++ document.onreadystatechange = () => { ++ debugLog("Document state changed:", document.readyState); ++ if (document.readyState === waitUntil) ++ mainLogic(); ++ }; ++ } ++ ++ else { ++ debugLog("Waiting until ", waitUntil, " event is triggered on document"); ++ getPromiseFromEvent(document, waitUntil).then(() => { ++ debugLog(waitUntil, " is triggered on document, starting the snippet"); ++ mainLogic(); ++ }).catch(err => { ++ debugLog("There was an error while waiting for the event.", err); ++ }); ++ } ++ } ++ else { ++ ++ mainLogic(); ++ } ++ } ++ ++ let {MutationObserver: MutationObserver$9, WeakSet: WeakSet$9, getComputedStyle: getComputedStyle$4} = $(window); ++ ++ function hideIfContainsAndMatchesStyle(search, ++ selector = "*", ++ searchSelector = null, ++ style = null, ++ searchStyle = null, ++ waitUntil, ++ windowWidthMin = null, ++ windowWidthMax = null ++ ) { ++ const debugLog = getDebugger("hide-if-contains-and-matches-style"); ++ const hiddenMap = new WeakSet$9(); ++ if (searchSelector == null) ++ searchSelector = selector; ++ ++ const searchRegExp = toRegExp(search); ++ ++ const styleRegExp = style ? toRegExp(style) : null; ++ const searchStyleRegExp = searchStyle ? toRegExp(searchStyle) : null; ++ const mainLogic = () => { ++ const callback = () => { ++ if ((windowWidthMin && window.innerWidth < windowWidthMin) || ++ (windowWidthMax && window.innerWidth > windowWidthMax) ++ ) ++ return; ++ for (const element of $$(searchSelector)) { ++ if (hiddenMap.has(element)) ++ continue; ++ if (searchRegExp.test($(element).textContent)) { ++ if (!searchStyleRegExp || ++ searchStyleRegExp.test(getComputedCSSText(element))) { ++ const closest = $(element).closest(selector); ++ if (!closest) ++ continue; ++ if (!styleRegExp || styleRegExp.test(getComputedCSSText(closest))) { ++ win(); ++ hideElement(closest); ++ hiddenMap.add(element); ++ debugLog("Matched: ", ++ closest, ++ "which contains: ", ++ element, ++ " for params: ", ++ ...arguments); ++ } ++ else { ++ debugLog( ++ "In this element the searchStyle matched but style didn't:\n", ++ closest, ++ getComputedStyle$4(closest), ++ ...arguments); ++ } ++ } ++ else { ++ debugLog( ++ "In this element the searchStyle didn't match:\n", ++ element, ++ getComputedStyle$4(element), ++ ...arguments); ++ } ++ } ++ } ++ }; ++ ++ const mo = new MutationObserver$9(callback); ++ const win = raceWinner( ++ "hide-if-contains-and-matches-style", ++ () => mo.disconnect() ++ ); ++ mo.observe(document, {childList: true, characterData: true, subtree: true}); ++ callback(); ++ }; ++ waitUntilEvent(debugLog, mainLogic, waitUntil); ++ } ++ ++ let { ++ clearTimeout, ++ fetch, ++ getComputedStyle: getComputedStyle$3, ++ setTimeout: setTimeout$2, ++ Map: Map$1, ++ MutationObserver: MutationObserver$8, ++ Uint8Array ++ } = $(window); ++ ++ function hideIfContainsImage(search, selector, searchSelector) { ++ if (searchSelector == null) ++ searchSelector = selector; ++ ++ let searchRegExp = toRegExp(search); ++ ++ const debugLog = getDebugger("hide-if-contains-image"); ++ ++ let callback = () => { ++ for (let element of $$(searchSelector)) { ++ let style = getComputedStyle$3(element); ++ let match = $(style["background-image"]).match(/^url\("(.*)"\)$/); ++ if (match) { ++ fetchContent(match[1]).then(content => { ++ if (searchRegExp.test(uint8ArrayToHex(new Uint8Array(content)))) { ++ let closest = $(element).closest(selector); ++ if (closest) { ++ win(); ++ hideElement(closest); ++ debugLog("Matched: ", closest, " for:", ...arguments); ++ } ++ } ++ }); ++ } ++ } ++ }; ++ ++ let mo = new MutationObserver$8(callback); ++ let win = raceWinner( ++ "hide-if-contains-image", ++ () => mo.disconnect() ++ ); ++ mo.observe(document, {childList: true, subtree: true}); ++ callback(); ++ } ++ ++ let fetchContentMap = new Map$1(); ++ ++ function fetchContent(url, {as = "arrayBuffer", cleanup = 60000} = {}) { ++ ++ let uid = as + ":" + url; ++ let details = fetchContentMap.get(uid) || { ++ remove: () => fetchContentMap.delete(uid), ++ result: null, ++ timer: 0 ++ }; ++ clearTimeout(details.timer); ++ details.timer = setTimeout$2(details.remove, cleanup); ++ if (!details.result) { ++ details.result = fetch(url).then(res => res[as]()).catch(details.remove); ++ fetchContentMap.set(uid, details); ++ } ++ return details.result; ++ } ++ ++ function toHex(number, length = 2) { ++ let hex = $(number).toString(16); ++ ++ if (hex.length < length) ++ hex = $("0").repeat(length - hex.length) + hex; ++ ++ return hex; ++ } ++ ++ function uint8ArrayToHex(uint8Array) { ++ return uint8Array.reduce((hex, byte) => hex + toHex(byte), ""); ++ } ++ ++ const {parseFloat: parseFloat$1, Math: Math$1, MutationObserver: MutationObserver$7, WeakSet: WeakSet$8} = $(window); ++ const {min} = Math$1; ++ ++ const ld = (a, b) => { ++ const len1 = a.length + 1; ++ const len2 = b.length + 1; ++ const d = [[0]]; ++ let i = 0; ++ let I = 0; ++ ++ while (++i < len2) ++ d[0][i] = i; ++ ++ i = 0; ++ while (++i < len1) { ++ const c = a[I]; ++ let j = 0; ++ let J = 0; ++ d[i] = [i]; ++ while (++j < len2) { ++ d[i][j] = min(d[I][j] + 1, d[i][J] + 1, d[I][J] + (c != b[J])); ++ ++J; ++ } ++ ++I; ++ } ++ return d[len1 - 1][len2 - 1]; ++ }; ++ ++ function hideIfContainsSimilarText( ++ search, selector, ++ searchSelector = null, ++ ignoreChars = 0, ++ maxSearches = 0 ++ ) { ++ const visitedNodes = new WeakSet$8(); ++ const debugLog = getDebugger("hide-if-contains-similar-text"); ++ const $search = $(search); ++ const {length} = $search; ++ const chars = length + parseFloat$1(ignoreChars) || 0; ++ const find = $([...$search]).sort(); ++ const guard = parseFloat$1(maxSearches) || Infinity; ++ ++ if (searchSelector == null) ++ searchSelector = selector; ++ ++ debugLog("Looking for similar text: " + $search); ++ ++ const callback = () => { ++ for (const element of $$(searchSelector)) { ++ if (visitedNodes.has(element)) ++ continue; ++ ++ visitedNodes.add(element); ++ const {innerText} = $(element); ++ const loop = min(guard, innerText.length - chars + 1); ++ for (let i = 0; i < loop; i++) { ++ const str = $(innerText).substr(i, chars); ++ const distance = ld(find, $([...str]).sort()) - ignoreChars; ++ if (distance <= 0) { ++ const closest = $(element).closest(selector); ++ debugLog("Found similar text: " + $search, closest); ++ if (closest) { ++ win(); ++ hideElement(closest); ++ break; ++ } ++ } ++ } ++ } ++ }; ++ ++ let mo = new MutationObserver$7(callback); ++ let win = raceWinner( ++ "hide-if-contains-similar-text", ++ () => mo.disconnect() ++ ); ++ mo.observe(document, {childList: true, characterData: true, subtree: true}); ++ callback(); ++ } ++ ++ let {getComputedStyle: getComputedStyle$2, Map, WeakSet: WeakSet$7, parseFloat} = $(window); ++ ++ const {ELEMENT_NODE: ELEMENT_NODE$3, TEXT_NODE} = Node; ++ ++ function hideIfContainsVisibleText(search, selector, ++ searchSelector = null, ++ ...attributes) { ++ let entries = $([]); ++ const optionalParameters = new Map([ ++ ["-snippet-box-margin", "2"], ++ ["-disable-bg-color-check", "false"], ++ ["-check-is-contained", "false"] ++ ]); ++ ++ for (let attr of attributes) { ++ attr = $(attr); ++ let markerIndex = attr.indexOf(":"); ++ if (markerIndex < 0) ++ continue; ++ ++ let key = attr.slice(0, markerIndex).trim().toString(); ++ let value = attr.slice(markerIndex + 1).trim().toString(); ++ ++ if (key && value) { ++ if (optionalParameters.has(key)) ++ optionalParameters.set(key, value); ++ else ++ entries.push([key, value]); ++ } ++ } ++ ++ let defaultEntries = $([ ++ ["opacity", "0"], ++ ["font-size", "0px"], ++ ++ ["color", "rgba(0, 0, 0, 0)"] ++ ]); ++ ++ let attributesMap = new Map(defaultEntries.concat(entries)); ++ ++ function isTextVisible(element, style, {bgColorCheck = true} = {}) { ++ if (!style) ++ style = getComputedStyle$2(element); ++ ++ style = $(style); ++ ++ for (const [key, value] of attributesMap) { ++ let valueAsRegex = toRegExp(value); ++ if (valueAsRegex.test(style.getPropertyValue(key))) ++ return false; ++ } ++ ++ let color = style.getPropertyValue("color"); ++ if (bgColorCheck && style.getPropertyValue("background-color") == color) ++ return false; ++ ++ return true; ++ } ++ ++ function getPseudoContent(element, pseudo, {bgColorCheck = true} = {}) { ++ let style = getComputedStyle$2(element, pseudo); ++ if (!isVisible(element, style) || ++ !isTextVisible(element, style, {bgColorCheck})) ++ return ""; ++ ++ let {content} = $(style); ++ if (content && content !== "none") { ++ let strings = $([]); ++ ++ content = $(content).trim().replace( ++ /(["'])(?:(?=(\\?))\2.)*?\1/g, ++ value => `\x01${strings.push($(value).slice(1, -1)) - 1}` ++ ); ++ ++ content = content.replace( ++ /\s*attr\(\s*([^\s,)]+)[^)]*?\)\s*/g, ++ (_, name) => $(element).getAttribute(name) || "" ++ ); ++ ++ return content.replace( ++ /\x01(\d+)/g, ++ (_, index) => strings[index]); ++ } ++ return ""; ++ } ++ ++ function isContained(childNode, parentNode, {boxMargin = 2} = {}) { ++ const child = $(childNode).getBoundingClientRect(); ++ const parent = $(parentNode).getBoundingClientRect(); ++ const stretchedParent = { ++ left: parent.left - boxMargin, ++ right: parent.right + boxMargin, ++ top: parent.top - boxMargin, ++ bottom: parent.bottom + boxMargin ++ }; ++ return ( ++ (stretchedParent.left <= child.left && ++ child.left <= stretchedParent.right && ++ stretchedParent.top <= child.top && ++ child.top <= stretchedParent.bottom) && ++ (stretchedParent.top <= child.bottom && ++ child.bottom <= stretchedParent.bottom && ++ stretchedParent.left <= child.right && ++ child.right <= stretchedParent.right) ++ ); ++ } ++ ++ function getVisibleContent(element, ++ closest, ++ style, ++ parentOverflowNode, ++ originalElement, ++ { ++ boxMargin = 2, ++ bgColorCheck, ++ checkIsContained ++ } = {}) { ++ let checkClosest = !style; ++ if (checkClosest) ++ style = getComputedStyle$2(element); ++ ++ if (!isVisible(element, style, checkClosest && closest)) ++ return ""; ++ ++ if (!parentOverflowNode && ++ ( ++ $(style).getPropertyValue("overflow-x") === "hidden" || ++ $(style).getPropertyValue("overflow-y") === "hidden" ++ ) ++ ) ++ parentOverflowNode = element; ++ ++ let text = getPseudoContent(element, ":before", {bgColorCheck}); ++ for (let node of $(element).childNodes) { ++ switch ($(node).nodeType) { ++ case ELEMENT_NODE$3: ++ text += getVisibleContent(node, ++ element, ++ getComputedStyle$2(node), ++ parentOverflowNode, ++ originalElement, ++ { ++ boxMargin, ++ bgColorCheck, ++ checkIsContained ++ } ++ ); ++ break; ++ case TEXT_NODE: ++ ++ if (parentOverflowNode) { ++ if (isContained(element, parentOverflowNode, {boxMargin}) && ++ isTextVisible(element, style, {bgColorCheck})) ++ text += $(node).nodeValue; ++ } ++ else if (isTextVisible(element, style, {bgColorCheck})) { ++ if (checkIsContained && ++ !isContained(element, originalElement, {boxMargin})) ++ continue; ++ text += $(node).nodeValue; ++ } ++ break; ++ } ++ } ++ return text + getPseudoContent(element, ":after", {bgColorCheck}); ++ } ++ const boxMarginStr = optionalParameters.get("-snippet-box-margin"); ++ const boxMargin = parseFloat(boxMarginStr) || 0; ++ ++ const bgColorCheckStr = optionalParameters.get("-disable-bg-color-check"); ++ const bgColorCheck = !(bgColorCheckStr === "true"); ++ ++ const checkIsContainedStr = optionalParameters.get("-check-is-contained"); ++ const checkIsContained = (checkIsContainedStr === "true"); ++ ++ let re = toRegExp(search); ++ let seen = new WeakSet$7(); ++ ++ const mo = hideIfMatches( ++ (element, closest) => { ++ if (seen.has(element)) ++ return false; ++ ++ seen.add(element); ++ let text = getVisibleContent(element, closest, null, null, element, { ++ boxMargin, ++ bgColorCheck, ++ checkIsContained ++ } ++ ); ++ let result = re.test(text); ++ if (debug() && text.length) ++ log(result, re, text); ++ return result; ++ }, ++ selector, ++ searchSelector ++ ); ++ mo.race(raceWinner( ++ "hide-if-contains-visible-text", ++ () => { ++ mo.disconnect(); ++ } ++ )); ++ } ++ ++ let {MutationObserver: MutationObserver$6, WeakSet: WeakSet$6, getComputedStyle: getComputedStyle$1} = $(window); ++ ++ function hideIfHasAndMatchesStyle(search, ++ selector = "*", ++ searchSelector = null, ++ style = null, ++ searchStyle = null, ++ waitUntil = null, ++ windowWidthMin = null, ++ windowWidthMax = null ++ ) { ++ const debugLog = getDebugger("hide-if-has-and-matches-style"); ++ const hiddenMap = new WeakSet$6(); ++ if (searchSelector == null) ++ searchSelector = selector; ++ ++ const styleRegExp = style ? toRegExp(style) : null; ++ const searchStyleRegExp = searchStyle ? toRegExp(searchStyle) : null; ++ const mainLogic = () => { ++ const callback = () => { ++ if ((windowWidthMin && window.innerWidth < windowWidthMin) || ++ (windowWidthMax && window.innerWidth > windowWidthMax) ++ ) ++ return; ++ for (const element of $$(searchSelector)) { ++ if (hiddenMap.has(element)) ++ continue; ++ if ($(element).querySelector(search) && ++ (!searchStyleRegExp || ++ searchStyleRegExp.test(getComputedCSSText(element)))) { ++ const closest = $(element).closest(selector); ++ if (closest && (!styleRegExp || ++ styleRegExp.test(getComputedCSSText(closest)))) { ++ win(); ++ hideElement(closest); ++ hiddenMap.add(element); ++ debugLog("Matched: ", ++ closest, ++ "which contains: ", ++ element, ++ " for params: ", ++ ...arguments); ++ } ++ else { ++ debugLog( ++ "In this element the searchStyle matched but style didn't:\n", ++ closest, ++ getComputedStyle$1(closest), ++ ...arguments); ++ } ++ } ++ else { ++ debugLog( ++ "In this element the searchStyle didn't match:\n", ++ element, ++ getComputedStyle$1(element), ++ ...arguments); ++ } ++ } ++ }; ++ ++ const mo = new MutationObserver$6(callback); ++ const win = raceWinner( ++ "hide-if-has-and-matches-style", ++ () => mo.disconnect() ++ ); ++ mo.observe(document, {childList: true, subtree: true}); ++ callback(); ++ }; ++ waitUntilEvent(debugLog, mainLogic, waitUntil); ++ } ++ ++ let {getComputedStyle, MutationObserver: MutationObserver$5, WeakSet: WeakSet$5} = $(window); ++ ++ function hideIfLabelledBy(search, selector, searchSelector = null) { ++ let sameSelector = searchSelector == null; ++ ++ let searchRegExp = toRegExp(search); ++ ++ let matched = new WeakSet$5(); ++ ++ let callback = () => { ++ for (let node of $$(selector)) { ++ let closest = sameSelector ? ++ node : ++ $(node).closest(searchSelector); ++ if (!closest || !isVisible(node, getComputedStyle(node), closest)) ++ continue; ++ ++ let attr = $(node).getAttribute("aria-labelledby"); ++ let fallback = () => { ++ if (matched.has(closest)) ++ return; ++ ++ if (searchRegExp.test( ++ $(node).getAttribute("aria-label") || "" ++ )) { ++ win(); ++ matched.add(closest); ++ hideElement(closest); ++ } ++ }; ++ ++ if (attr) { ++ for (let label of $(attr).split(/\s+/)) { ++ let target = $(document).getElementById(label); ++ if (target) { ++ if (!matched.has(target) && searchRegExp.test(target.innerText)) { ++ win(); ++ matched.add(target); ++ hideElement(closest); ++ } ++ } ++ else { ++ fallback(); ++ } ++ } ++ } ++ else { ++ fallback(); ++ } ++ } ++ }; ++ ++ let mo = new MutationObserver$5(callback); ++ let win = raceWinner( ++ "hide-if-labelled-by", ++ () => mo.disconnect() ++ ); ++ mo.observe(document, {characterData: true, childList: true, subtree: true}); ++ callback(); ++ } ++ ++ $(window); ++ ++ const noopProfile = { ++ mark() {}, ++ end() {}, ++ toString() { ++ return "{mark(){},end(){}}"; ++ } ++ }; ++ ++ function profile(id, rate = 10) { ++ return noopProfile; ++ } ++ ++ let {MutationObserver: MutationObserver$4, WeakSet: WeakSet$4} = $(window); ++ ++ const {ELEMENT_NODE: ELEMENT_NODE$2} = Node; ++ ++ function hideIfMatchesXPath(query, scopeQuery) { ++ const {mark, end} = profile(); ++ const debugLog = getDebugger("hide-if-matches-xpath"); ++ ++ const startHidingMutationObserver = scopeNode => { ++ const queryAndApply = initQueryAndApply(`xpath(${query})`); ++ const seenMap = new WeakSet$4(); ++ const callback = () => { ++ mark(); ++ queryAndApply(node => { ++ if (seenMap.has(node)) ++ return false; ++ seenMap.add(node); ++ win(); ++ if ($(node).nodeType === ELEMENT_NODE$2) ++ hideElement(node); ++ else ++ $(node).textContent = ""; ++ debugLog("Matched: ", node, " for selector: ", query); ++ }); ++ end(); ++ }; ++ const mo = new MutationObserver$4(callback); ++ const win = raceWinner( ++ "hide-if-matches-xpath", ++ () => mo.disconnect() ++ ); ++ mo.observe( ++ scopeNode, {characterData: true, childList: true, subtree: true}); ++ callback(); ++ }; ++ ++ if (scopeQuery) { ++ ++ let count = 0; ++ let scopeMutationObserver; ++ const scopeQueryAndApply = initQueryAndApply(`xpath(${scopeQuery})`); ++ const findMutationScopeNodes = () => { ++ scopeQueryAndApply(scopeNode => { ++ ++ startHidingMutationObserver(scopeNode); ++ count++; ++ }); ++ if (count > 0) ++ scopeMutationObserver.disconnect(); ++ }; ++ scopeMutationObserver = new MutationObserver$4(findMutationScopeNodes); ++ scopeMutationObserver.observe( ++ document, {characterData: true, childList: true, subtree: true} ++ ); ++ findMutationScopeNodes(); ++ } ++ else { ++ ++ startHidingMutationObserver(document); ++ } ++ } ++ ++ let {MutationObserver: MutationObserver$3, WeakSet: WeakSet$3} = $(window); ++ ++ const {ELEMENT_NODE: ELEMENT_NODE$1} = Node; ++ ++ function hideIfMatchesComputedXPath(query, searchQuery, searchRegex, ++ waitUntil) { ++ const {mark, end} = profile(); ++ const debugLog = getDebugger("hide-if-matches-computed-xpath"); ++ ++ if (!searchQuery || !query) { ++ debugLog("No query or searchQuery provided."); ++ return; ++ } ++ ++ const computeQuery = foundText => query.replace("{{}}", foundText); ++ ++ const startHidingMutationObserver = foundText => { ++ const computedQuery = computeQuery(foundText); ++ debugLog("Starting hiding elements that match query: ", computedQuery); ++ const queryAndApply = initQueryAndApply(`xpath(${computedQuery})`); ++ const seenMap = new WeakSet$3(); ++ const callback = () => { ++ mark(); ++ queryAndApply(node => { ++ if (seenMap.has(node)) ++ return false; ++ seenMap.add(node); ++ win(); ++ if ($(node).nodeType === ELEMENT_NODE$1) ++ hideElement(node); ++ else ++ $(node).textContent = ""; ++ debugLog("Matched: ", node, " for selector: ", query); ++ }); ++ end(); ++ }; ++ const mo = new MutationObserver$3(callback); ++ const win = raceWinner( ++ "hide-if-matches-computed-xpath", ++ () => mo.disconnect() ++ ); ++ mo.observe( ++ document, {characterData: true, childList: true, subtree: true}); ++ callback(); ++ }; ++ ++ const re = toRegExp(searchRegex); ++ ++ const mainLogic = () => { ++ if (searchQuery) { ++ debugLog("Started searching for: ", searchQuery); ++ const seenMap = new WeakSet$3(); ++ let searchMO; ++ const searchQueryAndApply = initQueryAndApply(`xpath(${searchQuery})`); ++ const findMutationSearchNodes = () => { ++ searchQueryAndApply(searchNode => { ++ if (seenMap.has(searchNode)) ++ return false; ++ seenMap.add(searchNode); ++ debugLog("Found node: ", searchNode); ++ if (searchNode.innerHTML) { ++ debugLog("Searching in: ", searchNode.innerHTML); ++ const foundTextArr = searchNode.innerHTML.match(re); ++ if (foundTextArr && foundTextArr.length) { ++ let foundText = ""; ++ ++ foundTextArr[1] ? foundText = foundTextArr[1] : ++ foundText = foundTextArr[0]; ++ debugLog("Matched search query: ", foundText); ++ startHidingMutationObserver(foundText); ++ } ++ } ++ }); ++ }; ++ ++ searchMO = new MutationObserver$3(findMutationSearchNodes); ++ searchMO.observe( ++ document, {characterData: true, childList: true, subtree: true} ++ ); ++ findMutationSearchNodes(); ++ } ++ }; ++ ++ waitUntilEvent(debugLog, mainLogic, waitUntil); ++ } ++ ++ let { ++ parseInt: parseInt$1, ++ setTimeout: setTimeout$1, ++ Error: Error$2, ++ MouseEvent: MouseEvent$2, ++ MutationObserver: MutationObserver$2, ++ WeakSet: WeakSet$2 ++ } = $(window); ++ ++ function simulateEvent(event, selector, delay = "0") { ++ if (!event) ++ throw new Error$2("[simulate-event snippet]: No event type provided."); ++ if (!selector) ++ throw new Error$2("[simulate-event snippet]: No selector provided."); ++ ++ let queryAndApply = initQueryAndApply(selector); ++ let delayInMiliseconds = parseInt$1(delay, 10); ++ let dispatchedNodes = new WeakSet$2(); ++ ++ let observer = new MutationObserver$2(findNodesAndDispatchEvents); ++ observer.observe(document, {childList: true, subtree: true}); ++ findNodesAndDispatchEvents(); ++ ++ function findNodesAndDispatchEvents() { ++ queryAndApply(node => { ++ if (!dispatchedNodes.has(node)) { ++ dispatchedNodes.add(node); ++ setTimeout$1(() => { ++ $(node).dispatchEvent( ++ new MouseEvent$2(event, {bubbles: true, cancelable: true}) ++ ); ++ }, delayInMiliseconds); ++ } ++ }); ++ } ++ } ++ ++ let { ++ parseInt, ++ setTimeout, ++ Error: Error$1, ++ MouseEvent: MouseEvent$1, ++ MutationObserver: MutationObserver$1, ++ WeakSet: WeakSet$1 ++ } = $(window); ++ ++ const VALID_TYPES = ["auxclick", "click", "dblclick", "gotpointercapture", ++ "lostpointercapture", "mouseenter", "mousedown", ++ "mouseleave", "mousemove", "mouseout", "mouseover", ++ "mouseup", "pointerdown", "pointerenter", ++ "pointermove", "pointerover", "pointerout", ++ "pointerup", "pointercancel", "pointerleave"]; ++ ++ function simulateMouseEvent(...selectors) { ++ const debugLog = getDebugger("simulate-mouse-event"); ++ const MAX_ARGS = 7; ++ if (selectors.length < 1) ++ throw new Error$1("[simulate-mouse-event snippet]: No selector provided."); ++ if (selectors.length > MAX_ARGS) { ++ ++ selectors = selectors.slice(0, MAX_ARGS); ++ } ++ function parseArg(theRule) { ++ if (!theRule) ++ return null; ++ ++ const result = { ++ selector: "", ++ continue: false, ++ trigger: false, ++ event: "click", ++ delay: "500", ++ clicked: false, ++ found: false ++ }; ++ const textArr = theRule.split("$"); ++ let options = []; ++ if (textArr.length >= 2) ++ options = textArr[1].toLowerCase().split(","); ++ ++ [result.selector] = textArr; ++ ++ for (const option of options) { ++ if (option === "trigger") { ++ result.trigger = true; ++ } ++ else if (option === "continue") { ++ result.continue = true; ++ } ++ else if (option.startsWith("event")) { ++ const event = option.toLowerCase().split("="); ++ event[1] ? result.event = event[1] : result.event = "click"; ++ } ++ else if (option.startsWith("delay")) { ++ const delay = option.toLowerCase().split("="); ++ delay[1] ? result.delay = delay[1] : result.delay = "500"; ++ } ++ } ++ if (!VALID_TYPES.includes(result.event)) { ++ debugLog(result.event, ++ " might be misspelled, check for typos.\n", ++ "These are the supported events:", ++ VALID_TYPES); ++ } ++ return result; ++ } ++ ++ const parsedArgs = $([]); ++ ++ $(selectors).forEach(rule => { ++ const parsedRule = parseArg(rule); ++ parsedArgs.push(parsedRule); ++ }); ++ ++ function checkIfAllSelectorsFound() { ++ parsedArgs.forEach(arg => { ++ if (!arg.found) { ++ const queryAll = initQueryAll(arg.selector); ++ const elems = queryAll(); ++ if (elems.length > 0) ++ arg.found = true; ++ } ++ }); ++ return parsedArgs.every(arg => arg.found); ++ } ++ ++ function triggerEvent(node, event, delay) { ++ ++ if (!node || !event) ++ return; ++ ++ if (event === "click" && node.click) { ++ node.click(); ++ debugLog( ++ "Clicked on this node:\n", node, "\nwith a delay of", delay, "ms" ++ ); ++ } ++ else { ++ node.dispatchEvent( ++ new MouseEvent$1(event, {bubbles: true, cancelable: true}) ++ ); ++ debugLog( ++ "A", ++ event, ++ "event was dispatched with a delay of", ++ delay, ++ "ms on this node:\n", ++ node ++ ); ++ } ++ } ++ let allFound = false; ++ ++ const [last] = parsedArgs.slice(-1); ++ last.trigger = true; ++ ++ let dispatchedNodes = new WeakSet$1(); ++ ++ let observer = new MutationObserver$1(findNodesAndDispatchEvents); ++ observer.observe(document, {childList: true, subtree: true}); ++ findNodesAndDispatchEvents(); ++ ++ function findNodesAndDispatchEvents() { ++ ++ if (!allFound) ++ allFound = checkIfAllSelectorsFound(); ++ if (allFound) { ++ for (const parsedRule of parsedArgs) { ++ const queryAndApply = initQueryAndApply(parsedRule.selector); ++ const delayInMiliseconds = parseInt(parsedRule.delay, 10); ++ if (parsedRule.trigger) { ++ queryAndApply(node => { ++ if (!dispatchedNodes.has(node)) { ++ dispatchedNodes.add(node); ++ if (parsedRule.continue) { ++ setInterval(() => { ++ triggerEvent(node, parsedRule.event, parsedRule.delay); ++ }, delayInMiliseconds); ++ } ++ else { ++ setTimeout(() => { ++ triggerEvent(node, parsedRule.event, parsedRule.delay); ++ }, delayInMiliseconds); ++ } ++ } ++ }); ++ } ++ } ++ } ++ } ++ } ++ ++ const snippets = { ++ log, ++ race, ++ "debug": setDebug, ++ "hide-if-matches-xpath": hideIfMatchesXPath, ++ "hide-if-matches-computed-xpath": hideIfMatchesComputedXPath, ++ "hide-if-contains": hideIfContains, ++ "hide-if-contains-similar-text": hideIfContainsSimilarText, ++ "hide-if-contains-visible-text": hideIfContainsVisibleText, ++ "hide-if-contains-and-matches-style": hideIfContainsAndMatchesStyle, ++ "hide-if-has-and-matches-style": hideIfHasAndMatchesStyle, ++ "hide-if-labelled-by": hideIfLabelledBy, ++ "hide-if-contains-image": hideIfContainsImage, ++ "simulate-event-poc": simulateEvent, ++ "simulate-mouse-event": simulateMouseEvent ++ }; ++ ++ let {MutationObserver} = $(window); ++ ++ const {ELEMENT_NODE} = Node; ++ ++ function hideIfMatchesXPath3(query, scopeQuery) { ++ let {mark, end} = profile(); ++ ++ function queryNodes() { ++ return fontoxpath.evaluateXPathToNodes(query, document, null, null, { ++ language: fontoxpath.evaluateXPath.XQUERY_3_1_LANGUAGE ++ }); ++ } ++ ++ let debugLog = getDebugger("hide-if-matches-xpath3"); ++ ++ const startHidingMutationObserver = scopeNode => { ++ const seenMap = new WeakSet(); ++ const callback = () => { ++ mark(); ++ ++ const nodes = queryNodes(); ++ for (const node of $(nodes)) { ++ if (seenMap.has(node)) ++ return false; ++ seenMap.add(node); ++ win(); ++ if ($(node).nodeType === ELEMENT_NODE) ++ hideElement(node); ++ else ++ $(node).textContent = ""; ++ debugLog("Matched: ", node, " for selector: ", query); ++ } ++ end(); ++ }; ++ ++ const mo = new MutationObserver(callback); ++ const win = raceWinner( ++ "hide-if-matches-xpath3", ++ () => mo.disconnect() ++ ); ++ mo.observe( ++ scopeNode, {characterData: true, childList: true, subtree: true}); ++ callback(); ++ }; ++ ++ if (scopeQuery) { ++ ++ let count = 0; ++ let scopeMutationObserver; ++ const scopeNodes = queryNodes(); ++ const findMutationScopeNodes = () => { ++ for (const scopeNode of $(scopeNodes)) { ++ ++ startHidingMutationObserver(scopeNode); ++ count++; ++ } ++ if (count > 0) ++ scopeMutationObserver.disconnect(); ++ }; ++ ++ scopeMutationObserver = new MutationObserver(findMutationScopeNodes); ++ scopeMutationObserver.observe( ++ document, {characterData: true, childList: true, subtree: true} ++ ); ++ findMutationScopeNodes(); ++ } ++ else { ++ ++ startHidingMutationObserver(document); ++ } ++ } ++ ++ snippets["hide-if-matches-xpath3"] = hideIfMatchesXPath3; ++ let context; ++ for (const [name, ...args] of filters) { ++ if (snippets.hasOwnProperty(name)) { ++ try { context = snippets[name].apply(context, args); } ++ catch (error) { console.error(error); } ++ } ++ } ++ context = void 0; ++})(e, ...t); ++ ++const callback = (environment, ...filters) => { ++ /*! ++ * This file is part of eyeo's Anti-Circumvention Snippets module (@eyeo/snippets), ++ * Copyright (C) 2006-present eyeo GmbH ++ * ++ * @eyeo/snippets is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 3 as ++ * published by the Free Software Foundation. ++ * ++ * @eyeo/snippets is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with @eyeo/snippets. If not, see . ++ */ ++ const $$1 = Proxy; ++ ++ const {apply: a, bind: b, call: c} = Function; ++ const apply$2 = c.bind(a); ++ const bind = c.bind(b); ++ const call = c.bind(c); ++ ++ const callerHandler = { ++ get(target, name) { ++ return bind(c, target[name]); ++ } ++ }; ++ ++ const caller = target => new $$1(target, callerHandler); ++ ++ const proxy = (source, target) => new $$1(source, { ++ apply: (_, self, args) => apply$2(target, self, args) ++ }); ++ ++ const handler$2 = { ++ get(target, name) { ++ return bind(target[name], target); ++ } ++ }; ++ ++ const bound = target => new $$1(target, handler$2); ++ ++ const { ++ assign: assign$1, ++ defineProperties: defineProperties$1, ++ freeze: freeze$1, ++ getOwnPropertyDescriptor: getOwnPropertyDescriptor$3, ++ getOwnPropertyDescriptors: getOwnPropertyDescriptors$1, ++ getPrototypeOf ++ } = bound(Object); ++ ++ const {hasOwnProperty} = caller({}); ++ ++ const {species} = Symbol; ++ ++ const handler$1 = { ++ get(target, name) { ++ const Native = target[name]; ++ class Secure extends Native {} ++ ++ const proto = getOwnPropertyDescriptors$1(Native.prototype); ++ delete proto.constructor; ++ freeze$1(defineProperties$1(Secure.prototype, proto)); ++ ++ const statics = getOwnPropertyDescriptors$1(Native); ++ delete statics.length; ++ delete statics.prototype; ++ statics[species] = {value: Secure}; ++ return freeze$1(defineProperties$1(Secure, statics)); ++ } ++ }; ++ ++ const secure = target => new $$1(target, handler$1); ++ ++ const libEnvironment = typeof environment !== "undefined" ? environment : ++ {}; ++ ++ if (typeof globalThis === "undefined") ++ window.globalThis = window; ++ ++ const {apply: apply$1, ownKeys} = bound(Reflect); ++ ++ const worldEnvDefined = "world" in libEnvironment; ++ const isIsolatedWorld = worldEnvDefined && libEnvironment.world === "ISOLATED"; ++ const isMainWorld = worldEnvDefined && libEnvironment.world === "MAIN"; ++ const isChrome = typeof chrome === "object" && !!chrome.runtime; ++ const isOtherThanChrome = typeof browser === "object" && !!browser.runtime; ++ const isExtensionContext$2 = !isMainWorld && ++ (isIsolatedWorld || isChrome || isOtherThanChrome); ++ const copyIfExtension = value => isExtensionContext$2 ? ++ value : ++ create(value, getOwnPropertyDescriptors(value)); ++ ++ const { ++ create, ++ defineProperties, ++ defineProperty, ++ freeze, ++ getOwnPropertyDescriptor: getOwnPropertyDescriptor$2, ++ getOwnPropertyDescriptors ++ } = bound(Object); ++ ++ const invokes = bound(globalThis); ++ const classes = isExtensionContext$2 ? globalThis : secure(globalThis); ++ const {Map: Map$8, RegExp: RegExp$1, Set: Set$2, WeakMap: WeakMap$4, WeakSet: WeakSet$3} = classes; ++ ++ const augment = (source, target, method = null) => { ++ const known = ownKeys(target); ++ for (const key of ownKeys(source)) { ++ if (known.includes(key)) ++ continue; ++ ++ const descriptor = getOwnPropertyDescriptor$2(source, key); ++ if (method && "value" in descriptor) { ++ const {value} = descriptor; ++ if (typeof value === "function") ++ descriptor.value = method(value); ++ } ++ defineProperty(target, key, descriptor); ++ } ++ }; ++ ++ const primitive = name => { ++ const Super = classes[name]; ++ class Class extends Super {} ++ const {toString, valueOf} = Super.prototype; ++ defineProperties(Class.prototype, { ++ toString: {value: toString}, ++ valueOf: {value: valueOf} ++ }); ++ const type = name.toLowerCase(); ++ const method = callback => function() { ++ const result = apply$1(callback, this, arguments); ++ return typeof result === type ? new Class(result) : result; ++ }; ++ augment(Super, Class, method); ++ augment(Super.prototype, Class.prototype, method); ++ return Class; ++ }; ++ ++ const variables$3 = freeze({ ++ frozen: new WeakMap$4(), ++ hidden: new WeakSet$3(), ++ iframePropertiesToAbort: { ++ read: new Set$2(), ++ write: new Set$2() ++ }, ++ abortedIframes: new WeakMap$4() ++ }); ++ ++ const startsCapitalized = new RegExp$1("^[A-Z]"); ++ ++ var env = new Proxy(new Map$8([ ++ ++ ["chrome", ( ++ isExtensionContext$2 && ( ++ (isChrome && chrome) || ++ (isOtherThanChrome && browser) ++ ) ++ ) || void 0], ++ ["isExtensionContext", isExtensionContext$2], ++ ["variables", variables$3], ++ ++ ["console", copyIfExtension(console)], ++ ["document", globalThis.document], ++ ["performance", copyIfExtension(performance)], ++ ["JSON", copyIfExtension(JSON)], ++ ["Map", Map$8], ++ ["Math", copyIfExtension(Math)], ++ ["Number", isExtensionContext$2 ? Number : primitive("Number")], ++ ["RegExp", RegExp$1], ++ ["Set", Set$2], ++ ["String", isExtensionContext$2 ? String : primitive("String")], ++ ["WeakMap", WeakMap$4], ++ ["WeakSet", WeakSet$3], ++ ++ ["MouseEvent", MouseEvent] ++ ]), { ++ get(map, key) { ++ if (map.has(key)) ++ return map.get(key); ++ ++ let value = globalThis[key]; ++ if (typeof value === "function") ++ value = (startsCapitalized.test(key) ? classes : invokes)[key]; ++ ++ map.set(key, value); ++ return value; ++ }, ++ has(map, key) { ++ return map.has(key); ++ } ++ }); ++ ++ class WeakValue { ++ has() { return false; } ++ set() {} ++ } ++ ++ const helpers = {WeakSet, WeakMap, WeakValue}; ++ const {apply} = Reflect; ++ ++ function transformOnce (callback) { const {WeakSet, WeakMap, WeakValue} = (this || helpers); ++ const ws = new WeakSet; ++ const wm = new WeakMap; ++ const wv = new WeakValue; ++ return function (any) { ++ if (ws.has(any)) ++ return any; ++ ++ if (wm.has(any)) ++ return wm.get(any); ++ ++ if (wv.has(any)) ++ return wv.get(any); ++ ++ const value = apply(callback, this, arguments); ++ ws.add(value); ++ if (value !== any) ++ (typeof any === 'object' && any ? wm : wv).set(any, value); ++ return value; ++ }; ++ } ++ ++ const {Map: Map$7, WeakMap: WeakMap$3, WeakSet: WeakSet$2, setTimeout} = env; ++ ++ let cleanup = true; ++ let cleanUpCallback = map => { ++ map.clear(); ++ cleanup = !cleanup; ++ }; ++ ++ var transformer = transformOnce.bind({ ++ WeakMap: WeakMap$3, ++ WeakSet: WeakSet$2, ++ ++ WeakValue: class extends Map$7 { ++ set(key, value) { ++ if (cleanup) { ++ cleanup = !cleanup; ++ setTimeout(cleanUpCallback, 0, this); ++ } ++ return super.set(key, value); ++ } ++ } ++ }); ++ ++ const {concat, includes, join, reduce, unshift} = caller([]); ++ ++ const globals = secure(globalThis); ++ ++ const { ++ Map: Map$6, ++ WeakMap: WeakMap$2 ++ } = globals; ++ ++ const map = new Map$6; ++ const descriptors = target => { ++ const chain = []; ++ let current = target; ++ while (current) { ++ if (map.has(current)) ++ unshift(chain, map.get(current)); ++ else { ++ const descriptors = getOwnPropertyDescriptors$1(current); ++ map.set(current, descriptors); ++ unshift(chain, descriptors); ++ } ++ current = getPrototypeOf(current); ++ } ++ unshift(chain, {}); ++ return apply$2(assign$1, null, chain); ++ }; ++ ++ const chain = source => { ++ const target = typeof source === 'function' ? source.prototype : source; ++ const chained = descriptors(target); ++ const handler = { ++ get(target, key) { ++ if (key in chained) { ++ const {value, get} = chained[key]; ++ if (get) ++ return call(get, target); ++ if (typeof value === 'function') ++ return bind(value, target); ++ } ++ return target[key]; ++ }, ++ set(target, key, value) { ++ if (key in chained) { ++ const {set} = chained[key]; ++ if (set) { ++ call(set, target, value); ++ return true; ++ } ++ } ++ target[key] = value; ++ return true; ++ } ++ }; ++ return target => new $$1(target, handler); ++ }; ++ ++ const { ++ isExtensionContext: isExtensionContext$1, ++ Array: Array$2, ++ Number: Number$1, ++ String: String$1, ++ Object: Object$9 ++ } = env; ++ ++ const {isArray} = Array$2; ++ const {getOwnPropertyDescriptor: getOwnPropertyDescriptor$1, setPrototypeOf: setPrototypeOf$1} = Object$9; ++ ++ const {toString: toString$1} = Object$9.prototype; ++ const {slice} = String$1.prototype; ++ const getBrand = value => call(slice, call(toString$1, value), 8, -1); ++ ++ const {get: nodeType} = getOwnPropertyDescriptor$1(Node.prototype, "nodeType"); ++ ++ const chained = isExtensionContext$1 ? {} : { ++ Attr: chain(Attr), ++ CanvasRenderingContext2D: chain(CanvasRenderingContext2D), ++ CSSStyleDeclaration: chain(CSSStyleDeclaration), ++ Document: chain(Document), ++ Element: chain(Element), ++ HTMLCanvasElement: chain(HTMLCanvasElement), ++ HTMLElement: chain(HTMLElement), ++ HTMLImageElement: chain(HTMLImageElement), ++ HTMLScriptElement: chain(HTMLScriptElement), ++ MutationRecord: chain(MutationRecord), ++ Node: chain(Node), ++ ShadowRoot: chain(ShadowRoot), ++ ++ get CSS2Properties() { ++ return chained.CSSStyleDeclaration; ++ } ++ }; ++ ++ const upgrade = (value, hint) => { ++ if (hint !== "Element" && hint in chained) ++ return chained[hint](value); ++ ++ if (isArray(value)) ++ return setPrototypeOf$1(value, Array$2.prototype); ++ ++ const brand = getBrand(value); ++ if (brand in chained) ++ return chained[brand](value); ++ ++ if (brand in env) ++ return setPrototypeOf$1(value, env[brand].prototype); ++ ++ if ("nodeType" in value) { ++ switch (call(nodeType, value)) { ++ case 1: ++ if (!(hint in chained)) ++ throw new Error("unknown hint " + hint); ++ return chained[hint](value); ++ case 2: ++ return chained.Attr(value); ++ case 3: ++ return chained.Node(value); ++ case 9: ++ return chained.Document(value); ++ } ++ } ++ ++ throw new Error("unknown brand " + brand); ++ }; ++ ++ var $ = isExtensionContext$1 ? ++ value => (value === window || value === globalThis ? env : value) : ++ transformer((value, hint = "Element") => { ++ if (value === window || value === globalThis) ++ return env; ++ ++ switch (typeof value) { ++ case "object": ++ return value && upgrade(value, hint); ++ ++ case "string": ++ return new String$1(value); ++ ++ case "number": ++ return new Number$1(value); ++ ++ default: ++ throw new Error("unsupported value"); ++ } ++ }); ++ ++ const handler = { ++ get(target, name) { ++ const context = target; ++ while (!hasOwnProperty(target, name)) ++ target = getPrototypeOf(target); ++ const {get, set} = getOwnPropertyDescriptor$3(target, name); ++ return function () { ++ return arguments.length ? ++ apply$2(set, context, arguments) : ++ call(get, context); ++ }; ++ } ++ }; ++ ++ const accessor = target => new $$1(target, handler); ++ ++ let debugging = false; ++ ++ function debug() { ++ return debugging; ++ } ++ ++ function setDebug() { ++ debugging = true; ++ } ++ ++ const {console: console$3} = $(window); ++ ++ const noop = () => {}; ++ ++ function log(...args) { ++ if (debug()) ++ $(args).unshift("%c DEBUG", "font-weight: bold"); ++ ++ console$3.log(...args); ++ } ++ ++ function getDebugger(name) { ++ return bind(debug() ? log : noop, null, name); ++ } ++ ++ let {Math: Math$1, RegExp} = $(window); ++ ++ function regexEscape(string) { ++ return $(string).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); ++ } ++ ++ function toRegExp(pattern) { ++ let {length} = pattern; ++ ++ if (length > 1 && pattern[0] === "/") { ++ let isCaseSensitive = pattern[length - 1] === "/"; ++ ++ if (isCaseSensitive || (length > 2 && $(pattern).endsWith("/i"))) { ++ let args = [$(pattern).slice(1, isCaseSensitive ? -1 : -2)]; ++ if (!isCaseSensitive) ++ args.push("i"); ++ ++ return new RegExp(...args); ++ } ++ } ++ ++ return new RegExp(regexEscape(pattern)); ++ } ++ ++ function randomId() { ++ ++ return $(Math$1.floor(Math$1.random() * 2116316160 + 60466176)).toString(36); ++ } ++ ++ let { ++ parseFloat, ++ variables: variables$2, ++ Array: Array$1, ++ Error: Error$7, ++ Map: Map$5, ++ Object: Object$8, ++ ReferenceError: ReferenceError$2, ++ Set: Set$1, ++ WeakMap: WeakMap$1 ++ } = $(window); ++ ++ let {onerror} = accessor(window); ++ ++ let NodeProto$1 = Node.prototype; ++ let ElementProto$2 = Element.prototype; ++ ++ let propertyAccessors = null; ++ ++ function wrapPropertyAccess(object, property, descriptor, ++ setConfigurable = true) { ++ let $property = $(property); ++ let dotIndex = $property.indexOf("."); ++ if (dotIndex == -1) { ++ ++ let currentDescriptor = Object$8.getOwnPropertyDescriptor(object, property); ++ if (currentDescriptor && !currentDescriptor.configurable) ++ return; ++ ++ let newDescriptor = Object$8.assign({}, descriptor, { ++ configurable: setConfigurable ++ }); ++ ++ if (!currentDescriptor && !newDescriptor.get && newDescriptor.set) { ++ let propertyValue = object[property]; ++ newDescriptor.get = () => propertyValue; ++ } ++ ++ Object$8.defineProperty(object, property, newDescriptor); ++ return; ++ } ++ ++ let name = $property.slice(0, dotIndex).toString(); ++ property = $property.slice(dotIndex + 1).toString(); ++ let value = object[name]; ++ if (value && (typeof value == "object" || typeof value == "function")) ++ wrapPropertyAccess(value, property, descriptor); ++ ++ let currentDescriptor = Object$8.getOwnPropertyDescriptor(object, name); ++ if (currentDescriptor && !currentDescriptor.configurable) ++ return; ++ ++ if (!propertyAccessors) ++ propertyAccessors = new WeakMap$1(); ++ ++ if (!propertyAccessors.has(object)) ++ propertyAccessors.set(object, new Map$5()); ++ ++ let properties = propertyAccessors.get(object); ++ if (properties.has(name)) { ++ properties.get(name).set(property, descriptor); ++ return; ++ } ++ ++ let toBeWrapped = new Map$5([[property, descriptor]]); ++ properties.set(name, toBeWrapped); ++ Object$8.defineProperty(object, name, { ++ get: () => value, ++ set(newValue) { ++ value = newValue; ++ if (value && (typeof value == "object" || typeof value == "function")) { ++ ++ for (let [prop, desc] of toBeWrapped) ++ wrapPropertyAccess(value, prop, desc); ++ } ++ }, ++ configurable: setConfigurable ++ }); ++ } ++ ++ function overrideOnError(magic) { ++ let prev = onerror(); ++ onerror((...args) => { ++ let message = args.length && args[0]; ++ if (typeof message == "string" && $(message).includes(magic)) ++ return true; ++ if (typeof prev == "function") ++ return apply$2(prev, this, args); ++ }); ++ } ++ ++ function abortOnRead(loggingPrefix, context, property, ++ setConfigurable = true) { ++ let debugLog = getDebugger(loggingPrefix); ++ ++ if (!property) { ++ debugLog("no property to abort on read"); ++ return; ++ } ++ ++ let rid = randomId(); ++ ++ function abort() { ++ debugLog(`${property} access aborted`); ++ throw new ReferenceError$2(rid); ++ } ++ ++ debugLog(`aborting on ${property} access`); ++ ++ wrapPropertyAccess(context, ++ property, ++ {get: abort, set() {}}, ++ setConfigurable); ++ overrideOnError(rid); ++ } ++ ++ function abortOnWrite(loggingPrefix, context, property, ++ setConfigurable = true) { ++ let debugLog = getDebugger(loggingPrefix); ++ ++ if (!property) { ++ debugLog("no property to abort on write"); ++ return; ++ } ++ ++ let rid = randomId(); ++ ++ function abort() { ++ debugLog(`setting ${property} aborted`); ++ throw new ReferenceError$2(rid); ++ } ++ ++ debugLog(`aborting when setting ${property}`); ++ ++ wrapPropertyAccess(context, property, {set: abort}, setConfigurable); ++ overrideOnError(rid); ++ } ++ ++ function abortOnIframe( ++ properties, ++ abortRead = false, ++ abortWrite = false ++ ) { ++ let abortedIframes = variables$2.abortedIframes; ++ let iframePropertiesToAbort = variables$2.iframePropertiesToAbort; ++ ++ for (let frame of Array$1.from(window.frames)) { ++ if (abortedIframes.has(frame)) { ++ for (let property of properties) { ++ if (abortRead) ++ abortedIframes.get(frame).read.add(property); ++ if (abortWrite) ++ abortedIframes.get(frame).write.add(property); ++ } ++ } ++ } ++ ++ for (let property of properties) { ++ if (abortRead) ++ iframePropertiesToAbort.read.add(property); ++ if (abortWrite) ++ iframePropertiesToAbort.write.add(property); ++ } ++ ++ queryAndProxyIframe(); ++ if (!abortedIframes.has(document)) { ++ abortedIframes.set(document, true); ++ addHooksOnDomAdditions(queryAndProxyIframe); ++ } ++ ++ function queryAndProxyIframe() { ++ for (let frame of Array$1.from(window.frames)) { ++ ++ if (!abortedIframes.has(frame)) { ++ abortedIframes.set(frame, { ++ read: new Set$1(iframePropertiesToAbort.read), ++ write: new Set$1(iframePropertiesToAbort.write) ++ }); ++ } ++ ++ let readProps = abortedIframes.get(frame).read; ++ if (readProps.size > 0) { ++ let props = Array$1.from(readProps); ++ readProps.clear(); ++ for (let property of props) ++ abortOnRead("abort-on-iframe-property-read", frame, property); ++ } ++ ++ let writeProps = abortedIframes.get(frame).write; ++ if (writeProps.size > 0) { ++ let props = Array$1.from(writeProps); ++ writeProps.clear(); ++ for (let property of props) ++ abortOnWrite("abort-on-iframe-property-write", frame, property); ++ } ++ } ++ } ++ } ++ ++ function addHooksOnDomAdditions(endCallback) { ++ let descriptor; ++ ++ wrapAccess(NodeProto$1, ["appendChild", "insertBefore", "replaceChild"]); ++ wrapAccess(ElementProto$2, ["append", "prepend", "replaceWith", "after", ++ "before", "insertAdjacentElement", ++ "insertAdjacentHTML"]); ++ ++ descriptor = getInnerHTMLDescriptor(ElementProto$2, "innerHTML"); ++ wrapPropertyAccess(ElementProto$2, "innerHTML", descriptor); ++ ++ descriptor = getInnerHTMLDescriptor(ElementProto$2, "outerHTML"); ++ wrapPropertyAccess(ElementProto$2, "outerHTML", descriptor); ++ ++ function wrapAccess(prototype, names) { ++ for (let name of names) { ++ let desc = getAppendChildDescriptor(prototype, name); ++ wrapPropertyAccess(prototype, name, desc); ++ } ++ } ++ ++ function getAppendChildDescriptor(target, property) { ++ let currentValue = target[property]; ++ return { ++ get() { ++ return function(...args) { ++ let result; ++ result = apply$2(currentValue, this, args); ++ endCallback && endCallback(); ++ return result; ++ }; ++ } ++ }; ++ } ++ ++ function getInnerHTMLDescriptor(target, property) { ++ let desc = Object$8.getOwnPropertyDescriptor(target, property); ++ let {set: prevSetter} = desc || {}; ++ return { ++ set(val) { ++ let result; ++ result = call(prevSetter, this, val); ++ endCallback && endCallback(); ++ return result; ++ } ++ }; ++ } ++ } ++ ++ let {Object: NativeObject} = window; ++ function findOwner(root, path) { ++ if (!(root instanceof NativeObject)) ++ return; ++ ++ let object = root; ++ let chain = $(path).split("."); ++ ++ if (chain.length === 0) ++ return; ++ ++ for (let i = 0; i < chain.length - 1; i++) { ++ let prop = chain[i]; ++ ++ if (!hasOwnProperty(object, prop)) ++ return; ++ ++ object = object[prop]; ++ ++ if (!(object instanceof NativeObject)) ++ return; ++ } ++ ++ let prop = chain[chain.length - 1]; ++ ++ if (hasOwnProperty(object, prop)) ++ return [object, prop]; ++ } ++ ++ const decimals = $(/^\d+$/); ++ ++ function overrideValue(value) { ++ switch (value) { ++ case "false": ++ return false; ++ case "true": ++ return true; ++ case "null": ++ return null; ++ case "noopFunc": ++ return () => {}; ++ case "trueFunc": ++ return () => true; ++ case "falseFunc": ++ return () => false; ++ case "emptyArray": ++ return []; ++ case "emptyObj": ++ return {}; ++ case "undefined": ++ return void 0; ++ case "": ++ return value; ++ default: ++ if (decimals.test(value)) ++ return parseFloat(value); ++ ++ throw new Error$7("[override-property-read snippet]: " + ++ `Value "${value}" is not valid.`); ++ } ++ } ++ ++ let {HTMLScriptElement: HTMLScriptElement$1, Object: Object$7, ReferenceError: ReferenceError$1} = $(window); ++ let Script = Object$7.getPrototypeOf(HTMLScriptElement$1); ++ ++ function abortCurrentInlineScript(api, search = null) { ++ const debugLog = getDebugger("abort-current-inline-script"); ++ const re = search ? toRegExp(search) : null; ++ ++ const rid = randomId(); ++ const us = $(document).currentScript; ++ ++ let object = window; ++ const path = $(api).split("."); ++ const name = $(path).pop(); ++ ++ for (let node of $(path)) { ++ object = object[node]; ++ if ( ++ !object || !(typeof object == "object" || typeof object == "function")) { ++ debugLog(path, " is not found"); ++ return; ++ } ++ } ++ ++ const {get: prevGetter, set: prevSetter} = ++ Object$7.getOwnPropertyDescriptor(object, name) || {}; ++ ++ let currentValue = object[name]; ++ if (typeof currentValue === "undefined") ++ debugLog("The property", name, "doesn't exist yet. Check typos."); ++ ++ const abort = () => { ++ const element = $(document).currentScript; ++ if (element instanceof Script && ++ $(element, "HTMLScriptElement").src == "" && ++ element != us && ++ (!re || re.test($(element).textContent))) { ++ debugLog(path, " is aborted \n", element); ++ throw new ReferenceError$1(rid); ++ } ++ }; ++ ++ const descriptor = { ++ get() { ++ abort(); ++ ++ if (prevGetter) ++ return call(prevGetter, this); ++ ++ return currentValue; ++ }, ++ set(value) { ++ abort(); ++ ++ if (prevSetter) ++ call(prevSetter, this, value); ++ else ++ currentValue = value; ++ } ++ }; ++ ++ wrapPropertyAccess(object, name, descriptor); ++ ++ overrideOnError(rid); ++ } ++ ++ function abortOnIframePropertyRead(...properties) { ++ abortOnIframe(properties, true, false); ++ } ++ ++ function abortOnIframePropertyWrite(...properties) { ++ abortOnIframe(properties, false, true); ++ } ++ ++ function abortOnPropertyRead(property, setConfigurable) { ++ const configurableFlag = !(setConfigurable === "false"); ++ abortOnRead("abort-on-property-read", window, property, configurableFlag); ++ } ++ ++ function abortOnPropertyWrite(property, setConfigurable) { ++ const configurableFlag = !(setConfigurable === "false"); ++ abortOnWrite("abort-on-property-write", window, property, configurableFlag); ++ } ++ ++ let {Error: Error$6} = $(window); ++ let {cookie: documentCookies} = accessor(document); ++ ++ function cookieRemover(cookie) { ++ if (!cookie) ++ throw new Error$6("[cookie-remover snippet]: No cookie to remove."); ++ ++ let debugLog = getDebugger("cookie-remover"); ++ let re = toRegExp(cookie); ++ ++ if (!$(/^http|^about/).test(location.protocol)) { ++ debugLog("Snippet only works for http or https and about."); ++ return; ++ } ++ ++ debugLog("Parsing cookies for matches"); ++ ++ for (const pair of $(getCookieMatches())) { ++ let $hostname = $(location.hostname); ++ let name = $(pair).split("=")[0]; ++ let expires = "expires=Thu, 01 Jan 1970 00:00:00 GMT"; ++ let path = "path=/"; ++ let domain = "domain=" + $hostname.slice($hostname.indexOf(".") + 1); ++ ++ documentCookies(`${$(name).trim()}=;${expires};${path};${domain}`); ++ ++ debugLog(`Set expiration date on ${name}`); ++ } ++ ++ function getCookieMatches() { ++ const arr = $(documentCookies()).split(";"); ++ return arr.filter(str => re.test($(str).split("=")[0])); ++ } ++ } ++ ++ let { ++ document: document$1, ++ getComputedStyle, ++ isExtensionContext, ++ variables: variables$1, ++ Array, ++ MutationObserver: MutationObserver$2, ++ Object: Object$6, ++ XPathEvaluator, ++ XPathExpression, ++ XPathResult ++ } = $(window); ++ ++ let {querySelectorAll} = document$1; ++ let $$ = querySelectorAll && bind(querySelectorAll, document$1); ++ ++ const {assign, setPrototypeOf} = Object$6; ++ ++ class $XPathExpression extends XPathExpression { ++ evaluate(...args) { ++ return setPrototypeOf( ++ apply$2(super.evaluate, this, args), ++ XPathResult.prototype ++ ); ++ } ++ } ++ ++ class $XPathEvaluator extends XPathEvaluator { ++ createExpression(...args) { ++ return setPrototypeOf( ++ apply$2(super.createExpression, this, args), ++ $XPathExpression.prototype ++ ); ++ } ++ } ++ ++ function hideElement(element) { ++ if (variables$1.hidden.has(element)) ++ return; ++ ++ notifyElementHidden(element); ++ ++ variables$1.hidden.add(element); ++ ++ let {style} = $(element); ++ let $style = $(style, "CSSStyleDeclaration"); ++ let properties = $([]); ++ let {debugCSSProperties} = libEnvironment; ++ ++ for (let [key, value] of (debugCSSProperties || [["display", "none"]])) { ++ $style.setProperty(key, value, "important"); ++ properties.push([key, $style.getPropertyValue(key)]); ++ } ++ ++ new MutationObserver$2(() => { ++ for (let [key, value] of properties) { ++ let propertyValue = $style.getPropertyValue(key); ++ let propertyPriority = $style.getPropertyPriority(key); ++ if (propertyValue != value || propertyPriority != "important") ++ $style.setProperty(key, value, "important"); ++ } ++ }).observe(element, {attributes: true, ++ attributeFilter: ["style"]}); ++ } ++ ++ function notifyElementHidden(element) { ++ if (isExtensionContext && typeof checkElement === "function") ++ checkElement(element); ++ } ++ ++ function initQueryAndApply(selector) { ++ let $selector = selector; ++ if ($selector.startsWith("xpath(") && ++ $selector.endsWith(")")) { ++ let xpathQuery = $selector.slice(6, -1); ++ let evaluator = new $XPathEvaluator(); ++ let expression = evaluator.createExpression(xpathQuery, null); ++ ++ let flag = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE; ++ ++ return cb => { ++ if (!cb) ++ return; ++ let result = expression.evaluate(document$1, flag, null); ++ let {snapshotLength} = result; ++ for (let i = 0; i < snapshotLength; i++) ++ cb(result.snapshotItem(i)); ++ }; ++ } ++ return cb => $$(selector).forEach(cb); ++ } ++ ++ function initQueryAll(selector) { ++ let $selector = selector; ++ if ($selector.startsWith("xpath(") && ++ $selector.endsWith(")")) { ++ let queryAndApply = initQueryAndApply(selector); ++ return () => { ++ let elements = $([]); ++ queryAndApply(e => elements.push(e)); ++ return elements; ++ }; ++ } ++ return () => Array.from($$(selector)); ++ } ++ ++ let {ELEMENT_NODE, TEXT_NODE, prototype: NodeProto} = Node; ++ let {prototype: ElementProto$1} = Element; ++ let {prototype: HTMLElementProto} = HTMLElement; ++ ++ let { ++ console: console$2, ++ variables, ++ DOMParser, ++ Error: Error$5, ++ MutationObserver: MutationObserver$1, ++ Object: Object$5, ++ ReferenceError ++ } = $(window); ++ ++ let {getOwnPropertyDescriptor} = Object$5; ++ ++ function freezeElement(selector, options = "", ...exceptions) { ++ let observer; ++ let subtree = false; ++ let shouldAbort = false; ++ let exceptionSelectors = $(exceptions).filter(e => !isRegex(e)); ++ let regexExceptions = $(exceptions).filter(e => isRegex(e)).map(toRegExp); ++ let rid = randomId(); ++ let targetNodes; ++ let queryAll = initQueryAll(selector); ++ ++ checkOptions(); ++ let data = { ++ selector, ++ shouldAbort, ++ rid, ++ exceptionSelectors, ++ regexExceptions, ++ changeId: 0 ++ }; ++ if (!variables.frozen.has(document)) { ++ variables.frozen.set(document, true); ++ proxyNativeProperties(); ++ } ++ observer = new MutationObserver$1(searchAndAttach); ++ observer.observe(document, {childList: true, subtree: true}); ++ searchAndAttach(); ++ ++ function isRegex(s) { ++ return s.length >= 2 && s[0] == "/" && s[s.length - 1] == "/"; ++ } ++ ++ function checkOptions() { ++ let optionsChunks = $(options).split("+"); ++ if (optionsChunks.length === 1 && optionsChunks[0] === "") ++ optionsChunks = []; ++ for (let chunk of optionsChunks) { ++ switch (chunk) { ++ case "subtree": ++ subtree = true; ++ break; ++ case "abort": ++ shouldAbort = true; ++ break; ++ default: ++ throw new Error$5("[freeze] Unknown option passed to the snippet." + ++ " [selector]: " + selector + ++ " [option]: " + chunk); ++ } ++ } ++ } ++ ++ function proxyNativeProperties() { ++ let descriptor; ++ ++ descriptor = getAppendChildDescriptor( ++ NodeProto, "appendChild", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(NodeProto, "appendChild", descriptor); ++ ++ descriptor = getAppendChildDescriptor( ++ NodeProto, "insertBefore", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(NodeProto, "insertBefore", descriptor); ++ ++ descriptor = getAppendChildDescriptor( ++ NodeProto, "replaceChild", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(NodeProto, "replaceChild", descriptor); ++ ++ descriptor = getAppendDescriptor( ++ ElementProto$1, "append", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(ElementProto$1, "append", descriptor); ++ ++ descriptor = getAppendDescriptor( ++ ElementProto$1, "prepend", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(ElementProto$1, "prepend", descriptor); ++ ++ descriptor = getAppendDescriptor( ++ ElementProto$1, ++ "replaceWith", ++ isFrozenOrHasFrozenParent, ++ getSnippetDataFromNodeOrParent ++ ); ++ wrapPropertyAccess(ElementProto$1, "replaceWith", descriptor); ++ ++ descriptor = getAppendDescriptor( ++ ElementProto$1, ++ "after", ++ isFrozenOrHasFrozenParent, ++ getSnippetDataFromNodeOrParent ++ ); ++ wrapPropertyAccess(ElementProto$1, "after", descriptor); ++ ++ descriptor = getAppendDescriptor( ++ ElementProto$1, ++ "before", ++ isFrozenOrHasFrozenParent, ++ getSnippetDataFromNodeOrParent ++ ); ++ wrapPropertyAccess(ElementProto$1, "before", descriptor); ++ ++ descriptor = getInsertAdjacentDescriptor( ++ ElementProto$1, ++ "insertAdjacentElement", ++ isFrozenAndInsideTarget, ++ getSnippetDataBasedOnTarget ++ ); ++ wrapPropertyAccess(ElementProto$1, "insertAdjacentElement", descriptor); ++ ++ descriptor = getInsertAdjacentDescriptor( ++ ElementProto$1, ++ "insertAdjacentHTML", ++ isFrozenAndInsideTarget, ++ getSnippetDataBasedOnTarget ++ ); ++ wrapPropertyAccess(ElementProto$1, "insertAdjacentHTML", descriptor); ++ ++ descriptor = getInsertAdjacentDescriptor( ++ ElementProto$1, ++ "insertAdjacentText", ++ isFrozenAndInsideTarget, ++ getSnippetDataBasedOnTarget ++ ); ++ wrapPropertyAccess(ElementProto$1, "insertAdjacentText", descriptor); ++ ++ descriptor = getInnerHTMLDescriptor( ++ ElementProto$1, "innerHTML", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(ElementProto$1, "innerHTML", descriptor); ++ ++ descriptor = getInnerHTMLDescriptor( ++ ElementProto$1, ++ "outerHTML", ++ isFrozenOrHasFrozenParent, ++ getSnippetDataFromNodeOrParent ++ ); ++ wrapPropertyAccess(ElementProto$1, "outerHTML", descriptor); ++ ++ descriptor = getTextContentDescriptor( ++ NodeProto, "textContent", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(NodeProto, "textContent", descriptor); ++ ++ descriptor = getTextContentDescriptor( ++ HTMLElementProto, "innerText", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(HTMLElementProto, "innerText", descriptor); ++ ++ descriptor = getTextContentDescriptor( ++ NodeProto, "nodeValue", isFrozen, getSnippetData ++ ); ++ wrapPropertyAccess(NodeProto, "nodeValue", descriptor); ++ ++ function isFrozen(node) { ++ return node && variables.frozen.has(node); ++ } ++ ++ function isFrozenOrHasFrozenParent(node) { ++ try { ++ return node && ++ (variables.frozen.has(node) || ++ variables.frozen.has($(node).parentNode)); ++ } ++ catch (error) { ++ return false; ++ } ++ } ++ ++ function isFrozenAndInsideTarget(node, isInsideTarget) { ++ try { ++ return node && ++ (variables.frozen.has(node) && isInsideTarget || ++ variables.frozen.has($(node).parentNode) && ++ !isInsideTarget); ++ } ++ catch (error) { ++ return false; ++ } ++ } ++ ++ function getSnippetData(node) { ++ return variables.frozen.get(node); ++ } ++ ++ function getSnippetDataFromNodeOrParent(node) { ++ try { ++ if (variables.frozen.has(node)) ++ return variables.frozen.get(node); ++ let parent = $(node).parentNode; ++ return variables.frozen.get(parent); ++ } ++ catch (error) {} ++ } ++ ++ function getSnippetDataBasedOnTarget(node, isInsideTarget) { ++ try { ++ if (variables.frozen.has(node) && isInsideTarget) ++ return variables.frozen.get(node); ++ let parent = $(node).parentNode; ++ return variables.frozen.get(parent); ++ } ++ catch (error) {} ++ } ++ } ++ ++ function searchAndAttach() { ++ targetNodes = queryAll(); ++ markNodes(targetNodes, false); ++ } ++ ++ function markNodes(nodes, isChild = true) { ++ for (let node of nodes) { ++ if (!variables.frozen.has(node)) { ++ variables.frozen.set(node, data); ++ if (!isChild && subtree) { ++ new MutationObserver$1(mutationsList => { ++ for (let mutation of $(mutationsList)) ++ markNodes($(mutation, "MutationRecord").addedNodes); ++ }).observe(node, {childList: true, subtree: true}); ++ } ++ if (subtree && $(node).nodeType === ELEMENT_NODE) ++ markNodes($(node).childNodes); ++ } ++ } ++ } ++ ++ function logPrefixed(id, ...args) { ++ log(`[freeze][${id}] `, ...args); ++ } ++ ++ function logChange(nodeOrDOMString, target, property, snippetData) { ++ let targetSelector = snippetData.selector; ++ let chgId = snippetData.changeId; ++ let isDOMString = typeof nodeOrDOMString == "string"; ++ let action = snippetData.shouldAbort ? "aborting" : "watching"; ++ console$2.groupCollapsed(`[freeze][${chgId}] ${action}: ${targetSelector}`); ++ switch (property) { ++ case "appendChild": ++ case "append": ++ case "prepend": ++ case "insertBefore": ++ case "replaceChild": ++ case "insertAdjacentElement": ++ case "insertAdjacentHTML": ++ case "insertAdjacentText": ++ case "innerHTML": ++ case "outerHTML": ++ logPrefixed(chgId, ++ isDOMString ? "text: " : "node: ", ++ nodeOrDOMString); ++ logPrefixed(chgId, "added to node: ", target); ++ break; ++ case "replaceWith": ++ case "after": ++ case "before": ++ logPrefixed(chgId, ++ isDOMString ? "text: " : "node: ", ++ nodeOrDOMString); ++ logPrefixed(chgId, "added to node: ", $(target).parentNode); ++ break; ++ case "textContent": ++ case "innerText": ++ case "nodeValue": ++ logPrefixed(chgId, "content of node: ", target); ++ logPrefixed(chgId, "changed to: ", nodeOrDOMString); ++ break; ++ } ++ logPrefixed(chgId, `using the function "${property}"`); ++ console$2.groupEnd(); ++ snippetData.changeId++; ++ } ++ ++ function isExceptionNode(element, expSelectors) { ++ if (expSelectors) { ++ let $element = $(element); ++ for (let exception of expSelectors) { ++ if ($element.matches(exception)) ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ function isExceptionText(string, regExceptions) { ++ if (regExceptions) { ++ for (let exception of regExceptions) { ++ if (exception.test(string)) ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ function abort(id) { ++ throw new ReferenceError(id); ++ } ++ ++ function checkHTML(htmlText, parent, property, snippetData) { ++ let domparser = new DOMParser(); ++ let {body} = $(domparser.parseFromString(htmlText, "text/html")); ++ let nodes = $(body).childNodes; ++ let accepted = checkMultiple(nodes, parent, property, snippetData); ++ let content = $(accepted).map(node => { ++ switch ($(node).nodeType) { ++ case ELEMENT_NODE: ++ return $(node).outerHTML; ++ case TEXT_NODE: ++ return $(node).textContent; ++ default: ++ return ""; ++ } ++ }); ++ return content.join(""); ++ } ++ ++ function checkMultiple(nodesOrDOMStrings, parent, property, snippetData) { ++ let accepted = $([]); ++ for (let nodeOrDOMString of nodesOrDOMStrings) { ++ if (checkShouldInsert(nodeOrDOMString, parent, property, snippetData)) ++ accepted.push(nodeOrDOMString); ++ } ++ return accepted; ++ } ++ ++ function checkShouldInsert(nodeOrDOMString, parent, property, snippetData) { ++ let aborting = snippetData.shouldAbort; ++ let regExceptions = snippetData.regexExceptions; ++ let expSelectors = snippetData.exceptionSelectors; ++ let id = snippetData.rid; ++ if (typeof nodeOrDOMString == "string") { ++ let domString = nodeOrDOMString; ++ if (isExceptionText(domString, regExceptions)) ++ return true; ++ if (debug()) ++ logChange(domString, parent, property, snippetData); ++ if (aborting) ++ abort(id); ++ return debug(); ++ } ++ ++ let node = nodeOrDOMString; ++ switch ($(node).nodeType) { ++ case ELEMENT_NODE: ++ if (isExceptionNode(node, expSelectors)) ++ return true; ++ if (aborting) { ++ if (debug()) ++ logChange(node, parent, property, snippetData); ++ abort(id); ++ } ++ if (debug()) { ++ hideElement(node); ++ logChange(node, parent, property, snippetData); ++ return true; ++ } ++ return false; ++ case TEXT_NODE: ++ if (isExceptionText($(node).textContent, regExceptions)) ++ return true; ++ if (debug()) ++ logChange(node, parent, property, snippetData); ++ if (aborting) ++ abort(id); ++ return false; ++ default: ++ return true; ++ } ++ } ++ ++ function getAppendChildDescriptor(target, property, shouldValidate, ++ getSnippetData) { ++ let desc = getOwnPropertyDescriptor(target, property) || {}; ++ let origin = desc.get && call(desc.get, target) || desc.value; ++ if (!origin) ++ return; ++ ++ return { ++ get() { ++ return function(...args) { ++ if (shouldValidate(this)) { ++ let snippetData = getSnippetData(this); ++ if (snippetData) { ++ let incomingNode = args[0]; ++ if (!checkShouldInsert(incomingNode, this, property, snippetData)) ++ return incomingNode; ++ } ++ } ++ return apply$2(origin, this, args); ++ }; ++ } ++ }; ++ } ++ ++ function getAppendDescriptor( ++ target, property, shouldValidate, getSnippetData ++ ) { ++ let desc = getOwnPropertyDescriptor(target, property) || {}; ++ let origin = desc.get && call(desc.get, target) || desc.value; ++ if (!origin) ++ return; ++ return { ++ get() { ++ return function(...nodesOrDOMStrings) { ++ if (!shouldValidate(this)) ++ return apply$2(origin, this, nodesOrDOMStrings); ++ ++ let snippetData = getSnippetData(this); ++ if (!snippetData) ++ return apply$2(origin, this, nodesOrDOMStrings); ++ ++ let accepted = checkMultiple( ++ nodesOrDOMStrings, this, property, snippetData ++ ); ++ if (accepted.length > 0) ++ return apply$2(origin, this, accepted); ++ }; ++ } ++ }; ++ } ++ ++ function getInsertAdjacentDescriptor( ++ target, property, shouldValidate, getSnippetData ++ ) { ++ let desc = getOwnPropertyDescriptor(target, property) || {}; ++ let origin = desc.get && call(desc.get, target) || desc.value; ++ if (!origin) ++ return; ++ ++ return { ++ get() { ++ return function(...args) { ++ let [position, value] = args; ++ let isInsideTarget = ++ position === "afterbegin" || position === "beforeend"; ++ if (shouldValidate(this, isInsideTarget)) { ++ let snippetData = getSnippetData(this, isInsideTarget); ++ if (snippetData) { ++ let parent = isInsideTarget ? ++ this : ++ $(this).parentNode; ++ let finalValue; ++ switch (property) { ++ case "insertAdjacentElement": ++ if (!checkShouldInsert(value, parent, property, snippetData)) ++ return value; ++ break; ++ ++ case "insertAdjacentHTML": ++ finalValue = checkHTML(value, parent, property, snippetData); ++ if (finalValue) ++ return call(origin, this, position, finalValue); ++ ++ return; ++ ++ case "insertAdjacentText": ++ if (!checkShouldInsert(value, parent, property, snippetData)) ++ return; ++ break; ++ } ++ } ++ } ++ return apply$2(origin, this, args); ++ }; ++ } ++ }; ++ } ++ ++ function getInnerHTMLDescriptor( ++ target, property, shouldValidate, getSnippetData ++ ) { ++ let desc = getOwnPropertyDescriptor(target, property) || {}; ++ let {set: prevSetter} = desc; ++ if (!prevSetter) ++ return; ++ ++ return { ++ set(htmlText) { ++ if (!shouldValidate(this)) ++ return call(prevSetter, this, htmlText); ++ ++ let snippetData = getSnippetData(this); ++ if (!snippetData) ++ return call(prevSetter, this, htmlText); ++ let finalValue = checkHTML(htmlText, this, property, snippetData); ++ if (finalValue) ++ return call(prevSetter, this, finalValue); ++ } ++ }; ++ } ++ ++ function getTextContentDescriptor( ++ target, property, shouldValidate, getSnippetData ++ ) { ++ let desc = getOwnPropertyDescriptor(target, property) || {}; ++ let {set: prevSetter} = desc; ++ if (!prevSetter) ++ return; ++ ++ return { ++ set(domString) { ++ if (!shouldValidate(this)) ++ return call(prevSetter, this, domString); ++ ++ let snippetData = getSnippetData(this); ++ if (!snippetData) ++ return call(prevSetter, this, domString); ++ if (checkShouldInsert(domString, this, property, snippetData)) ++ return call(prevSetter, this, domString); ++ } ++ }; ++ } ++ } ++ ++ $(window); ++ ++ function raceWinner(name, lose) { ++ ++ return noop; ++ } ++ ++ const {Map: Map$4, MutationObserver, Object: Object$4, Set, WeakSet: WeakSet$1} = $(window); ++ ++ let ElementProto = Element.prototype; ++ let {attachShadow} = ElementProto; ++ ++ let hiddenShadowRoots = new WeakSet$1(); ++ let searches = new Map$4(); ++ let observer = null; ++ ++ function hideIfShadowContains(search, selector = "*") { ++ ++ let key = `${search}\\${selector}`; ++ if (!searches.has(key)) { ++ searches.set(key, [toRegExp(search), selector, raceWinner() ++ ]); ++ } ++ ++ const debugLog = getDebugger("hide-if-shadow-contain"); ++ ++ if (!observer) { ++ observer = new MutationObserver(records => { ++ let visited = new Set(); ++ for (let {target} of $(records)) { ++ ++ let parent = $(target).parentNode; ++ while (parent) ++ [target, parent] = [parent, $(target).parentNode]; ++ ++ if (hiddenShadowRoots.has(target)) ++ continue; ++ ++ if (visited.has(target)) ++ continue; ++ ++ visited.add(target); ++ for (let [re, selfOrParent, win] of searches.values()) { ++ if (re.test($(target).textContent)) { ++ let closest = $(target.host).closest(selfOrParent); ++ if (closest) { ++ win(); ++ ++ $(target).appendChild( ++ document.createElement("style") ++ ).textContent = ":host {display: none !important}"; ++ ++ hideElement(closest); ++ ++ hiddenShadowRoots.add(target); ++ debugLog("Hiding: ", closest, " for params: ", ...arguments); ++ } ++ } ++ } ++ } ++ }); ++ ++ Object$4.defineProperty(ElementProto, "attachShadow", { ++ ++ value: proxy(attachShadow, function() { ++ ++ let root = apply$2(attachShadow, this, arguments); ++ debugLog("attachShadow is called for: ", root); ++ ++ observer.observe(root, { ++ childList: true, ++ characterData: true, ++ subtree: true ++ }); ++ ++ return root; ++ }) ++ }); ++ } ++ } ++ ++ const {Error: Error$4, JSON: JSON$2, Map: Map$3, Object: Object$3} = $(window); ++ ++ let paths$1 = null; ++ ++ function jsonOverride(rawOverridePaths, value, ++ rawNeedlePaths = "", filter = "") { ++ if (!rawOverridePaths) ++ throw new Error$4("[json-override snippet]: Missing paths to override."); ++ ++ if (typeof value == "undefined") ++ throw new Error$4("[json-override snippet]: No value to override with."); ++ ++ if (!paths$1) { ++ let debugLog = getDebugger("json-override"); ++ ++ let {parse} = JSON$2; ++ paths$1 = new Map$3(); ++ ++ Object$3.defineProperty(window.JSON, "parse", { ++ value: proxy(parse, function(str) { ++ let result = apply$2(parse, this, arguments); ++ ++ for (let {prune, needle, filter: flt, value: val} of paths$1.values()) { ++ if (flt && !flt.test(str)) ++ continue; ++ ++ if ($(needle).some(path => !findOwner(result, path))) ++ return result; ++ ++ for (let path of prune) { ++ let details = findOwner(result, path); ++ if (typeof details != "undefined") { ++ debugLog(`Found ${path} replaced it with ${val}`); ++ details[0][details[1]] = overrideValue(val); ++ } ++ } ++ } ++ ++ return result; ++ }) ++ }); ++ debugLog("Wrapped JSON.parse for override"); ++ } ++ ++ paths$1.set(rawOverridePaths, { ++ prune: $(rawOverridePaths).split(/ +/), ++ needle: rawNeedlePaths.length ? $(rawNeedlePaths).split(/ +/) : [], ++ filter: filter ? toRegExp(filter) : null, ++ value ++ }); ++ } ++ ++ let {Error: Error$3, JSON: JSON$1, Map: Map$2, Object: Object$2} = $(window); ++ ++ let paths = null; ++ ++ function jsonPrune(rawPrunePaths, rawNeedlePaths = "") { ++ if (!rawPrunePaths) ++ throw new Error$3("Missing paths to prune"); ++ ++ if (!paths) { ++ let debugLog = getDebugger("json-prune"); ++ ++ let {parse} = JSON$1; ++ paths = new Map$2(); ++ ++ Object$2.defineProperty(window.JSON, "parse", { ++ value: proxy(parse, function() { ++ let result = apply$2(parse, this, arguments); ++ ++ for (let {prune, needle} of paths.values()) { ++ if ($(needle).some(path => !findOwner(result, path))) ++ return result; ++ ++ for (let path of prune) { ++ let details = findOwner(result, path); ++ if (typeof details != "undefined") { ++ debugLog(`Found ${path} and deleted`); ++ delete details[0][details[1]]; ++ } ++ } ++ } ++ ++ return result; ++ }) ++ }); ++ debugLog("Wrapped JSON.parse for prune"); ++ } ++ ++ paths.set(rawPrunePaths, { ++ prune: $(rawPrunePaths).split(/ +/), ++ needle: rawNeedlePaths.length ? $(rawNeedlePaths).split(/ +/) : [] ++ }); ++ } ++ ++ let {Error: Error$2} = $(window); ++ ++ function overridePropertyRead(property, value) { ++ if (!property) { ++ throw new Error$2("[override-property-read snippet]: " + ++ "No property to override."); ++ } ++ if (typeof value === "undefined") { ++ throw new Error$2("[override-property-read snippet]: " + ++ "No value to override with."); ++ } ++ ++ let debugLog = getDebugger("override-property-read"); ++ ++ let cValue = overrideValue(value); ++ ++ let newGetter = () => { ++ debugLog(`${property} override done.`); ++ return cValue; ++ }; ++ ++ debugLog(`Overriding ${property}.`); ++ ++ wrapPropertyAccess(window, property, {get: newGetter, set() {}}); ++ } ++ ++ let {Error: Error$1, Map: Map$1, Object: Object$1, console: console$1} = $(window); ++ ++ let {toString} = Function.prototype; ++ let EventTargetProto = EventTarget.prototype; ++ let {addEventListener} = EventTargetProto; ++ ++ let events = null; ++ ++ function preventListener(event, eventHandler, selector) { ++ if (!event) ++ throw new Error$1("[prevent-listener snippet]: No event type."); ++ ++ if (!events) { ++ events = new Map$1(); ++ ++ let debugLog = getDebugger("[prevent]"); ++ ++ Object$1.defineProperty(EventTargetProto, "addEventListener", { ++ value: proxy(addEventListener, function(type, listener) { ++ for (let {evt, handlers, selectors} of events.values()) { ++ ++ if (!evt.test(type)) ++ continue; ++ ++ let isElement = this instanceof Element; ++ ++ for (let i = 0; i < handlers.length; i++) { ++ let handler = handlers[i]; ++ let sel = selectors[i]; ++ ++ let handlerMatch = () => handler.test( ++ call( ++ toString, ++ typeof listener === "function" ? ++ listener : listener.handleEvent ++ ) ++ ); ++ ++ if ( ++ (handler && !handlerMatch()) || ++ (sel && !(isElement && $(this).matches(sel))) ++ ) ++ continue; ++ ++ if (debug()) { ++ console$1.groupCollapsed("DEBUG [prevent] was successful"); ++ debugLog(`type: ${type} matching ${evt}`); ++ debugLog("handler:", listener); ++ if (handler) ++ debugLog(`matching ${handler}`); ++ if (sel) ++ debugLog("on element: ", this, ` matching ${sel}`); ++ debugLog("was prevented from being added"); ++ console$1.groupEnd(); ++ } ++ return; ++ } ++ } ++ return apply$2(addEventListener, this, arguments); ++ }) ++ }); ++ ++ debugLog("Wrapped addEventListener"); ++ } ++ ++ if (!events.has(event)) ++ events.set(event, {evt: toRegExp(event), handlers: [], selectors: []}); ++ ++ let {handlers, selectors} = events.get(event); ++ ++ handlers.push(eventHandler ? toRegExp(eventHandler) : null); ++ selectors.push(selector); ++ } ++ ++ let {URL, fetch} = $(window); ++ ++ let {delete: deleteParam, has: hasParam} = caller(URLSearchParams.prototype); ++ ++ let parameters; ++ ++ function stripFetchQueryParameter(name, urlPattern = null) { ++ const debugLog = getDebugger("strip-fetch-query-parameter"); ++ ++ if (!parameters) { ++ parameters = new Map(); ++ window.fetch = proxy(fetch, (...args) => { ++ let [source] = args; ++ if (typeof source === "string") { ++ let url = new URL(source); ++ for (let [key, reg] of parameters) { ++ if (!reg || reg.test(source)) { ++ if (hasParam(url.searchParams, key)) { ++ debugLog(`${key} has been stripped from url ${source}`); ++ deleteParam(url.searchParams, key); ++ args[0] = url.href; ++ } ++ } ++ } ++ } ++ return apply$2(fetch, self, args); ++ }); ++ } ++ parameters.set(name, urlPattern && toRegExp(urlPattern)); ++ } ++ ++ function trace(...args) { ++ ++ apply$2(log, null, args); ++ } ++ ++ const snippets = { ++ "abort-current-inline-script": abortCurrentInlineScript, ++ "abort-on-iframe-property-read": abortOnIframePropertyRead, ++ "abort-on-iframe-property-write": abortOnIframePropertyWrite, ++ "abort-on-property-read": abortOnPropertyRead, ++ "abort-on-property-write": abortOnPropertyWrite, ++ "cookie-remover": cookieRemover, ++ "debug": setDebug, ++ "freeze-element": freezeElement, ++ "hide-if-shadow-contains": hideIfShadowContains, ++ "json-override": jsonOverride, ++ "json-prune": jsonPrune, ++ "override-property-read": overridePropertyRead, ++ "prevent-listener": preventListener, ++ "strip-fetch-query-parameter": stripFetchQueryParameter, ++ "trace": trace ++ }; ++ let context; ++ for (const [name, ...args] of filters) { ++ if (snippets.hasOwnProperty(name)) { ++ try { context = snippets[name].apply(context, args); } ++ catch (error) { console.error(error); } ++ } ++ } ++ context = void 0; ++}; ++const graph = new Map([["abort-current-inline-script",null],["abort-on-iframe-property-read",null],["abort-on-iframe-property-write",null],["abort-on-property-read",null],["abort-on-property-write",null],["cookie-remover",null],["debug",null],["freeze-element",null],["hide-if-shadow-contains",null],["json-override",null],["json-prune",null],["override-property-read",null],["prevent-listener",null],["strip-fetch-query-parameter",null],["trace",null]]); ++callback.get = snippet => graph.get(snippet); ++callback.has = snippet => graph.has(snippet); ++ ++ if (t.every(([name]) => !callback.has(name))) return; ++ const append = () => { ++ URL.revokeObjectURL( ++ Object.assign( ++ document.documentElement.appendChild(document.createElement("script")), ++ {async: false, src: URL.createObjectURL(new Blob([ ++ "(" + callback + ")(..." + JSON.stringify([e, ...t]) + ")" ++ ]))} ++ ).src ++ ); ++ }; ++ try { append(); } ++ catch (_) { ++ document.addEventListener("readystatechange", append, {once:true}); ++ } ++} diff --git a/components/resources/adblocking/snippets/dist/isolated-first.jst b/components/resources/adblocking/snippets/dist/isolated-first.jst new file mode 100755 --- /dev/null @@ -4531,7 +8344,7 @@ new file mode 100755 @@ -0,0 +1,3624 @@ +(e, ...t) => { +/*! -+ * snippets v0.7.0 ++ * snippets v0.7.0 (https://gitlab.com/eyeo/anti-cv/snippets/-/tree/5f54b58f039a604088d65991f2829a9a081832f6/dist) + * https://gitlab.com/eyeo/snippets/-/commit/d7c80795567d9f9c44a6ebaa789baceab85f31f9 + * + * This file is part of eyeo's Anti-Circumvention Snippets module (@eyeo/snippets), @@ -8202,6 +12015,15 @@ diff --git a/third_party/blink/renderer/core/exported/web_document.cc b/third_pa auto* parsed_sheet = MakeGarbageCollected( MakeGarbageCollected(*document)); parsed_sheet->ParseString(source_code); +@@ -283,7 +293,7 @@ WebStyleSheetKey WebDocument::InsertAbpElemhideStylesheet( + if (IsValidAbpRule(parsed_sheet->RuleAt(n))) + ++n; + else { +- parsed_sheet->SetMutable(); ++ parsed_sheet->StartMutation(); + parsed_sheet->WrapperDeleteRule(n); + LOG(WARNING) << "[eyeo] Broken rule"; + } @@ -295,9 +305,6 @@ WebStyleSheetKey WebDocument::InsertAbpElemhideStylesheet( {SchedulingPolicy::DisableBackForwardCache()}); } @@ -8212,17 +12034,6 @@ diff --git a/third_party/blink/renderer/core/exported/web_document.cc b/third_pa document->GetStyleEngine().InjectSheet(injection_key, parsed_sheet, origin); return injection_key; } -diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec ---- a/tools/gritsettings/resource_ids.spec -+++ b/tools/gritsettings/resource_ids.spec -@@ -678,7 +678,6 @@ - "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/hats/resources.grd": { - "META": {"sizes": {"includes": [10]}}, - "includes": [4980], -- }, - # END chrome/ WebUI resources section - - # START chrome/ miscellaneous section. diff --git a/tools/typescript/definitions/adblock_private.d.ts b/tools/typescript/definitions/adblock_private.d.ts --- a/tools/typescript/definitions/adblock_private.d.ts +++ b/tools/typescript/definitions/adblock_private.d.ts diff --git a/build/patches/00Fix-chromium-build-bugs.patch b/build/patches/00Fix-chromium-build-bugs.patch index 7fecc35e..7337ce36 100644 --- a/build/patches/00Fix-chromium-build-bugs.patch +++ b/build/patches/00Fix-chromium-build-bugs.patch @@ -2,31 +2,39 @@ From: Your Name Date: Wed, 6 Sep 2023 17:55:01 +0000 Subject: Fix chromium build bugs +because of +https://bugs.chromium.org/p/chromium/issues/detail?id=1491776#c10 --- - BUILD.gn | 1 - - .../AutofillSaveCardBottomSheetBridge.java | 2 +- - .../org/chromium/chrome/browser/tab/TabImpl.java | 2 +- - ...me_browser_main_extra_parts_nacl_deprecation.cc | 2 ++ - .../api/autofill_private/autofill_util.cc | 2 ++ - .../api/reading_list/reading_list_event_router.h | 2 +- - .../navigation_predictor_metrics_document_data.h | 2 ++ - chrome/browser/safe_browsing/BUILD.gn | 1 + - ..._auction_consented_debugging_infobar_delegate.h | 2 +- - .../read_anything/read_anything_container_view.cc | 12 ++++++------ - chrome/browser/ui/views/tabs/tab.cc | 2 +- - chrome/browser/ui/views/tabs/tab_group_header.cc | 2 +- - .../app_management/app_management_page_handler.cc | 2 ++ - chrome/browser/usb/chrome_usb_delegate.cc | 2 ++ - .../autofill/core/browser/data_model/address.cc | 4 ++-- - components/autofill/core/browser/form_structure.cc | 2 ++ - .../core/browser/webdata/autofill_table.cc | 12 ++++++------ - components/omnibox/browser/omnibox_field_trial.cc | 4 ++-- - .../phishing_classifier/phishing_image_embedder.cc | 14 +++----------- - content/browser/browser_interface_binders.cc | 1 + - crypto/BUILD.gn | 3 +++ - net/BUILD.gn | 1 + - third_party/libevent/BUILD.gn | 2 ++ - 23 files changed, 45 insertions(+), 34 deletions(-) + BUILD.gn | 1 - + .../AutofillSaveCardBottomSheetBridge.java | 2 +- + .../chromium/chrome/browser/tab/TabImpl.java | 2 +- + .../intent_helper/intent_picker_helpers.cc | 2 ++ + ...owser_main_extra_parts_nacl_deprecation.cc | 2 ++ + .../download/download_ui_safe_browsing_util.h | 2 +- + .../api/autofill_private/autofill_util.cc | 2 ++ + .../reading_list/reading_list_event_router.h | 2 +- + ...vigation_predictor_metrics_document_data.h | 2 ++ + chrome/browser/safe_browsing/BUILD.gn | 1 + + .../tpcd/support/tpcd_support_manager.cc | 2 +- + ...ion_consented_debugging_infobar_delegate.h | 2 +- + .../read_anything_container_view.cc | 12 +++---- + chrome/browser/ui/views/tabs/tab.cc | 2 +- + .../browser/ui/views/tabs/tab_group_header.cc | 2 +- + .../app_management_page_handler.cc | 2 ++ + chrome/browser/usb/chrome_usb_delegate.cc | 2 ++ + .../core/browser/data_model/address.cc | 2 +- + .../autofill/core/browser/form_structure.cc | 2 ++ + .../core/browser/webdata/autofill_table.cc | 36 +++++++++---------- + .../omnibox/browser/autocomplete_controller.h | 2 +- + .../omnibox/browser/omnibox_field_trial.cc | 4 +-- + components/omnibox/browser/omnibox_view.cc | 2 ++ + .../browser/tailored_word_break_iterator.cc | 2 +- + .../phishing_image_embedder.cc | 14 ++------ + content/browser/browser_interface_binders.cc | 1 + + crypto/BUILD.gn | 3 ++ + net/BUILD.gn | 1 + + third_party/libevent/BUILD.gn | 2 ++ + 29 files changed, 64 insertions(+), 49 deletions(-) diff --git a/BUILD.gn b/BUILD.gn --- a/BUILD.gn @@ -63,6 +71,25 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.jav public int getId() { return mId; } +diff --git a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc +--- a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc ++++ b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc +@@ -32,6 +32,7 @@ + namespace apps { + namespace { + ++#if BUILDFLAG(IS_MAC) + std::vector CombinePossibleMacAppWithOtherApps( + std::vector apps, + absl::optional mac_app) { +@@ -40,6 +41,7 @@ std::vector CombinePossibleMacAppWithOtherApps( + } + return apps; + } ++#endif + + PickerEntryType GetPickerEntryType(AppType app_type) { + PickerEntryType picker_entry_type = PickerEntryType::kUnknown; diff --git a/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc b/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc --- a/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc +++ b/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc @@ -82,6 +109,18 @@ diff --git a/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc } // namespace +diff --git a/chrome/browser/download/download_ui_safe_browsing_util.h b/chrome/browser/download/download_ui_safe_browsing_util.h +--- a/chrome/browser/download/download_ui_safe_browsing_util.h ++++ b/chrome/browser/download/download_ui_safe_browsing_util.h +@@ -9,7 +9,7 @@ class Profile; + + namespace download { + class DownloadItem; +-}; ++} + + // Utilities for determining how to display a download in the desktop UI based + // on Safe Browsing state and verdict. diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc --- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc @@ -136,6 +175,18 @@ diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsin ] if (safe_browsing_mode == 1) { # "Safe Browsing Full" files in addition to the "basic" ones to use for +diff --git a/chrome/browser/tpcd/support/tpcd_support_manager.cc b/chrome/browser/tpcd/support/tpcd_support_manager.cc +--- a/chrome/browser/tpcd/support/tpcd_support_manager.cc ++++ b/chrome/browser/tpcd/support/tpcd_support_manager.cc +@@ -38,7 +38,7 @@ TpcdSupportManager::TpcdSupportManager( + std::unique_ptr delegate) + : content::WebContentsObserver(web_contents), + content::WebContentsUserData(*web_contents), +- delegate_(std::move(delegate)){}; ++ delegate_(std::move(delegate)){} + + TpcdSupportManager::~TpcdSupportManager() = default; + diff --git a/chrome/browser/ui/startup/bidding_and_auction_consented_debugging_infobar_delegate.h b/chrome/browser/ui/startup/bidding_and_auction_consented_debugging_infobar_delegate.h --- a/chrome/browser/ui/startup/bidding_and_auction_consented_debugging_infobar_delegate.h +++ b/chrome/browser/ui/startup/bidding_and_auction_consented_debugging_infobar_delegate.h @@ -235,15 +286,6 @@ diff --git a/chrome/browser/usb/chrome_usb_delegate.cc b/chrome/browser/usb/chro diff --git a/components/autofill/core/browser/data_model/address.cc b/components/autofill/core/browser/data_model/address.cc --- a/components/autofill/core/browser/data_model/address.cc +++ b/components/autofill/core/browser/data_model/address.cc -@@ -40,7 +40,7 @@ Address::Address(AddressCountryCode country_code) - !i18n_model_definition::IsCustomHierarchyAvailableForCountry( - country_code)) {} - --Address::~Address() = default; -+Address::~Address() = default - - Address& Address::operator=(const Address& address) { - if (this == &address) { @@ -59,7 +59,7 @@ Address& Address::operator=(const Address& address) { structured_address_->CopyFrom(address.GetStructuredAddress()); @@ -275,25 +317,61 @@ diff --git a/components/autofill/core/browser/form_structure.cc b/components/aut diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc --- a/components/autofill/core/browser/webdata/autofill_table.cc +++ b/components/autofill/core/browser/webdata/autofill_table.cc -@@ -426,12 +426,12 @@ void InsertBuilder(sql::Database* db, - } - - // Renames the table `from` into `to` and returns true if successful. --bool RenameTable(sql::Database* db, -- std::string_view from, -- std::string_view to) { -- return db->Execute( -- base::StrCat({"ALTER TABLE ", from, " RENAME TO ", to}).c_str()); +@@ -961,24 +961,24 @@ time_t GetEndTime(const base::Time& end) { + // Returns |s| with |escaper| in front of each of occurrence of a character + // from |special_chars|. Any occurrence of |escaper| in |s| is doubled. For + // example, Substitute("hello_world!", "_%", '!'') returns "hello!_world!!". +-std::u16string Substitute(const std::u16string& s, +- const std::u16string& special_chars, +- const char16_t& escaper) { +- // Prepend |escaper| to the list of |special_chars|. +- std::u16string escape_wildcards(special_chars); +- escape_wildcards.insert(escape_wildcards.begin(), escaper); +- +- // Prepend the |escaper| just before |special_chars| in |s|. +- std::u16string result(s); +- for (char16_t c : escape_wildcards) { +- for (size_t pos = 0; (pos = result.find(c, pos)) != std::u16string::npos; +- pos += 2) { +- result.insert(result.begin() + pos, escaper); +- } +- } +- +- return result; -} -+// bool RenameTable(sql::Database* db, -+// std::string_view from, -+// std::string_view to) { -+// return db->Execute( -+// base::StrCat({"ALTER TABLE ", from, " RENAME TO ", to}).c_str()); ++// std::u16string Substitute(const std::u16string& s, ++// const std::u16string& special_chars, ++// const char16_t& escaper) { ++// // Prepend |escaper| to the list of |special_chars|. ++// std::u16string escape_wildcards(special_chars); ++// escape_wildcards.insert(escape_wildcards.begin(), escaper); ++ ++// // Prepend the |escaper| just before |special_chars| in |s|. ++// std::u16string result(s); ++// for (char16_t c : escape_wildcards) { ++// for (size_t pos = 0; (pos = result.find(c, pos)) != std::u16string::npos; ++// pos += 2) { ++// result.insert(result.begin() + pos, escaper); ++// } ++// } ++ ++// return result; +// } - // Wrapper around `sql::Database::DoesColumnExist()`, because that function - // only accepts const char* parameters. + // This helper function binds the `profile`s properties to the placeholders in + // `s`, in the order the columns are defined in the header file. +diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h +--- a/components/omnibox/browser/autocomplete_controller.h ++++ b/components/omnibox/browser/autocomplete_controller.h +@@ -208,7 +208,7 @@ class AutocompleteController : public AutocompleteProviderListener, + OpenTabProvider* open_tab_provider() const { return open_tab_provider_; } + + const AutocompleteInput& input() const { return input_; } +- const AutocompleteResult& result() const { return published_result_; }; ++ const AutocompleteResult& result() const { return published_result_; } + // Groups `published_result_` by search vs URL. + // See also `AutocompleteResult::GroupSuggestionsBySearchVsURL()`. + void GroupSuggestionsBySearchVsURL(size_t begin, size_t end); diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc @@ -311,6 +389,36 @@ diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omni } MLConfig& ScopedMLConfigForTesting::GetMLConfig() { +diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc +--- a/components/omnibox/browser/omnibox_view.cc ++++ b/components/omnibox/browser/omnibox_view.cc +@@ -56,12 +56,14 @@ bool RichAutocompletionEitherNonPrefixEnabled() { + kRichAutocompletionAutocompleteNonPrefixShortcutProvider.Get(); + } + ++#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) + // Return true if the given match uses a vector icon with a background. + bool HasVectorIconBackground(const AutocompleteMatch& match) { + return OmniboxFieldTrial::IsActionsUISimplificationEnabled() && + (match.type == AutocompleteMatchType::HISTORY_CLUSTER || + match.type == AutocompleteMatchType::PEDAL); + } ++#endif + + } // namespace + +diff --git a/components/omnibox/browser/tailored_word_break_iterator.cc b/components/omnibox/browser/tailored_word_break_iterator.cc +--- a/components/omnibox/browser/tailored_word_break_iterator.cc ++++ b/components/omnibox/browser/tailored_word_break_iterator.cc +@@ -18,7 +18,7 @@ TailoredWordBreakIterator::TailoredWordBreakIterator( + pos_(0), + word_breaks_{u"0123456789"}, + non_word_breaks_{u"_"}, +- all_breaks_{word_breaks_ + non_word_breaks_} {}; ++ all_breaks_{word_breaks_ + non_word_breaks_} {} + + TailoredWordBreakIterator::~TailoredWordBreakIterator() {} + diff --git a/components/safe_browsing/content/renderer/phishing_classifier/phishing_image_embedder.cc b/components/safe_browsing/content/renderer/phishing_classifier/phishing_image_embedder.cc --- a/components/safe_browsing/content/renderer/phishing_classifier/phishing_image_embedder.cc +++ b/components/safe_browsing/content/renderer/phishing_classifier/phishing_image_embedder.cc diff --git a/build/patches/00Internal-firewall.patch b/build/patches/00Internal-firewall.patch index 969d48d1..3e33d1ca 100644 --- a/build/patches/00Internal-firewall.patch +++ b/build/patches/00Internal-firewall.patch @@ -24,9 +24,9 @@ License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html services/firewall/public/firewall_service.cc | 46 ++ services/firewall/public/firewall_service.h | 57 +++ services/firewall/tools/annotation_model.py | 49 ++ - services/firewall/tools/annotations.xml | 448 ++++++++++++++++++ + services/firewall/tools/annotations.xml | 466 ++++++++++++++++++ services/firewall/tools/builders_template.py | 72 +++ - services/firewall/tools/codegen.py | 82 ++++ + services/firewall/tools/codegen.py | 82 +++ services/firewall/tools/decode_template.py | 85 ++++ services/firewall/tools/gen_builders.py | 65 +++ services/firewall/tools/rules.xml | 83 ++++ @@ -34,11 +34,11 @@ License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html services/network/network_context.cc | 73 +++ .../network/public/cpp/simple_url_loader.cc | 18 + .../network/public/cpp/simple_url_loader.h | 3 + - .../platform/loader/fetch/fetch_utils.cc | 171 ++++++- + .../platform/loader/fetch/fetch_utils.cc | 191 ++++++- .../loader/fetch/url_loader/url_loader.cc | 4 +- .../scripts/auditor/auditor.py | 1 + .../scripts/auditor/util.py | 1 + - 29 files changed, 1527 insertions(+), 21 deletions(-) + 29 files changed, 1566 insertions(+), 20 deletions(-) create mode 100644 services/firewall/public/BUILD.gn create mode 100644 services/firewall/public/firewall_features.cc create mode 100644 services/firewall/public/firewall_features.h @@ -625,7 +625,7 @@ diff --git a/services/firewall/tools/annotations.xml b/services/firewall/tools/a new file mode 100644 --- /dev/null +++ b/services/firewall/tools/annotations.xml -@@ -0,0 +1,448 @@ +@@ -0,0 +1,466 @@ + +